stm32定时器扫描数码管(无锁存器)和矩阵按键

如果不使用定时器,会有很多冲突。比如数码管显示不正常,按键响应问题。

定时器时间消隐效果还不错,根据实验室另一个光伏项目的朋友用stc15代码改过来的。

数码管

#ifndef __LED_H
#define __LED_H	 
#include "sys.h"

#define DX0 PAout(0)
#define DX1 PAout(1)
#define DX2 PAout(2)
#define DX3 PAout(3)
#define DX4 PAout(4)
#define DX5 PAout(5)
#define DX6 PAout(6)
#define DX7 PAout(7)
#define LED1  PAout(8)
#define LED2  PAout(9)
#define LED3  PAout(10)
#define LED4  PAout(11)
#define LED5  PAout(12)
#define LED6  PCout(8)
#define Beep PGout(9)

#define D0 PEout(0)
#define D1 PEout(1)
#define D2 PEout(2)
#define D3 PEout(3)



void LED_Init(void);
void Display(u8 index);


		 				    
#endif
#include "led.h"

u8 seg_tab[17] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,\
  0x88,0x83,0xC6,0xA1,0x86,0x8E,0xBF};
void LED_Init(void)
{
 
    GPIO_InitTypeDef  GPIO_InitStructure;
	  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);   
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOG, ENABLE);	
		
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;				
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		//推挽输出
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 
	 GPIO_Init(GPIOA, &GPIO_InitStructure);				
	 GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12);
  
	 GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
 	 GPIO_Init(GPIOE, &GPIO_InitStructure);
	 GPIO_SetBits(GPIOE,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
  
   GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_8;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
 	 GPIO_Init(GPIOC, &GPIO_InitStructure);
	 GPIO_SetBits(GPIOC,GPIO_Pin_8);
   
   GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_9;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
 	 GPIO_Init(GPIOG, &GPIO_InitStructure);
	 GPIO_SetBits(GPIOG,GPIO_Pin_9);

  TIM_DeInit( TIM6 );                  //将TIM6寄存器重置为缺省值
	TIM_InternalClockConfig( TIM6 );   
  TIM_TimeBaseStructure.TIM_Period=10;      //扫描周期5ms  
  TIM_TimeBaseStructure.TIM_Prescaler=35999;   
  TIM_TimeBaseStructure.TIM_ClockDivision=0;
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM6,&TIM_TimeBaseStructure); 
  
  TIM_ClearFlag( TIM6, TIM_FLAG_Update ); //清除溢出中断标志位
	TIM_ARRPreloadConfig( TIM6, DISABLE ); //禁止ARR预装载缓冲器
	TIM_ITConfig( TIM6,TIM_IT_Update,ENABLE );// 打开更新事件中断
  TIM_Cmd(TIM6,ENABLE);                     //使能TIM6
                 
}

void Display(u8 index)	
{
	DX0 = seg_tab[index]&0x01;
	DX1 = (seg_tab[index]>>1)&0x01;
	DX2 = (seg_tab[index]>>2)&0x01;
	DX3 = (seg_tab[index]>>3)&0x01;
	DX4 = (seg_tab[index]>>4)&0x01;
	DX5 = (seg_tab[index]>>5)&0x01;
	DX6 = (seg_tab[index]>>6)&0x01;
	DX7 = (seg_tab[index]>>7)&0x01;
}
  • 中断服务函数
void TIM6_IRQHandler()    //数码管扫描
{ 
    if(TIM_GetITStatus(TIM6,TIM_IT_Update)!=RESET)
  {
    D0=D1=D2=D3=1;
    switch(s)
    {
      case 1:D0=0;Display(t1);break;
      case 2:D1=0;Display(t2);break;
      case 3:D2=0;Display(t3);break;
      case 4:D3=0;Display(t4);break;
    }
    s++; if(s>4) s=1;
    TIM_ClearITPendingBit(TIM6,TIM_IT_Update);    
  }
}
#include "key.h"
#include "led.h"
#include "sys.h" 
#define PORT GPIOF->IDR
//行接PF0-3,列接FD4-7
void KEY_Init() 
{ 
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);   //TIM7按键扫描
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);//使能PF口时钟
  
  TIM_DeInit( TIM7 );                  //将TIM6寄存器重置为缺省值
	TIM_InternalClockConfig( TIM7 );   
  TIM_TimeBaseStructure.TIM_Period=20;      //扫描周期10ms
  TIM_TimeBaseStructure.TIM_Prescaler=35999;   
  TIM_TimeBaseStructure.TIM_ClockDivision=0;
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM7,&TIM_TimeBaseStructure); 
  
  TIM_ClearFlag( TIM7, TIM_FLAG_Update ); //清除溢出中断标志位
	TIM_ARRPreloadConfig( TIM7, DISABLE ); //禁止ARR预装载缓冲器
	TIM_ITConfig( TIM7,TIM_IT_Update,ENABLE );// 打开更新事件中断
  TIM_Cmd(TIM7,ENABLE);                     
 
}

