完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
转rtx操作系统
本章教程为大家讲解几个重要的概念,临界段,任务锁和中断锁。 本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。 11.1 临界段 11.2 中断锁 11.3 任务锁 11.4 RTX任务锁的实现 11.5 实验例程说明 11.1 临界段 代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断。为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而临界段代码执行完毕后,要立即开中断。 由于Cortex-M3/M4的RTX内核库中没有关闭中断的操作,也就是说RTX的源码中不存在临界段。如果源码中有临界段的话,会给系统带来什么问题呢?比如此时某个任务正在调用系统API函数,而且此时中断正好关闭了,也就是进入到了临界区中,这个时候如果有一个紧急的中断事件被触发,这个中断就不能得到及时执行,必须等到中断开启才可以得到执行,如果关中断时间超过了紧急中断能够容忍的限度,危害是可想而知的。像uCOS-II,uCOS-III和FreeRTOS的源码中都是有临界段的。 除了上面说的操作系统源码所带的临界段以外,用户写应用的时候也有临界段的问题,比如以下两种: u 读取或者修改变量(特别是任务间通信的全局变量)的代码,一般来说这是最常见的临界代码。 u 调用公共函数的代码,特别是不可重入的函数,如果多个任务都访问这个函数,结果是可想而知的。 总之,对于临界段要做到执行时间越短越好,要不会影响系统的实时性。 |
|
相关推荐
|
|
11.2 中断锁
中断锁就是RTOS提供的开关中断函数,因为Cortex-M3/M4的RTX源码中没有关闭中断的操作,所以也就没有提供开关中断函数。 由于RTX没有提供开关中断函数,如果用户自己的应用代码需要开关中断的话怎么办呢?裸机时如何开关中断的,在使用了RTX后仍然使用以前的开关中断函数即可。 |
|
|
|
|
|
11.3 任务锁
简单的说,为了防止当前任务的执行被其它高优先级的任务打断而提供的锁机制就是任务锁。实现任务锁可以通过给调度器加锁或者直接关闭RTOS内核定时器(就是前面一直说的系统滴答定时器)来实现。 u 通过给调度器加锁实现 给调度器加锁的话,就无法实现任务切换,高优先级任务也就无法抢占低优先级任务的执行,同时高优先级任务也是无法向低优先级任务切换的。像uCOS-II和uCOS-III是采用的这 种方法实现任务锁。特别注意,这种方式只是禁止了调度器工作,并没有关闭任何中断。 u 通过关闭RTOS内核定时器实现 关闭了RTOS内核定时器的话,也就关闭了通过RTOS内核定时器中断实现任务切换的功能,因为在退出定时器中断时需要检测当前需要执行的最高优先级任务,如果有高优先级任务就绪的话需要做任务切换。RTX操作系统是采用的这种方式实现任务锁的。 |
|
|
|
|
|
11.4 RTX任务锁的实现
使用如下2个函数可以实现RTX任务的开锁和解锁: u tsk_lock u tsk_unlock 关于这2个函数的讲解及其使用方法可以看教程第3章3.3小节里面说的参考资料rlarm.chm文件 下面我们也对这两个函数做一下讲解。 |
|
|
|
|
|
11.4.1 函数tsk_lock
函数原型: void tsk_lock (void); 函数描述: 函数tsk_lock用于禁止RTX内核定时器中断,因此也就禁止了任务切换。 使用这个函数要注意以下问题: 1. 函数tsk_lock不支持嵌套调用。 2. 不允许在中断服务程序中调用tsk_lock。 3. RTX内核定时器被关闭期间,RTX内核任务调度器和需要时间片调度的任务被阻塞。设置的任务延迟时间不再工作。因此,强烈建议关RTX内核定时器中断的时间越短越好。 |
|
|
|
|
|
使用举例:
复制代码 #include void protect_critical_op () { tsk_lock (); do_critical_op (); tsk_unlock (); } |
|
|
|
|
|
11.4 RTX任务锁的实现
使用如下2个函数可以实现RTX任务的开锁和解锁: u tsk_lock u tsk_unlock 关于这2个函数的讲解及其使用方法可以看教程第3章3.3小节里面说的参考资料rlarm.chm文件 下面我们也对这两个函数做一下讲解。 |
|
|
|
|
|
11.4.1 函数tsk_lock
函数原型: void tsk_lock (void); 函数描述: 函数tsk_lock用于禁止RTX内核定时器中断,因此也就禁止了任务切换。 使用这个函数要注意以下问题: 1. 函数tsk_lock不支持嵌套调用。 2. 不允许在中断服务程序中调用tsk_lock。 3. RTX内核定时器被关闭期间,RTX内核任务调度器和需要时间片调度的任务被阻塞。设置的任务延迟时间不再工作。因此,强烈建议关RTX内核定时器中断的时间越短越好。 使用举例: 复制代码 #include void protect_critical_op () { tsk_lock (); do_critical_op (); tsk_unlock (); } |
|
|
|
|
|
11.4.2 函数tsk_unlock
函数原型: void tsk_unlock (void); 函数描述: 函数tsk_unlock用于使能RTX内核定时器中断,因此也就重新开启任务切换。注意tsk_unlock一定要跟tsk_lock配套使用。 使用这个函数要注意以下问题: 1. 函数tsk_lock不支持嵌套调用。 2. 不允许在中断服务程序中调用tsk_lock。 使用举例: 复制代码 #include void protect_critical_op () { tsk_lock (); do_critical_op (); tsk_unlock (); } |
|
|
|
|
|
11.5 实验例程说明
11.5.1 STM32F103开发板实验 配套例子: V4-407_RTX实验_任务锁 实验目的: 1. 学习RTX的任务锁使用 2. RTX的任务锁是通过关闭系统时钟节拍中断实现的 实验内容: 1. K1按键按下,串口打印。 2. 在调用printf函数的地方都加上任务锁,防止多个任务调用此函数造成冲突,以至于串口打印出现乱码。 3. 各个任务实现的功能如下: AppTaskUserIF任务 :按键消息处理。 AppTaskLED任务 :LED闪烁,并串口打印任务正在运行。 AppTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印任务正在运行。 AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。 |
|
|
|
|
|
RTX配置:
RTX配置向导详情如下: u Task Configuration l Number of concurrent running tasks 允许创建4个任务,实际创建了如下四个任务 AppTaskUserIF任务 :按键消息处理。 AppTaskLED任务 :LED闪烁。 AppTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印任务正在运行。 AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。 l Number of tasks with user-provided stack 创建的4个任务都是采用自定义堆栈方式。 |
|
|
|
|
|
程序设计:
u 任务栈大小分配: staticuint64_t AppTaskUserIFStk[512/8]; /* 任务栈 */ staticuint64_t AppTaskLEDStk[256/8]; /* 任务栈 */ staticuint64_t AppTaskMsgProStk[512/8]; /* 任务栈 */ staticuint64_t AppTaskStartStk[512/8]; /* 任务栈 */ 将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。 u 系统栈大小分配: |
|
|
|
|
|
RTX初始化:
复制代码 /* ********************************************************************************************************* * 函 数 名: main * 功能说明: 标准c程序入口。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ int main (void) { /* 初始化外设 */ bsp_Init(); /* 创建启动任务 */ os_sys_init_user (AppTaskStart, /* 任务函数 */ 4, /* 任务优先级 */ &AppTaskStartStk, /* 任务栈 */ sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */ while(1); } |
|
|
|
|
|
RTX任务创建:
复制代码 /* ********************************************************************************************************* * 函 数 名: AppTaskCreate * 功能说明: 创建应用任务 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppTaskCreate (void) { HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */ 1, /* 任务优先级 */ &AppTaskUserIFStk, /* 任务栈 */ sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */ HandleTaskLED = os_tsk_create_user(AppTaskLED, /* 任务函数 */ 2, /* 任务优先级 */ &AppTaskLEDStk, /* 任务栈 */ sizeof(AppTaskLEDStk)); /* 任务栈大小,单位字节数 */ HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro, /* 任务函数 */ 3, /* 任务优先级 */ &AppTaskMsgProStk, /* 任务栈 */ sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */ } |
|
|
|
|
|
11.5.2 STM32F407开发板实验
配套例子: V5-407_RTX实验_任务锁 实验目的: 1. 学习RTX的任务锁使用 2. RTX的任务锁是通过关闭系统时钟节拍中断实现的 实验内容: 1. K1按键按下,串口打印。 2. 在调用printf函数的地方都加上任务锁,防止多个任务调用此函数造成冲突,以至于串口打印出现乱码。 3. 各个任务实现的功能如下: AppTaskUserIF任务 :按键消息处理。 AppTaskLED任务 :LED闪烁,并串口打印任务正在运行。 AppTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印任务正在运行。 AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。 |
|
|
|
|
|
RTX配置:
RTX配置向导详情如下: u Task Configuration l Number of concurrent running tasks 允许创建4个任务,实际创建了如下四个任务 AppTaskUserIF任务 :按键消息处理。 AppTaskLED任务 :LED闪烁。 AppTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印任务正在运行。 AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。 l Number of tasks with user-provided stack 创建的4个任务都是采用自定义堆栈方式。 |
|
|
|
|
|
169 浏览 0 评论
零知开源——基于STM32F407VET6零知增强板的四路独立计时器
1587 浏览 0 评论
零知开源——STM32F4实现ILI9486显示屏UI界面系列教程(一):电子书阅读器功能
1715 浏览 0 评论
CW32L010 ESC Driver 电机控制套件快速上手指南
1268 浏览 1 评论
2063 浏览 1 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
13703 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-7-12 09:53 , Processed in 0.850350 second(s), Total 74, Slave 66 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191