STM32
直播中

低调de炫耀爱

11年用户 762经验值
私信 关注
[问答]

STM32的两个按键是怎样去控制跑马灯的运行及停止的

STM32的两个按键是怎样去控制跑马灯的运行及停止的?有哪些操作步骤?

回帖(1)

何瑾

2021-11-17 10:54:54
  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才会改变。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分