本文内容:本文主要介绍寄存器原理和地址配置方式,以及用汇编语言和c语言调用寄存器将LED点亮
目录
一、何为寄存器
二、GPIO
(一)简介
(二)工作模式
(三)GPIO的寻址
三、 点灯
(一)汇编点灯
(二)C语言点灯
?(三)库函数实现流水灯
四、总结
五、参考文章?
一、何为寄存器
用官话来讲,寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。
简单的讲,如果将我们的计算机比作一栋大楼,而寄存器就是这栋大楼中的每一间房子,寄存器地址便可以看做是房子的门牌号,只不过这个门牌号有点特殊,是由01比特流构成的。
二、GPIO
(一)简介
GPIO
是通用输入输出端口的简称,简单来说就是
STM32
可控制的引脚,
STM32
芯片
的
GPIO
引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。
所有的
GPIO
引脚都有基本的输入输出功能。
(二)工作模式
typedef enum
{
GPIO_Mode_AIN = 0x0, // 模拟输入
GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入
GPIO_Mode_IPD = 0x28, // 下拉输入
GPIO_Mode_IPU = 0x48, // 上拉输入
GPIO_Mode_Out_OD = 0x14, // 开漏输出
GPIO_Mode_Out_PP = 0x10, // 推挽输出
GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出
GPIO_Mode_AF_PP = 0x18 // 复用推挽输出
} GPIOMode_TypeDef;
我们点亮LED灯,需要设置成推挽输出模式。
(三)GPIO的寻址
?详细请移步到这位大佬,讲的很清晰:
STM32寄存器的简介、地址查找,与直接操作寄存器_geekYatao-CSDN博客
三、 点灯
(一)汇编点灯
下面为点亮PB5连接的LED的汇编程序:
注:选择运行环境时,不用再勾选 “Startup” 和 “CORE”。
LED0 EQU 0x42218194
RCC_APB2ENR EQU 0x40021018
;GPIOA_CRH EQU 0x40010804
GPIOB_CRL EQU 0x40010C00
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
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
BL LED_Init
MainLoop BL LED_ON
BL Delay
BL LED_OFF
BL Delay
B MainLoop
LED_Init
PUSH {R0,R1, LR}
LDR R0,=RCC_APB2ENR
ORR R0,R0,#0x08
LDR R1,=RCC_APB2ENR
STR R0,[R1]
LDR R0,=GPIOB_CRL
BIC R0,R0,#0XFF0FFFFF
LDR R1,=GPIOB_CRL
STR R0,[R1]
LDR R0,=GPIOB_CRL
ORR R0,R0,#0X00300000
LDR R1,=GPIOB_CRL
STR R0,[R1]
MOV R0,#1
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
LED_ON
PUSH {R0,R1, LR}
MOV R0,#0
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF
PUSH {R0,R1, LR}
MOV R0,#1
LDR R1,=LED0
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,#330
BCC DelayLoop0
MOVS R0,#0
ADDS R1,R1,#1
CMP R1,#330
BCC DelayLoop0
MOVS R0,#0
MOVS R1,#0
ADDS R2,R2,#1
CMP R2,#15
BCC DelayLoop0
POP {R0,R1,PC}
END
下面用mcuisp烧录程序
烧录成功
下面是连线:?
将LED的一端接PB5,一端接3.3V
注:最好别接5V,没有电阻的保护,很容易烧,笔者已经烧了好几个
这里我用的是准备电赛时买的STM32F103RC小黑板
效果如图:
?
(二)C语言点灯
我是用的正点原子的点灯程序改的,因为文件太多,下面只列举了部分主要文件
代码如下:
test.c
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
LED_Init(); //LED初始化
while(1)
{
LED0=0;
delay_ms(1000); //延时1s
LED0=1;
delay_ms(1000);
}
}
?led.h
#ifndef __LED_H
#define __LED_H
#include "sys.h"
#define LED0 PAout(8) // PA8
void LED_Init(void);
#endif
?led.c
#include "sys.h"
#include "led.h"
//LED IO初始化
void LED_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X00000003;//PA8 推挽输出
GPIOA->ODR|=1<<8; //PA8 输出高
}
LED两端分别连到PA8和3.3V
效果如图:
?(三)库函数实现流水灯
相比寄存器的代码,库函数可读性更高,用起来更方便,这也是笔者之前一直在用的方式,下面用库函数写个流水灯
代码如下:
main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //LED初始化
while(1)
{
LED0=0;
delay_ms(1000); //延时1s
LED0=1;
delay_ms(1000);
LED1=0;
delay_ms(1000);
LED1=1;
delay_ms(1000);
LED2=0;
delay_ms(1000);
LED2=1;
delay_ms(1000);
}
}
led.h
#ifndef __LED_H
#define __LED_H
#include "sys.h"
#define LED0 PAout(6) // PA6
#define LED1 PBout(7) // PA7
#define LED2 PBout(8) // PA8
void LED_Init(void);
#endif
led.c
#include "led.h"
//LED IO3?ê??ˉ
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8; //PB6,PB7,PB8端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定函数初始化GPIOB
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8); //PB6,PB7,PB8输出高
}
这里要用到3个LED,每个LED的长引脚连3.3V,短引脚分别连PB6,7,8
硬件的效果如下:
四、总结
本次实验主要进行了LED的寄存器点灯实验,之前一直都是用库函数来写,并没有用过寄存器,这次使用也确实感受到了它的繁琐,尤其是GPIO地址,还需要查阅手册,可读性很差,编程过程中也遇到了很多困难,不过通过查阅资料,也了解到了寄存器的寻址原理,虽然繁琐,但是更直观的和计算机进行交流,感觉还是不错的。
五、参考文章?
?STM32汇编程序及点灯实验_lxy13608322474的博客-CSDN博客
STM32寄存器的简介、地址查找,与直接操作寄存器_geekYatao-CSDN博客
|