1.题目具体内容:按键控制跑马灯停止,按下按键二跑马灯停止,所有灯熄灭,再按按键一跑马灯
从头开始运行。
使用定时器控制跑马灯,里面有一个参数相当于开关,当参数为1时启动流水灯,当参数为其他时流水灯熄灭。
按键控制参数,达到本题要求。
1.LED灯宏定义 按键宏定义
#define LED1_ON() GPIO_ResetBits(GPIOA , GPIO_Pin_8); //PA8 输出低电平,使其发光
#define LED1_OFF() GPIO_SetBits(GPIOA , GPIO_Pin_8); //PA8 输出高电平,使其灭
#define LED2_ON() GPIO_ResetBits(GPIOB , GPIO_Pin_1); //PB1 输出低电平,使其发光
#define LED2_OFF() GPIO_SetBits(GPIOB , GPIO_Pin_1); //PB1 输出高电平,使其灭
#define LED3_ON() GPIO_ResetBits(GPIOA , GPIO_Pin_7); //PA7 输出低电平,使其发光
#define LED3_OFF() GPIO_SetBits(GPIOA , GPIO_Pin_7); //PA7 输出高电平,使其灭
#define LED4_ON() GPIO_ResetBits(GPIOB , GPIO_Pin_2); //PB2 输出低电平,使其发光
#define LED4_OFF() GPIO_SetBits(GPIOB , GPIO_Pin_2); //PB2 输出高电平,使其灭
#define KEY1() GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_5)
#define KEY2() GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_0)
#define KEY3() GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)
2.LED灯初始化 按键初始化 定时器初始化
void LED_Pin_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE); //使能PAPB端口时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8; //LED1--》PA8 LED3--》PA7端口配置, 推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 ; //LED2--》PB1 , LED4--》PB2端口配置, 推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
LED1_OFF();
LED2_OFF();
LED3_OFF();
LED4_OFF();
}
void KEY_Pin_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); //使能PAPB端口时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_0; //KEY1--》PB5 KEY2--》PB0端口配置
GPIO_Init(GPIOB, &GPIO_InitStructure); //IO口速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ; //KEY3--》PA6端口配置
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//初始化TIM2控制引脚及配置其中断方式、优先级
void TIM2_Int_Init(u16 arr , u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2时钟
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到2000为2ms
TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值 1Mhz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM2 , TIM_IT_Update , ENABLE ); //使能指定的TIM2中断,允许更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIM2外设,开始计数
}
3.编写中断服务函数即开关 设定三个变量,一个是开关mode,一个是tim2_count,由于定时器是每2ms运行一次,为达到流水灯的效果,令4000ms执行一次LED灯循环;最后一个为tim2_stats,令1000ms执行一次一个灯亮起
//TIM2中断服务处理函数
void TIM2_IRQHandler()
{
if(TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET) //检查指定的TIM2中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM2 , TIM_IT_Update ); //清除TIM2的中断待处理位:TIM 中断源
if(mode==1)
{
tim2_count++; //对2毫秒中断进行累加,累计到1000毫秒即500次,
if(tim2_count 》= 500)
{
tim2_count = 0;
tim2_stats++; //对1秒时间进行累加
if (tim2_stats % 4 == 1 )
{
LED1_ON();
LED2_OFF();
LED3_OFF();
LED4_OFF();
}
else if(tim2_stats % 4 == 2)
{
LED1_OFF();
LED2_ON();
LED3_OFF();
LED4_OFF();
}
else if(tim2_stats % 4 == 3)
{
LED1_OFF();
LED2_OFF();
LED3_ON();
LED4_OFF();
}
else if(tim2_stats % 4 == 0)
{
LED1_OFF();
LED2_OFF();
LED3_OFF();
LED4_ON();
}
}
}
else
{
LED1_OFF();
LED2_OFF();
LED3_OFF();
LED4_OFF();
}
}
}
最后一步就是编写主函数,通过按键控制mode即控制开关
#include “stm32f10x.h”
#include “delay.h”
int main()
{
u8 key1stat = 0;
delay_init(); //调用精确延时初始化函数
LED_Pin_Init(); //调用LED引脚控制初始化函数
KEY_Pin_Init();
TIM2_Int_Init(2000 , 72 - 1); //调用定时器2初始化函数,配置计数2000,进行72预分频
while(1) //无限循环,等待TIM4中断产生
{
if(KEY1() == 0) //判断KEY1是否已按下
{
delay_ms(3); //延时消抖
while(KEY1() == 0); //等待KEY1松手
delay_ms(3); //再次延时消抖
mode=1;
tim2_stats=0;
}
if(KEY2()==0)
{
mode=0;
}
}
}
由于本题是按下KEY1流水灯从头开始,所以不要忘了将tim2_stats清零达到重新来过的效果呀
本题感悟:
题主在写本题时曾想用主函数是流水灯,令外部中断控制流水灯,可是外部中断只能控制一次流水灯就清除标志位了,无法达到永久的效;或者是在外部中断中编写流水灯,但是当中断发生时只能执行一次流水灯也被清除标志位了。这两种方法都是使用死循环来控制流水灯。从而达不到想要的效果,因为是两个永久,流水灯永久循环,消失永久循环。而定时器可以达到通过执行时间来控制流水灯,每两毫秒执行一次中断,达到流水灯循环的效果,并且也可以永久保存mode值,直到下一次按键改变mode才会改变。
1.题目具体内容:按键控制跑马灯停止,按下按键二跑马灯停止,所有灯熄灭,再按按键一跑马灯
从头开始运行。
使用定时器控制跑马灯,里面有一个参数相当于开关,当参数为1时启动流水灯,当参数为其他时流水灯熄灭。
按键控制参数,达到本题要求。
1.LED灯宏定义 按键宏定义
#define LED1_ON() GPIO_ResetBits(GPIOA , GPIO_Pin_8); //PA8 输出低电平,使其发光
#define LED1_OFF() GPIO_SetBits(GPIOA , GPIO_Pin_8); //PA8 输出高电平,使其灭
#define LED2_ON() GPIO_ResetBits(GPIOB , GPIO_Pin_1); //PB1 输出低电平,使其发光
#define LED2_OFF() GPIO_SetBits(GPIOB , GPIO_Pin_1); //PB1 输出高电平,使其灭
#define LED3_ON() GPIO_ResetBits(GPIOA , GPIO_Pin_7); //PA7 输出低电平,使其发光
#define LED3_OFF() GPIO_SetBits(GPIOA , GPIO_Pin_7); //PA7 输出高电平,使其灭
#define LED4_ON() GPIO_ResetBits(GPIOB , GPIO_Pin_2); //PB2 输出低电平,使其发光
#define LED4_OFF() GPIO_SetBits(GPIOB , GPIO_Pin_2); //PB2 输出高电平,使其灭
#define KEY1() GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_5)
#define KEY2() GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_0)
#define KEY3() GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)
2.LED灯初始化 按键初始化 定时器初始化
void LED_Pin_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE); //使能PAPB端口时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8; //LED1--》PA8 LED3--》PA7端口配置, 推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 ; //LED2--》PB1 , LED4--》PB2端口配置, 推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
LED1_OFF();
LED2_OFF();
LED3_OFF();
LED4_OFF();
}
void KEY_Pin_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); //使能PAPB端口时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_0; //KEY1--》PB5 KEY2--》PB0端口配置
GPIO_Init(GPIOB, &GPIO_InitStructure); //IO口速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ; //KEY3--》PA6端口配置
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//初始化TIM2控制引脚及配置其中断方式、优先级
void TIM2_Int_Init(u16 arr , u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2时钟
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到2000为2ms
TIM_TimeBaseStructure.TIM_Prescaler = psc; //设置用来作为TIMx时钟频率除数的预分频值 1Mhz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM2 , TIM_IT_Update , ENABLE ); //使能指定的TIM2中断,允许更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIM2外设,开始计数
}
3.编写中断服务函数即开关 设定三个变量,一个是开关mode,一个是tim2_count,由于定时器是每2ms运行一次,为达到流水灯的效果,令4000ms执行一次LED灯循环;最后一个为tim2_stats,令1000ms执行一次一个灯亮起
//TIM2中断服务处理函数
void TIM2_IRQHandler()
{
if(TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET) //检查指定的TIM2中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM2 , TIM_IT_Update ); //清除TIM2的中断待处理位:TIM 中断源
if(mode==1)
{
tim2_count++; //对2毫秒中断进行累加,累计到1000毫秒即500次,
if(tim2_count 》= 500)
{
tim2_count = 0;
tim2_stats++; //对1秒时间进行累加
if (tim2_stats % 4 == 1 )
{
LED1_ON();
LED2_OFF();
LED3_OFF();
LED4_OFF();
}
else if(tim2_stats % 4 == 2)
{
LED1_OFF();
LED2_ON();
LED3_OFF();
LED4_OFF();
}
else if(tim2_stats % 4 == 3)
{
LED1_OFF();
LED2_OFF();
LED3_ON();
LED4_OFF();
}
else if(tim2_stats % 4 == 0)
{
LED1_OFF();
LED2_OFF();
LED3_OFF();
LED4_ON();
}
}
}
else
{
LED1_OFF();
LED2_OFF();
LED3_OFF();
LED4_OFF();
}
}
}
最后一步就是编写主函数,通过按键控制mode即控制开关
#include “stm32f10x.h”
#include “delay.h”
int main()
{
u8 key1stat = 0;
delay_init(); //调用精确延时初始化函数
LED_Pin_Init(); //调用LED引脚控制初始化函数
KEY_Pin_Init();
TIM2_Int_Init(2000 , 72 - 1); //调用定时器2初始化函数,配置计数2000,进行72预分频
while(1) //无限循环,等待TIM4中断产生
{
if(KEY1() == 0) //判断KEY1是否已按下
{
delay_ms(3); //延时消抖
while(KEY1() == 0); //等待KEY1松手
delay_ms(3); //再次延时消抖
mode=1;
tim2_stats=0;
}
if(KEY2()==0)
{
mode=0;
}
}
}
由于本题是按下KEY1流水灯从头开始,所以不要忘了将tim2_stats清零达到重新来过的效果呀
本题感悟:
题主在写本题时曾想用主函数是流水灯,令外部中断控制流水灯,可是外部中断只能控制一次流水灯就清除标志位了,无法达到永久的效;或者是在外部中断中编写流水灯,但是当中断发生时只能执行一次流水灯也被清除标志位了。这两种方法都是使用死循环来控制流水灯。从而达不到想要的效果,因为是两个永久,流水灯永久循环,消失永久循环。而定时器可以达到通过执行时间来控制流水灯,每两毫秒执行一次中断,达到流水灯循环的效果,并且也可以永久保存mode值,直到下一次按键改变mode才会改变。
举报