云班课选做

阅读附件中的代码,回答:

  • ucos是如何分层的?
  • HAL都有哪些代码?
  • 分析任务是如何切换的。

一、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都有哪些代码

  • 背景介绍:
    硬件抽象层技术最初是由Microsoft公司为确保WindowsNT的稳定性和兼容性而提出的。针对过去Windows系列操作系统经常出现的系统死机或崩溃等现象,Microsoft总结发现,程序设计直接与硬件通信,是造成系统不稳定的主要原因。在得出这个结论的基础上,微软公司在WindowsNT上取消了对硬件的直接访问,首先提出了硬件抽象层(Hardware Abstraction Layer,简称HAL)的概念。
  • 概念:
    硬件抽象层就是:“将硬件差别与操作系统其他层相隔离的一薄层软件,它是通过采用使多种不同硬件在操作系统的其他部分看来是同一种虚拟机的做法来实现的。“后来,这种HAL设计思路被一些嵌入式操作系统参考,其系统内核被分成两层,上层称为“内核(Kernel)”,底层则称为“硬件抽象层”。在EOS中,HAL独立于EOS内核;对于操作系统和应用软件而言,HAL是对底层架构的抽象。综合分析HAL层的代码,可以发现这些代码与底层硬件设备是紧密相关的。因此,可以将硬件抽象层定义为所有依赖于底层硬件的软件。即使有些EOS的HAL在物理上是与系统内核紧密联系的,甚至相互交叉的,但是从功能上可以从分层技术的角度去分析它。
  • 作用:
    硬件抽象层是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化。它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植。 从软硬件测试的角度来看,软硬件的测试工作都可分别基于硬件抽象层来完成,使得软硬件测试工作的并行进行成为可能。
    硬件抽象层是一个编程层,允许计算机操作系统在逻辑层而不是硬件层与硬件设备交互。Windows 2000就是支持硬件抽象层的操作系统之一。操作系统核心或者硬件驱动程序都可以调用硬件抽象层。无论哪种情况,调用程序都不用了解硬件的具体设计细节,只需要给出抽象层所需的参数即可。
    官方给出的HAL库的包含结构:
  • stm32f2xx.h主要包含STM32同系列芯片的不同具体型号的定义,是否使用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.h:stm32f2xx_hal.c/h 主要实现HAL库的初始化、系统滴答相关函数、及CPU的调试模式配置
stm32f2xx_hal_conf.h :该文件是一个用户级别的配置文件,用来实现对HAL库的裁剪,其位于用户文件目录,不要放在库目录中
  • 接下来对于HAL库的源码文件进行一下说明,HAL库文件名均以stm32f2xx_hal开头,后面加上_外设或者模块名(如:stm32f2xx_hal_adc.c):
    库文件:
    stm32f2xx_hal_ppp.c/.h // 主要的外设或者模块的驱动源文件,包含了该外设的通用API
    stm32f2xx_hal_ppp_ex.c/.h // 外围设备或模块驱动程序的扩展文件。这组文件中包含特定型号或者系列的芯片的特殊API。以及如果该特定的芯片内部有不同的实现方式,则该文件中的特殊API将覆盖_ppp中的通用API。
    stm32f2xx_hal.c/.h // 此文件用于HAL初始化,并且包含DBGMCU、重映射和基于systick的时间延迟等相关的API
    其他库文件

用户级别文件:

    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的任务调度系统是怎样执行的。

原文地址:https://www.cnblogs.com/xyejava/p/12108482.html

时间: 2024-10-13 11:49:22

云班课选做的相关文章

疫情下的在线上课方案:QQ直播+蓝墨云班课

目录 疫情下的在线上课方案:QQ直播+蓝墨云班课 使用QQ进行直播 材料 QQ直播步骤 其他问题 使用蓝墨云班课加强学习效果 教材问题 参考资料 疫情下的在线上课方案:QQ直播+蓝墨云班课 全国新型冠状病毒肺炎疫情肯定要影响到开学后上课了,很多学校都考虑线上开课方案了,我觉得这是提升教学信息化的一个良机. 多年来我倡导"老师做教练,学生做中学",积极推广翻转课堂.如果您熟悉翻转课堂,其实问题就解决了,不熟悉翻转课堂的老师可以参考一下我写的 "基于蓝墨云班课的翻转课堂实践&qu

