嵌入式每日八股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

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

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

全部评论

相关推荐

避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
评论
1
3
分享

创作者周榜

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