热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

单片机中断全局变量保护方法

首先要明白这几个知识点:关键字volatile的使用,原子操作,临界区的使用。明白的直接跳到文中的4.全局变量的使用及保护处查看。1.关键字volatile关键字volatile用

首先要明白这几个知识点:关键字volatile的使用,原子操作,临界区的使用。明白的直接跳到文中的4.全局变量的使用及保护处查看。

1.关键字volatile

关键字volatile用于告诉编译器,说明被修身的变量可能会被意想不到地改变,防止编译器对代码进行优化。

比如如下程序:

1 ucNms=0x65;
2 ucNms=0x66;
3 ucNms=0x67;
4 ucNms=0x68;

上述4条语句,如果变量在声明的时候(unsigned char ucNms;)没有使用volatile,那么编译器有可能对其优化,只编译最后一条语句ucNms=0x68;(即忽略前三条语句,只产生一条机器汇编代码);如果变量在声明的时候(volatile unsigned char ucNms;)使用了volatile,则编译器会逐一地进行编译并产生四条相应的机器代码(产生四条代码)。

精确地说就是,编译器在编译这个变量语句时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。所以下面几个情况在声明的时候需要用volatile关键字对其修饰:

1)并行设备的硬件寄存器(如:状态寄存器)

2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

3)多线程应用中被几个任务共享的变量

2.原子操作

原子操作可以理解为不被打断的操作,可以是一个步骤的操作,也可以是多个步骤的操作,总之确保操作不被打断。

3.临界区

指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。



4.全局变量的使用及保护

单片机裸机编程,使用全局变量时,一般是一个或多个*.c文件(或模块)中会使用到某个全局变量(假设为A),还有中断中也会用到这个全局变量。这样在使用时就要考虑变量的安全性。单片机裸机编程是前后台系统,如下图:


 

 



单片机裸机编程前后台系统

首先要明白大循环(后台)对这个变量的访问是依次的,不管全局变量A是在哪一个模块或者*.c文件中,每一个时刻只有一个地方对变量A访问。然后中断和中断嵌套程序中也会有对全局变量A的访问。

于是就存在这样的问题,大循环(后台)在访问全局变量A时(比如说访问到一半时),被中断(前台)程序打断并修改了全局变量A,这样大循环(后台)程序再次对全局变量A访问,就会导致访问到的A存在不确定性。从而会影响程序的不正常运行。

这样就可以很明确的知道,只要在大循环(后台)访问A时,不让中断(前台)打断其访问即可。确保对A的访问是原子操作。于是就有这样的解决方法:

关中断-->>全局变量A-->>开中断

有的时候,如果访问变量A的过程比较长,可以对全局变量A做一个副本拷贝a,用拷贝的a作为模块处理的数据。于是就有了这样:

关中断-->>访问全局变量A-->>副本拷贝a-->>开中断->>操作副本拷贝a

这种复杂的情况也可以做一个锁这样做:

大循环(后台):

关中断-->>上锁-->>开中断-->>访问变量A-->>关中断-->>解锁-->>开中断

中断(前台):

如果是解锁的,操作全局变量A,如果是上锁的就不操作

当然,如果访问全局变量A本身就是一个原子操作(比如一条指令就可以访问完成),这样也就不需要做开关中断的处理了。



示例1:禁止中断方法保护全局变量

大循环(后台)

ET0=0; //禁止定时中断
访问全局变量A;
其他代码部分;
ET0=1; //开启允许定时中断

定时器中断(前台)

操作全局变量A;


示例2:加锁的方法保护全局变量

大循环(后台)

ET0=0; //禁止定时中断
Lock = 1;
ET0=1; //开启允许定时中断
访问全局变量A;
其他代码部分;
ET0=0; //禁止定时中断
Lock =0;
ET0=1; //开启允许定时中断

定时器中断(前台)

If(lock ==0) 操作全局变量A;
else{;}


示例3:加锁的方法保护全局变量

大循环(后台)

Lock = 1;//若此条语句对应汇编指令是原子操作可以不用开关中断保护此锁
访问全局变量A;
其他代码部分;
Lock =0;//若此条语句对应汇编指令是原子操作可以不用开关中断保护此锁

