单片机学习小组
直播中

CDCNKA

8年用户 1201经验值
擅长:385288
私信 关注

如何实现按键控制LED灯?

编程的要点是什么?
如何实现按键控制LED灯?

回帖(1)

朱晓妤

2022-1-26 15:18:19
本文展示了STM32 按键Systick 扫描 识别操作
内容涉及
IO口输入输出,枚举建立
按键按下有效,松开有效,长按有效,长按松开有效
Systicks 扫描方法

一、 编程要点

  按键:
1. 使能 GPIO 端口时钟;
2. 初始化 GPIO 目标引脚为输入模式(浮空输入);
3. 编写简单测试程序,检测按键的状态,实现按键控制 LED 灯。
Systicks:
1、设置重装载寄存器的值
2、清除当前数值寄存器的值
3、配置控制与状态寄存器
二、使用步骤

1.理解原理图





代码如下:
: STM32F103ZET6 输出口为PB5低电平点有效
: STM32F103ZET6 Key检测脚为PA8


2.建立Systicks输出的 头文件 Systick_book.h
代码如下(示例):


#ifndef  __SYSTIC_BOOK_H_
#define  __SYSTIC_BOOK_H_


#include "stm32f10x.h"
#include  "Key_book.h"

typedef enum {
                _Systick_us = 1,
                _Systick_ms = 2,
                _Systick_s = 3,
} Systick_time_state_t;


void fn_Systick_Delay(uint32_t  _Delay_time , Systick_time_state_t  _Systick_time_state_t);
void fn_Systick_Delay_Handler_set(uint32_t  _Delay_ms , Systick_time_state_t  _Systick_time_state_t);
void fn_SysTick_delay_decrement(void);
void SysTick_Handler(void);


#endif


3.建立Systicks输出的 头文件 Systick_book.c
代码如下(示例):


#include "Systick_book.h"


/************************************************************
* @brief  
* void fn_Systick_Delay(uint32_t  _Delay_time ,
Systick_time_state_t  _Systick_time_state_t){
* @param  
* @retval
*************************************************************/
void fn_Systick_Delay(uint32_t  _Delay_time , Systick_time_state_t  _Systick_time_state_t){
   uint32_t  i;
   if(_Systick_time_state_t == _Systick_us){SysTick_Config(SystemCoreClock/1000000);}
   if(_Systick_time_state_t == _Systick_ms){
    SysTick_Config(SystemCoreClock/1000);
   }  
   else{SysTick_Config(SystemCoreClock);}      
   for( i=0;i<_Delay_time ; i++){
    while(!((SysTick->CTRL)&(1<<16)));
   }
   SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;


}


/************************************************************
* @brief  
* void fn_Systick_Delay_Handler_set(uint32_t  _Delay_ms ,
*       Systick_time_state_t  _Systick_time_state_t){
* @param  
* @retval
*************************************************************/
static uint32_t _SysTick_delay  = 0 ;
void fn_Systick_Delay_Handler_set(uint32_t  _Delay_ms , Systick_time_state_t  _Systick_time_state_t){
  if(_Systick_time_state_t == _Systick_us){SysTick_Config(SystemCoreClock/1000000);}
  if(_Systick_time_state_t == _Systick_ms){
      SysTick_Config(SystemCoreClock/1000);
  }  
  else{SysTick_Config(SystemCoreClock);}      
  _SysTick_delay = _Delay_ms ;
}


/************************************************************
* @brief  
* void fn_SysTick_delay_decrement(void)
* @param  
* @retval
*************************************************************/
static uint32_t SysTick_delay = 0 ;
void fn_SysTick_delay_decrement(void){
  if(SysTick_delay++ > _SysTick_delay){
    SysTick_delay = 0;
    bkey_10ms = 1;
  }
}


/************************************************************
* @brief  
* void SysTick_Handler(void)
* @param  
* @retval
*************************************************************/
void SysTick_Handler(void){
  fn_SysTick_delay_decrement();
}


4.建立Key采集的 头文件 Key_book.h
代码如下(示例):


#ifndef  __KEY_BOOK_H_
#define  __KEY_BOOK_H_




#include "stm32f10x.h"
#include "Led_book.h"


#define   KEY_IN_GPIO_Port      GPIOA
#define   KEY_IN_GPIO_Clock     RCC_APB2Periph_GPIOA
#define   KEY_IN_GPIO_Pin       GPIO_Pin_0
#define   KEY_IN_GPIO_Pin_Bit   0
#define   Key_IN_GPIO_Modle     GPIO_Mode_IN_FLOATING   //浮空输入




