STM32F103寄存器方式点亮LED

本文介绍了STM32F103芯片的存储器映射和寄存器映射原理,详细阐述了存储器区域功能划分和寄存器映射的概念。通过实例展示了如何使用C语言访问寄存器控制GPIO端口,实现流水灯效果,加深了对STM32外设控制的理解。
摘要由CSDN通过智能技术生成

一、STM32F103系列芯片的存储器映射和寄存器映射原理

1.存储器映射
存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址 的过程就称为存储器映射,具体见下图。如果给存储器再分配一个地址就叫存储器重映射。

存储器区域功能划分

在这 4GB 的地址空间中,ARM 已经粗线条的平均分成了 8 个块,每块 512MB,每个 块也都规定了用途,具体分类见表格 6-1。每个块的大小都有 512MB,显然这是非常大的,芯片厂商在每个块的范围内设计各具特色的外设时并不一定都用得完,都是只用了其中的 一部分而已。

存储器功能分类
在这里插入图片描述
在这里插入图片描述
2.寄存器映射
我们知道,存储器本身没有地址,给存储器分配地址的过程叫存储器映射,那什么叫 寄存器映射?寄存器到底是什么?

在存储器 Block2 这块区域,设计的是片上外设,它们以四个字节为一个单元,共 32bit, 每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到 每个单元的起始地址,然后通过 C 语言指针的操作方式来访问这些单元,如果每次都是通 过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的 不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个 给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。

比如,我们找到 GPIOB 端口的输出数据寄存器 ODR 的地址是 0x4001 0C0C(至于这 个地址如何找到可以先跳过,后面我们会有详细的讲解),ODR 寄存器是 32bit,低 16bit 有效,对应着 16 个外部 IO,写 0/1 对应的的 IO 则输出低/高电平。现在我们通过 C 语言指 针的操作方式,让 GPIOB 的 16 个 IO 都输出高电平。

二、 用C语言寄存器实现流水灯

在这里插入图片描述
接线

main.c

#define RCC_AP2ENR	*((unsigned volatile int*)0x40021018)
	//----------------GPIOA配置寄存器 ------------------------
#define GPIOA_CRH	*((unsigned volatile int*)0x40010804)
#define	GPIOA_ORD	*((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 ------------------------
#define GPIOB_CRL	*((unsigned volatile int*)0x40010C00)
#define	GPIOB_ORD	*((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 ------------------------
#define GPIOC_CRH	*((unsigned volatile int*)0x40011004)
#define	GPIOC_ORD	*((unsigned volatile int*)0x4001100C)
//-------------------简单的延时函数-----------------------
void  Delay_ms( volatile  unsigned  int  t)
{
     unsigned  int  i;
     while(t--)
         for (i=0;i<800;i++);
}
//------------------------主函数--------------------------
int main()
{
	int j=100;
	RCC_AP2ENR|=1<<2;			//APB2-GPIOA外设时钟使能
	RCC_AP2ENR|=1<<3;			//APB2-GPIOB外设时钟使能	
	RCC_AP2ENR|=1<<4;			//APB2-GPIOC外设时钟使能
	//这两行代码可以合为 RCC_APB2ENR|=1<<3|1<<4;
	GPIOA_CRH&=0xFFF0FFFF;		//设置位 清零	
	GPIOA_CRH|=0x00020000;		//PA12推挽输出
	GPIOA_ORD|=1<<12;			//设置初始灯为亮
	
	GPIOB_CRL&=0xFFFFFF0F;		//设置位 清零	
	GPIOB_CRL|=0x00000020;		//PB1推挽输出
	GPIOB_ORD|=1<<1;			//设置初始灯为灭
	
	GPIOC_CRH&=0xF0FFFFFF;		//设置位 清零
	GPIOC_CRH|=0x02000000;   	//PC14推挽输出
	GPIOC_ORD|=1<<14;			//设置初始灯为灭	
	while(j)
	{	
		GPIOA_ORD=0x1<<12;		//PA12高电平	
		Delay_ms(3000000);
		GPIOA_ORD=0x0<<12;		//PA12低电平
		Delay_ms(3000000);
		
		GPIOB_ORD=0x1<<1;		//PB1高电平	
		Delay_ms(3000000);
		GPIOB_ORD=0x0<<1;		//PB1低电平
		Delay_ms(3000000);
		
		GPIOC_ORD=0x1<<14;		//PC14高电平	
		Delay_ms(3000000);
		GPIOC_ORD=0x0<<14;		//PC14低电平
		Delay_ms(3000000);
	}
}

在这里插入图片描述
在这里插入图片描述

汇编代码

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          ;GPIO_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;GPIO_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    ;GPIO_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

编译生成hex文件
在这里插入图片描述
在这里插入图片描述
结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、总结

通过查阅资料与请教,慢慢的理解了stm32的工作原理,以及串行口的转换关系,基本掌握了软硬件结合的实验。

四、参考文献

https://blog.csdn.net/geek_monkey/article/details/86291377
https://blog.csdn.net/geek_monkey/article/details/86293880
https://blog.csdn.net/m0_51120713/article/details/120832645?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163488412516780357238656%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163488412516780357238656&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-120832645.pc_search_ecpm_flag&utm_term=STM32F103%E5%AF%84%E5%AD%98%E5%99%A8%E6%96%B9%E5%BC%8F%E7%82%B9%E4%BA%AELED%E6%B5%81%E6%B0%B4%E7%81%AF&spm=1018.2226.3001.4187

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值