STM32单片机(五)-寄存器地址理解和控制LED闪烁

2023-05-16

芯片:stm32f103zet6

1、存储单元一般应具有存储数据和读写数据的功能,一般以8位二进制作为一个存储单元,也就是一个字节.每个单元有一个地址,是一个整数编码,可以表示为二进制整数。

2、stm32是32位单片机,说明基本的寄存器是32位的,4字节。内存地址需要4位

3、基址也就是基础地址,最开始的地址,这个查看芯片手册,是人家规定的。

4、偏移,即偏移地址,一般是正整数,也是增加的数字。比如基址是10,偏移是4,地址就是10+4=14.

下面STM32F10xxx中内置外设的起始地址。

每个外设的起始地址就是,每个外设的基址了,当然这个基址也可以再分解为基址和偏移地址。

比如,GPIOB的起始地址是0X4001 0C00,可以分解为

片上外设基地址:0x40000000    GPIO都挂载到APB2总线:APB2偏移:0x10000,RCC在APB2总线的偏移是 0x0C00

GPIOB外设上有什么寄存器呢? 

 

看看其中的CRL寄存器,偏移是0x00 。如果要找GPIOB的CRL寄存器,则起始地址0X4001 0C00+偏移0x00

 

ODR偏移是0x0C,如果要找GPIOB的ODR寄存器,则起始地址0X4001 0C00+偏移0x0C

 来,用用吧。

我就让我的开发板的一个LED闪烁。

电路是这样的

现在要让GPIOB0输出低电平,灯亮,高电平,灯灭。

stm32使用一个外设得使能相应的时钟,即RCC。

我现在要使用GPIOB0,首先使能GPIOB的时钟,时钟也是寄存器控制的啊,查上面的地址表,RCC的基址是

0x40021000,使能GPIOB的时钟,它是由RCC_APB2ENR控制的,因为挂在APB2总线上。偏移是0x18

则RCC_APB2ENR地址:0x40021000+0x18=0x40021018

再设置GPIOB的IO模式,CRL寄存器控制。(CRL控制低8位引脚IO的模式,CRH控制高八位IO的模式,四位控制一个io的模式,一个寄存器控制8个引脚,共32位,一个寄存器)

 设置GPIOB的电平高低,ODR寄存器控制(直接对相应的引脚,写入1或者0就行,1,高电平,0,低电平)

 工程文件结构:起始文件,头文件,源文件

/*  片上外设基地址  */
#define PERIPH_BASE              ((unsigned int)0x40000000)

/*  总线基地址,GPIO都挂载到APB2上 */
#define APB2PERIPH_BASE			(PERIPH_BASE + 0x10000)

/*  GPIOB外设基地址  */
#define GPIOB_BASE				(APB2PERIPH_BASE + 0x0C00)

/*  GPIOB寄存器地址,强制转换成指针  */
#define GPIOB_CRL					*(unsigned int*) (GPIOB_BASE+0x00)
#define GPIOB_CRH					*(unsigned int*) (GPIOB_BASE+0x04)
#define GPIOB_IDR					*(unsigned int*) (GPIOB_BASE+0x08)
#define GPIOB_ODR					*(unsigned int*) (GPIOB_BASE+0x0C)
#define GPIOB_BSRR				*(unsigned int*) (GPIOB_BASE+0x10)
#define GPIOB_BRR					*(unsigned int*) (GPIOB_BASE+0x14)
#define GPIOB_LCKR				*(unsigned int*) (GPIOB_BASE+0x18)

/*  RCC外设基地址   */
#define RCC_BASE					(0x40021000  +  0x1000) 
/* RCC的AHB1时钟使能寄存器地址,强制转换成指针  */
#define RCC_APB2ENR				    *(unsigned int*)(RCC_BASE+0x18)

SystemInit()是为了骗过启动文件,这里应该配置时钟树,下次再讲。 对于那些逻辑运算不懂,看前面的stm32编程要点。

#include "stm32f1.h"

void SystemInit()

{

}

void delay(int t)

