如何用按键控制不同的LED流转模式?

LEDs

357人已加入

描述

实现的任务就是用LCD做一个菜单,用按键控制不同的LED流转模式。

第一步--熟悉硬件

滤波器

这个就是普通的按键连接方式,没有硬件上消抖所以,就得软件处理了。经过查阅原理图发现,按键连接的引脚是PA0,PA8,PB1,PB2。其中PA0有唤醒的功能,不知道会不会考。

第二步--软件设计

LED,LCD相关的东西我在上一篇以及做了,在这里就不说了。

那么就是介绍按键输入相关。

首先就是对按键的初始化

void Key_GPIO_Config(void)
{
  GPIO_InitTypeDef  GPIO_Strue;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  GPIO_Strue.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_8;
  GPIO_Strue.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Strue.GPIO_Speed =GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_Strue);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  GPIO_Strue.GPIO_Pin = GPIO_Pin_1| GPIO_Pin_2;
  GPIO_Init(GPIOB, &GPIO_Strue);
}

之后就是对按键处理。

因为有抖动所以就要消抖。有的教程是延时消抖,但是延时的过程中CPU就是空闲下来了,无法对外界消息做出回应,在对时间要求较高的场和中就不太适用。既然我是要学习的,就要和实际看齐,就要想一种不太占用CPU的方法。这是定时器就出来了,我们将一大段的延时拆成一小段一小段的,这样不就减轻CPU的压力了?

在处理抖动的问题上,我们可以采用一种滤波的方式,每隔一段时间采一下值,然后判断这些值,如果这些值稳定在一个值,那么就说明按键处于按下或者弹起的状态。下面的程序就是实现这种消抖的方式

void KEY_Scan(void)
{
  uint8_t i;
  uint8_t key_buff[] ={0xff,0xff,0xff,0xff};

  key_buff[0]= (key_buff[0] < < 1) | KEY1;
  key_buff[1]= (key_buff[1] < < 1) | KEY2;
  key_buff[2]= (key_buff[2] < < 1) | KEY3;
  key_buff[3]= (key_buff[3] < < 1) | KEY4;
  for(i = 0; i < 4; i ++)
  {
    if((key_buff[i] & 0x0f) == 0x0f)
    {
      keySta[i] = 1;
    }
    else if((key_buff[i] & 0x0f) == 0x00)
    {
      keySta[i] = 0;
    }
    else{}
  }
}

要实现每隔一段时间就进行一次扫描就需要用定时器扫描,将定时器配置成1ms进一次中断,然后在中断里进行一次扫描。

那么接下来就是配置定时器,这里选择定时器4。

void TIM4_Config()
{
  TIM_TimeBaseInitTypeDef TIM_structure;
  NVIC_InitTypeDef NVIC_structure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  TIM_structure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_structure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式 向上计数
  TIM_structure.TIM_RepetitionCounter = 0;//设置重复计数值
  //设置1ms进入一次中断,,TIM4在APB1时钟线上36MHz,那就36预分频
  //但是根据说明,如果APB1的预分频系数=1;则频率不变,否则x2
  //例程的预分频x2需要按照72M配置
  TIM_structure.TIM_Prescaler = 72 -1;  //就是1m 它的倒数就是时间
  TIM_structure.TIM_Period = 1000-1; //这就是1ms
  TIM_TimeBaseInit(TIM4, &TIM_structure);
  TIM_ClearFlag(TIM4, TIM_FLAG_Update);
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  TIM_Cmd(TIM4, ENABLE);  
  //中断配置;
  NVIC_structure.NVIC_IRQChannel = TIM4_IRQn;
  NVIC_structure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_structure.NVIC_IRQChannelSubPriority = 2;
  NVIC_structure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_structure);
}

再写一下中断程序就差不多了

void TIM4_IRQHandler()
{
  if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
  {
    KEY_Scan();
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
  }
}

之后就是主程序

先来一个开机选择界面

LCD_Clear(Black);
  LCD_SetBackColor(Blue2);
  LCD_SetTextColor(Black);
  LCD_DisplayStringLine(Line0, (uint8_t *)"     LED Control    ");
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);
  LCD_DisplayStringLine(Line1, (uint8_t *)"        .__        ");
  LCD_DisplayStringLine(Line2, (uint8_t *)"   _____|__|__  ___");
  LCD_DisplayStringLine(Line3, (uint8_t *)"  /  ___/    /  /");
  LCD_DisplayStringLine(Line4, (uint8_t *)"  ___ |  | >    < ");
  LCD_DisplayStringLine(Line5, (uint8_t *)" /____  >__/__/_ ");
  LCD_DisplayStringLine(Line6, (uint8_t *)"      /         /");
  LCD_DisplayStringLine(Line7, (uint8_t *)"________________________");
  LCD_DisplayStringLine(Line8, (uint8_t *)"Press B1 to start...");