typedef union {
  struct{
    unsigned char BIT0:1;unsigned char BIT1:1;unsigned char BIT2:1;unsigned char BIT3:1;
    unsigned char BIT4:1;unsigned char BIT5:1;unsigned char BIT6:1;unsigned char BIT7:1;
    //unsigned char BIT8:1;unsigned char BIT9:1;unsigned char BIT10:1;unsigned char BIT11:1;
    //unsigned char BIT12:1;unsigned char BIT13:1;unsigned char BIT14:1;unsigned char BIT15:1;
  }DATA_BIT;
  uint8_t DATA_BYTE;
}Per_key_type;


extern volatile  Per_key_type key_flag;
  #define bkey_10ms         key_flag.DATA_BIT.BIT0
  #define bkey_judge        key_flag.DATA_BIT.BIT1
  #define bkey_judge_long   key_flag.DATA_BIT.BIT2
  #define bkey_Effect       key_flag.DATA_BIT.BIT3
  #define bkey_LongEffect   key_flag.DATA_BIT.BIT4
  #define bkey_Effect_Lose  key_flag.DATA_BIT.BIT5
  #define bkey_Effect_LLose key_flag.DATA_BIT.BIT6
  
void  fn_Key_GPIO_Config( GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock , uint16_t _GPIO_Pin_x , GPIOMode_TypeDef  _GPIOMode_TypeDef );
void  fn_Key_Init(void);
void  fn_key_judge(void);
void  fn_key_Effect(void);  
void  fn_key_Check(void);
#endif


5.建立Key采集的 头文件 Key_book.c
代码如下(示例):


#include  "Key_book.h"



volatile  Per_key_type key_flag;


/**************************************************************
* @brief  
* void  fn_Key_GPIO_Config( GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock ,
*                  uint16_t _GPIO_Pin_x , GPIOMode_TypeDef  _GPIOMode_TypeDef );
* @param  
* @retval
*************************************************************/
void  fn_Key_GPIO_Config( GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock , uint16_t _GPIO_Pin_x , GPIOMode_TypeDef  _GPIOMode_TypeDef ){
    GPIO_InitTypeDef  GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = _GPIOMode_TypeDef;
    GPIO_InitStruct.GPIO_Pin = _GPIO_Pin_x;
    RCC_APB2PeriphClockCmd(_GPIO_Clock,ENABLE);
    GPIO_Init(_GPIO_x , &GPIO_InitStruct);  
}


/**************************************************************
* @brief  
* void fn_Key_Init(void);
* @param  
* @retval
*************************************************************/
void  fn_Key_Init(void){
    fn_Key_GPIO_Config(KEY_IN_GPIO_Port,KEY_IN_GPIO_Clock,KEY_IN_GPIO_Pin,Key_IN_GPIO_Modle);
}


/************************************************************
* @brief  
* void  fn_key_judge(void);
* @param  
* @retval
**************************************************************/
#define  _LONG_key  30
static uint16_t count_key ;
void  fn_key_judge(void){
   
   if(!bkey_10ms){return;}
   bkey_10ms = 0;
   if(GPIO_ReadInputDataBit(KEY_IN_GPIO_Port,KEY_IN_GPIO_Pin)){
     if(count_key++<3){return;}
     if(!bkey_judge){
       bkey_judge = 1;
       bkey_Effect = 1;
     }else{
       if(count_key>_LONG_key){
          bkey_judge_long = 1;
          bkey_LongEffect = 1;
       }
     }
   }
   else{
     count_key = 0;
     if(bkey_judge){
        bkey_judge = 0;
        if(bkey_judge_long){
            bkey_judge_long = 0;
            bkey_Effect_LLose = 1;
        }else{
            bkey_judge_long = 0;
            bkey_Effect_Lose = 1;
        }
     }else{
        bkey_judge = 0;         
     }
  }
}


/************************************************************
* @brief  
* void fn_key_Effect(void);
* @param  
* @retval
*************************************************************/
void  fn_key_Effect(void){
  if(bkey_Effect){
    bkey_Effect = 0;
    fn_LED_Corporate(LED_OUT_GPIO_Port,LED_OUT_GPIO_Pin,LED_Corporate_Toggle);
  }
}


/**************************************************************
* @brief  
* void fn_key_Check(void);
* @param  
* @retval
*************************************************************/
void fn_key_Check(void){
  fn_key_judge();
  fn_key_Effect();
}


6.利用之前的LED输出的 头文件 Led_book.h
代码如下(示例):


#ifndef  __LED_BOOK_H_
#define  __LED_BOOK_H_


#include "stm32f10x.h"


#define   LED_OUT_GPIO_Port     GPIOB                 //GPIO Point
#define   LED_OUT_GPIO_Clock    RCC_APB2Periph_GPIOB  //GPIO clock
#define   LED_OUT_GPIO_Pin      GPIO_Pin_5            
#define   LED_OUT_GPIO_Pin_Bit  5
#define   LED_OUT_GPIO_Modle    GPIO_Mode_Out_PP




typedef enum {
                LED_Corporate_On = 1,
                LED_Corporate_OFF = 2,
                LED_Corporate_Toggle = 3,
} LED_Corporate_state_t;