20155317 2016-2017-2 蓝墨云班课考题第2周

20155317 2016-2017-2 蓝墨云班课考题第2周 三: 1.用gcc -g编译vi输入的代码 2.在main函数中设置一个行断点 3.在main函数增加一个空循环,循环次数为自己学号后4位,设置一个约为学号一半的条件断点 4.提交调试过程截图(一定包含条件断点的),要全屏,包含自己的学号信息 第一步:输入 gcc -g *.c -o mian 第二步:首先在mian中写入一个空循环,以学号为最终的结束点 第三步:再输入gdb main 进入调试阶段:在调试阶段里,首先输入start

20162330 第十二周 蓝墨云班课 hash

题目要求 利用除留余数法为下列关键字集合的存储设计hash函数,并画出分别用开放寻址法和拉链法解决冲突得到的空间存储状态(散列因子取0.75) 关键字集合:85,75,57,60,65,(你的8位学号相加值),98,74,89,12,5,46,97,13,69,52,92 实现思路 线性探测开放寻址法: 1.调用哈希函数处理键得到哈希值,用值除以表的长度后取余数,从而确定表中的一个位置. 2.如果该位置非空,则探测下一个位置,到达表最后一项时,折回表头. 3.如果回到原来哈希位置上时还未找到空闲

20175312 2018-2019-2 《Java程序设计》第6周课下选做——类定义

20175312 2018-2019-2 <Java程序设计>第6周课下选做--类定义 设计思路 1.我觉得Book其实就是一个中转的作用,由测试类Bookself通过Book输入数据,然后在验证通过后再取出. 2.在Book.java中储存测试类中输入的数据,然后验证信息是否一样,一样则输出,否则就返回false. 测试代码 Bookself.java public class Bookself { public static void main(String[] args) { Book

类定义(课下选做)

类定义(课下选做) 要求 Book类包含书名,作者,出版社和出版日期 数据都要定义getter和setter 至少三个构造方法,接收并初始化这些数据 覆盖toString方法,返回良好的含有多行的书的描述信息 覆盖equals方法,书名.作者.出版社和出版日期完全相同说明两本书相同. 创建一个测试类BookShelf 思路 根据要求最好分为两个类,即Book和BookShelf 在Book类中定义四个getter,返回书名.作者.出版社和出版日期 在BookShelf类中定义四个setter,赋

20175314薛勐 程序设计中临时变量的使用(课下测试,选做)

程序设计中临时变量的使用(课下测试,选做) 要求 定义一个数组:int arr[] = {1,2,3,4,5,6,7,8}; 打印原始数组的值:for(int i:arr){System.out.print(i + " "); } System.out.println();// 添加代码删除上面数组中的5 ... 打印出 1 2 3 4 6 7 8 0:for(int i:arr){System.out.print(i + " ");} System.out.pri

20165201 课下作业第十周(选做)

#20165201 课下作业第十周(选做) 相关知识点总结 补做代码运行结果截图 补做代码链接 相关知识点的总结 课上内容的补做,结果截图 教材第十五章的代码分析 补做教材第十五章的编程题目 提交补做的博客作业的连接 主动找老师进行作业答辩 原文地址:https://www.cnblogs.com/cbmwtsl/p/9000384.html

类定义(课下选做)

一.设计思路 之前在课上做过类似的题目,首先分析,这个题的重点在重写toString类和equals类 首先,是toString类,直接重写public String toString(){return 字符串:}返回要输出的字符串即可 然后是equals类 用public boolean equals(Object o){内容}重写 先用if(this==o)判断地址是否相同,若相同直接true 再用if(o==null)判断对象是否为空``` 接着用if (getClass()!=o.get

20175314薛勐 数据结构-排序(选做)

数据结构-排序(选做) 要求 在数据结构和算法中,排序是很重要的操作,要让一个类可以进行排序,有两种方法: 有类的源代码,针对某一成员变量排序,让类实现Comparable接口,调用Collection.sort(List) 没有类的源代码,或者多种排序,新建一个类,实现Comparator接口 调用Collection.sort(List, Compatator) 针对下面的Student类,使用Comparator编程完成以下功能: 在测试类StudentTest中新建学生列表,包括自己和学