STM32F103寄存器方式点亮LED流水灯与GPIO简单讲解 您所在的位置:网站首页 led灯芯片是什么材料制作的原理呢 STM32F103寄存器方式点亮LED流水灯与GPIO简单讲解

STM32F103寄存器方式点亮LED流水灯与GPIO简单讲解

2024-07-12 20:20| 来源: 网络整理| 查看: 265

前言:

以本文章主要讲解以正点原子STM32mini板(STM32F103RC)+面板板+3只红绿蓝LED 搭建电路,使用GPIOB、GPIOC、GPIOD这3个端口控制LED灯,轮流闪烁。与STM32F103系列芯片的地址映射和寄存器映射原理等

注:

       本篇博客是基于正点原子STM32mini开发板(STM32F103RC)所作,不同的32板子可能会有所不同,注意区分。

目录

一、stm32芯片寄存器与GPIO端口简介

1.地址映射和寄存器映射原理

2.GPIO简介与工作模式

3.输入输出简介

4.GPIO初始化步骤

5.实例

1.对于单个GPIO口的初始化如下

2.对于多个GPIO口的初始化如下

二、软件设计

1.实验原理

2.代码编写

1.配置寄存器

2.主函数编写

3.程序的烧录

三、硬件部分

1.材料与GPIO口的选择

2.连线

3.结果展示 

四、汇编语言实现流水灯

1.代码部分

2.实验结果

五、参考网站

 

一、stm32芯片寄存器与GPIO端口简介

   寄存器是 CPU 内部的构造,它主要用于信息的存储。

1.地址映射和寄存器映射原理

      存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射。

寄存器映射:       每个寄存器都是32bit,占用4个Byte即4个存储单元。可以把寄存器看作一个特殊的单元,一个这样的单元占32bit,只要找到这个单元的起始地址就可以对其进行操作。

      其映射地址 = 外设总基地址(块基地址)+ 总线相对于外设总基地址的偏移 + 具体外设基地址相对于总线基地址的偏移 + 寄存器相对于具体外设基地址的偏移。

2.GPIO简介与工作模式

GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚。

GPIO的工作模式主要有八种:4种输入方式,4种输出方式。

分别为输入浮空,输入上拉,输入下拉,模拟输入; 输出方式为开漏输出,开漏复用输出,推挽输出,推挽复用输出。

(1)GPIO_Mode_AIN 模拟输入 (应用ADC模拟输入,或者低功耗下省电) (2)GPIO_Mode_IN_FLOATING 浮空输入 (浮空就是浮在半空,可以被其他物体拉上或者拉下,可以用于按键输入) (3)GPIO_Mode_IPD 下拉输入 (IO内部下拉电阻输入) (4)GPIO_Mode_IPU 上拉输入 (IO内部上拉电阻输入) (5)GPIO_Mode_Out_OD 开漏输出(开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行) (6)GPIO_Mode_Out_PP 推挽输出 (推挽就是有推有拉电平都是确定的,不需要上拉和下拉,IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的 ) (7)GPIO_Mode_AF_OD 复用开漏输出(片内外设功能(I2C的SCL,SDA)) (8)GPIO_Mode_AF_PP 复用推挽输出 (片内外设功能(TX1,MOSI,MISO.SCK.SS))

3.输入输出简介

 

输入: 进行数据的采集,外部电路通过IO口输入模拟量,然后通过“TTL肖特基触发器”(肖特基触发器是将相对缓慢变化的模拟信号变成矩形信号,便于后面读取),进入输入数据寄存器,最后就能给CPU读取数据。

输出: GPIO的输出与51的 IO口是差不多的概念,都是输出高、低电平来控制外部电路:

处理过程:CPU下达输出高或低电平指令,指令配置“位设置/清除寄存器(GPIOx_BSRR)”(设置就是“1”高电平,清除就是“0”低电平),再由位寄存器配置输出数据寄存器(GPIOx_ODR),经过一个选择器(选择是一般输出还是复用功能输出),然后进行输出控制,控制是什么模式:推挽、开漏或者关闭,然后输出高或低电平到IO口。

下面是正点原子手册上的一些介绍:    

  STM32 的每个 IO 端口都有 7 个寄存器来控制。他们分别是:配置模式的 2 个 32 位的端口 配置寄存器 CRL 和 CRH ; 2 个 32 位的数据寄存器 IDR 和 ODR ; 1 个 32 位的置位 / 复位寄存器 BSRR ;一个 16 位的复位寄存器 BRR ; 1 个 32 位的锁存寄存器 LCKR ;这里我们仅介绍常用 的 几个寄存器,我们常用的 IO 端口寄存器只有 4 个: CRL 、 CRH 、 IDR 、 ODR 。       CRL 和 CRH 控制着每个 IO 口的模式及输出速率。 STM32 的 IO 口位配置表如表

STM32 输出模式配置如表 

 

 接下来我们看看端口低配置寄存器 CRL 的描述

 

该寄存器的复位值为0X4444 4444,从上图可以看到,复位值其实就是配置端口为浮空输入模式。从上图还可以得出:STM32 的CRL控制着每组IO端口(A~G)的低8位的模式。 每个IO端口的位占用CRL的 4 个位,高两位为CNF,低两位为MODE。这里我们可以记住几个常用的配置,比如0X0表示模拟输入模式(ADC 用)、0X3表示推挽输出模式(做输出口用,50M速率)、0X8表示上/下拉输入模式(做输入口用)、0XB表示复用输出(使用IO口的第二功能,50M速率)。

   CRH的作用和CRL完全一样,只是CRL控制的是低8位输出口,而CRH控制的是高8位输出口。这里我们对CRH就不做详细介绍了。

   给个实例,比如我们要设置PORTA的8位为上拉输入,13位为复用输出。代码如下:

GPIOC->CRH&=0XFFF00FFF;//清掉这 2 个位原来的设置,同时也不影响其他位的设置 GPIOC->CRH|=0X00038000; //PC11 输入,PC12 输出 GPIOC->ODR=1给IO口电平->控制LED亮灭

stm32的点灯则是,通过使能外设GPIO时钟,发出指令给外设GPIO,外设GPIO收到指令后,着手配置自己的寄存器,然后给IO口模式,让其实现各种功能。 其过程:CPU给指令->GPIO收到指令->配置内部寄存器->配置IO口模式(注意是模式)->控制LED亮灭

2.代码编写 1.配置寄存器

led.h

#ifndef __LED_H #define __LED_H #include "sys.h" //LED端口定义 #define LED0 BIT_ADDR(GPIOB_ODR_Addr,6) // PB6输出 #define LED1 BIT_ADDR(GPIOC_ODR_Addr,6) // PC6输出 #define LED2 BIT_ADDR(GPIOD_ODR_Addr,2) // PD2输出 void LED_Init(void); //初始化 #endif

 led.c 

#include "sys.h" #include "led.h" //初始化PB6、PC6和PD2为输出口,并使能这3个口的时钟 //LEDIO初始化 void LED_Init(void) { RCC->APB2ENR|=1ODR|=1CRL|=0X00000300;//PD2推挽输出 GPIOD->ODR|=10; j--) for(k =200; k>0; k--); } int main(void) { LED_Init(); //初始化与LED连接的硬件接口 while(1) { LED0=0; //灯亮 LED1=1; //灯灭 LED2=1; delay(20); //延时 LED0=1; LED1=0; LED2=1; delay(20); LED0=1; LED1=1; LED2=0; delay(20); } } 3.程序的烧录

用对应的线接stm32板子的usb232接口使之与pc连接。

这里我用的是FlyMcu。点击搜索串口,我的串口是COM5  串口波特率则可以通过bps那里设置