{

	 int i;

	 for( ;t>0; t--)

	 for(i=0;i<2000;i++);

}

int main(void)
{
	
	RCC_APB2ENR |= (1<<3);

	//清空控制PB0的端口
	GPIOB_CRL &= ~(0x0F<<(4*0)); 
	//配置PB0为通用推挽输出,速度为50M
	GPIOB_CRL |= (0x03<<(4*0));

	while(1)
	{
		
		GPIOB_ODR =0x00;
		delay(1000);
		
	
		GPIOB_ODR =0x01;
		delay(1000);
		
		
	}
	
}

现在我们怎么算这个偏移呢,我也是理解了好一会,只能说C语言还不够。
有了首地址  0x4002 3830  
也可以直接加偏移量,用宏定义。

在正点原子中,利用的是,结构体的内存对齐原则
**内存对齐,对齐规则是按照成员的声明顺序,依次安排内存,其偏移量为成员大小的整数倍,0看做任何成员的整数倍,最后结构体的大小为最大成员的整数倍**可以参考下面两篇文章。
https://blog.csdn.net/shi2huang/article/details/80290192
https://blog.csdn.net/weixin_40853073/article/details/81451792

好好理解 变量的地址,值,内存,之间的关系。很容易懵。下面会具体举例

再来理解  结构体  RCC_TypeDef 
因为每个寄存器变量都是32位的值,4个字节,所以占4个内存地址

所以每个变量代表的地址偏移量都是4的倍数,例如

```
typedef struct
{
  __IO uint32_t CR;            /*!< RCC clock control register,                                  Address offset: 0x00 */
  __IO uint32_t PLLCFGR;       /*!< RCC PLL configuration register,                              Address offset: 0x04 */
  __IO uint32_t CFGR;          /*!< RCC clock configuration register,                            Address offset: 0x08 */
  __IO uint32_t CIR;           /*!< RCC clock interrupt register,                                Address offset: 0x0C */
  __IO uint32_t AHB1RSTR;      /*!< RCC AHB1 peripheral reset register,                          Address offset: 0x10 */
  __IO uint32_t AHB2RSTR;      /*!< RCC AHB2 peripheral reset register,                          Address offset: 0x14 */
  __IO uint32_t AHB3RSTR;      /*!< RCC AHB3 peripheral reset register,                          Address offset: 0x18 */
  uint32_t      RESERVED0;     /*!< Reserved, 0x1C                                                                    */
  __IO uint32_t APB1RSTR;      /*!< RCC APB1 peripheral reset register,                          Address offset: 0x20 */
  __IO uint32_t APB2RSTR;      /*!< RCC APB2 peripheral reset register,                          Address offset: 0x24 */
  uint32_t      RESERVED1[2];  /*!< Reserved, 0x28-0x2C                                                               */
  __IO uint32_t AHB1ENR;       /*!< RCC AHB1 peripheral clock register,                          Address offset: 0x30 */
  __IO uint32_t AHB2ENR;       /*!< RCC AHB2 peripheral clock register,                          Address offset: 0x34 */
  __IO uint32_t AHB3ENR;       /*!< RCC AHB3 peripheral clock register,                          Address offset: 0x38 */
  uint32_t      RESERVED2;     /*!< Reserved, 0x3C                                                                    */
  __IO uint32_t APB1ENR;       /*!< RCC APB1 peripheral clock enable register,                   Address offset: 0x40 */
  __IO uint32_t APB2ENR;       /*!< RCC APB2 peripheral clock enable register,                   Address offset: 0x44 */
  uint32_t      RESERVED3[2];  /*!< Reserved, 0x48-0x4C                                                               */
  __IO uint32_t AHB1LPENR;     /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */
  __IO uint32_t AHB2LPENR;     /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */
  __IO uint32_t AHB3LPENR;     /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */
  uint32_t      RESERVED4;     /*!< Reserved, 0x5C                                                                    */
  __IO uint32_t APB1LPENR;     /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */
  __IO uint32_t APB2LPENR;     /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */
  uint32_t      RESERVED5[2];  /*!< Reserved, 0x68-0x6C                                                               */
  __IO uint32_t BDCR;          /*!< RCC Backup domain control register,                          Address offset: 0x70 */
  __IO uint32_t CSR;           /*!< RCC clock control & status register,                         Address offset: 0x74 */
  uint32_t      RESERVED6[2];  /*!< Reserved, 0x78-0x7C                                                               */
  __IO uint32_t SSCGR;         /*!< RCC spread spectrum clock generation register,               Address offset: 0x80 */
  __IO uint32_t PLLI2SCFGR;    /*!< RCC PLLI2S configuration register,                           Address offset: 0x84 */
  __IO uint32_t PLLSAICFGR;    /*!< RCC PLLSAI configuration register,                           Address offset: 0x88 */
  __IO uint32_t DCKCFGR;       /*!< RCC Dedicated Clocks configuration register,                 Address offset: 0x8C */

} RCC_TypeDef;
```

