当前位置:   article > 正文

【STM32单片机学习】第四课:GPIO控制LED(用寄存器编程)_stm32gpiob的地址

stm32gpiob的地址

【朱老师课程总结】

第一部分、章节目录

3.4.1.STM32的GPIO模块数据手册详解1

3.4.2.STM32的GPIO模块数据手册详解2

3.4.3.原理图分析与MDK工程建立

3.4.4.写代码控制GPIO点亮熄灭LED

         3.4.5.STM32时钟设置函数移植与讲解1

3.4.6.STM32时钟设置函数移植与讲解2

3.4.7.STM32外设编程经验总结


第二部分、随堂记录

3.4.1.STM32的GPIO模块数据手册详解1

数据手册第8章:通用和复用功能I/O(GPIO 和AFIO)

3.4.1.1、GPIO功能描述

(1)每个I/O端口(GPIOx)包含的寄存器

  • 两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH)
  • 两个32位数据输入/输出寄存器(GPIOx_IDR和GPIOx_ODR)
  • 一个32位端口位置位/复位寄存器(GPIOx_BSRR)                   置位:写1,复位:写0
  • 一个16位端口位复位寄存器(GPIOx_BRR)                             也是32位寄存器,只不过高16位保留不用!
  • 一个32位端口配置锁定寄存器(GPIOx_LCKR)

    PS:BRR和BSRR复位功能相似、在STM32F103C8中每个GPIO端口包括16个引脚

(2)每个端口的每个位可以由软件分别配置成多种输入输出模式。

  • 输入浮空
  • 输入上拉
  • 输入下拉
  • 模拟输入
  • 开漏输出
  • 推挽式输出
  • 推挽式复用功能
  • 开漏复用功能

详细了解可以看这个文件:GPIO输入输出模式详解
(3)每个端口都可以配置三种最大输出翻转速度
在配置寄存器里设置即可


后面都是关于硬件设计的,只要做了解即可!

(4)外设的GPIO配置

PS:GPIO端口和引脚的关系:一个GPIO端口是一组GPIO引脚,一个引脚就是在板子上的一个接线点,比如下面,PA是一个GPIO端口,PAx(x=0...15)就是一个引脚

3.4.2.STM32的GPIO模块数据手册详解2

(1)GPIO寄存器描述

  • GPIO的寄存器基地址是0x40010800
     
  •  端口配置低寄存器(GPIOx_CRL) (x=A..E)
  •  端口配置高寄存器(GPIOx_CRH) (x=A..E)
    为什么会有两个端口配置寄存器呢?因为一个端口配置寄存器只能配置8个引脚,两个就可以配置一个端口!CNFx位和MODE位关联配置输入/输出模式、输出模式xMHz
  •  端口输入数据寄存器(GPIOx_IDR) (x=A..E)
  •  端口输出数据寄存器(GPIOx_ODR) (x=A..E)
  •  端口位设置/ 清除寄存器(GPIOx_BSRR) (x=A..E)
    是对ODR位置位/复位
    如果BRy和BSy同时被置位,BSy有优先权。
  • 端口位清除寄存器 端口位清除寄存器(GPIOx_BRR) (x=A..E)

  • 端口配置锁定寄存器 端口配置锁定寄存器(GPIOx_LCKR) (x=A..E)

(2)复用
AFIO的起始地址:0x4001 0000

3.4.3.原理图分析与MDK工程建立

3.4.3.1、硬件接线
(1)杜邦现连接P0端口到LED接口J19,这样相当于8个LED分别对应PB8-PB15

  • PB8—LED0,PB9—LED1...
  • PB8-PB15是咱们的P0端口

(2)LED是共阴,所以GPIO输出0就亮,输出1就灭!
接线如下:


3.4.3.2、MDK工程建立

(1)根据STC51的经验

  • 打开keil—New project—添加main.c—Create hex file—编程运行!我们先试一下!
    在main.c中添加代码!
  1. int main(void)
  2. {
  3. }
  • 点击编译,发现报错了!


原因在于,我们没有给它加启动文件!

  • 启动文件,见过吗?
    在STC51开发时,我们新建一个文件,他就会添加一个文件STARTUP.A51,这个就是启动文件!在STM32中,启动文件是什么呢?
  • 启动文件简介
  • 启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:
    1、初始化堆栈指针SP=_initial_sp
    2、初始化PC 指针= Reset_Handler
    3、初始化中断向量表
    4、配置系统时钟
    5、调用C 库函数_main 初始化用户堆栈,从而最终调用main 函数去到C 的世界    
  1. ;从启动文件都main.c代码段
  2. ; Reset Handler
  3. Reset_Handler PROC
  4. EXPORT Reset_Handler [WEAK]
  5. IMPORT __main
  6. LDR R0, =__main
  7. BX R0
  8. ENDP
  • 在寄存器编程时,大家可以先用下面这个启动文件,下一节库函数编程再细讲!
  • 下载地址

  • 再次编译就无误了!

至此,一个新建立的工程就算完成了,目前还没开始在main.c中写代码!


3.4.4.写代码控制GPIO点亮熄灭LED

3.4.4.1、编程思路

  • 我们通过对GPIO寄存器编程来控制LED的亮灭,需要配置寄存器的输入输出模式、需要选择引脚、需要往输出寄存器写值
  • 每个GPIO寄存器在内存中都有自己的地址,我们可以通过给地址内写值来配置寄存器