对于STM32F103,可以设置为最高:460800,而如果是 F4,则建议最高设置为:76800 即可。

DTR的低电平复位,RTS高电平进BootLoader

效验与编译后执行勾选,点击开始编程输出正常时烧录完成

三、硬件部分 1.材料与GPIO口的选择

材料:正点原子stm32mini开发板+杜邦线+红、黄、绿led灯+面包板

 

GPIO口选择GPIOB、GPIOC、GPIOD这3个端口控制LED灯具体为PB6、PC6、PD2(可以自行选择,只需要稍微修改代码即可)

2.连线

按着stm32手册连线即可

LED灯的短脚连接IO口,长脚连接3.3V(注:尽量不要连接5V的端口,5V的端口没有电阻保护,容易烧坏LED灯)

 

3.结果展示 

 

 

四、汇编语言实现流水灯 1.代码部分 RCC_APB2ENR EQU 0x40021018 GPIOA_CRH EQU 0x40010804 GPIOA_ODR EQU 0x4001080C GPIOB_CRL EQU 0x40010C00 ;寄存器映射 GPIOB_ODR EQU 0x40010C0C GPIOC_CRH EQU 0x40011004 GPIOC_ODR EQU 0x4001100C Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 ;NOINIT: = NO Init,不初始化。READWRITE : 可读,可写。ALIGN =3 : 2^3 对齐,即8字节对齐。 Stack_Mem SPACE Stack_Size __initial_sp AREA RESET, DATA, READONLY __Vectors DCD __initial_sp DCD Reset_Handler AREA |.text|, CODE, READONLY THUMB REQUIRE8 PRESERVE8 ENTRY Reset_Handler MainLoop BL LED2_Init BL LED2_ON BL Delay ;LED2灯闪烁 BL LED2_OFF BL Delay BL LED1_Init BL LED1_ON BL Delay ;LED1灯闪烁 BL LED1_OFF BL Delay BL LED3_Init BL LED3_ON BL Delay ;LED3灯闪烁 BL LED3_OFF BL Delay B MainLoop LED1_Init PUSH {R0,R1, LR} ;R0,R1,LR中的值放入堆栈 LDR R0,=RCC_APB2ENR ;LDR是把地址装载到寄存器中(比如R0)。 ORR R0,R0,#0x08 ;开启端口GPIOB的时钟,ORR 按位或操作,01000将R0的第二位置1,其他位不变 LDR R1,=RCC_APB2ENR STR R0,[R1] ;STR是把值存储到寄存器所指的地址中,将r0里存储的值给rcc寄存器 ;上面一部分汇编代码是控制时钟的 LDR R0,=GPIOB_CRL ORR R0,R0,#0X00000020 ;GPIOB_Pin_1配置为通用推挽输出;开启的是pb1,所以是2,为0010,是推挽输出模式,最大速度为2mhz LDR R1,=GPIOB_CRL STR R0,[R1] LDR R0,=GPIOB_ODR BIC R0,R0,#0X00000002 ;BIC 先把立即数取反,再按位与 LDR R1,=GPIOB_ODR ;GPIOB_Pin_1输出为0;由r1控制ord寄存器 STR R0,[R1] ;将ord寄存器的值变为r0的值 POP {R0,R1,PC} ;将栈中之前存的R0,R1,LR的值返还给R0,R1,PC LED1_OFF PUSH {R0,R1, LR} LDR R0,=GPIOB_ODR BIC R0,R0,#0X00000002 ;因为是PB1所以对应二进制0010;GPIOB_Pin_1输出为0,LED1熄灭 LDR R1,=GPIOB_ODR STR R0,[R1] POP {R0,R1,PC} LED1_ON PUSH {R0,R1, LR} LDR R0,=GPIOB_ODR ORR R0,R0,#0X00000002 ;GPIOB_Pin_1输出为1,LED1亮 LDR R1,=GPIOB_ODR STR R0,[R1] POP {R0,R1,PC} LED2_Init PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈 LDR R0,=RCC_APB2ENR ORR R0,R0,#0x04 ;打开GPIOA的时钟 LDR R1,=RCC_APB2ENR STR R0,[R1] LDR R0,=GPIOA_CRH ORR R0,R0,#0X00020000 ;GPIOA_Pin_12配置为通用推挽输出 LDR R1,=GPIOA_CRH STR R0,[R1] LDR R0,=GPIOA_ODR BIC R0,R0,#0X00001000 LDR R1,=GPIOA_ODR ;GPIOA_Pin_12输出为0 STR R0,[R1] POP {R0,R1,PC} LED2_OFF PUSH {R0,R1, LR} LDR R0,=GPIOA_ODR BIC R0,R0,#0X00001000 ;GPIOA_Pin_12输出为0,LED2熄灭 LDR R1,=GPIOA_ODR STR R0,[R1] POP {R0,R1,PC} LED2_ON PUSH {R0,R1, LR} LDR R0,=GPIOA_ODR ORR R0,R0,#0X00001000 ;GPIOA_Pin_12输出为1,LED2亮 LDR R1,=GPIOA_ODR STR R0,[R1] POP {R0,R1,PC} LED3_Init PUSH {R0,R1, LR} LDR R0,=RCC_APB2ENR ORR R0,R0,#0x10 ;打开GPIOC的时钟 LDR R1,=RCC_APB2ENR STR R0,[R1] LDR R0,=GPIOC_CRH ORR R0,R0,#0X02000000 ;GPIOC_Pin_14配置为通用推挽输出 LDR R1,=GPIOC_CRH STR R0,[R1] LDR R0,=GPIOC_ODR BIC R0,R0,#0X00004000 ;GPIOC_Pin_14输出为0 LDR R1,=GPIOC_ODR STR R0,[R1] POP {R0,R1,PC} LED3_OFF PUSH {R0,R1, LR} LDR R0,=GPIOC_ODR BIC R0,R0,#0X00004000 ;GPIOC_Pin_14输出为0,LED3熄灭 LDR R1,=GPIOC_ODR STR R0,[R1] POP {R0,R1,PC} LED3_ON PUSH {R0,R1, LR} LDR R0,=GPIOC_ODR ORR R0,R0,#0X00004000 ;GPIOC_Pin_14输出为1,LED3亮 LDR R1,=GPIOC_ODR STR R0,[R1] POP {R0,R1,PC} Delay PUSH {R0,R1, LR} MOVS R0,#0 MOVS R1,#0 MOVS R2,#0 DelayLoop0 ADDS R0,R0,#1 CMP R0,#300 BCC DelayLoop0 MOVS R0,#0 ADDS R1,R1,#1 CMP R1,#300 BCC DelayLoop0 MOVS R0,#0 MOVS R1,#0 ADDS R2,R2,#1 CMP R2,#15 BCC DelayLoop0 POP {R0,R1,PC} END

 其他过程都类似的

2.实验结果

 ps建议: 正点原子和野火的板子和操作手册都很不错的,值得学习,本次代码就是在正点原子所给的资料里面的流水灯代码所改,是新手起步的好教程。面包版和杜邦线也是非常好用的硬件工具,不需要复杂的焊接。

五、参考网站

都是大佬 推荐观看 

https://blog.csdn.net/weixin_44188050/article/details/103999663icon-default.png?t=L9C2https://blog.csdn.net/weixin_44188050/article/details/103999663https://blog.csdn.net/geek_monkey/article/details/86291377icon-default.png?t=L9C2https://blog.csdn.net/geek_monkey/article/details/86291377

https://blog.csdn.net/qq_46467126/article/details/120791793icon-default.png?t=L9C2https://blog.csdn.net/qq_46467126/article/details/120791793



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有