定时器中断(前台)

If(lock ==0) 操作全局变量A;
else{;}


总结下:中断全局变量尽量要用volatile修饰,中断全局变量要原子操作访问,要时刻明白中断全局变量是临界区资源,共享访问时需要保护。

 

转发自:http://www.360doc.com/content/19/0117/10/39315025_809417729.shtml#



推荐阅读
  • Golang与微服务架构:构建高效微服务
    本文探讨了Golang在微服务架构中的应用,包括Golang的基本概念、微服务开发的优势、常用开发工具以及具体实践案例。 ... [详细]
  • 本文档提供了详细的MySQL安装步骤,包括解压安装文件、选择安装类型、配置MySQL服务以及设置管理员密码等关键环节,帮助用户顺利完成MySQL的安装。 ... [详细]
  • 本文介绍了JSP的基本概念、常用标签及其功能,并通过示例详细说明了如何在JSP页面中使用Java代码。 ... [详细]
  • 本文详细解析了Java中流的概念,特别是OutputStream和InputStream的区别,并通过实际案例介绍了如何实现Java对象的序列化。文章不仅解释了流的基本概念,还探讨了序列化的重要性和具体实现步骤。 ... [详细]
  • 深入解析mt_allocator内存分配器(二):多线程与单线程场景下的实现
    本文详细介绍了mt_allocator内存分配器在多线程和单线程环境下的实现机制。该分配器以2的幂次方字节为单位分配内存,支持灵活的配置和高效的性能。文章分为内存池特性描述、内存池实现、单线程内存池实现、内存池策略类实现及多线程内存池实现等部分,深入探讨了内存池的初始化、内存分配与回收的具体实现。 ... [详细]
  • Node.js模块化的优势及实践
    本文探讨Node.js模块化的重要性和具体实现方式,包括其带来的代码复用性增强、可维护性提升、以及如何有效避免命名冲突等问题。 ... [详细]
  • 本文档旨在提供C语言的基础知识概述,涵盖常量、变量、数据类型、控制结构及函数定义等内容。特别强调了常量的不同类型及其在程序中的应用,以及如何正确声明和使用函数。 ... [详细]
  • Java高级工程师学习路径及面试准备指南
    本文基于一位朋友的PDF面试经验整理,涵盖了Java高级工程师所需掌握的核心知识点,包括数据结构与算法、计算机网络、数据库、操作系统等多个方面,并提供了详细的参考资料和学习建议。 ... [详细]
  • C基本语法C程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。现在让我们简要地看一下什么是类、对象,方法、即时变量。对象-对象具有状态和行为 ... [详细]
  • CSS技巧:创建带有背景图的按钮
    本文详细探讨了使用CSS创建带有背景图片的按钮的方法,并提供了具体的实例代码,帮助开发者解决实际开发中的相关问题。 ... [详细]
  • 本文介绍了多种Eclipse插件,包括XML Schema Infoset Model (XSD)、Graphical Editing Framework (GEF)、Eclipse Modeling Framework (EMF)等,涵盖了从Web开发到图形界面编辑的多个方面。 ... [详细]
  • 基于OpenCV的小型图像检索系统开发指南
    本文详细介绍了如何利用OpenCV构建一个高效的小型图像检索系统,涵盖从图像特征提取、视觉词汇表构建到图像数据库创建及在线检索的全过程。 ... [详细]
  • GCC(GNU Compiler Collection)是GNU项目下的一款功能全面且高效的多平台编译工具,广泛应用于Linux操作系统中。本文将详细介绍GCC的特点及其基本使用方法。 ... [详细]
  • 本文档提供了首次周测的答案解析,涵盖特殊符号、命令作用、路径说明以及实战练习等内容。 ... [详细]
  • SSE图像算法优化系列三:超高速导向滤波实现过程纪要(欢迎挑战)
    自从何凯明提出导向滤波后,因为其算法的简单性和有效性,该算法得到了广泛的应用,以至于新版的matlab都将其作为标准自带的函数之一了&#x ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有