3.4.4.2、寄存器信息确认
(1)STM32 GPIOB的起始地址是:0x40010C00
(2)有可能涉及到的GPIO的地址:
  
(3)会用到的寄存器

  • 由于PB8-PB15为GPIOB的高八个引脚,所以会使用CRH寄存器
  • 因为要做输出,所以要使用ODR寄存器
  • BSRR和BRR可以选用!    

3.4.4.3、C语言操作寄存器
(1)ARM是内存与IO统一编址的

  • 所以ARM中的所有外设都是通过寄存器的方式来操作的
  • 后面学的库函数编程,本质上也是寄存器编程,只不过是STM32已经做好了寄存器的封装!

(2)每个寄存器都有地址

  • C语言通过这些地址来操作这些寄存器位,用到的C语言技巧主要是C语言的位操作和C语言指针。

(3)常见面试题:用C语言向内存地址0x30000004写入16,如何做?

  1.     *(unsigned int *)0x30000004 = 16;  
  2. 或者
  3.     unsigned int *p = (unsigned int *)0x30000004;    
  4. *p = 16;

(4)编程

  • 我们可以设置输出模式为推挽输出、输出翻转速度为50MHz
  • 因此CRH =  0x33333333
  • 我们可以先点亮所有灯
  • 所以ODR = 0x00000000(8-15位为0,其他0/1都可以!)

(5)代码如下(但是你会发现,灯根本不亮,为什么呢?后面分析)

  1. #define GPIOB_CRH 0x40010C04
  2. #define GPIOB_ODR 0x40010C0C
  3. int main(void)
  4. {
  5. //GPIOB设置成推挽输出模式,速度是50MHz
  6. *((unsigned int *) GPIOB_CRH) = 0x33333333;
  7. *((unsigned int *) GPIOB_ODR) = 0x00000000;
  8. //也可以用BSRR将PB8-PB15都复位成0
  9. //*((unsigned int *) GPIOB_BSRR) = 0xff000000;
  10. while(1);
  11. }

3.4.5.STM32时钟设置函数移植与讲解1

3.4.6.1、LED不亮问题解决
(1)为什么LED灯不亮呢?

  • STM32中的每一个外设都对应了一个时钟,当我们想要使用某一个外设的时候,必须先要开启它的时钟才行。GPIO需要时钟使能才能工作!

(2)GPIO的时钟使能如何实现?

  • 查看数据手册中的:APB2 外设时钟使能寄存器(RCC_APB2ENR)

  • 我们想要端口时钟使能,只要配置RCC_APB2ENR相应位。



通过查询RCC寄存器组的基地址和RCC_APB2ENR的地址偏移量,得到RCC_APB2ENR的地址为0x40021018

  • 于是RCC_APB2ENR = 0x00000008就可以开启GPIOB的时钟使能开关!
  1. #define GPIOB_CRH 0x40010C04
  2. #define GPIOB_ODR 0x40010C0C
  3. #define RCC_APB2ENR 0x40021018
  4. int main(void)
  5. {
  6. //GPIO时钟使能
  7. *((unsigned int *)RCC_APB2ENR) = 0x00000008;
  8. //GPIOB设置成推挽输出模式,速度是50MHz
  9. *((unsigned int *) GPIOB_CRH) = 0x33333333;
  10. *((unsigned int *) GPIOB_ODR) = 0x00000000;
  11. while(1);
  12. }

3.4.6.2、GPIO点亮LED灯的流程

  • Step1:使能GPIO的时钟
  • Step2:初始化GPIO引脚至相应的模式:推挽输出+50MHz
  • Step3:控制GPIO引脚输出高低电平
  • Step4:使用GPIO控制LED

到这里我们基本上已经完成了GPIO点亮小灯的设置,下面是关于官方时钟示例代码的移植。为什么移植?
上节课讲过,上电复位之后,系统的默认时钟是内部的HSI,我们研究下如何将时钟从HSI转换到HSE。

3.4.6.4、时钟代码移植
官方示例代码:LED闪烁
重点是:void Set_SysClockTo72MHz(void);


3.4.6.STM32时钟设置函数移植与讲解2

新建rcc.h和rcc.c实现HSI—>HSE的转换!主要是根据时钟框图

咱们时钟配置过程:HSE OSCIN(8M)——PLLSRC——PLLMUL(倍频*9=72M)——PLLCLK——SYSCLK(72M)—— AHB预分频(*1)——APB2(*1=72M)——PCLK2

  • RCC上电复位
  • RCC开启外部时钟HSE
  • FLASH预取指(预取指的作用)
  • 选择HSE不分频作为PLL输入
  • PLL倍频
  • 设置APB1、APB2、AHB分频
  • PLL时钟开启
  • 选择PLL作为Sysclk来源
  • 系统时钟配置成功

代码下载  
 

3.4.7.STM32外设编程经验总结

3.5.7.1、STM32和51或其他简单单片机的相同
(1)开关环境都是Keil
(2)都是看原理图和数据手册
(3)都是用C语言
3.4.7.2、STM32和51或其他简单单片机的不同
(1)工程会更复杂,会用到Keil的一些高级设置
(2)原理图和数据手册比简单单片机更复杂(复杂不是难)
(3)STM32会用到C语言的更多高级特性
3.4.7.3、外设编程思路
(1)都是套路
(2)会出现问题,这时候就需要调试能力(不一定非要调试器)
(3)注意熟悉和体会这种套路,后面引入库函数就是从这里讲起的

本节课结束!


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/507138
推荐阅读
相关标签
  

闽ICP备14008679号