嵌入式每日八股1.31

volatile用法

**读硬件寄存器时(如某传感器的端口/裸机程序编写时)**并行设备的硬件寄存器。存储器映射的硬件寄存器通常加volatile,因为寄存器随时可以被外设硬件修改。当声明指向设备寄存器的指针时一定要用volatile,告诉编译器不要对存储在这个地址的数据进行假设。

//假设某烟雾传感器的 硬件寄存器如下(当又烟雾时报警变为1)
#define GPA1DAT (*(volatile unsigned int*)0xE0200084) 

void main(){
 while (1){//反复读取GPA1DAT值,当为1时火灾报警
    if (GPA1DAT) {  //如不加volatile,编译器优化后,变成只读一次,
                    //后面用的是副本数据。一直为0
	fire()      
	break;
     }
 }
}

解释

1.#define GPA1DAT (*(volatile unsigned int*)0xE0200084) 
将 GPA1DAT 宏定义为地址 0xE0200084 上的内容

2.(volatile unsigned int*)0xE0200084
将0xE0200084强制转换为地址int型指针(相当于*p中的p,指的是地址)

3.(*(volatile unsigned int*)0xE0200084)
这句代码则代表地址为0xE0200084上的存放内容(相当于*p,指的是地址上的内容)

4.#define GPA1DAT (*(volatile unsigned int*)0xE0200084) 
将地址0xE0200084上的内容定义为GPA1DAT,如果操作GPA1DAT = 1;则地址0x40000000上存放的内容就变成了1,也可以读.
//裸机程序编写时
//main.c
#define CNF	    (*(volatile  int*)0x6000D204) //配置寄存器 (0:GPIO  1:SFIO)
#define OE   	(*(volatile  int*)0x6000D214) //输出使能寄存器 (1:使能 0:关闭)
#define OUT     (*(volatile  int*)0x6000D224) //输出寄存器(1:高电平 0:低电平)

#define MSK_CNF (*(volatile  int*)0x6000D284) //配置屏蔽寄存器(高位1:屏蔽 高位0:不屏蔽 低位1:GPIO模式 低位0:SFIO模式)
#define MSK_OE  (*(volatile  int*)0x6000D294) //输出使能屏蔽寄存器(高位1:禁止写   低位1:使能)
#define MSK_OUT (*(volatile  int*)0x6000D2A4) //输出屏蔽寄存器(高位1:禁止写   低位1:高电平)

#define DAP4_SCLK_PJ7 (*(volatile  int*)0x70003150)//管脚复用

//开灯
void led_on(void)
{
 //管脚复用
 DAP4_SCLK_PJ7 = DAP4_SCLK_PJ7&(~(1 << 4));             //【位清零程序写法】
 //取消GPIO3_PJ7 引脚的屏蔽
 MSK_CNF = (MSK_CNF)|(1<<7); //取消对GPIO模下引脚的屏蔽    //【位置一程序写法】
 MSK_OE = (MSK_OE)|(1<<7); //取消引脚 使能屏蔽
 //配置GPIO3_PJ7 引脚  输出高电平
 CNF = (CNF)|(1<<7);  //配置引脚为 GPIO模式
 OE = (OE)|(1<<7);    //使能引脚
 OUT = (OUT)|(1<<7);  //引脚输出高电平,点亮灯
}

int main(void) 
{ 
 led_on();

 while(1)
 {
 }
 return 0;
}

中断中对共享变量的修改一个中断服务程序中修改的供其他程序检测的变量。volatile提醒编译器,它后面所定义的变量随时都有可能改变。因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。

static int i=0; //应加volatile修饰
int main(void)
{
  ...
  while (1){
  if (i) { //虽中断中更改了i的值,但因未声明i是易变的,
 	      //编译器优化后,导致它读的是副本数据,导致一直循环不退出
    break;
  }
 }
}
void interrupt(void)
{
   i=1;  //中断中改变 i的值,但
}

多线程中对共享的变量的修改多线程应用中被几个任务共享的变量。单地说就是防止编译器对代码进行优化,比如如下程序:

volatile  char  bStop  =  0;  //注意:需声明为volatile,线程而才能通过它停止线程1
                          //如不声明,编译器优化后,变成一直读副本数据。
void thread1(){  
  while(!bStop)  {
    //...一直循环做一些事情
  }  
}
void thread2(){  
   //...处理一些事情后。
   bStop =1; //终止线程2  
} 

【嵌入式八股】精华版(免费216问精华八股) https://www.nowcoder.com/creation/manager/columnDetail/0rOeJm

【嵌入式八股】一、语言篇https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM

【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym

【嵌入式八股】三、硬件篇https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM

【嵌入式八股】四、嵌入式Linux篇https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0

嵌入式每日八股 文章被收录于专栏

嵌入式每日八股嵌入式每日八股

全部评论

相关推荐

不愿透露姓名的神秘牛友
06-21 11:33
昨天是学校最后一场招聘会,鼠鼠去参加了,全场只有一个招聘java的岗位,上来先做一份笔试题,做完后他拿张纸对答案,然后开始问简历上的问题,深圳小厂,6-8k(题目如下),后面还有两轮面试。然后我就在招聘现场逛呀逛,看到有公司招聘电商运营,给的比上年的小厂还多,鼠鼠就去了解了下,然后hr跟鼠鼠要了份简历,虽然我的简历上面全是求职Java开发相关的内容,但是hr还是鼓励我说没关系,她帮我把简历给老板看看,下周一会给我通知。招聘会结束后鼠鼠想了一段时间,也和朋友聊了聊,发现我可能是不太适合这个方向,然后就跟爸爸说回家了给我发条微信,我有些话想跟他说说。晚上爸爸到家了,跟我发了条微信,我立马跑出图书馆跟他打起了电话,这个通话长达一个小时,主要是跟爸爸坦白说我不想找这行了,是你的儿子太没用了,想试试其他行业。然后爸爸也跟我说了很多,说他从来没有希望我毕业后就赚大钱的想法,找不到就回家去,回家了再慢慢找,实在找不到就跟他干(帮别人装修房子,个体户),他也知道工作不好找,让我不要那么焦虑,然后就是聊一些家常琐事。对于后面的求职者呢我有点建议想提一下,就是如果招实习的时间或者秋招开始,而你的简历又很差的情况下,不要说等做好项目填充完简历之后再投,那样就太晚了,建议先把熟悉的项目写上简历,然后边投边面边完善,求职是一个人进步的过程,本来就比别人慢,等到一切都准备好后再投岂不是黄花菜都凉了。时间够的话还是建议敲一遍代码,因为那样能让你加深一下对项目的理解,上面那些说法只是针对时间不够的情况。当然,这些建议可能没啥用,因为我只是一个loser,这些全是建立在我理想的情况下,有没有用还需其他人现身说法。上篇帖子没想到学校被人认了出来,为了不丢脸只能匿名处理了。
KPLACE:找研发类或技术类,主要还是要1.多投 2.多做准备,很多方面都要做准备 3.要有心理准备,投累了就休息一两天,再继续,要相信自己能找到
投递58到家等公司7个岗位
点赞 评论 收藏
分享
评论
1
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务