基于汇编和C语言STM32流水灯依次闪烁

目录

一、初始化

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

1.1 总线基地址

1.2 外设基地址

1.3 外设寄存器地址

1.4接线

1.4.1 将串口USB转TTL线与stm32核心板连接如图所示

1.4.2 并且要设.BOOT0 与 BOOT1 配置启动方式。 

1.5 程序下载

1.6 总的实际连线图

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

2.1 工程文件

2.1.1 main.c

2.1.2加入设备

2.2 编译生成hex文件

2.3 用mcuisp烧入stm32如1.5步骤所示。

2.4 实验成果​

 三、汇编语言实现流水灯

3.1 汇编代码

3.2添加工程文件

3.4 烧录程序 

 3.5实验成果

 四、心得


一、初始化

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

1.1 总线基地址

总线名称总线基地址相对外设基地址的偏移
APB10x4000 00000x0
APB20x4001 00000x0001 0000
AHB0x4001 80000x0001 8000

1.2 外设基地址

外设名称外设基地址相对 APB2 总线的地址偏移
GPIOA0x4001 08000x0000 0800
GPIOB0x4001 0C000x0000 0C00
GPIOC0x4001 10000x0000 1000
GPIOD0x4001 14000x0000 1400
GPIOE0x4001 18000x0000 1800
GPIOF0x4001 1C000x0000 1C00
GPIOG0x4001 20000x0000 2000

1.3 外设寄存器地址

本文要用到GPIOA,GPIOB,GPIOC。

下列表格是通过查表得出如果需要了解寄存器地址原理请访问STM32寄存器的简介、地址查找,与直接操作寄存器_geekYatao-CSDN博客_stm32寄存器

STM32从地址到寄存器_geekYatao-CSDN博客_stm32寄存器地址

寄存器名称寄存器地址相对 GPIOA 基址的偏移
GPIOA_CRL0x4001 08000x00
GPIOA_CRH0x4001 08040x04
GPIOA_IDR0x4001 08080x08
GPIOA_ODR0x4001 080C0x0C
GPIOA_BSRR0x4001 08100x10
GPIOA_BRR0x4001 08140x14
GPIOA_LCKR0x4001 08180x18
寄存器名称寄存器地址相对 GPIOB 基址的偏移
GPIOB_CRL0x4001 0C000x00
GPIOB_CRH0x4001 0C040x04
GPIOB_IDR0x4001 0C080x08
GPIOB_ODR0x4001 0C0C0x0C
GPIOB_BSRR0x4001 0C100x10
GPIOB_BRR0x4001 0C140x14
GPIOB_LCKR0x4001 0C180x18
寄存器名称寄存器地址相对 GPIOC 基址的偏移
GPIOC_CRL0x4001 10000x00
GPIOC_CRH0x4001 10040x04
GPIOC_IDR0x4001 10080x08
GPIOC_ODR0x4001 100C0x0C
GPIOC_BSRR0x4001 10100x10
GPIOC_BRR0x4001 10140x14
GPIOC_LCKR0x4001 10180x18
寄存器名称寄存器地址相对 GPIOD 基址的偏移
GPIOD_CRL0x4001 14000x00
GPIOD_CRH0x4001 14040x04
GPIOD_IDR0x4001 14080x08
GPIOD_ODR0x4001 140C0x0C
GPIOD_BSRR0x4001 14100x10
GPIOD_BRR0x4001 0C140x14
GPIOD_LCKR0x4001 0C180x18

因为stm32最小板仅有ABC三个引脚系列。0-7位为CRL,8-15位为CRH,相对基址的偏移即从基址开始多少十六进制后是此寄存器地址的开始,不同的寄存器有不同的地址,需要去访问该地址,就需要查表。

时钟寄存器在APB2线

 

 因此后续代码都是0x00000002对应的是0010

高位同理

1.4接线

1.4.1 将串口USB转TTL线与stm32核心板连接如图所示
 

1.4.2 并且要设.BOOT0 与 BOOT1 配置启动方式。 

BOOT1=xBOOT0=0从用户闪存启动,这是正常的工作模式。 
BOOT1=0BOOT0=1(ISP方式)从系统存储器启动,这种模式启动的程序功能由厂家设置。
BOOT1=1BOOT0=1从内置SRAM启动,这种模式可以用于调试.

如图所示

1.5 程序下载

1.6 总的实际连线图

 因为本文主要用到PA12,PB1,PC14引脚。

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

2.1 工程文件

2.1.1 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);
	}
}

 使用高电平点亮低电平熄灭

2.1.2加入设备

2.2 编译生成hex文件

2.3 用mcuisp烧入stm32如1.5步骤所示。

2.4 实验成果

 三、汇编语言实现流水灯

3.1 汇编代码

1.s

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

3.2添加工程文件

因为自带starup启动文件因此不需要添加设备

 3.3 进行编译生成hex文件

3.4 烧录程序 

 3.5实验成果

 四、心得

  深刻的了解了在动手方面自己的不足,但是通过查阅资料与请教,慢慢的理解了stm32的工作原理,以及串行口的转换关系,真正意义上的掌握了软硬件结合的实验,整个实验操作下来其实也就代码比较的繁琐,而实验过程与原理是很清晰容易理解的。

参考文献

stm32花式点流水灯_星&&河的博客-CSDN博客

STM32寄存器的简介、地址查找,与直接操作寄存器_geekYatao-CSDN博客_stm32寄存器

STM32从地址到寄存器_geekYatao-CSDN博客_stm32寄存器地址

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值