WHCSRL 技术网

【内嵌08】STM32F103C8T6寄存器方法使用面包板点亮LED流水灯。


关于STM32F103系列芯片的地址映射和寄存器映射原理,GPIO端口的初始化设置步骤,请参考我的前一篇博客。
【嵌入式07】寄存器映射原理详解,GPIO端口的初始化设置步骤

一、题目简述

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

二、简述:初始化GPIO,点亮LED灯

外设的功能都是完全不同的,但初始化都是大同小异的。
点灯是所有学单片机的人都应该学会的第一项技能,这样子才算入门。

51单片机的点灯是,通过控制寄存器将片外引脚(我们称之为IO口)拉低拉高,输出高低电平,以控制LED亮灭。
其过程:单片机给指令->控制寄存器->给IO口电平->控制LED亮灭

stm32的点灯则是,通过使能外设GPIO时钟,发出指令给外设GPIO,外设GPIO收到指令后,着手配置自己的寄存器,然后给IO口模式,让其实现各种功能。
其过程:CPU给指令->GPIO收到指令->配置内部寄存器->配置IO口模式(注意是模式)->控制LED亮灭

三、工程文件模板的建立


建立模板要用到的SYSTEM文件及启动文件,包括点灯时需要的C8T6数据手册,以及烧录用到的FlyMcu,网盘自取。
链接:https://pan.baidu.com/s/1jxbVCa_filfR9ZRlmP6SMw
提取码:k4lv


新建工程Light2文件,工程名为light,因为之后实验采用C8T6板,因此这里选择STM32F103C8
之后弹出的添加库文件窗口Manage Run-Time Environment,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境,不过这里我们不做介绍。选择Cancel即可。
在这里插入图片描述到这里,我们还只是建了一个框架,还需要添加启动代码,以及.c 文件等。

先介绍一下启动代码:启动代码是一段和硬件相关的汇编代码。
主要作用如下:
1、堆栈(SP)的初始化;
2、初始化程序计数器(PC);
3、设置向量表异常事件的入口地址;
4、调用 main 函数。

ST 公司提供了 3 个启动文件给我们,分别用于不同容量的 STM32 芯片,这三个文件是:
startup_stm32f10x_ld.s,startup_stm32f10x_md.s,startup_stm32f10x_hd.s
其中,ld.s 适用于小容量 产品;md.s 适用于中等容量产品;hd 适用于大容量产品;
这里的容量是指 FLASH 的大小.判断方法如下:

小容量:FLASH≤32K
中容量:64K≤FLASH≤128K
大容量:256K≤FLASH

这里,我查看了一下C8T6的数据手册,在这里插入图片描述
其Flash容量为128K,属于中容量,因此我在这里采用startup_stm32f10x_md.s作为启动文件。
启动文件借用了正点原子版本,上面网盘链接可下载。
或者可以到这个网址去下载:http://www.openedv.com/posts/list/313.htm
将启动文件拷贝到Light2工程文件夹下。
在这里插入图片描述
我们找到 Target1Source Group1→双击→设置打开文件类型为 Asm Source file→选择 startup_stm32f10x_hd.s→点击 Add,如下图所示
在这里插入图片描述
这里看到的 2 个文件夹:ListingsObjects,是 KEIL 自行创建的,用于保存编译过程中生成的一些文件。
添加完之后,得到如下界面
在这里插入图片描述
先关闭 KEIL 软件

为了不让之后生成的文件显得混乱,在Light2文件夹下新建一个OBJ文件,用于存放生成的中间文件。

USER 文件夹专门用来存放启动文件(startup_stm32f10x_md.s)、工程文件(test.uvprojx)等不可缺少的文件,而 OBJ 则用来存放这些编译过程中产生的中间文件(包括.hex 文件也将存放在这个文件夹里面)。然后把 Listings 和Objects 文件夹里面的东西全部移到 OBJ 文件夹下。

