const和volatile之间的合作
- 【1】const修饰变量
- 【2】const修饰数组
- 【3】const修饰指针
- 【4】const修饰函数
- 【5】volatile的应用
- 【6】volatile详解
- 【7】const和volatile配合
- 【8】AHB (高级高性能总线)
- 【9】APB (高级外围总线)
在学习ADC之前掌握这些
#define __IO volatile //值可以被改变 每次必须从内存获取值 防止被编译器优化
#define __I volatile const //值不希望被改变,保持这个值为只读常量
#define __STATIC_INLINE static inline //内敛函数 适用代码短的函数
typedef void (*ADC_CallbackType)(void); ///< ADC回调函数指针
//静态函数指针数组 初始化函数指针类型的NULL
static ADC_CallbackType g_adcCallback[1] = {(ADC_CallbackType)NULL};
#if defined(__CC_ARM)
#pragma anon_unions //keil中默认是不支持匿名结构体的,需要编译指令#pragma anon_unions指名。
#elif defined(CCARM__)
#pragma language=extended //IAR对所用语言(这里是C)做的一些扩展,也就是说这里可以用扩展的功能
#elif defined (__ICCARM__)
/* anonymous unions are enabled by default:默认启用匿名联合 */
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#elif defined(__TMS470__)
/* anonymous unions are enabled by default */
#elif defined(__TASKING__)
#pragma warning 586
#else
#warning Not supported compiler type //警告不支持编译器类型
#endif
【1】const修饰变量
const修饰的变量为只读变量,不能给只读变量直接赋值(即const修饰的变量不能出现在等号左边)
但是可以通过指针访问这一块内存区域然后间接修改该值。
【2】const修饰数组
C中const修饰的数组是只读的,const修饰的数组空间不可被改变(即数组内存放的值),
但是又正如const常量一样,可以通过指针访问该内存区域进行间接修改。
#include < stdio.h >
int main()
{
const int arr[3] = {0, 1, 2};
//arr[2] = 0; error:read-only 不能改变值
//printf("%d\n", arr[2]);
return 0 ;
}
【3】const修饰指针
(1)例如这种:const int* p; int const*p;
当const在*左侧时,const修饰的指针可以更改指针指向,不能通过指针修改指向的内存空间所存放的值。
int test1 = 10;
int test2 = 20;
const int *p = &test1; //int const* p = &test1;
//*p = 30; error 不可改变值
p = &test2; //可以改变指向
(2)例如这种:int* const p;
当const在*右侧时,const修饰的指针指向的地址不可改变, 但是指针指向的地址存放的内容可以进行修改。
int test1 = 10;
int test2 = 20;
int *const p = &test1;
//p = &test2; error 不可改变指向
*p = 30; //可以改变值
【4】const修饰函数
(1)const修饰函数参数表示在函数体内不希望改变参数的值
(2)const修饰函数返回值表示返回值不可改变,多用于返回指针的情形
【5】volatile的应用
volatile用于告诉编译器必须每次去内存中取变量值
`
(1) 并行设备的硬件【寄存器】(如:状态寄存器)
(2) 一个【中断服务子程序】中会访问到的非自动变量
(2) 【多线程】应用中被几个任务共享的变量
`
【6】volatile详解
(1)volatile可理解为“编译器警告指示字”
(2)volatile用于告诉编译器必须每次去内存中取变量值
(3)volatile主要修饰可能被多个线程访问的变量
(4)volatile也可以修饰可能被未知因数更改的变量
int obj = 10; //volatile int obj = 10;
int a = 0;
int b = 0;
a = obj;
sleep(100);//发生中断 obj值被改变
b = obj;
【1】编译器在编译的时候发现obj没有被当做左值使用,因此会“聪明”的优化, 将obj替换成10,所以就把a和b都赋值为10。
【2】在上述程序中,在sleep的100s内如果发生了 硬件中断
(在这里我将其简单理解为外部突发的异常使得程序变量值发生突然改变,这种改变也可能在程序执行时),
可能obj的值突然变为了100,然而因为编译器的优化,b=obj;可以被编译器优化看成b=10;【实际是b=100才对】
那么当我们想要通过b获取obj在硬件中断后发生改变而产生的值时,却无法观察的到,所以可以将obj定义为volatile类型,
及告诉编译器不要做任何的优化,每次都老老实实的【去内存中取出该变量的值】。(在多线程中也会用到该关键字volatile)
【7】const和volatile配合
const和volatile可以同时修饰一个变量。
volatile const int a;
const volatile int a; //顺序无关紧要
只读的状态寄存器,它是volatile,因为它可能被意想不到地改变,
同时它又是const,因为程序不应该试图去修改它。volatile和const并不矛盾,
只是控制的范围不一样,一个在程序本身之外,另一个是程序本身。
【1】#define __IO volatile //值可以被改变 每次必须从内存获取值 防止被编译器优化,可以初始化时赋值变量
【2】#define __I volatile const //值不希望被改变,每次必须从内存获取值 防止被编译器优化,只给这类变量赋值常量
【8】AHB (高级高性能总线)
AHB,Advanced High performance Bus,高级高性能总线,这是一种系统总线。
AHB
主要用于高性能模块(如CPU、DMA和DSP
等)之间的连接。
AHB 系统由主模块、从模块和基础结构(Infrastructure)3部分组成, 整个AHB总线上的传输都由主模块发出
,由从模块负责回应
。
【9】APB (高级外围总线)
APB,Advanced Peripheral Bus,这是一种外围总线。
APB主要用于低带宽的周边外设之间的连接,例如UART
、1284
等,它的总线架构不像 AHB支持多个主模块,
在APB里面唯一的主模块就是APB 桥
。
APB2负责AD,I/O,高级TIM,串口1;
APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM。
从图可以看出这些外设是如何和总线连接的,配置时钟时,就需要正确初始化
STM32参考图