标签:关机 cti 设备驱动 art api min 行操作 映射 并且
阅读附件中的代码,回答:
一、ucos是如何分层的
共分三层,分别是:上层访问抽象接口层、设备管理核心数据结构层、硬件设备驱动模块层。
(1)上层访问抽象接口层: 一般的抽象层设计会直接在这一层提供5个访问接口API: DeviceOpen、DevGetch、DevPutch、DevControl. DeviceClose,分别用于打开设备、读设备、写设备、设备控制和关闭设备。而在这个设计里面更改了这种定义模式提供两个公用的接口DeviceOpen 和DeviceClose,同时为不同的外设分别提供特定的抽象接口,在移植的时候利
用这些抽象接口的不变性保证应用程序的可移植能力。这样做的优点更适合于有单片机开发经验的工程人员直接调用。
例如UART提供的抽象接口有: v. _MiniPrintf最小格式化字符串函数;UARTSet串口参数设置。暂时没实再格式化字符输入。
IIC提供的抽象接口有: I2CMasterSend IIC 主模式发送;
I2CMasterReceive IIC 主模式接收; I2CSlaverReceive IIC 从模式接收。
其它的还有SPI,外部中断管理。在里只简单介绍下UART和IIC。
(2)设备管理核心数据结构层:这是通用驱动框架的核心,主要用每个设备分配一个设备控制块,通过链表形式进行管理,该链表定义为设备控制块链表DEV_CONTROL_BLOCK* HvlConList。 在这一层, 为系统中的每个硬件设备分配唯一的设备ID。上层应用程序通过将设备ID作为参数传递给DeviceOpen函数实现对相应设备的核心管理数据结构的定位搜索,通过搜索,DeviceOpen函数找到相应设备控制块,申请设备的使用权限,获得相应硬件设备的操作句柄,该句柄指向具体的外设底层操作函数列表,返回该设备句柄;再通过上层抽象接口层提供的接口函数对设备进行访问。
(3)硬件设备驱动模块层:这-一层是硬件设备驱动模块功能的实现层,对各个硬件设备的驱动在相应的硬件设备驱动模块中完成。各个硬件设备驱动模块,原则上需要实现如下几个函数: DevGetch、 DevPut ch、DevControl,分别完成相应设备的读、写、控制,当然,可以根据具体设备的特性,只实现3个驱动函数的其中一部分,例如,如果某设备不支持写操作,那么就不
用实现DevPutch函数。
二、HAL都有哪些代码
#if defined(STM32F205xx)
#include "stm32f205xx.h"
#elif defined(STM32F215xx)
#include "stm32f215xx.h"
#elif defined(STM32F207xx)
#include "stm32f207xx.h"
#elif defined(STM32F217xx)
#include "stm32f217xx.h"
#else
#error "Please select first the target STM32F2xx device used in your application (in stm32f2xx.h file)"
#endif
stm32f2xx_hal.h:stm32f2xx_hal.c/h 主要实现HAL库的初始化、系统滴答相关函数、及CPU的调试模式配置
stm32f2xx_hal_conf.h :该文件是一个用户级别的配置文件,用来实现对HAL库的裁剪,其位于用户文件目录,不要放在库目录中
用户级别文件:
stm32f2xx_hal_msp_template.c // 只有.c没有.h。它包含用户应用程序中使用的外设的MSP初始化和反初始化(主程序和回调函数)。使用者复制到自己目录下使用模板。
stm32f2xx_hal_conf_template.h // 用户级别的库配置文件模板。使用者复制到自己目录下使用
system_stm32f2xx.c // 此文件主要包含SystemInit()函数,该函数在刚复位及跳到main之前的启动过程中被调用。 **它不在启动时配置系统时钟(与标准库相反)**。 时钟的配置在用户文件中使用HAL API来完成。
startup_stm32f2xx.s // 芯片启动文件,主要包含堆栈定义,终端向量表等
stm32f2xx_it.c/.h // 中断处理函数的相关实现
main.c/.h
三、分析任务是如何切换的
一般函数的生命周期很简单,从开始调用函数起,直到函数返回,即结束。这样一来就完成了这个函数的使命,它也就不再需要了。对于一般的函数就是这样,但是回过头想想,对于一个系统、OS、或者工业控制中的一个控制器重的系统个,函数返回是很轻易很随便的就能返回吗?返回就意味着函数结束,死亡,若是想系统这样一个很大的函数,它的返回就意味着系统结束。因此,对于系统的函数返回有些时候我们不希望它返回,返回时是需要好好设计的,像嵌入式中的控制程序我们也并不需要它返回,直接关机就好了。因此,一个系统往往就是一个很大的循环,不停的扫描,而我们编程的时候对于这个死循环是需要好好设计的。考虑以下一个控制要求,
@.按键控制电机启、停、正转反转,并每秒发送CAN报文报告当前情况。
我们可以有多种方法实现这一要求:
方法一:每次在循环体重扫描当前按键的电平,从而进入对应的控制电机函数,如果所有电平都没有信号则直接进入下一个循环。发送CAN报文就直接用一个定时中断。这样的好处就是编程简单直白,每次循环进入不同的电机控制函数,坏处很明显,一定要等待到下一个循环才能进入其他的电机控制函数,每次循环的时间不好控制,不管你用函数指针还是if/else来判断,每次循环一定要等待电机动作结束才能进入下一个循环。
方法二:改用外部中断来处理按键。仅当按键按下时触发外部中断,从而控制响应的电机进行操作。这样的好处就是循环体简单,可以仅仅就是一个计数器加一,所有控制都等中断来实现。但这样带来的问题也很明显,就是中断嵌套问题。比如当电机正转时按下停止按钮,这时由于是在中断中,停止按钮是否真的能够得到响应?这就涉及到中断嵌套问题,并不见得所有CPU都能支持中断嵌套。
方法三:采用RTOS的思想,加入任务调度系统。每次任务调度系统就是一个小小的循环,对于各个任务进行轮询,当这次轮询发现某任务是已经就绪的优先级最高的任务,则交给CPU处理,所有中断与任务,任务与任务之间有通讯机制可以交换信息。当然实际上并不仅仅只在任务调度器轮询时才进行任务的切换,实际上的操作比这个复杂一些,我的这篇文章就想以uCOS-II为例讨论RTOS的任务调度系统是怎样执行的。
标签:关机 cti 设备驱动 art api min 行操作 映射 并且
原文地址:https://www.cnblogs.com/xyejava/p/12108482.html