蓝桥杯嵌入式开发指南 02-LED 和定时器配置

实例

通过配置 LED 灯和定时器,使所有的 LED 灯间隔 1 秒钟闪烁。

电路分析



打开蓝桥杯开发板的电路图,可以看到板载的 8 个可编程 LED 灯公共端接到 3V3,故 LED 灯均为低电平点亮,另一端通过 HC573 锁存器连接到电路的 H D0-H D7, 由 H D0-H D7 通过跳线帽连接到 M PC8-M PC15,锁存器的使能端 N LE 由跳线帽连接到 M PD2

电路上,LCD 和 LED 共用 PC8-PC15 引脚,当 N LE 为高电平时,此时可以通过 PC8-PC15 改变 LED 灯的状态,当 N LE 为低电平时,无论 PC8-PC15 如何改变,均不会影响 LED 灯的状态。

工程建立

从官方提供的赛点资源中,拷贝 8 - 液晶驱动参考例程,打开其中的工程文件,作为本次的工程基础。

添加库函数

本例中使用到了定时器来控制灯的翻转时间,故要添加以下库函数:

  • stm32f10x_tim.c
  • misc.c

初始化 LED

编写 LED 初始化函数,程序代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void LED_Init(void)
{
//声明GPIO结构体
GPIO_InitTypeDef GPIO_InitStructure;
//使能PC控制时钟和锁存器使能PD控制时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);

//配置PD2为推挽输出模式
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOD,&GPIO_InitStructure);

//配置PC8-PC15为推挽输出模式
GPIO_InitStructure.GPIO_Pin=0xFF00; //0xFF00,即为同时选中了GPIO_Pin_8到GPIO_Pin_15
GPIO_Init(GPIOC,&GPIO_InitStructure);

//使能573锁存器,允许修改LED状态
GPIO_SetBits(GPIOD,GPIO_Pin_2);
//设置PC8-PC15为高电平,初始化上电关闭所有LED灯
GPIO_SetBits(GPIOC,0xFF00);
//失能573锁存器,保持LED关闭状态
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}

通常题目要求上电初始化时关闭所有无关外设,开发板在默认状态下 LED 灯为上电点亮,通过程序的 18-23 行实现上电关闭。

配置定时器

下面配置定时器 1 来实现计时功能。
初始化定时器 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void Timer1_Init(void)
{
//声明TimeBase结构体和NVIC结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;

//使能定时器1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

//配置定时器1为1ms定时
TIM_TimeBaseStructure.TIM_Period = 1000-1;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter=0; //使用定时器1和8时要添加这一句
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

//开启定时器1更新中断
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);

//使能定时器1
TIM_Cmd(TIM1,ENABLE);

//配置定时器1中断优先级并使能定时器1中断
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

TIM_ClearFlag(TIM1,TIM_FLAG_Update);
}

特别提醒


对于高级定时器 TIM1 和 TIM8,一定要对成员变量 TIM_RepetitionCounter 进行配置。


该变量用于配置 TIMx->RCR 寄存器,其作用简单来说就是重复计数,即为重复溢出多少次产生一次溢出中断,其具体作用可参考 STM32F1 数据手册,需要特别注意的是,如果不对该寄存器进行配置,上电的时候寄存器值可是随机的,导致定时结果不准确:

1
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	//使用定时器1和8时要添加这一句

声明 1 秒钟定时标志的全局变量:

1
u8 Flag1s=0;

配置定时器 1 中断:

1
2
3
4
5
6
7
8
9
10
11
12
13
void TIM1_UP_IRQHandler(void)
{
static u16 cnt=0;
if(TIM_GetITStatus(TIM1,TIM_IT_Update)==SET) //1ms到
{
TIM_ClearITPendingBit(TIM1,TIM_IT_Update); //清除中断等待标志
if(++cnt>=1000) //计时是否到1s
{
cnt=0; //清空计时
Flag1s=1; //1s到
}
}
}

修改主程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int main(void)
{
//定义LED状态变量
u8 LED_Status=0;

SysTick_Config(SystemCoreClock/1000);
Delay_Ms(200);
STM3210B_LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);

//调用定时器1初始化程序
Timer1_Init();
//调用LED初始化程序
LED_Init();

while(1)
{
//定时翻转LED状态
if(Flag1s) //1秒计时到
{
Flag1s=0; //计时标志清零
LED_Status=~LED_Status; //改变LED状态
GPIO_SetBits(GPIOD,GPIO_Pin_2); //使能573锁存器
GPIO_WriteBit(GPIOC,0xFF00,LED_Status); //写入新的LED状态
GPIO_ResetBits(GPIOD,GPIO_Pin_2); //失能573锁存器,保持LED状态
}
}
}

下载测试

将程序通过 Colink 下载到开发板中,可以看到所有的 LED 以 1 秒钟的间隔进行闪烁。