龙空技术网

STM32嵌入式-LED 闪烁实验

EasyProgram 260

前言:

如今我们对“用c语言实现灯的闪烁”大概比较关心,大家都想要知道一些“用c语言实现灯的闪烁”的相关资讯。那么小编同时在网摘上汇集了一些有关“用c语言实现灯的闪烁””的相关知识,希望我们能喜欢,小伙伴们快快来学习一下吧!

STM32 最简单的外设莫过于 IO 口的高低电平控制了,本章将通过一个经典的 LED 闪烁程序,带大家开启 STM32 之旅, 通过本章的学习, 你将了解STM32 的 IO 口作为输出使用的方法。在本章中我们将通过代码控制STM32 开发板上的 8 个 LED,实现闪烁灯的效果。 本章分为以下学习目标:

1、 了解 STM32 拥有几种 GPIO 模式。

2、 怎么学会设置 STM32 的 GPIO 输出控制 LED 灯。

1.1 硬件设计

首先我们来看一下我们开发板上面 LED 的接线图:

LED硬件接线图

从上面的图,我们可以看到 LED 灯是接到单片机的 PC 口的 PC0 到 PC7。而点 亮一盏 LED 的原理就是把相应的 LED 接到单片机的相应的 IO 口输出低电平,IO口 输出为高电平就能够熄灭 LED所以要实现 LED 闪烁也就是将单片机 PC 管脚每隔一段时间不输出一个高低电平脉冲即可。

1.2: STM32 的 IO 口简介

本章将要实现的是控制 STM32 开发板上的 8 个 LED 实现 LED 灯闪烁的效果,该实验的关键在于如何控制 STM32 的 IO 口输出。了解了 STM32 的IO 口如何输出的,就可以实现闪烁灯了。通过这一章的学习, 你将初步掌握STM32 基本 IO 口的使用,而这是迈向 STM32 的第一步。所以我们在这一章将讲解一些知识为后面的实验做铺垫。在讲解STM32 的 GPIO 之前,首先打开我们光盘的第一个实验工程 LED 闪烁实验,可以看到我们的实验工程目录:

工程项目视图

接下来我们逐一讲解一下我们的工程目录下面的组以及重要文件。

① StdPeriph_Driver 下面存放的是 ST 官方提供的固件库函数,里面的函数我们可以根据需要添加和删除,这里面的文件内容用户不需要修改。

② Startup 下面存放的是固件库必须的启动文件。这里面的文件用户不需要修改。

③ cmsis 下面存放的是固件库必须的核心文件。这里面的文件用户不需要修改。

④ APP 下面存放的是每个实验的外设驱动代码,他的实现是通过调用StdPeriph_Driver 内 的 固 件 库 文 件 实 现 的 , 比 如 led.c 里 面 调 用stm32f10x_gpio.c 里面的函数对 led 进行初始化,这里面的函数是讲解的重点。 后面的实验中可以看到会引入多个源文件。

⑤ user 下面存放的主要是用户代码。 stm32f10x_it.c 里面存放的是中断服务函数,public 存放的是公用函数,Main.c 函数主要存放的是主函数了,这个大家应该很清楚。准备内容我们就讲解到这里,接下来我们就要进入我们 LED 闪烁实验的讲解部分了。 这里需要说明一下,我们在讲解固件库之前会首先对重要寄存器进行一个讲解,这样是为了大家对寄存器有个初步的了解。大家学习固件库,并不需要记住每个寄存器的作用,而只是通过了解寄存器来对外设一些功能有个大致的了解,这样对以后的学习也很有帮助。

首先要提一下,在固件库中,GPIO 端口操作对应的库函数函数以及相关定义在文件 stm32f10x_gpio.h 和 stm32f10x_gpio.c 中。STM32 的 IO 口相比51 而言要复杂得多,所以使用起来也困难很多。 首先 STM32 的 IO 口可以由软件配置成如下 8 种模式:

STM32输入输出模式表

每个 IO 口可以自由编程, 但 IO 口寄存器必须要按 32 位字被访问。STM32 的很多 IO 口都是 5V 兼容的,这些 IO 口在与 5V 电平的外设连接的时候很有优势,具体哪些 IO 口是 5V 兼容的,可以从该芯片的数据手册管脚描述章节查到( I/O Level 标 FT 的就是 5V 电平兼容的)。STM32 的每个 IO 端口都有 7 个寄存器来控制。他们分别是:配置模式的 2个 32 位的端口配置寄存器 CRL 和 CRH; 2 个 32 位的数据寄存器 IDR 和ODR; 1 个 32 位的置位/复位寄存器 BSRR;一个 16 位的复位寄存器 BRR; 1个 32 位的锁存寄存器 LCKR。大家如果想要了解每个寄存器的详细使用方法,可以参考《 STM32 中文参考手册 V10》P105~P129。CRL 和 CRH 控制着每个 IO口的模式及输出速率。

STM32 的 IO 口位配置表

STM32 输出模式配置表

接下来我们看看端口低配置寄存器 CRL 的描述,如下图所示:

该寄存器的复位值为 0X4444 4444,从图 6.1.4 可以看到,复位值其实就是配置端口为浮空输入模式。从上图还可以得出:STM32 的 CRL 控制着每组 IO端口( A~G)的低 8 位的模式。每个 IO 端口的位占用 CRL 的 4 个位,高两位为 CNF,低两位为 MODE。这里我们可以记住几个常用的配置,比如 0X0 表示模拟输入模式( ADC 用)、 0X3 表示推挽输出模式(做输出口用,50M 速率)、0X8 表示上/下拉输入模式(做输入口用)、 0XB 表示复用输出(使用 IO 口的第二功能, 50M 速率)。CRH 的作用和 CRL 完全一样,只是 CRL 控制的是低 8位输出口,而 CRH 控制的是高 8 位输出口。这里我们对 CRH 就不做详细介绍了。在这里我们用来控制 LED 的时候, IO 口可以设置为推挽输出模式。而大家可 能有点疑惑,那其他输出模式的时候,是什么时候使用呢?一般来说复用功能 的输出是在使用 STM32 内部外设的时候使用,比如说 ADC、 SPI 等,到后面我 们使用的时候回逐渐讲到。而输出模式呢,我们看到还有个开漏输出,我们为 什么不用开漏输出来控制 LED 灯呢?其实推挽输出和开漏输出学过模拟电路的 同学应该都知道它的工作原理,一般来说推挽输出:可以输出高,低电平,连接数 字器件;开漏输出:输出端相当于三极管的集电极, 要得到高电平状态需要上拉电阻才行, 适合于做电流型的驱动,其吸收电流的能力相对强(一般 20ma以内)。所以这里 我们选择推挽输出控制 LED 灯。

1.3: V3.5 库函数的函数介绍

1.3.1 设置 GPIO 模式

而如何设置 STM32 的 GPIO 模式呢?

在 3.5 的库中,它提供了一个初始化函数, GPIO_Init( GPIO_TypeDef*GPIOx,GPIO_InitTypeDef* GPIO_InitStruct)这么个函数,通过调用这个函数我们就可以配置 GPIO 口的模式 了。这个函数的详细说明,大家可以翻看《 STM32固件库使用手册(中文翻译版).pdf》在书签的第 10 个通过输入输出( GPIO)中查找到这个函数的详细说明。(在这里给大家说明一点就是这个函数库使用说明不是 3.5 的库,不过大致是相 同的, 3.5 的库中文函数说明没有找到,如果没有找到相应的函数,大家还可以查找《 stm32f10x_stdperiph_lib_um.chm》这个说明,这个是英文版原本函数说 明。)在这里我们来简单介绍一下 GPIO_Init( GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct)这么个函数。

GPIO_Init函数

这个函数有两个参数,第一个参数是用来指定要设置 GPIO,取值范围为GPIOA~GPIOG,比如你要设置 GPIOA,那么就是 GPIOA。第二个参数为初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。这个结构体的定义如下:

GPIO初始化参数结构体

它一共定义定义了三个参数:

1、 GPIO_Pin:用来选择要设置的 Pin 口。

2、 GPIO_Speed:用来设置 IO 口的速率

3、 GPIO_Mode:用来选择要设置的 IO 模式。

而这些参数的设置,库函数中也帮你定义好了,只要你选择就好了。 比如:推挽输出在库函数中定义为 GPIO_Mode_Out_PP。 接下来我们来看一下我们库函数,例程里面的 LED 初始化。

void LED_Init() //端口初始化

{

GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化 GPIO

SystemInit(); //时钟初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);

/* 配置 GPIO 的模式和 IO 口 */

GPIO_InitStructure.GPIO_Pin=LED; //选择你要设置的 IO 口

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率

GPIO_Init(GPIOC,&GPIO_InitStructure); /* 初始化 GPIO */

}

从原理图中,我们知道控制 LED 的单片机 IO 口分别是 PC 口的 PC0~PC7。所以 我们要设置的 GPIO_Pin 就是 GPIOC 中的 PC0~PC7。在 led.h 头文件中,我们将整个 PC 口定义为 LED,定义了:

#define LED GPIO_Pin_All //管脚宏定义

LED_Init()函数中 GPIO_Pin 选择的时候包括了 PC0~PC7。可能大家注意到,在这个初始化函数中还有个开启 GPIO 时钟的函数,这个 是做什么用的呢。 STM32 为了降低功耗,所以每个外设都设有一个时钟开关, 在单片机启动的时候,这个外设的时钟都是关闭的,而你要使用相应的外设的 时候就要将它的时钟打开,这里我们要使用 GPIOC,那么我们就要将 GPIOC 的 时钟打开。(这个打开时钟是要注意的,一般初学者最容易犯的错误就是没有将时钟打开,所以你的外设一直都不工作。)

1.3.2: GPIO 的输出 在库函数中也定义了,相应的输出函数。

GPIO_Write()函数

这个函数一次是要操作一组 GPIO 的,也就是说它是一次操作 16 个 Pin 口的。所以大家使用的时候要注意。

GPIO_SetBits()函数

这个函数是将相应的位设置为 1。

GPIO_ResetBits()函数

这个函数是将相应的位清除为 0。

接下来我们看一下我们设置 LED 灯闪烁的函数。

void led_display()

{

GPIO_SetBits(GPIOC,LED);

delay(6000000);//延时约为 1s

GPIO_ResetBits(GPIOC,LED);delay(6000000);

}

在设置 GPIO_Pin 这个参数的时候,应该是选择相应的参数。我们打开 LED 闪烁的例程,然后将鼠标放到 GPIO_Pin_0 位置,然后右键选择 Go To Definition of“GPIO_Pin_0”。我们可以看到:

#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */

#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */

#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */

#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */

#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */

#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */

#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */

#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */

其实呢,这个参数就是一个每个 IO 口的对应位为 1,所以我们就可以很简单 的知道,我们输入的状态值可以很简单的转化为设置的 Pin 口值了。

1.4 主函数

int main()

{

LED_Init(); //LED 端口及时钟初始化

while(1)

{

led_display(); //led 显示

}

}

我们直接将 LED 初始化及闪烁的子函数调用即可。

标签: #用c语言实现灯的闪烁