LED是开发板上较为简单的模块,我们来学习如何配置LED,最后实现简单的流水灯。
蓝桥杯嵌入式板子上共有8路LED输出,在进行LED的配置之前,我们先要了解LED所对应的引脚。
打开蓝桥杯比赛提供中的原理图,可以看到8个LED灯对应PC端口的PC8~PC15,LED灯的左边连接着一个74HC573锁存器。
LE为锁存控制端,OE为使能端,1D~8D为数据输入端,1Q~8Q为数据输出端。当LE为高时,Q输出将随数据D输入而变;当LE为低时,将输出锁存在已建立的数据电平上。锁存器的输出控制不影响锁存器的内部工作,即老数据可以保持,甚至当输出被关闭时,新的数据也可以置入。这个锁存器的手册在蓝桥杯比赛提供的数据手册文件夹中就有,可以查阅它更加具体的功能。
因为8路LED的引脚和LCD显示屏的引脚是共用的,如果不进行数据锁存,那么8路LED将会亮灭混乱。
了解了LED的连接,接下来我们就可以开始配置LED了,配置代码如下:
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = 0xff00;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIOC->ODR |= 0xff00;
GPIOD->ODR |= (0x1 << 2); //打开LE锁存器
GPIOD->ODR &= ~(0x1 << 2); //关闭LE锁存器
}
第一步:在配置STM32外设的时候,任何时候都要先使能该外设的时钟。GPIO是挂载在APB2总线上的外设,在固件库中对挂载在APB2总线上的外设时钟使能是通过函数RCC_APB2PeriphClockCmd()来实现的。在stm32f10x_rcc.h中可以快速找到这个函数,第5行代码的作用是使能APB2总线上的GPIOC、GPIOD的时钟。
第二步:在配置完时钟之后,我们就要对引脚进行具体配置,在stm32f10x_gpio.h中找到GPIO_Init()函数,GPIOC和GPIOD的IO口的初始化参数都是在结构体变量GPIO_InitStructure中。因为端口用做LED输出,所以配置为推挽输出模式。
由于需要配置的端口较多,一个一个写很麻烦,我们找到固件库的定义。
我们把Pin8~Pin15端口直接加起来得到0xff00,所以在代码第7行直接一次性配置完。由上面的原理图可看出锁存器的控制引脚为PD2,所以还需配置PD2引脚。
第三步:因为开发板复位后,LED默认是点亮的,因此初始化时我们要把LED全熄灭。接下来就是对锁存器的操作了,其实就是对PD2引脚的控制(拉高、拉低),可以使用库函数进行配置,也可以直接操作寄存器,我个人比较喜欢直接对寄存器进行操作,两种方法按个人喜好选取。
u16 LED=0xffff;
void Led_Set(void)
{
GPIOC->ODR = LED;
GPIOD->ODR |= (1<<2); //打开锁存
GPIOD->ODR &= ~(1<<2); //关闭锁存
}
void Led_Set(u16 led,u8 state)
{
if(state==1)
{
GPIO_ResetBits(GPIOC,led);
GPIO_SetBits(GPIOD,GPIO_Pin_2); //打开锁存
GPIO_ResetBits(GPIOD,GPIO_Pin_2); //关闭锁存
}
else
{
GPIO_SetBits(GPIOC,led);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}
}
寄存器配置方法使用到ODR寄存器,ODR为端口输出寄存器,它的具体作用可以查看stm32手册,有详细介绍每一位的作用。
到此,LED的配置就完成了,现在我们来写个简单的流水灯来试试效果。
LED配置与上面代码相同,既然是流水灯,就应该有流水间隔,工程模版中提供了延时函数,就没有必要自己再配置一个定时器做延时。
代码如下
#include "stm32f10x.h"
#include "io.h"
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);
extern u16 LED;
//流水灯
void LED_Show()
{
static u8 i=8;
LED = 0xffff;
LED &= ~(0x01<<i);
if(++i>=16)
i=8;
Led_Set();
}
//Main Body
int main(void)
{
SysTick_Config(SystemCoreClock/1000);
Led_Init();
while(1)
{
LED_Show();
Delay_Ms(500);
}
}
//1ms延时函数
void Delay_Ms(u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
流水间隔为500ms,可以根据需要调整,把程序烧录到开发板中,就可以看到流水灯效果。