STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解

文章目录

  • 一、寄存器原理
    • 1.什么是寄存器
    • 2.如何访问寄存器
  • 二、GPIO端口的初始化设置
    • 1.时钟配置
      • (1)找到时钟使能寄存器映射基地址
      • (2)找到端口偏移地址以及对应端口所在位置
      • (3)使能对应端口时钟
    • 2.端口输出寄存器配置
      • (1)找到找到GPIOX的基地址
      • (2)找到端口输入寄存器的地址偏移
      • (3)对应引脚寄存器,基地址+偏移量
    • 3.输入输出模式和输出速率设置
  • 三、C语言实现流水灯
    • 1.流水灯原理
    • 2.c语言实现
      • (1)创建项目
      • (2)写入代码
      • (3)编译运行
  • 四、程序烧录
    • 1.线路连接
      • (1)连接方法
      • (2)连接实物图
    • 2.烧录
  • 五、硬件连接
  • 六、运行效果
  • 七、实验总结
  • 八、参考文章

一、寄存器原理

1.什么是寄存器

寄存器是 CPU 内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的 时序逻辑电路 ,但这种时序逻辑电路只包含存储电路。 寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以由N个 锁存器 或触发器可以构成N位寄存器。寄存器是 中央处理器 内的组成部分。寄存器是有限存储容量的高速存储部件,它们可用来暂存指令、数据和位址。在计算机领域,寄存器是CPU内部的元件,包括 通用寄存器 、专用寄存器和控制寄存器。寄存器拥有非常高的读写速度,所以在寄存器之间的数据传送非常快。

2.如何访问寄存器

存放数据的寄存器是最好理解的,如果你需要读取一个数据,直接到这个寄存器所在的地方来问问他,数据是多少就行了。问寄存器这个动作,叫做访问寄存器。不同的数据会存放在不同的寄存器,例如引脚PA2与PB8的高低电平数据(1或0)肯定放在不同的寄存器里,那么怎么区分不同的寄存器呢?通过地址,不同的寄存器有不同的地址
**所以需要找到其地址,怎么找到某个寄存器的地址?查看数据手册。**在简单了解寄存器后,我们开始配置

二、GPIO端口的初始化设置

1.时钟配置

想要配置时钟首先要访问其寄存器,找到地址。

(1)找到时钟使能寄存器映射基地址

时钟控制名字叫做RCC,属于AHB总线,查看数据手册如下:
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第1张图片得出复位和时钟控制RCC的地址从0x4002 1000开始

(2)找到端口偏移地址以及对应端口所在位置

STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第2张图片
手册RCC_APB2ENR,位3是IOPBEN,名字是IO端口B时钟使能,就是我们想要的。把RCC_APB2ENR的位3赋值为1,就是开启GPIOB时钟。

(3)使能对应端口时钟

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

	RCC_APB2ENR|=1<<2|1<<3|1<<4;			//APB2-GPIOA、GPIOB、GPIOC外设时钟使能	

2.端口输出寄存器配置

本次实验使用GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚控制LED灯,GPIO是属于APB2的。
同理,也要访问其地址。

(1)找到找到GPIOX的基地址

STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第3张图片
结论是,
所有GPIOA相关的寄存器,都住在0x4001 0800到0x4001 0BFF范围内。
所有GPIOB相关的寄存器,都住在0x4001 0C00到0x4001 0FFF范围内。
所有GPIOC相关的寄存器,都住在0x4001 1000到0x4001 13FF范围内。

(2)找到端口输入寄存器的地址偏移

分别用到A4、B5、C14三个引脚。其中A4、B5属于端口配置低寄存器偏移地址为0x00,C13属于端口配置高寄存器偏移地址为0x04。
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第4张图片
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第5张图片

(3)对应引脚寄存器,基地址+偏移量

相应端口配置器GPIOA_CRL地址为GPIOA的基址+上偏移量

//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL		*((unsigned volatile int*)0x40010C00)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)


3.输入输出模式和输出速率设置

我们需要的是输出高低电平,所以要设置为输出。输出模式又有好几种输出:STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第6张图片
推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。
开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
开漏是需要外接上拉电阻才可以输出高电平的,这里并不适合。所以需要设置为推挽输出,没有复用,输出速度按要求设置为2Mhz

GPIOA_CRL&=0xFFF0FFFF;		//设置位 清零	
GPIOA_CRL|=0x00020000;		//PA4推挽输出,把第19、18、17、16位变为0010

GPIOB_CRL&=0xFF0FFFFF;		//设置位 清零	
GPIOB_CRL|=0x00200000;		//PB5推挽输出,把第23、22、21、20变为0010
 
GPIOC_CRH&=0xFF0FFFFF;		//设置位 清零	
GPIOC_CRH|=0x00200000;		//PC14推挽输出,把第23、22、21、20变为0010

三、C语言实现流水灯

1.流水灯原理

