STM32F4多按键多点灯模式及其矩形波的输出

开启这一年单片机第一次基础培训,这次用了STM32F407ZG的板子。

一. 概述

代码烧入后通过按下按键实现相应功能

(KEY0控制跑马灯和闪烁的切换;KEY1不同占空比的切换;KEY2在不同占空比下频率的切换。灵敏度高,不同按键不同情况下可随时切换状态,但这次小题没有用到LCD,输出矩形波还得靠示波器。)

二. 功能简介

(1)跑马灯的实现

(2)通过按键实现跑马灯与闪烁的切换

(3)呼吸灯

(4)输出一个100HZ,占空比为50%的矩形波

(5)通过按键切换25%,90%占空比的矩形波

(6)通过按键切换不同频率的矩形波

三. 相关部分代码

1.宏定义

//读取按键宏定义
#define READ_KEY0 HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)//读取引脚的电平状态
#define READ_KEY1 HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)
#define READ_KEY2 HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)

2.相关自定义函数声明

void run_led(void);   //跑马灯与闪烁
void duty_ratio(void);   //矩形波

uint8_t run_led_shift();   //跑马灯与闪烁之间模式切换
uint8_t duty_ratio_shift();  //矩形波不同占空比的转换
uint8_t choose_run();  //转到跑马灯
uint8_t choose_ratio();  //转到矩形波

3.相关函数

uint8_t  choose=0;
uint8_t  k=0, l=0, m=0, n=0, i=0; 
static uint8_t key_up = 1; //按键松开标志


/* 跑马灯与闪烁 */
void run_led(void)
{
   uint32_t time=0;
  
   HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, 1);  
   HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
  
   if( 1==i )
   {
     HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, 0);       
     for(time=0; time<500; time++)
     {
        HAL_Delay(100); 
        if( run_led_shift()||choose_ratio() )  return;
     } 
     HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
     HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);   
     for(time=0; time<500; time++)
     {
        HAL_Delay(100); 
        if( run_led_shift()||choose_ratio() )  return;
     }     
     HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
    
     if( run_led_shift()||choose_ratio() )  return;
  }  
  if( 0==i )
  {
     HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
     for(time=0; time<500; time++)
     {
        HAL_Delay(100); 
        if( run_led_shift()||choose_ratio() )  return;
     }    
     if( run_led_shift()||choose_ratio() )  return;
  }
}



/* 矩形波 */
void duty_ratio(void)
{
  uint8_t j=0;
  HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, 1);
  HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, 1);
  
  if( 0==READ_KEY0 )
  {
    HAL_Delay(500);
    if( 0==READ_KEY0 )
    {
      choose = 1;
      return ;
    }
  }
  
  if( 1==k )  /* 50% */
  {
    while(1)
    { 
      if( choose_run() )   break;
      if( duty_ratio_shift())  return;
      
      if( 0==READ_KEY2 )
      {
        HAL_Delay(500);
        if( 0==READ_KEY2)
        {
          m++;
          m%=3;
        }
        while( 0==READ_KEY2 ){};
      }    
      if( 0==m )  
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(501);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(501);
      }
      if( 1==m )  
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(1005);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(1005);
      }
      if( 2==m )  
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(250);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(250);
      }
    }  
  }
  
  else if( 2==k )    /* 25% */
  {  
    while(1)
    { 
      if( choose_run())   break;
      if( duty_ratio_shift())  return;
      
      if( 0==READ_KEY2 )
      {
        HAL_Delay(500);
        if( 0==READ_KEY2)
        {
          l++;
          l%=3;
        }
        while( 0==READ_KEY2 ){};
      }   
      if( 0==l )  
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(252);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(753);
      }
      if( 2==l )   
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(502);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(1510);
      }
      if( 1==l )   
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(100);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(300);
      }
    }  
  }
  else if( 3==k )     /* 90% */
  {
    while(1)
    {
      if( choose_run())   break;
      if( duty_ratio_shift())  return;
      
      if( 0==READ_KEY2 )
      {
        HAL_Delay(10);
        if( 0==READ_KEY2)
        {
          l++;
          l%=3;
        }
        while( 0==READ_KEY2 ){};
      }    
      if(0==l)  
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(908);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(98);
      }
      if(1==l)  
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(360);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(40);
      }
      if(2==l)  
      {
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
        HAL_Delay(1812);
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        HAL_Delay(198);
      }
    }  
  } 
  else if( 0==k )  //呼吸灯
  {
    while(1)
    {
      if( choose_run())   break;
      if( duty_ratio_shift())  return;
      
		  for(j=0; j<150 ;j++)
		  {
            if( duty_ratio_shift()||choose_run() )
            {
              return;
            }
            HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 0);
            HAL_Delay(j*10);
            if( duty_ratio_shift()||choose_run() )
            {
              return;
            }
            HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
            HAL_Delay(1500-j*10);
		  }
		  for(j=150; j>0; j--)
		  {
            if( duty_ratio_shift()||choose_run() )
            {
              return;
            }
            HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
            HAL_Delay(1500-j*10);
            if( duty_ratio_shift()||choose_run() )
            {
              return;
             }
            HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 0);
            HAL_Delay(j*10);
		  }		
    }
  }
  else
  {
    return ;
  }
}


