其实很简单:

    临界段就是不可中断的程序段,比如从UART中读取当前传递回来的值,如果有UART中断,此时这个值又会改变。同样临界段就是保护这类全局变量,如在读取时间节拍时,不应该被时钟更新时钟节拍标志。
    实现方法:就是关中断而已。
    关中断有3种情况:
1:虽关了中断还是可以有中断产生,那就是临界段本身开了中断?(自己理解是临界段内部自己又打开中断)这种方法不管他,没有用
2:清全局中断标志,这样是临界段完了后中断也是关的,不能回到临界前的状态
3:关全局中断前,保存全局中断标志,临界段后恢复。与2的区别是如果关全局中断前是开了全局中断的,3就可以恢复,而2不行,如果关全局中断前本身就是关的2,3一样。
注意:STM32有PRIMASK异常全局中断和faults故障全局中断,林阶段不用关faults PRIMASK和faults是程序状态寄存器CPSR的位。因此可以保存CPSR或者保存PRIMASK和faults如下是这两种方法 
  1. OS_cpu_a.asm文件中:
  2.  OS_ENTER_CRITICAL
    CPSID I ;Disable all the interrupts
    PUSH {R1,R2}
    LDR R1,=OSInterrputSum;OSInterrputSum++
    LDRB R2,[R1]
    ADD R2, R2,#
    STRB R2,[R1]
    POP {R1,R2}
    BX LR
  3.  ;/***************************************************************************************
    ;* 函数名称: OS_EXIT_CRITICAL
    ;*
    ;* 功能描述: 退出临界区
    ;*
    ;* 参 数: None
    ;*
    ;* 返 回 值: None
    ;*****************************************************************************************/
    OS_EXIT_CRITICAL
    PUSH {R1, R2}
    LDR R1,=OSInterrputSum;OSInterrputSum--
    LDRB R2,[R1]
    SUB R2, R2,#
    STRB R2,[R1]
    MOV R1,#
    CMP R2,# ; if OSInterrputSum=0,enable
    ; interrupts如果OSInterrputSum=0,
    MSREQ PRIMASK, R1
    POP {R1, R2}
    BX LR
 #define  OS_CRITICAL_METHOD
#if OS_CRITICAL_METHOD ==
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
#endif
;函数返回值存储在R0中
OS_CPU_SR_Save
MRS R0, PRIMASK ;保存全局中断标志 ; Set prio int mask to mask all (except faults除了故障中断)
CPSID I ;关中断
BX LR
;通过R0传递参数
OS_CPU_SR_Restore
MSR PRIMASK, R0 ;恢复全局中断标志
BX LR
 
UCOS开关中断函数移植
 
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()用来关中断和开中断。在执行临界段代码时要关中断,如果中断打开,临界段代码中的一些全局变量值可能会被中断服务子程序代码改变,或者因为中断引起的任务切换被其它任务函数改变。
 
何谓“临界段”?在网上搜了下:
 
临界段也称为关键代码段,它是指一个小代码段。在它能够执行前,它必须独占对某些共享资源的访问权。一旦线程执行进入了临界段。就意味着它获得了这些共享资源的访问权。那么在该线程处于临界段内的期间,其它同样需要独占这些共享资源的线程就必须等待,直到获得资源的线程离开临界段而释放资源。
 
在LPC2214上移植这两个函数。
在OS_CPU.H中定义采用第三种实现方法:
 
#define  OS_CRITICAL_METHOD    3
定义一个数据类型OS_CPU_SR
typedef unsigned int   OS_CPU_SR;  /* Define size of CPU status register (PSR = 32 bits) */
 
采用第3中方式,需要在UCOS-II函数中定义一个变量:
OS_CPU_SR  cpu_sr;
用来保存CPU的状态寄存器值。
 
定义关中断宏和开中断宏
#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}
 
函数声明:
#if OS_CRITICAL_METHOD == 3    /* Allocate storage for CPU status register          */    
    OS_CPU_SR  OS_CPU_SR_Save(void);
    void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif
以上都是在OS_CPU.H文件中的。
 
NO_INT      EQU     0xC0        ; Mask used to disable interrupts (Both FIR and IRQ)
OS_CPU_SR_Save()和OS_CPU_SR_Restore()函数用汇编语言编写,在OS_CPU_A.S文件中
OS_CPU_SR_Save
        MRS     R0,CPSR                     1
        ORR     R1,R0,#NO_INT               2
        MSR     CPSR_c,R1                   3
        MRS     R1,CPSR                     4
        AND     R1,R1,#NO_INT               5
        CMP     R1,#NO_INT                  6
        BNE     OS_CPU_SR_Save             7
        MOV     PC,LR                       8
 
1-      读CPSR,把CPSR的值送到R0
2-      把R0和常量#NO_INT相或,结果送给R1,把F和I位置1,禁止IRQ中断和FIQ中断。
3-      把R1的值送给CPSR的低8位,CPSR_c的_c是位域,指CPSR的低8位。
4-      把修改后的CPSR值送到R1
5-      R1的值和#NO_INT相与,结果送到R1
6-      比较R1和#NO_INT是否相等
7-      不相等,跳到OS_CPU_SR_Save重新关中断,直到相等。
8-      LR保存的是在调用OS_CPU_SR_Save函数时的断点地址,把LR的值送到PC,退出OS_CPU_SR_Save函数,开始执行临界段代码。这条命令的功能相当于51中的RET。
   注意:ARM中调用子程序时不会自动保存CPSR的值到SPSR,所以子程序返回时,执行MOV     PC,LR也不会把SPSR的值返回到CPSR。这是ARM种调用子程序和进入中断的区别。
 
   汇编函数的返回值是通过R0返回的,把修改前的CPSR值保存到cpu_sr.