现在可以理解:RCC->AHB1ENR|=1<<0; 

1、把1左移0位,等于0x00000001
2、和RCC->AHB1ENR的复位值:0x0010 0000相或,等于,0x0010 0001
再赋值给RCC->AHB1ENR
把外设GPIO A 时钟开启

3、RCC->AHB1ENR换成宏定义,
((RCC_TypeDef *) RCC_BASE)->AHB1ENR
RCC_TypeDef->AHB1ENR
换成地址
0x4002 3830

4、这个结构体是32位的所以对它进行32位操作,
0x4002 3830
0x4002 3831
0x4002 3832
0x4002 3833
4个地址的32位bit赋值,0x0010 0001
 


 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32单片机(五)-寄存器地址理解和控制LED闪烁 的相关文章

随机推荐

  • 生产者消费者问题--练习题目

    10 os考研题目 改题目中p0 xff0c p1两个进程可以互斥的进入临界区 xff0c 会出现饥饿现象 xff08 答案给的是D xff0c 但是自我认为可以出现饥饿现象 xff09 互斥的访问 xff1a p0 Flag 0 61 T
  • PromQL的简单使用

    PromQL的简单使用 一 背景二 PromQL的数据类型三 字面量1 字符串字面量2 浮点数字面量 四 时间序列选择器1 即时向量选择器1 组成部分2 指标名称和匹配器的组合3 匹配器 2 区间向量选择器1 时间格式 3 偏移量修改器 五
  • 一步一步在平衡车上实现卡尔曼滤波

    这是一个翻译版本 xff0c 其中的一些公式 xff0c 符号太多 xff0c 我就不一个一个去上传 xff0c 大家可以参考下面网址去对照着看 A practical approach to Kalman filter and how t
  • 浮点数的二进制表示(IEEE 754标准)

    浮点数是我们在程序里常用的数据类型 xff0c 它在内存中到底是怎么样的形式存在 xff0c 是我了解之前是觉得好神奇 xff0c 以此记录 xff0c 作为学习笔记 现代计算机中 xff0c 一般都以IEEE 754标准存储浮点数 xff
  • vscode如何打开settings.json

    解决方案步骤 xff1a 打开vscode编辑器 xff0c 本文演示的vscode是英文版 点击左下角齿轮状的图标 在弹出的菜单中选择 Settings Settings点击后 xff0c 会出现一个设置窗口 在Settings窗口中点击
  • Failed to execute ‘createObjectURL‘ on ‘URL‘ Overload resolution failed

    vue使用二进制流下载文件 xff0c 使用 link href 61 window URL createObjectURL blob 报错 xff1a Failed to execute createObjectURL on URL Ov
  • openwrt安装docker并启动

    在软件包中下载docker和dockerd 也可以自行下载ipk文件安装 安装成功后启动xshell连上openwrt 执行 etc init d dockerd 启动docker的daemon服务 若要dockerd自启动则执行 ln s
  • Mysql环境变量配置

    一 mysql的环境变量配置步骤 1 1 在桌面选择 计算机 的图标 xff0c 右键 gt 属性 gt 点击 高级系统设置 gt 点击 环境变量 2 2 新建MYSQL HOME变量 xff0c 并将值设置为C Program Files
  • MySQL安装配置教程(超级详细)

    一 下载MySQL Mysql官网下载地址 xff1a MySQL Download MySQL Installer Archived Versions 1 选择要安装的版本 xff0c 本篇文章选择的是5 7 31版本 xff0c 点击D
  • mysql字符切割的四种方式

    1 从左开始截取字符串 left xff08 str length xff09 说明 xff1a left xff08 被截取字段 xff0c 截取长度 xff09 select left 39 如果暴力不是为了杀戮 xff0c 那将变得毫
  • Podman 使用指南

    原文链接 xff1a Podman 使用指南 Podman 原来是 CRI O 项目的一部分 xff0c 后来被分离成一个单独的项目叫 libpod Podman 的使用体验和 Docker 类似 xff0c 不同的是 Podman 没有
  • ClickHouse查询语句详解

    ClickHouse查询语句兼容大部分SQL语法 xff0c 并且进行了更加丰富的扩展 xff0c 查询语句模板如下 xff1a WITH expr list subquery SELECT DISTINCT ON column1 colu
  • Mysql和Redis如何保证数据一致性

    文章目录 前言一 先更新数据库 xff0c 再更新redis二 先更新redis xff0c 在更新数据库三 先更新数据库 xff0c 再删除redis四 先删除redis xff0c 再更新数据库总结 前言 如何保证数据库和缓存双写一致
  • SQL——左连接(Left join)、右连接(Right join)、内连接(Inner join)

    文章目录 前言 一 概念 二 例子 总结 前言 最近在做SQL相关的练习 发现以前那么自信的SQL放久了不碰也变得棘手起来 特别是这一块表之间的内外连接 所以这篇是关于这个内外连接的整理 一 概念 首先还是介绍一下这三个的定义 1 Left
  • UCOSII之项目实战总结

    电子IT行业博大精深 xff0c 没有人能够用笔记本天天记录自己所学的知识 xff0c 于是乎 xff0c 撰写博客就成了每个 IT民工 的专长 再者 xff0c 写一篇博客 xff0c 其意义与不但记录了自己所需的知识 xff0c 更提高
  • 明白了一句话:“加速度信号对高频敏感,位移信号对低频敏感”

    以前听别人说这些 xff0c 然后记住了 但是一直不大理解 最近在调试IEPE传感器 xff0c 正好要算位移 速度 加速度 对于相同的速度 xff0c 频率越高 xff0c 加速度值就越大 因为从公式就能看出来 xff0c 对于固定频率的
  • ubuntu 16.04使用IntelRealSense D435i调用realsense ROS包时,报symbol lookup error和undefined symbol错误的解决办法

    在ubuntu 16 04使用IntelRealSense D435i调用realsense ROS包时 xff0c 运行 roscore roslaunch realsense2 camera rs rgbd launch 出现错误 xf
  • Android浪潮

    Google的Android手机就要席卷世界了 xff01 IT技术的发展常常太出人意料 xff0c 我也想不太清楚Google的Android平台究竟吸引人在哪里 xff0c 但我相信Android会很快改变手机平台的格局 新的形势会出人
  • 卡尔曼滤波相关介绍及优缺点

    1 卡尔曼滤波算法为什么会叫滤波算法 xff1f 以一维卡尔曼滤波为例 xff0c 如果我们单纯的相信测量的信号 xff0c 那么这个信号是包含噪声的 xff0c 是很毛糙的 xff0c 但是当我们运行卡尔曼滤波算法去做估计 xff0c 我
  • STM32单片机(五)-寄存器地址理解和控制LED闪烁

    芯片 xff1a stm32f103zet6 1 存储单元一般应具有存储数据和读写数据的功能 一般以8位二进制作为一个存储单元 也就是一个字节 每个单元有一个地址 是一个整数编码 可以表示为二进制整数 2 stm32是32位单片机 xff0