#define GPBCON (*(volatile unsigned *)0x56000010) 的理解

本文探讨了在不同计算机体系结构中,如何通过内存映射或端口映射访问设备寄存器。重点介绍了使用C语言进行内存映射访问的方法,解释了volatile关键字的作用及其在确保数据一致性和正确性方面的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。

           #define IOPIN   (*((volatile unsigned long *) 0xE0028000))   为例:作为一个宏定义语句,define是定义一个变量或常量的伪指令。首先( volatile unsigned long * )的意思是将后面的那个地址强制转换成 volatile unsigned long * unsigned long * 是无符号长整形,volatile 是一个类型限定符,如const一样,当使用volatile限定时,表示这个变量是依赖系统实现的,以为着这个变量会被其他程序或者计算机硬件修改,由于地址依赖于硬件,volatile就表示他的值会依赖于硬件。

      volatile 类型是这样的,其数据确实可能在未知的情况下发生变化。比如,硬件设备的终端更改了它,现在硬件设备往往也有自己的私有内存地址,比如显存,他们一般是通过映象的方式,反映到一段特定的内存地址当中,这样,在某些条件下,程序就可以直接访问这些私有内存了。另外,比如共享的内存地址,多个程序都对它操作的时候。你的程序并不知道,这个内存何时被改变了。如果不加这个voliatile修饰,程序是利用cache当中的数据,那个可能是过时的了,加了 voliatile,就在需要用的时候,程序重新去那个地址去提取,保证是最新的。归纳起来如下:

1. volatile变量可变 允许除了程序之外的比如硬件来修改他的内容  

2. 访问该数据任何时候都会直接访问该地址处内容,即通过cache提高访问速度的优化被取消 

 

       对于((volatile unsigned long *) 0xE0028000)为随硬件需要定义的一种地址,前面加上“*”指针,为直接指向该地址,整个定义约定符号IOPIN代替,调用的时候直接对指向的地址寄存器写内容既可。这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。上述表达式拆开来分析,首先(volatile unsigned long *) 0xE0028000的意思是把0xE0028000强制转换成volatile unsigned long类型的指针,暂记为p,那么就是#define A *p,即AP指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作。

 

对于(volatile unsigned char *)0x20我们再分析一下,它是由两部分组成:

 1)(unsigned char *)0x200x20只是个值,前面加(unsigned char *)表示0x20是个地址,而且这个地址类型是unsigned char ,意思是说读写这个地址时,要写进unsigned char 的值,读出也是unsigned char 

 2volatile,关键字volatile 确保本条指令不会因C 编译器的优化而被省略,且要求每次直接读值。例如用while((unsigned char *)0x20)时,有时系统可能不真正去读0x20的值,而是用第一次读出的值,如果这样,那这个循环可能是个死循环。用了volatile 则要求每次都去读0x20的实际值。

 

那么(volatile unsigned char *)0x20是一个固定的指针,是不可变的,不是变量。而char   *u则是个指针变量。

 再在前面加"*"*(volatile unsigned char *)0x20则变成了变量(普通的unsigned char变量,不是指针变量),如果#define i (*(volatile unsigned char *)0x20),那么与unsigned char i是一样了,只不过前面的i的地址是固定的。

 

那么你的问题就可解答了,(*(volatile unsigned char *)0x20)可看作是一个普通变量,这个变量有固定的地址,指向0x20。而0x20只是个常量,不是指针更不是变量。