这一步我自己做的有点凌乱,最后的文件夹结果如图所示,文件夹跟下面差不多一般就没有问题。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由于上面我们还没有任何代码在工程里面,这里我们把系统代码 copy 过来(即 SYSTEM文件夹,该文件夹由 ALIENTEK 提供,这些代码在任何 STM32F10x 的芯片上都是通用的,可以用于快速构建自己的工程。

同样在本节开头网盘链接内。
注意一定要拷贝寄存器版本
在这里插入图片描述
在 USER 文件夹下面找到 test.uvprojx,打开它,然后在 Target 目录树上点击右键→Manage Project Items,弹出对话框。

在上面对话框的中间栏,点新建(用红圈标出)按钮(也可以通过双击下面的空白处实现),新建 USERSYSTEM 两个组。然后点击 Add Files 按钮,把 SYSTEM 文件夹三个子文件夹里面的:sys.cusart.cdelay.c 加入到 SYSTEM 组中。注意:此时 USER 组下还是没有任何文件,我们只添加SYSTEM的三个。
在这里插入图片描述
点击 OK,退出该界面返回 IDE。
此时界面如图所示
在这里插入图片描述
接着,我们新建一个 test.c 文件,并保存在 USER 文件夹下。然后双击 USER 组,会弹出加载文件的对话框,此时我们在 USER 目录下选择 test.c 文件,加入到 USER 组下。
在这里插入图片描述

如果我们此时编译的话,生成的中间文件,还是会存放在 Listings 和 Objects 文件夹下,所以,我们先设置输出路径,再编译。

点击魔法棒,弹出 Options for Target’Target 1’对话框,选择 Output 选项卡→选中 Create Hex File(用于生成 Hex 文件,后面会用到)→点击 Select Folder for Objects→找到 OBJ 文件夹→点击 OK
在这里插入图片描述
接着,再设置 Listings 文件路径,在图 3.2.16 的基础上,打开 Listing 选项卡→点击 Select
Folder for Listings→找到 OBJ 文件夹→点击 OK

加入sys、delay、usart的include路径:
在这里插入图片描述
注意!我们必须根据所用 STM32F1 型号的容量,来输入相关宏定义,对于STM32F103 系列芯片,设置原则如下:

16KB≤FLASH≤32KB 选择:STM32F10X_LD 64KB≤FLASH≤128KB 选择:STM32F10X_MD
256KB≤FLASH≤512KB 选择:STM32F10X_HD

我们要将三个路径都加入
在这里插入图片描述
至此,一个完整的 STM32F1 开发工程模板下建立好了。接下来我们就可以进行代码下载和仿真调试了。

四、使用寄存器点亮LED灯——代码部分

1、硬件连接设计

根据题目要求,使用GPIOB,GPIOC,GPIOD端口来控制LED灯,在查询C8T6数据手册后,我选用了PB5,PC4,PD8管脚分别连接红绿蓝三种颜色的灯(由于我只有红绿黄三个小灯,在之后实际硬件中,会用黄灯代替蓝灯)
在这里插入图片描述

图中从 3 个 LED 灯的阳极各经过 1 个限流电阻连接到 3.3V 电源,阴极连接STM32 的 3 个 GPIO 引脚中,所以我们只要控制这三个引脚输出高低电平,即可控制其所连接 LED 灯的亮灭。

目标是把 GPIO 的引脚设置成推挽输出模式并且默认下拉,输出低电平,这样就能让 LED 灯亮起来了。


但是之后连电路的时候发现并没有PD管脚,于是自己改成了PA1PB0PB5只是在推挽输出、以及声明时代码有所不同,其他变化不大。

在这里插入图片描述

2、打开之前建立的工程模板

具体步骤请往上翻

3、代码编写

在Light2文件夹下新建一个HARDWARE文件夹,用来存储以后与硬件相关的代码。
在这里插入图片描述
然后我们打开 USER 文件夹下的 test.uvprojx 工程,新建两个文件,然后保存在HARDWARE→LED 文件夹下面,保存为 led.c,led.h
我们将文件添加到工程中,步骤如下图
在这里插入图片描述
在魔法棒这里将HARDWARE路径加进去,否则之后会报错。
在这里插入图片描述

下面来编写led.c文件,要用到GPIOB、GPIOC、GPIOD则,对应时钟设置:
在这里插入图片描述
在设置完时钟之后就是配置完时钟之后,LED_Init 配置了 目标三个端口 PB0 PB5 PA1 的模式为推挽输出,
并且默认输出 1。这样就完成了对这三个 IO 口的初始化。
代码如下:
led.c

#include "led.h"
//初始化 PB1 PC4 PD8为输出口.并使能这三个口的时钟 
//LED IO 初始化
void LED_Init(void)
{
	RCC->APB2ENR|=1<<2; //使能 PORTA 时钟 
	RCC->APB2ENR|=1<<3; //使能 PORTB 时钟 
//	RCC->APB2ENR|=1<<4; //使能 PORTC 时钟
//	RCC->APB2ENR|=1<<5; //使能 PORTD 时钟	
	GPIOB->CRL&=0XFF0FFFFF; 
	GPIOB->CRL|=0X00300000;//PB.5 推挽输出 
	GPIOB->ODR|=1<<5; //PB.5 输出高 
	
	GPIOB->CRL&=0XFFFFFFF0; 
	GPIOB->CRL|=0X00000003;//PB.0 推挽输出 
	GPIOB->ODR|=1<<0; //PB.0 输出高
	
	GPIOA->CRL&=0XFFFFFF0F; 
	GPIOA->CRL|=0X00000030;//PA.1 推挽输出 
	GPIOA->ODR|=1<<1; //PA.1 输出高
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这段代码里面最关键就是 3 个推挽输出代码的撰写

led.h

#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED 端口定义
#define LED0 PBout(5) // DS0
#define LED1 PBout(0) // DS1
#define LED2 PAout(1) // DS2
void LED_Init(void); //初始化 
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这段代码里面最关键就是 3 个宏定义:

#define LED0 PBout(5) // DS0
#define LED1 PBout(0) // DS1
#define LED2 PAout(1) // DS2
  • 1
  • 2
  • 3

在USER文件夹的test.c中撰写main函数
test.c

#include "sys.h"
#include "delay.h"
#include "led.h"
int main(void)
{ 
	Stm32_Clock_Init(9); //系统时钟设置
	delay_init(72); //延时初始化
	LED_Init(); //初始化与 LED 连接的硬件接口
	while(1)
	{
		LED0=0;
		LED1=1;
		LED2=1;
		delay_ms(1000);
		LED0=1;
		LED1=0;
		LED2=1;
		delay_ms(1000);
		LED0=1;
		LED1=1;
		LED2=0;
		delay_ms(1000);
	} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

代码包含了#include "led.h"这句,使得 LED0、LED1、LED2、LED_Init 等能在 main 函数里被调用。
接下来,main 函数先调用 Stm32_Clock_Init 函数,配置系统时钟为 9 倍频,也就是 8*9=72M(外部晶振是 8Mhz),然后调用 delay_init 函数,初始化延时函数。接着就是调用 LED_Init 来初始化 三个管脚 为输出。最后在死循环里面实现 LED0 LED1 LED2 交替闪烁,间隔为 1s。

我们编译看看是否报错。

没有报错!
那么就可以进行下载了。

4、硬件连接

5、烧录:STM32F103C8T6与PC端连接

打开C8T6数据手册,查找TXD和RXD管脚位置
PA9——TX
PA10——RX
在这里插入图片描述

在这里插入图片描述

务必将boot0设为1,boot1设为0,利用跳线帽实现
在这里插入图片描述

在这里插入图片描述
借助FLYMCU下载软件,即可将light.hex载入,软件资料同样可在网盘下载。
这里我利用FlyMcu进行。
在这里插入图片描述

五、使用寄存器点亮LED灯——电路部分

1、面包板介绍

面包板是由于板子上有很多小插孔,专为电子电路的无焊接实验设计制造的。由于各种电子元器件可根据需要随意插入或拔出,免去了焊接,节省了电路的组装时间,而且元件可以重复使用,所以非常适合电子电路的组装、调试和训练。
在这里插入图片描述

在这里插入图片描述
常见的最小单元面包板分上、中、下三部分, 上面和下面部分一般是由一行或两行的插孔构成的窄条,中间部分是由中间一条隔离凹 槽和上下各 5 行的插孔构成的宽条。
在这里插入图片描述
窄条上下两行之间电气不连通。

面包板背面示意图,看到背面示意图的情况,应当就很容易理解面包板之后应当如何接线了。
在这里插入图片描述

每 5 个插孔为一组,通常的面包板上有 10 组或 11 组。
对于 10 组的结构,左边 5 组内部电气连通,右边 5 组内部电气连通,但左右两边之间不连通,这种结构通常称为 5-5 结构。
还有一种 3-4-3 结构即左边 3 组内部电气连通,中间 4 组内部电气连通,右边 3 组内部电气连通,但左边 3 组、中间 4 组以及右边 3 组之间是不连通的。
对于 11 组的结构,左边 4 组内部电气连通,中间 3 组内部电气连通,右边 4 组内部电气连通,但左边 4 组、中间 3 组以及右边 4 组之间是不连通的,这种结构称为 4-3-4 结构。

中间部分宽条是由中间一条隔离凹槽和上下各 5 行的插孔构成。在同一列中的 5 个 插孔是互相连通的,列和列之间以及凹槽上下部分则是不连通的。
在这里插入图片描述

2、电路连接

让 STM32 一按复位键就开始跑代码,则需要配置 BOOT0 为 0,BOOT1 随便设置都可以。
在这里插入图片描述

在将C8T6连接到电路板之前,一定要先将BOOT0置位0,否则电路无效!!!

面包板连线,按照这个图连接,只不过我在实际电路时手头没有电阻,于是就没有连接电阻。
在这里插入图片描述
实际图连接

在这里插入图片描述
点灯实况
在这里插入图片描述
成功!

六、总结

面包板是个很方便的东西,比焊接快多了,以后可以多多利用。


建立模板要用到的SYSTEM文件及启动文件,包括点灯时需要的C8T6数据手册,以及烧录用到的FlyMcu,网盘自取。
链接:https://pan.baidu.com/s/1jxbVCa_filfR9ZRlmP6SMw
提取码:k4lv


参考
[1] https://blog.csdn.net/asdfg1075511750/article/details/79663568
[2] https://blog.csdn.net/countofdane/article/details/82561478
[3] https://blog.csdn.net/weixin_44784157/article/details/107448624

推荐阅读