STM32F103RCT6有两个位段区 (SRAM 最低1M空间和片内外设存储区最低1M空间), 这两个区域都有各自的别名区,在别名区中每个字会映射到位段区的一个位,所以在别名区修改一个字相当于修改位段区中对应的一个位
映射公式( 别名区中的字与位段区中的位对应关系 ):
位段区某个位在别名区的地址 = 别名区起始地址 + (目标位所在的字节,在位段中的序号 x 32)+(目标位的位置 x 4)
别名区起始地址:
SRAM: | 0x22000000 |
---|---|
Peripheral: | 0x42000000 |
目标位所在的字节,在位段中的序号: | 位段中的某个位,所在的那个字节,在位段中的序号 |
---|---|
目标位的位置: | 位段中的某个位,在所在的那个字节中的位置 (0 - 31) |
比较绕,看个例子就行了,
对于SRAM别名区地址,比如要计算,位段区地址为0x20004F01处,的字节中的第2位,对应的别名区的地址,
addr_sram = 0x22000000 + (0x4F01 x 32) + (2 x 4)
对 addr_sram 地址的读写操作就是相当于对 SRAM 中地址 0x20004F01 字节的第2位进行读写
对于外设别名区地址,比如要计算,位段区地址为 0x4001080C处,的字节中的第1位,对应的别名区地址,
addr_peripheral = 0x42000000 + (0x1080C x 32) + (1 x 4)
对 addr_peripheral 地址的读写操作就是相当于对 Peripheral 中地址 0x4001080C 字节的第1位进行读写
下面通过软件编程来进行验证:
1° 在 SRAM 位段区定义一个全局变量test_value,在他的别名区为此变量赋值为0x04(将此别名区地址值设置为0x01, 相当于将地址 0x20004F01 所在字节第2位置1, 即 test_value 值设置为0x04);
2° 读取 test_value 值,如果test_value值为0x04,点亮LED灯,否则熄灭LED灯。
4.代码编写
/* 将全局变量 test_value 定义到 0x20004F01地址上 */
__IO uint8_t test_value __attribute__ ((at(0x20004F01)));
/* 在while循环之前添加以下初始化代码 */
/* 初始化test_value值为0 */
test_value = 0x00;
printf("before, test_value = 0x%x\r\n", test_value);
/*
* SRAM 基址 0x20000000; SRAM 别名区基址 0x22000000
* 别名区地址=别名区起始地址+(目标位所在字节在位段中的序号x32)+(目标位的位置x4)
* 将此别名区地址值设置为0x01, 相当于将地址 0x20004F01 所在字节第2位置1, 即 test_value 值设置为0x04
*/
*((__IO uint32_t *)((uint32_t)0x22000000 + ((uint32_t)0x4F01 << 5) + ((uint32_t)2 << 2))) = 0x01;
printf("after, test_value = 0x%x\r\n", test_value);
RCC->APB2ENR |= ((uint16_t)0x01 << 3 ); //开启GPIOB时钟
/* 配置PB1为通用推挽输出模式,输出速率最大2MHz */
GPIOB->CRL &= ~((uint32_t)0x03 << 4); //将 MODE1[1:0] 清0
GPIOB->CRL |= ((uint32_t)0x02 << 4); //将 MODE1[1:0] 配置为10 输出模式,最大速率2MHz
GPIOB->CRL &= ~((uint32_t)0x03 << 6); //将 CNF1[1:0] 清0
GPIOB->CRL |= ((uint32_t)0x00 << 6); //将 CNF1[1:0] 配置为00 通用推挽输出模式
/* PB1引脚输出1(高电平),默认熄灭LED */
GPIOB->BSRR = ((uint32_t)0x01 << 1); //这里也可以使用ODR寄存器
if(0x04 == test_value) { //内存中的值为设置的值0x04
/*
* 外设基址 0x40000000; 外设别名区基址 0x42000000
* 别名区地址=别名区起始地址+(目标位所在字节在位段中的序号x32)+(目标位的位置x4)
* GPIOB的基地址是0x4001 0C00,ODR寄存器的偏移地址是0x0C,GPIOB_ODR地址就是0x4001 0C0C
* 那【目标位所在字节在位段中的序号】就是0x10C0C
* PB1是是由ODR寄存器第1位,所以目【标位的位置】就是1
* 将此别名区地址值设置为0, 相当于将 GPIOB->ODR 寄存器第1位清0, 即PB1输出低电平
*/
*((__IO uint32_t *)((uint32_t)0x42000000 + ((uint32_t)0x10C0C << 5) + ((uint32_t)1 << 2))) = 0;
}
else if(0x00 == test_value) {
/* PB1输出高电平 */
*((__IO uint32_t *)((uint32_t)0x42000000 + ((uint32_t)0x10C0C << 5) + ((uint32_t)1 << 2))) = 1;
}
else {
}
while(1);
将程序下载后可以打开串口调试助手查看赋值前后的test_value值,同时LED会点亮。
本例程代码可以在HAL库工程模板这一章节的最后,百度网盘链接分享处获取
以上是通过开发板进行实际验证的,下面使用软件仿真,
我们首先进入调试界面( 前面章节有提到,所以本篇以及后续章节都不再重复提及 ),
打开串口
运行程序,就可以在串口显示界面查看到输出的数据