然后就是控制界面

LCD_Clear(Black);
      LCD_SetBackColor(Blue);
      LCD_SetTextColor(Black);
      LCD_DisplayStringLine(Line0, (uint8_t *)"   Mode Selection    ");
      LCD_SetBackColor(Black);
      LCD_SetTextColor(White);
      LCD_DisplayStringLine(Line2, (uint8_t *)"       Mode1");
      LCD_DisplayStringLine(Line3, (uint8_t *)"       Mode2");
      LCD_DisplayStringLine(Line4, (uint8_t *)"       Mode3");
      LCD_DisplayStringLine(Line5, (uint8_t *)"       Mode4");
      LCD_DisplayStringLine(Line7, (uint8_t *)"_____________________");
      LCD_DisplayStringLine(Line8, (uint8_t *)"Runing:");
      LCD_DisplayStringLine(Line9, (uint8_t *)"Nothing.");

最后就是一堆逻辑,感觉写的复杂了

int main(void)
{
  uint8_t keyval;
  uint8_t mode;
  SysTick_Config(SystemCoreClock/1000);
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//抢占和响应优先级的范围0~3
  STM3210B_LCD_Init();
  LED_Enable_gpio_cofig();
  Key_GPIO_Config();
  TIM4_Config();


  while(1)
  {
    if(start_flag)
    {
      LCD_Clear(Black); 
      while(start_flag)
      {
        count_flag = 0;
        led_count = 0;
        LED_ENABLE();
        GPIO_Write(GPIOC, 0xff00);
        LED_DISENABLE();
        keyval = Get_KeyVal();
        if(keyval == 0xa1)
        {
          start_flag = 0;
        }
      }
    }
    else
    {
      mode = 1;
      while(start_flag == 0)
      {
        keyval = Get_KeyVal();
        if(keyval == 0xa3)
        {
          mode = mode + 1;
          if(mode > 4)
          {
            mode = 4;
          }
        }
        if(keyval == 0xa2)
        {
          mode = mode - 1;
          if(mode <= 1)
          {
            mode = 1;
          }          
        }
        switch(mode)
        {
          case 1:  LCD_DisplayChar(Line2, 16* 14, ' >');
               LCD_DisplayChar(Line3, 16* 14, ' ');
               LCD_DisplayChar(Line4, 16* 14, ' ');
               LCD_DisplayChar(Line5, 16* 14, ' ');
               break;
          case 2:  LCD_DisplayChar(Line2, 16* 14, ' ');
               LCD_DisplayChar(Line3, 16* 14, ' >');
               LCD_DisplayChar(Line4, 16* 14, ' ');
               LCD_DisplayChar(Line5, 16* 14, ' ');
               break;
          case 3:  LCD_DisplayChar(Line2, 16* 14, ' ');
               LCD_DisplayChar(Line3, 16* 14, ' ');
               LCD_DisplayChar(Line4, 16* 14, ' >');
               LCD_DisplayChar(Line5, 16* 14, ' ');
               break;
          case 4:  LCD_DisplayChar(Line2, 16* 14, ' ');
               LCD_DisplayChar(Line3, 16* 14, ' ');
               LCD_DisplayChar(Line4, 16* 14, ' ');
               LCD_DisplayChar(Line5, 16* 14, ' >');
               break;               
        }
        if(keyval == 0xa4)
        {
          count_flag = 1;  
          LCD_ClearLine(Line9);
          switch(mode)
          {
            case 1:  LCD_DisplayStringLine(Line9, (uint8_t *)"Mode1");break;
            case 2:  LCD_DisplayStringLine(Line9, (uint8_t *)"Mode2");break;
            case 3:  LCD_DisplayStringLine(Line9, (uint8_t *)"Mode3");break;
            case 4:  LCD_DisplayStringLine(Line9, (uint8_t *)"Mode4");break;       
          }
        }
        if(keyval == 0xa1)
        {
          start_flag = 1;
        }
        while(count_flag)
        {
          LED_ENABLE();
          GPIO_Write(GPIOC, led_buff[mode-1][led_count]);
          keyval = Get_KeyVal();
          if(keyval == 0xa4)
          {
            count_flag = 0;
            GPIO_Write(GPIOC, 0xff00);
            LED_DISENABLE();  
            LCD_ClearLine(Line9);
            LCD_DisplayStringLine(Line9, (uint8_t *)"Nothing.");
          }
          if(keyval == 0xa1)
          {
            start_flag = 1;
            count_flag = 0;
            GPIO_Write(GPIOC, 0xff00);
            LED_DISENABLE();  
          }          
        } 
      }
    }
  }
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分