STM32F103寄存器方式点亮LED流水灯


一、实验要求


1、学习和理解STM32F103系列芯片的地址映射和寄存器映射原理;了解GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)。

2、以 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED 搭建电路,使用GPIOB、GPIOC、GPIOD这3个端口控制LED灯,轮流闪烁,间隔时长1秒。
1)写出程序设计思路,包括GPIOx端口的各寄存器地址和详细参数
2)分别用汇编语言,C语言编程实现。


二、实验过程及结果


(一)任务1

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

在这里插入图片描述
1)地址映射
地址映射,也被称为存储器映射。存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程称为存储器映射,如果再分配一个地址就叫重映射。
在这里插入图片描述
ARM 将 4GB 的存储器空间,平均分成 8 块区域,每块区域的大小是 512MB,STM32 芯片只用其中一部分。ARM 对 4GB 容量分块是按照其功能划分,每块都有特殊的用途。
在这里插入图片描述
在 8 个 Block 里面,Block0、Block1 和 Block2包含了 STM32 芯片的内部 Flash、RAM 和片上外设。

存储器 Block0 内部区域功能划分

Block0 主要用于设计片内的 FLASH,STM32F103 系列芯片内部 FLASH 最大是 512KB。在芯片内部集成更大的 FLASH 或者 SRAM ,意味着芯片成本的增加,所以片内集成的FLASH 都不会太大。
在这里插入图片描述
存储器Block1内部区域功能划分

Block1用于设计片内的SRAM。
在这里插入图片描述
存储器Block2内部区域功能划分

Block2 用于设计片内外设,根据外设总线速度的不同,Block2 被划分为 AHB 和 APB 两部分,APB 又被分成 APB1 和 APB2 总线。
在这里插入图片描述
Block3/4/5中包含了FSMC扩展区域,可用于扩展外部存储器,比如 SRAM,NORFLASH 和 NANDFLASH 等。

2)寄存器映射
寄存器映射是在存储器映射的基础上进行的。
在存储器片上外设区域,以四个字节为一个单元,每个单元对应不同的功能。当我们控制这些单元时就可驱动外设工作,找到每个单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元。但若每次都是通过这种方式访问地址,不好记忆且易出错。因此,我们根据每个单元功能的不同,以功能为名给内存单元取一个别名,其实质就是寄存器名字。给已分配好地址(通过存储器映射实现)的有特定功能的内存单元取别名的过程就是寄存器映射。
在这里插入图片描述

2、GPIO端口的初始化设置

在这里插入图片描述
1)时钟
STM32的时钟是由内部或外部振荡器产生的“频率”,被称为“系统时钟”。最大为72MHz,换成周期T约为13.9ns。

2)GPIO工作模式

在这里插入图片描述

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

3)GPIO初始化步骤
第一步:使能GPIOx口的时钟。
第二步:指明GPIOx口的哪一位,这一位的速度大小以及模式。
第三步:调用GPIOx口初始化函数,进行初始化。
第四步:调用GPIO-SetBits函数,进行相应为的置位。

对于单个GPIO口的初始化如下
GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
第二步:设置GPIOA参数:输出OR输入,工作模式,端口翻转速率
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_6| GPIO_Pin_7| GPIO_Pin_8; //设定要操作的管脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
第三步:调用GPIOA口初始化函数,进行初始化。
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
第四步:调用GPIO-SetBits函数,进行相应为的置位。
GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出高

对于多个GPIO口的初始化如下
GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA,GPIOE的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
第二步:设置GPIOA,GPIOE参数:输出OR输入,工作模式,端口翻转速率
第三步:调用GPIOA口初始化函数,进行初始化。
第四步:调用GPIO-SetBits函数,进行相应为的置位。
▶把第二、三、四步合并分别设置GPIOA和GPIOE
先设置GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 第四个口,PA4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOA,&GPIO-InitST); //根据设定参数初始化GPIOA
GPIO_SetBits(GPIOA,GPIO_Pin_4); //输出高
再设置GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // 第三个口,PE3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOE,&GPIO-InitST); //根据设定参数初始化GPIOE
GPIO_SetBits(GPIOE,GPIO_Pin_3); //输出高

(二)任务2

1、STM32F103C8T6芯片

在这里插入图片描述
核心板原理图:

在这里插入图片描述

2、寄存器详情

查看寄存器组起始地址表,发现:RCC地址范围、寄存器地址范围。

在这里插入图片描述

寄存器地址:端口起始地址+偏移地址

1)时钟

在这里插入图片描述
2)GPIOx端口
端口配置寄存器有两个,分别为端口配置低寄存器(CRL)和端口配置高寄存器(CRH),每四位配置一个端口。

在这里插入图片描述
在这里插入图片描述
端口输出寄存器(ORD)在相应的位赋值可以控制输出电压,0为低电压,1为高电压。