OS_CPU_SR_Restore
        MSR     CPSR_c,R0           1
        MOV     PC,LR               2
1-      把R0的值送到CPSR的低8位。在ARM中用R0传递函数的参数,这句指令就是把保存在cpu_sr中的值送到CPSR低8位。高24位没有修改。为什么不直接用MSR     CPSR,R0呢?因为ARM指令中规定MSR命令中,CPSR必须指定位域。把这句改成MSR     CPSR_cxsf,R0,即把R0的32位都送给CPSR,应该也没问题。不过在OS_CPU_SR_Save函数中,CPSR的高24位并没有改变。所以这里只需要把保存在cpu_sr中的低8位送到CPSR就可以了。
2-退出OS_CPU_SR_Restore函数。

【转载】ucos临界段的更多相关文章

  1. RTX——第11章 临界段,任务锁和中断锁

    以下内容转载自安富莱电子: http://forum.armfly.com/forum.php 临界段代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码的执行不被 ...

  2. FreeRTOS 临界段和开关中断

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 临界段代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码的执行不被中断 ...

  3. μC/OS-Ⅲ中的临界段代码

    临界段代码(critical sections),也叫临界区(critical region),是指那些必须完整连续运行,不可被打断的代码段.μC/OS-Ⅲ系统中存在大量临界段代码.采用两种方式对临界 ...

  4. 临界段CCriticalSection的使用

    类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻仅仅同意一个线程存取资源或代码区.临界区在控制一次仅仅有一个线程改动数据或其他的控制资源时很实用.比如,在链 ...

  5. Windows环境下多线程编程原理与应用读书笔记(6)————临界段及其应用

    <一>临界段 临界段对象通过提供所有线程必须共享的对象来控制线程.只有拥有临界段对象的线程才能够访问保护的资源.在另一个线程可以访问该资源之前,前一线程必须释放临界段对象,一遍新的线程可以 ...

  6. RTX临界段,中断锁与任务锁

    临界段         代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而临界段代码执行完毕后,要立即开中断.    ...

  7. FreeRTOS不允许在中断服务程序和临界段中执行不确定的性的操作

    举例 等待事件标志组的任务,要是在中断服务程序中设置事件标志组,但不知道当前有多少个任务在等待此事件标志,这个操作即为不确定性操作,为了不在中断服务程序中执行此不确定性操作,只在中断服务程序中给一确定 ...

  8. 8.0-uC/OS-III临界段

    1.临界段 (临界段代码,也叫临界区,是指那些必须完整连续运行,不可被打断的代码段) 锁调度器,可以执行ISR,开启调度器不可执行ISR: (1).临界段代码,也称作临界域,是一段不可分割的代码. u ...

  9. FreeRTOS 中断配置和临界段

    中断屏蔽寄存器 PRIMASK.FAULTMASK和BASEPRI 1.PRIMASK:这是个只有1个位的寄存器.当它置1时, 就关掉所有可屏蔽的异常,只剩下 NMI和硬fault可以响应.它的缺省值 ...

随机推荐

  1. 用HTML做登录网页

    <html>  <head> 这里是文档的头部 ... ... ...<title>定义文档标题...</title> </head> &l ...

  2. qt字符数组转ASCII(十六进制)

    接收网络传输数据 QByteArray  array;//显示字符串 QString str = QString::fromLocal8Bit(array); m_receiveTxt.append( ...

  3. python实现异步调用函数

    import time from concurrent.futures import ThreadPoolExecutor def RunBenchmark(url): print('GET %s' ...

  4. JAVA主流日志梳理

    JAVA主流日志梳理 引入 历史故事 Log4j - JDK1.3及以前 JUL - JDK1.4 JCL - 日志门面commons-logging的出现 SLF4j - 可能是最好的日志框架 lo ...

  5. Maven搭建SSH框架

    工具:Eclipse(Maven管理工具)+Tomcat+Mysql. 1.新建一个Maven工程(maven-archetype-webapp). 打开File ——>new——>Mav ...

  6. 学习Python第七天

    进制拾遗: 二进制:01 八进制:01234567 十进制:0123456789 十六进制:0123456789ABCDEF 十进制转换八,十六进制语法 oct()八进制 关于8进制是逢8进一位的,我 ...

  7. JS自定义鼠标右击菜单

    自定义鼠标右击菜单要素: 禁止页面默认右击事件 设置右击菜单的样式以及菜单出现的位置(通过捕获鼠标点击位置来确定菜单的位置) 鼠标在指定控件(区域)上右击时显示菜单(默认菜单隐藏,点击鼠标右键时显示) ...

  8. Java面试题精选,大型网站系统架构你不得不懂的10个问题

    作者:JavaGuide(公众号) 下面这些问题都是一线大厂的真实面试问题,不论是对你面试还是说拓宽知识面都很有帮助.之前发过一篇8 张图读懂大型网站技术架构 可以作为不太了解大型网站系统技术架构朋友 ...

  9. Git的初步学习

    前言 感谢! 承蒙关照~ Git的初步学习 为什么要用Git和Github呢?它们的出现是为了用于提交项目和存储项目的,是一种很方便的项目管理软件和网址地址. 接下来看看,一家公司的基本流程图: 集中 ...

  10. Spark基础-scala学习(八、隐式转换与隐式参数)

    大纲 隐式转换 使用隐式转换加强现有类型 导入隐式转换函数 隐式转换的发生时机 隐式参数 隐式转换 要实现隐式转换,只要程序可见的范围内定义隐式转换函数即可.Scala会自动使用隐式转换函数.隐式转换 ...