/按键实验***********/ // 公司名称 :保定飞凌嵌入式技术有限公司 // 描 述 :按键控制蜂鸣器 // 版 权 :保定飞凌嵌入式技术有限公司 // 网 址 :www.witech.com.cn /***************************************************************/ /* 本实验接口说明 GPB5 ------ LED0 GPB6 ------ LED1 GPB8 ------ LED2 GPB10 ------ LED3 */ /------------------------地址声明---------------------------/ #define GPBCON (*(volatile unsigned )0x56000010) #define GPBDAT ((volatile unsigned )0x56000014) #define GPBUP ((volatile unsigned *)0x56000018) #define uchar unsigned char #define uint unsigned int /-----------------------定义全局变量------------------------/ /-----------------------函数声明----------------------------/ void Delay(int x); /------------------------------------------------------------/ 函数名称: Delay 功能描述: 延时函数 传 参: int x 返 回 值: 无 -------------------------------------------------------------/ void Delay(int x) { int k, j; while(x) { for (k=0;k<=0xff;k++) for(j=0;j<=0xff;j++); x--; } } /------------------------------------------------------------- 函数名称: ledMain 功能描述: 入口程序 初始化后,进入跑马灯死循环 传 参: 无 返 回 值: int 0 -------------------------------------------------------------/ int ledMain(void) { GPBCON = 0x1dd7fc; // GPB5,GPB6,GPB8,GPB10设置为输出 GPBDAT = ((1<<5)|(1<<6)|(1<<8)|(1<<10)); //使LED全灭 GPBDAT&=0xffe; //关闭蜂鸣器 GPBUP = 0x00; while (1) // 死循环 { GPBDAT = ~(1<<5); //LED0亮 Delay(500); GPBDAT = ~(1<<6); //LED1亮 Delay(500); GPBDAT = ~(1<<8); //LED2亮 Delay(500); GPBDAT = ~(1<<10); //LED3亮 Delay(500); } return 0; } ; init.s AREA |DATA|,CODE,READONLY ENTRY ldr r13, =0x1000 ;设置堆栈栈顶指针 IMPORT ledMain b ledMain END 预定义语句#define rGPBCON (*(volatile unsigned )0x56000010)中,关键字volatile的作用是什么?unsigned * 的作用的是什么? 第一个的作用是什么?rGPBCON代表的是什么特殊功能寄存器?其功能是什么? volatile 不稳定的,易变的,告诉编译器不要对volatile 修饰的变量或存储单元进行优化,其值随时可变,每次都直接访问存储单元。 unsigned * 的作用是强制类型转换,把0x56000010的本来的整数类型强制转换成无符号指针类型 第一个*的作用在地址0x56000010上,是指针运算符,访问地址为0x56000010的特殊功能寄存器 GPBCON是 GPIO的B端口的配置寄存器,为每一个GPIO B组的引脚定义功能(用2位定义一个引脚的功能) 00 - 输入 01-输出 10-定义具体硬件模块引脚功能 11 - 保留 把十六进制数0x1dd7fc转换成二进制,配置管脚GPB5的功能是什么?是GPBCON的哪些位段以及什么数值决定的? 语句rGPBDAT = ((1<<5)|(1<<6)|(1<<8)|(1<<10)); 执行后,GPB5、GPB6、GPB8、GPB10分别输出高电平还是低电平? 高电平, 对应的LED灯亮还是灭? 都处于熄灭状态(初始状态) 语句rGPBDAT = ~(1<<8); 执行后,GPB5、GPB6、GPB8、GPB10分别输出高电平还是低电平?对应的LED灯亮还是灭? GPB5、GPB6、GPB10输出高电平,对应的LED灯熄灭;GPB8输出低电平,对应的LED灯点亮 /按键实验***********/ // 公司名称 :保定飞凌嵌入式技术有限公司 // 描 述 :蜂鸣器 // 版 权 :保定飞凌嵌入式技术有限公司 // 网 址 :www.witech.com.cn /***************************************************************/ /* 本实验接口说明 GPB0 ------ 蜂鸣器控制口 */ void Delay(unsigned int); /------------------------地址声明-----------------------------/ #define GPBCON (*(volatile unsigned )0x56000010) #define GPBDAT ((volatile unsigned )0x56000014) #define GPBUP ((volatile unsigned *)0x56000018) /------------------------------------------------------------- 函数名称: BellMain 功能描述: 入口程序 初始化后,进入按键扫描死循环 传 参: 无 返 回 值: int 0 -------------------------------------------------------------/ int BellMain() { GPBUP &= 0XFFFFFFFE; //上拉使能GPB0 GPBCON &= 0XFFFFFFC; //GPB0设为输出 GPBCON |= 0X0000001; while(1) { GPBDAT &= 0xfe; //不能用!(非) Delay(40); GPBDAT |=0x1; //用与或方式,不影响其他位 Delay(40); } return(0); } /------------------------------------------------------------/ 函数名称: Delay 功能描述: 延时函数 延时count毫秒 传 参: int count 返 回 值: 无 -------------------------------------------------------------/ void Delay(unsigned int x ) { unsigned int i,j,k; for(i=0;i<=x;i++) for(j=0;j<=0xff;j++) for(k=0;k<=0xff;k++); } AREA |DATA|,CODE,READONLY ENTRY ldr r13,=0x1000 IMPORT BellMain b BellMain END1. BellMain ()函数中的两条语句rGPBCON &= 0xFFFFFFC; rGPBCON |= 0x0000001;的具体作用是什么? //上拉电阻使能GPB0 2. GPB0端口的上拉电阻有没有使能?判断依据是什么? 3. 语句rGPBDAT &= 0xFE; rGPBDAT |= 0x1; 的作用是什么? 写出实验小结
06-09
/**********************按键实验*********************************/ // 公司名称 :保定飞凌嵌入式技术有限公司 // 描 述 :按键控制蜂鸣器 // 版 权 :保定飞凌嵌入式技术有限公司 // 网 址 :www.witech.com.cn /***************************************************************/ /* 本实验接口说明 GPB5 ------ LED0 GPB6 ------ LED1 GPB8 ------ LED2 GPB10 ------ LED3 */ /*------------------------地址声明---------------------------*/ #define GPBCON (*(volatile unsigned *)0x56000010) #define GPBDAT (*(volatile unsigned *)0x56000014) #define GPBUP (*(volatile unsigned *)0x56000018) #define uchar unsigned char #define uint unsigned int /*-----------------------定义全局变量------------------------*/ /*-----------------------函数声明----------------------------*/ void Delay(int x); /*------------------------------------------------------------/ 函数名称: Delay 功能描述: 延时函数 传 参: int x 返 回 值: 无 -------------------------------------------------------------*/ void Delay(int x) { int k, j; while(x) { for (k=0;k<=0xff;k++) for(j=0;j<=0xff;j++); x--; } } /*------------------------------------------------------------- 函数名称: ledMain 功能描述: 入口程序 初始化后,进入跑马灯死循环 传 参: 无 返 回 值: int 0 -------------------------------------------------------------*/ int ledMain(void) { GPBCON = 0x1dd7fc; // GPB5,GPB6,GPB8,GPB10设置为输出 GPBDAT = ((1<<5)|(1<<6)|(1<<8)|(1<<10)); //使LED全灭 GPBDAT&=0xffe; //关闭蜂鸣器 GPBUP = 0x00; while (1) // 死循环 { GPBDAT = ~(1<<5); //LED0亮 Delay(500); GPBDAT = ~(1<<6); //LED1亮 Delay(500); GPBDAT = ~(1<<8); //LED2亮 Delay(500); GPBDAT = ~(1<<10); //LED3亮 Delay(500); } return 0; } ; init.s AREA |DATA|,CODE,READONLY ENTRY ldr r13, =0x1000 ;设置堆栈栈顶指针 IMPORT ledMain b ledMain END 1. 预定义语句#define rGPBCON (*(volatile unsigned *)0x56000010)中,关键字volatile的作用是什么?unsigned * 的作用的是什么? 第一个*的作用是什么?rGPBCON代表的是什么特殊功能寄存器?其功能是什么? volatile 不稳定的,易变的,告诉编译器不要对volatile 修饰的变量或存储单元进行优化,其值随时可变,每次都直接访问存储单元。 unsigned * 的作用是强制类型转换,把0x56000010的本来的整数类型强制转换成无符号指针类型 第一个*的作用在地址0x56000010上,是指针运算符,访问地址为0x56000010的特殊功能寄存器 GPBCON是 GPIO的B端口的配置寄存器,为每一个GPIO B组的引脚定义功能(用2位定义一个引脚的功能) 00 - 输入 01-输出 10-定义具体硬件模块引脚功能 11 - 保留 2. 把十六进制数0x1dd7fc转换成二进制,配置管脚GPB5的功能是什么?是GPBCON的哪些位段以及什么数值决定的? 3. 语句rGPBDAT = ((1<<5)|(1<<6)|(1<<8)|(1<<10)); 执行后,GPB5、GPB6、GPB8、GPB10分别输出高电平还是低电平? 高电平, 对应的LED灯亮还是灭? 都处于熄灭状态(初始状态) 4. 语句rGPBDAT = ~(1<<8); 执行后,GPB5、GPB6、GPB8、GPB10分别输出高电平还是低电平?对应的LED灯亮还是灭? GPB5、GPB6、GPB10输出高电平,对应的LED灯熄灭;GPB8输出低电平,对应的LED灯点亮
06-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值