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