32之寄存器点亮流水灯

本文内容:本文主要介绍寄存器原理和地址配置方式,以及用汇编语言和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 IO³õʼ»¯
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博客

猜你喜欢

转载自blog.csdn.net/m0_58414679/article/details/120737509