void fn_LED_GPIO_Config(GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock ,
          uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef);


void fn_LED_Corporate(GPIO_TypeDef* _GPIO_x , uint16_t _GPIO_Pin_x ,
          LED_Corporate_state_t _LED_Corporate_state_t );
  


#endif


7.利用之前的LED输出的 头文件 Led_book.c
代码如下(示例):


#include "Led_book.h"


#define LED_GPIO_Speed GPIO_Speed_10MHz
void fn_LED_GPIO_Config(GPIO_TypeDef* _GPIO_x , uint32_t _GPIO_Clock ,uint16_t _GPIO_Pin_x , GPIOMode_TypeDef _GPIOMode_TypeDef){
  GPIO_InitTypeDef  GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Mode = _GPIOMode_TypeDef;
  GPIO_InitStruct.GPIO_Pin = _GPIO_Pin_x;
  GPIO_InitStruct.GPIO_Speed = LED_GPIO_Speed;
  RCC_APB2PeriphClockCmd(_GPIO_Clock ,ENABLE);
  GPIO_Init(_GPIO_x , &GPIO_InitStruct) ;
}


void fn_LED_Corporate(GPIO_TypeDef*  _GPIO_x , uint16_t  _GPIO_Pin_x , LED_Corporate_state_t  _LED_Corporate_state_t ){
  
  switch(_LED_Corporate_state_t){
    case  LED_Corporate_On :
      GPIO_SetBits(_GPIO_x,_GPIO_Pin_x);
      break;
                case  LED_Corporate_OFF:
      GPIO_ResetBits(_GPIO_x,_GPIO_Pin_x);
      break;
                case  LED_Corporate_Toggle:
      GPIO_ReadOutputDataBit(_GPIO_x,_GPIO_Pin_x)?GPIO_ResetBits(_GPIO_x,_GPIO_Pin_x):GPIO_SetBits(_GPIO_x,_GPIO_Pin_x);
      break;   
  }
}


//practice
//fn_LED_GPIO_Config (LED_OUT_GPIO_Port,LED_OUT_GPIO_Clock,LED_OUT_GPIO_Pin,LED_OUT_GPIO_Modle);
// while(1){
//  delay(10000);
//  fn_LED_Corporate(LED_OUT_GPIO_Port,LED_OUT_GPIO_Pin,LED_Corporate_Toggle);                 
// }       


8.建立Systicks Key输出的 主程序 main.c
代码如下(示例):


/**
  ******************************************************************************
  * @file    GPIO/JTAG_Remap/main.c
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  *
  ******************************************************************************
  */


/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "PROJ_book.h"


/* Private functions ---------------------------------------------------------*/


/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
void delay(int x);
void fn_Main_Init(void);
int main(void)
{


//    fn_HRCC_SetSystic(RCC_PLLMul_9 );
//    fn_IRCC_SetSystic(RCC_PLLMul_9 );
//    fn_MCO_GPIO_Config();
      fn_Led_Init();
      fn_Key_Init();
      fn_Main_Init();
      fn_Systick_Delay_Handler_set(10,_Systick_ms);
      while(1){
        fn_key_Check();
      }
}


void fn_Main_Init(void){
  uint16_t  count_Init = 2;
  while(count_Init-->0){
    __LED_OUT__;
    fn_Systick_Delay(500,_Systick_ms);
    __LED_OUT__;
    fn_Systick_Delay(100,_Systick_ms);
    __LED_OUT__;
    fn_Systick_Delay(100,_Systick_ms);
    __LED_OUT__;
    fn_Systick_Delay(500,_Systick_ms);
  }
}


void delay(int x){
        int y = 0xFFFFF;
        while((x--)>0){
                while((y--)>0){
                        __NOP();
                        __NOP();
                        __NOP();
                        __NOP();
                        __NOP();
                }
        }
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/


STM32 Systick 笔记
STM32 RCC – RCC 程序


STM32 RCC – LED 程序


STM32 RCC – 主程序


09 _STM32f103 时钟树 RCC


总结
SysTick简介:
系统定时器,24位,只能递减,存在于内核,嵌套在NVIC中,所有的Cortex-M内核的单片机都具有这个定时器。       


counter在时钟的驱动下,从reload初值开始往下递减计数到0:
   产生中断和置位COUNTFLAG标志。
   然后又从reload值开始重新递减计数,如此循环。
   1-t:一个计数循环的时间,跟reload和CLK有关
2-CLK:72M或者9M,由CTRL寄存器配置
3-RELOAD:24位,用户自己配置


t = reload * ( 1/clk )
Clk = 72M时,t = (72) *(1/ 72 M )= 1US
Clk = 72M时,t = (72000) *(1/ 72 M )= 1MS
时间单位换算:
1s = 1000ms = 1000 000 us = 1000 000 000ns


举报

更多回帖

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