/* 转到跑马灯模式 */
uint8_t choose_run()
{
     if( READ_KEY0==0)
     {
       HAL_Delay(500);
       if( READ_KEY0==0)
       {
         choose = 1;
       }
       while( READ_KEY0==0 ){};
       return 1;
     }
     return 0;
}

/* 转到矩形波 */
uint8_t choose_ratio()  
{
     if( READ_KEY1==0)
     {
       HAL_Delay(500);
       if( READ_KEY1==0)
       {
         choose = 2;
       }
       while( READ_KEY1==0 ){};
       return 1;
     }
     return 0;
}

/* 跑马灯和闪烁转换 */
uint8_t run_led_shift()
{
     if( READ_KEY0==0 )
     {
       HAL_Delay(500);
       if( READ_KEY0==0 )
       {
         i++;
         i%=2;
       }
       while( READ_KEY0==0 ){};
       return 1;
     } 
     return 0;     
}

/* 矩形波的占空比切换 */
uint8_t duty_ratio_shift()
{
  if( 0==READ_KEY1 )
      {
        HAL_Delay(500);
        if( 0==READ_KEY1)
        {
          k++;
          k%=4;
        }
        while( READ_KEY1==0 ){};
        return 1;
      }
      return 0;
}

4.主函数

int main(void)
{
  SystemClock_Config();
  MX_GPIO_Init();

  HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, 1);
  HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, 1);
  HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, 1);
  
  while (1)
  {
// 跑马灯与闪烁
	  if (key_up && ( 0 == READ_KEY0 ))
	  {
		  HAL_Delay(500); //Ïû¶¶
		  key_up = 0;
		  if (READ_KEY0 == 0)
		  choose = 1;
	  }
	  else if (READ_KEY0 == 1)
	  {
		  key_up = 1;
	  }
  
// 矩形波
	  if (key_up && ( 0 == READ_KEY1 ))
	  {
		  HAL_Delay(500); //Ïû¶¶
		  key_up = 0;
		  if (READ_KEY1 == 0)
		  choose = 2;
	  }
	  else if (READ_KEY1 == 1)
	  {
	  	key_up = 1;
	  }

/* 小菜单 */    
    switch( choose )
    {
        case 1: 
          run_led();
          break;
        case 2:
          duty_ratio();
          break;       
        default:
          continue;
    }
  }
}

四. 所学与总结

1.检测按键是否松开

这个很重要,一开始没怎么注意,然后发现按键按下的时候一直检测,一不小心就跳到另一个模式去了,后边在高人指导下才了解到其重要性,加上之后程序运行的效果比之前好很多。总结了如下两种写法:

(1)加按键松开标志(学到了学长的代码)

uint8_t KEY_Scan(uint8_t mode) {
	static uint8_t key_up = 1; //按键松开标志  这里这里这里!!!
	if (mode)
	{
		key_up = 1; //支持连按
	}
	
	if (key_up && (KEY0 == 0 || KEY1 == 0 || KEY2 == 1))
	{
		HAL_Delay(10); //去抖动
		key_up = 0;
		if (KEY0 == 0)
			return KEY0_PRES;
		if (KEY1 == 0)
			return KEY1_PRES;
		if (KEY2 == 1)
			return KEY2_PRES;
	}
	else if (KEY0 == 1 && KEY1 == 1 && KEY2 == 0)
	{
		key_up = 1;
	}
	return 0; //按键按下
}

(2)while辅助

uint8_t choose_run()
{
     if( READ_KEY0==0)
     {
       HAL_Delay(500);
       if( READ_KEY0==0)
       {
         choose = 1;
       }
       while( READ_KEY0==0 ){};  //这里这里这里!!!
       return 1;
     }
     return 0;
}

2. 使用delay的按键灵敏度问题

(1)把延迟时间分成小段,如下:

for(time=0; time<500; time++)
{
    HAL_Delay(100); 
    if( run_led_shift()||choose_ratio() )  return;  //每循环一次判断一次
}    

(2)改写delay函数( while )

3. 多用宏定义define及ifdef,能大大提高代码可读性、移植性等,大大简化代码。

4. switch和if else结合使用,也莫忘了 ( ?:)

5. 合理运用全局变量

这个小题不难,我写的逻辑也简单易懂,但代码过于冗杂写了很多行,后边想了一下,合理运用switch和define可以很好地解决很多问题,也能让代码少很多,下次注意,加油加油。

猜你喜欢

转载自blog.csdn.net/qq_51368339/article/details/120863846
今日推荐