STM32学习笔记(四) —— 位段别名区的使用

STM32F103RCT6有两个位段区 (SRAM 最低1M空间和片内外设存储区最低1M空间), 这两个区域都有各自的别名区,在别名区中每个字会映射到位段区的一个位,所以在别名区修改一个字相当于修改位段区中对应的一个位

STM32学习笔记(四) —— 位段别名区的使用_第1张图片

映射公式( 别名区中的字与位段区中的位对应关系 ):

位段区某个位在别名区的地址 = 别名区起始地址 + (目标位所在的字节,在位段中的序号 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会点亮。

test_value

本例程代码可以在HAL库工程模板这一章节的最后,百度网盘链接分享处获取

以上是通过开发板进行实际验证的,下面使用软件仿真,

我们首先进入调试界面( 前面章节有提到,所以本篇以及后续章节都不再重复提及 ),
打开串口

在这里插入图片描述

运行程序,就可以在串口显示界面查看到输出的数据
在这里插入图片描述

你可能感兴趣的:(STM32学习笔记,stm32)