在这里插入图片描述

3、流水灯原理

将 GPIO 的引脚设置成推挽输出模式并且默认下拉,输出低电平, LED灯点亮。

4、C语言编程

1)源码

LED.c程序:

#include "stm32f10x.h"

#define RCC_APB2ENR	*((unsigned volatile int*)0x40021018)//APB2使能时钟寄存器

#define GPIOA_CRL	*((unsigned volatile int*)0x40010800)//GPIOA配置寄存器 
#define	GPIOA_ODR	*((unsigned volatile int*)0x4001080C)

#define GPIOB_CRH	*((unsigned volatile int*)0x40010C04)//GPIOB配置寄存器
#define	GPIOB_ODR	*((unsigned volatile int*)0x40010C0C)

#define GPIOC_CRH	*((unsigned volatile int*)0x40011004)//GPIOC配置寄存器
#define	GPIOC_ODR	*((unsigned volatile int*)0x4001100C)

void Delay(volatile unsigned int);

void Delay(volatile unsigned int t)//延时函数
{
     unsigned int i;
     while(t--)
         for(i=0;i<800;i++);
}

int main(void)
{	
	RCC_APB2ENR|=1<<2|1<<3|1<<4; //APB2-GPIOA、GPIOB、GPIOC外设时钟使能	
	
	GPIOA_CRL&=0x0FFFFFFF;		//设置位PA7 清零	
	GPIOA_CRL|=0x20000000;		//PA7推挽输出:0010
	GPIOA_ODR|=(1<<7);			//设置PA7为高电平 初始灯灭
	
	GPIOB_CRH&=0xFFFFFF0F;		//设置位PB9 清零	
	GPIOB_CRH|=0x00000020;		//PB9推挽输出:0010
	GPIOB_ODR|=(1<<9);			//设置PB9为高电平 初始灯灭
	 
	GPIOC_CRH&=0x0FFFFFFF;		//设置位PC15 清零	
	GPIOC_CRH|=0x20000000;		//PC15推挽输出:0010
	GPIOC_ODR|=(1<<15);		    //设置PC15为高电平 初始灯灭		

	while(1)
	{
	    GPIOA_ODR&=~(1<<7);		//PA7低电平,灯亮:置0,按位与
	 	Delay(1000000);
		GPIOA_ODR|=1<<7;		//PA7高电平,灯灭

        GPIOB_ODR&=~(1<<9);		//PB9低电平,灯亮:置0,按位与
        Delay(1000000);
		GPIOB_ODR|=1<<9;		//PB9高电平,灯灭

		GPIOC_ODR&=~(1<<15);	//PC15低电平,灯亮:置0,按位与
	    Delay(1000000);
		GPIOC_ODR|=1<<15;		//PC15高电平,灯灭
	}
}

2)步骤

① 项目创建
点击 Project ——> Open Project,打开之前实验“STM32汇编语言编程与仿真调试”创建的工程。

配置环境如下:
 工程的目标环境设置为STM32F103C8;
 CMSIS下选择CORE,Device下选择Startup;
 Output 中勾选 Create HEX File 生成 hex 文件;
 Debug中选择“Use Simulator”,设置Dialog DLL项为“DARMSTM.DLL”,parameter项为“-pSTM32F103C8”。

在这里插入图片描述
右击 Source Group 1 ,点击 Add New Item to Group;点击 C Flie(.c)创建C语言文件LED.c。

在这里插入图片描述
② 编译调试
编译程序:

在这里插入图片描述
设置示波器:

在这里插入图片描述
观察波形图:

在这里插入图片描述
③ 硬件操作
使用USB-TTL直接进行串口下载,将USB-TTL的GND和3.3V接入STM32系统板的GND和3.3V,然后TXD和RXD分别接入A10和A9引脚。
在这里插入图片描述
接入后按照程序中GPIOx的引脚接上LED灯,且最小核心板要利用跳线帽实现boot0置1,boot1置0。

在这里插入图片描述
安装 USB 转串口驱动—CH340 版本。

在这里插入图片描述
打开 mcuisp 软件,开始烧录。

配置如下:
搜索串口,设置波特率 115200(尽量不要设置太高) 
选择要下载的HEX文件 
校验、编程后执行DTR低电平复位,RTS高电平进入bootloader 
开始编程,如果出现一直连接的情况,按一下开发板的复位键RESET

在这里插入图片描述

5、汇编语言编程

LED.s程序:

RCC_APB2ENR EQU 0x40021018;配置RCC寄存器,时钟,0x40021018为时钟地址

GPIOB_BASE EQU 0x40010C00
GPIOC_BASE EQU 0x40011000
GPIOA_BASE EQU 0x40010800
	
GPIOB_CRL EQU 0x40010C00
GPIOC_CRH EQU 0x40011004
GPIOA_CRL EQU 0x40010800
	