s8 scan_MatrixKey()
{
 u8 column;//列
 u8 row;//行
 u8 tmp;//临时变量
 s8 MatrixKey_value = 20;//初始值不能为0~15 
 static u8 key_count = 0;//按键被中断扫描的次数

 ///////////IO口的配置/////////////
 //低8位为推挽输出
 GPIOF->CRL &= 0X00000000;
 GPIOF->CRL |= 0X33333333;
 //初值:低4位为低,次低4位为高
 GPIOF->ODR &= 0XFF00;
 GPIOF->ODR |= 0X00F0;
 //次低4位为上拉输入
 GPIOF->CRL &= 0X0000FFFF;
 GPIOF->CRL |= 0X88880000;
  
 tmp = PORT;//必须要
 if (tmp != 0XF0)//如果有键按下
 {
  //防止长按时,持续自增导致变量溢出
  if (key_count <= 2) 
  {
    key_count++;
  }
 }
 //若产生抖动按键被抬起则计数清0 
 else
  key_count = 0;
 
 //若按键连续2次扫描均处于按下状态
 //则认为按键确实被按下了
 if (key_count == 2)
 {
 column = tmp & 0X00F0;//获取列号 
 
 ///////////IO口的配置/////////////
 //低8位为推挽输出
 GPIOF->CRL &= 0X00000000;
 GPIOF->CRL |= 0X33333333;
 //翻转:低4位为高,次低4位为低
 GPIOF->ODR &= 0XFF00;
 GPIOF->ODR |= 0X000F;//低4位为高,次低4位为低
 //低4位为上拉输入
 GPIOF->CRL &= 0XFFFF0000;
 GPIOF->CRL |= 0X00008888; 
 
 row = PORT & 0X000F;//获取行号
 switch (column | row)//column|row为按键被按下对应端口的编码
 { 
 //按键对应的码表(可以根据需求调整欲返回的键值) 
 case 0XEE: MatrixKey_value = 1; break;   //S1
 case 0XDE: MatrixKey_value = 2; break;
 case 0XBE: MatrixKey_value = 3; break;
 case 0X7E: MatrixKey_value = 4; break;
 case 0XED: MatrixKey_value = 5; break;
 case 0XDD: MatrixKey_value = 6; break;
 case 0XBD: MatrixKey_value = 7; break;
 case 0X7D: MatrixKey_value = 8; break;    //S8
 case 0XEB: MatrixKey_value = 9; break;
 case 0XDB: MatrixKey_value = 10; break;
 case 0XBB: MatrixKey_value = 11; break;
 case 0X7B: MatrixKey_value = 12; break;
 case 0XE7: MatrixKey_value = 13; break;
 case 0XD7: MatrixKey_value = 14; break;
 case 0XB7: MatrixKey_value = 15; break;
 case 0X77: MatrixKey_value = 16; break;  //S16
 default :   break;
 }
 } 
 //若没有按键被按下(已松手)则扫描次数清0
 //方便下次按下扫描计数
 if ((PORT & 0X00FF) == 0x00F0)
 {
  key_count = 0;  
 }
 return MatrixKey_value;
}

记得添加外部全局变量 

这个按键扫描函数是从别人博客上用的。

void key_FUC()
{
  key_value=scan_MatrixKey();
  if(key_value==1)            //S1模式选择
  {
    flag_mode++;
    LCD_Clear(BACK_COLOR);delay_ms(25);
    if(flag_mode==1)      {dianji(0,5999); t3=3;t4=0; }
    else if(flag_mode==2) { delay_ms(25);dianji(1,6999); t3=6;t4=0; }
    else if(flag_mode==3) { delay_ms(25);dianji(1,5999);t3=1;t4=0; }
    else { LED1=LED2=LED3=LED4=LED5=LED6=1; LED4=0;dianji(1,7999);t3=1;t4=0; }
    
    if(flag_mode>5)                  //暂停后再次按下,
    {
      
      if(flag_mode==7) flag_mode=0;   //之前遇到bug,模式走完stop后再次按S1就不显示界面了,我的算法很垃圾
      flag_mode= mode_t+1;          //stop模式按下S1后,到下一个模式
      if(flag_mode>4) flag_mode=0;  //防止立即进入模式1导致计数从10开始的bug,目前还没想修复 
    }
    
  }
  
  else if(key_value==2)       //重复进入自检,但是再次按任意键时得两次
  {
    LCD_Clear(BACK_COLOR);
    dianji(0,9999);
    flag_mode=7;
  }
  else if(key_value==3)            //停止按钮
  {
    dianji(0,9999);
    flag_mode=5;
  }
    else if(key_value==4)          
  {
   bj_set-=1;
  }
    else if(key_value==5)           
  {
   bj_set+=1;
  }
  
  else ;

}

void TIM7_IRQHandler()    //按键
{ 
    if(TIM_GetITStatus(TIM7,TIM_IT_Update)!=RESET)
  {
    scan_MatrixKey();
    key_FUC();
    TIM_ClearITPendingBit(TIM7,TIM_IT_Update);   
  }

}

这个按键里的程序是我之前练习一个单片机省赛题目写的,以后有空聊

你可能感兴趣的:(stm32)