本次实验采用三个灯实现,亮灯状态用1表示,灭灯状态用0表示。
初始状态为0 0 0,
状态一为1 0 0
状态二为0 1 0
状态三为0 0 1
状态三结束后继续进入状态一,一直循环达到流水灯效果。

2.c语言实现

(1)创建项目

点击【project】->[New…】
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第7张图片
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第8张图片
选择STM32F103C8开发板

STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第9张图片
创建项目出现弹窗,勾选setup项和core
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第10张图片

在source group里创建led.c,选择【Add New Item to Group… …】
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第11张图片
添加代码文件,设置名称
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第12张图片

(2)写入代码

注意项目结构,使用的引脚是PA7,PB9,PC15

代码如下:

#include "stm32f10x.h"
//----------------APB2使能时钟寄存器 ---------------------
#define RCC_APB2ENR		*((unsigned volatile int*)0x40021018)
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
#define	GPIOA_ODR		*((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL		*((unsigned volatile int*)0x40010C00)
#define	GPIOB_ODR		*((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)
#define	GPIOC_ODR		*((unsigned volatile int*)0x4001100C)


//延时函数
 void Delay()
 {
   u32 i=0;
   for(;i<5000000;i++);
 }
 int main(void)
 {	
	RCC_APB2ENR|=1<<2|1<<3|1<<4;			//APB2-GPIOA、GPIOB、GPIOC外设时钟使能	
	
	GPIOA_CRL&=0xFFF0FFFF;		//设置位 清零	
	GPIOA_CRL|=0x00020000;		//PB5推挽输出
	GPIOA_ODR&=~(1<<4);			//设置初始灯为灭
	
	GPIOB_CRL&=0xFF0FFFFF;		//设置位 清零	
	GPIOB_CRL|=0x00200000;		//PB5推挽输出
	GPIOB_ODR&=~(1<<5);			//设置初始灯为灭
	 
	GPIOC_CRH&=0xF0FFFFFF;		//设置位 清零	
	GPIOC_CRH|=0x02000000;		//PB5推挽输出
	GPIOC_ODR&=~(1<<14);			//设置初始灯为灭		
	 

	 

	while(1){
		//A灯
		GPIOA_ODR|=1<<4;		//PB5高电平
	 	Delay();
		GPIOA_ODR&=~(1<<4);		//PB5低电平,因为是置0,所以用按位与


		
		//B灯
		GPIOB_ODR|=1<<5;		//PB5高电平
	 	Delay();
		GPIOB_ODR&=~(1<<5);		//PB5低电平,因为是置0,所以用按位与


		
		
		//C灯
		GPIOC_ODR|=1<<14;		//PB5高电平
	 	Delay();
		GPIOC_ODR&=~(1<<14);		//PB5低电平,因为是置0,所以用按位与


		
		}
}

(3)编译运行

运行成功,要注意勾选[get hex file]
在这里插入图片描述

四、程序烧录

1.线路连接

(1)连接方法

对于USB转TTL模块和stm32f103c8t6连接
1、TXD-接 PA10/USART1_RX

2、RXD-接 PA9/USART1_TX

3、3V3 GND 接供电,将BOOT0接3V3后再供电,即可进入下载模式。
在这里插入图片描述
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第13张图片

(2)连接实物图

STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第14张图片

2.烧录

在build之后会在object文件夹下有对应的hex文件生成
在这里插入图片描述
连接到电脑,打开mcuisp,上传HEX文件到stm32f103c8t6上:
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第15张图片
首先读取器件信息
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第16张图片
然后开始编程
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第17张图片
程序烧录完毕

五、硬件连接

根据题目要求,使用GPIOB,GPIOC,GPIOD端口来控制LED灯,在查询C8T6数据手册后,选用了PA7,PB9,PC15管脚分别连接红绿黄三种颜色的灯,实物图如下:
STM32F103C8T6以寄存器方式借助面包板搭建电路点亮LED流水灯详解_第18张图片

六、运行效果

让 STM32 一按复位键就开始运行代码,则需要配置 BOOT0 为 0,在将C8T6连接到电路板之前,一定要先将BOOT0置位0,否则电路无效。



流水灯成功运行!

七、实验总结

通过这次使用C语言,在Keil 5上编译生成HEX文件并使用STM32寄存器方式进行的点亮LED流水灯实验,让我有了一番不一样的体验,虽然在过程中遇到了一些硬件上的问题,但询问同学后还是得以解决,让我明白了在仿真器上操作和使用硬件进行操作还是存在区别的,使用硬件进行操作的过程中会学到更多的基础知识,能进一步的学习和理解STM32F103系列芯片的地址映射和寄存器映射原理,了解GPIO端口的初始化设置三步骤,总之收获很大。

八、参考文章

https://blog.csdn.net/weixin_47554309/article/details/120810913
https://blog.csdn.net/geek_monkey/article/details/86293880

你可能感兴趣的:(stm32,单片机,arm)