GPIOB_ODR EQU 0x40010C0C
GPIOC_ODR EQU 0x4001100C
GPIOA_ODR EQU 0x4001080C

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               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                    
                    
                AREA    |.text|, CODE, READONLY
                    
                THUMB
                REQUIRE8
                PRESERVE8
                    
                ENTRY
Reset_Handler 
				bl LED_Init;bl:带链接的跳转指令。当使用该指令跳转时,当前地址(PC)会自动送入LR寄存器
				
MainLoop        BL LED_ON_C
                BL Delay
                BL LED_OFF_C
                BL Delay
				BL LED_ON_A
                BL Delay
                BL LED_OFF_A
                BL Delay
				BL LED_ON_B
                BL Delay
                BL LED_OFF_B
                BL Delay
                
                B MainLoop;B:无条件跳转。
LED_Init;LED初始化
                PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈
                ;控制时钟
                LDR R0,=RCC_APB2ENR;LDR是把地址装载到寄存器中(比如R0)。
                ORR R0,R0,#0x1c
                LDR R1,=RCC_APB2ENR
                STR R0,[R1]
				
				
                ;初始化GPIOA_CRL
                LDR R0,=GPIOA_CRL
                BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
                LDR R1,=GPIOA_CRL
                STR R0,[R1]
				
                LDR R0,=GPIOA_CRL
                ORR R0,#0x00000001
                LDR R1,=GPIOA_CRL
                STR R0,[R1]
                ;将PA0置1
                MOV R0,#0x01
                LDR R1,=GPIOA_ORD
                STR R0,[R1]
				
				
                ;初始化GPIOB_CRL
                LDR R0,=GPIOB_CRL
                BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
                LDR R1,=GPIOB_CRL
                STR R0,[R1]
				
                LDR R0,=GPIOB_CRL
                ORR R0,#0x00000001
                LDR R1,=GPIOB_CRL
                STR R0,[R1]
                ;将PB0置1
                MOV R0,#0x01
                LDR R1,=GPIOA_ORD
                STR R0,[R1]
				
				
				 ;初始化GPIOC
                LDR R0,=GPIOC_CRH
                BIC R0,R0,#0x0fffffff
                LDR R1,=GPIOC_CRH
                STR R0,[R1]
				
                LDR R0,=GPIOC_CRH
                ORR R0,#0x01000000
                LDR R1,=GPIOC_CRH
                STR R0,[R1]
                ;将PC15置1
                MOV R0,#0x8000
                LDR R1,=GPIOC_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC};将栈中之前存的R0,R1,LR的值返还给R0,R1,PC
LED_ON_A
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x00
                LDR R1,=GPIOA_ORD 
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED_OFF_A
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x01
                LDR R1,=GPIOA_ORD 
                STR R0,[R1]
             
                POP {R0,R1,PC}  
LED_ON_B;亮灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x00
                LDR R1,=GPIOB_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED_OFF_B;熄灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x01
                LDR R1,=GPIOB_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC}  
LED_ON_C;亮灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x00
                LDR R1,=GPIOC_ORD
                STR R0,[R1]
             
                POP {R0,R1,PC}
             
LED_OFF_C;熄灯
                PUSH {R0,R1, LR}    
                
                MOV R0,#0x0100
                LDR R1,=GPIOC_ORD
                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}    
                NOP
                
				END

硬件操作过程同C语言编程时相同。

6、实际效果

stm32流水灯


三、实验总结


通过完成本次STM32F103寄存器方式点亮LED流水灯实验,我了解了STM32F103系列芯片的地址映射和寄存器映射原理,更加深入地学习了GPIOx端口寄存器和GPIO端口初始化设置的知识,进一步知晓了stm32系列开发板和面包板等硬件的连接方式。STM32F103寄存器方式点亮LED流水灯是最基础的LED实验,但对我而言仍有较大的难度,从如何利用C语言实现编程代码,如何设置GPIO端口实现流水灯的亮灭和闪烁以及其中原理等等,每一步都是在不断地学习和消化老师讲解的知识。在本次实验操作的过程中,我深刻认识到仿真操作和硬件操作存在着很大的区别,使用硬件操作不仅能学到更多与硬件相关的基础知识,同时还能锻炼我的动手操作能力。总而言之,硬件操作与仿真操作相结合的实验方式让我受益匪浅。


四、参考资料


1、零死角玩转STM32—F103指南者.pdf
2、STM32F10xxx参考手册.pdf
3、3 . 存储器映射 和 寄存器映射
4、STM32入门-GPIO初始化步骤
5、STM32寄存器点亮流水灯的三种方法
6、STM32F103寄存器方式点亮LED流水灯

  • 0
    点赞
  • 5
    收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姝歌

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值