<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 不用延時(shí)去抖的按鍵程序

          不用延時(shí)去抖的按鍵程序

          作者: 時(shí)間:2016-11-13 來(lái)源:網(wǎng)絡(luò) 收藏
          今天完成一個(gè)很好的按鍵程序,一般教科書(shū)上寫(xiě)的都是延時(shí)去抖,那樣一旦進(jìn)入按鍵掃描子程序就不得不等待延時(shí),這樣會(huì)影響cpu做其他的事。一種高效的按鍵掃描方法是用定時(shí)掃描。把所有程序都附在下面,希望大家能看懂,也請(qǐng)多多指教。本程序的主要功能是采樣定時(shí)掃描的高效按鍵掃描程序設(shè)置電壓電流的值,實(shí)時(shí)顯示在lcd1602上,在1602上可左移、右移,數(shù)值加減,以及設(shè)置/確認(rèn)(復(fù)用鍵),還有一個(gè)短路鍵。

          //主函數(shù) main

          本文引用地址:http://www.ex-cimer.com/article/201611/316430.htm

          #include <msp430x14x.h>
          #include "key.h"
          #include "lcd1602.h"

          uchar Key_Flag=0;
          uchar Keyval = 0;
          uchar Respond_Key_Flag=0; //響應(yīng)鍵
          uchar Set_Confirm_Flag=0; //設(shè)設(shè)置/確認(rèn)標(biāo)志

          uchar Volt_buf[5]={1,2,.,2,6};
          uchar Curr_buf[5]={0,5,.,5,4};

          void Init_port();
          void Init_SysClk();
          void Init_TimerB();
          void key_process();
          //////////////////主函數(shù)///////////////
          void main()
          {
          WDTCTL = WDTPW + WDTHOLD; //關(guān)閉看門(mén)狗
          Init_port();
          Init_LCD() ;
          Init_SysClk();
          Init_TimerB();
          _EINT();

          Disp1Char(0,0,U) ;
          Disp1Char(1,0,:) ;
          DispNChar(3,0, 5,Volt_buf);
          Disp1Char(0x0F,0,V) ;

          Disp1Char(0,1,I) ;
          Disp1Char(1,1,:) ;
          DispNChar(3,1, 5,Curr_buf);
          Disp1Char(0x0F,1,A) ;



          while(1)
          {
          key_process();


          }

          }
          /*******************************************
          函數(shù)名稱:key_process
          功 能:根據(jù)按鍵值執(zhí)行任務(wù)
          參 數(shù):無(wú)
          返回值 :無(wú)
          ********************************************/
          void key_process()
          {
          static uchar x=3;
          uchar keyvalue;
          static uchar key_one_flag=0;

          keyvalue = Key_Scan();
          Keyval = 0;
          if(Set_Confirm_Flag == 1)
          {
          if(keyvalue == 1) //設(shè)置/確認(rèn)鍵
          {
          key_one_flag ^= 1;
          if(key_one_flag==1)
          {
          write_cmd(0x0f); //打開(kāi)顯示屏,顯示光標(biāo),光標(biāo)所在位置的字符閃爍
          LocateXY(3,0); //向液晶寫(xiě)入顯示字符位置的坐標(biāo)信息
          }
          else
          {
          write_cmd(0x0c);//開(kāi)顯示, 關(guān)光標(biāo),光標(biāo)所在位置的字符不閃爍
          Set_Confirm_Flag =0;
          }
          }

          if((keyvalue == 2)&&( Respond_Key_Flag==1)) //短路鍵
          {

          Respond_Key_Flag=0;
          Disp1Char(3,0,Z) ;
          //TACCR0 = 65535; //PWM占空比設(shè)置為百分之百
          }


          if((keyvalue == 3)&&( Respond_Key_Flag==1)) //左移
          {

          Respond_Key_Flag=0;
          if(x >3)
          {
          --x;
          if(x<8)
          LocateXY(x,0);
          else
          LocateXY(x-5,1);
          }
          else
          {
          x=12;
          LocateXY(x-5,1);
          }
          }



          if((keyvalue == 4)&&( Respond_Key_Flag==1)) //右移
          {
          Respond_Key_Flag=0;

          if(x < 12)
          {
          ++x;
          if(x<8)
          LocateXY(x,0);
          else
          LocateXY(x-5,1);
          }
          else
          {
          x=3;
          LocateXY(x,0);
          }

          }




          if((keyvalue == 5)&&( Respond_Key_Flag==1)) //數(shù)值"+"鍵
          {
          Respond_Key_Flag=0;

          if(x<3 || x>12)
          {
          write_data( ) ;
          }
          else if(x==5||x==10)
          {
          write_data(.) ;
          if(x==5)
          LocateXY(x,0);
          if(x==10)
          LocateXY(x-5,1);

          }
          else
          {
          if((x>=3)&&(x<=7))
          {
          if(Volt_buf[x-3]<9)
          Volt_buf[x-3] += 1;
          else Volt_buf[x-3]=0;
          Disp1Char(x,0,Volt_buf[x-3]) ;
          LocateXY(x,0);
          }
          else
          {
          if(Curr_buf[x-8]<9)
          Curr_buf[x-8] += 1;
          else Curr_buf[x-8]=0;
          Disp1Char(x-5,1,Curr_buf[x-8]) ;
          LocateXY(x-5,1);
          }
          }
          }




          if((keyvalue == 6)&&( Respond_Key_Flag==1)) //數(shù)值"-"鍵
          {
          Respond_Key_Flag=0;

          if(x<3 || x>12)
          {
          write_data( ) ;
          }
          else if(x==5||x==10)
          {
          write_data(.) ;
          if(x==5)
          LocateXY(x,0);
          if(x==10)
          LocateXY(x-5,1);

          }
          else
          {
          if((x>=3)&&(x<=7))
          {
          if(Volt_buf[x-3]>0)
          Volt_buf[x-3] -= 1;
          else Volt_buf[x-3]=9;
          Disp1Char(x,0,Volt_buf[x-3]) ;
          LocateXY(x,0);
          }
          else
          {
          if(Curr_buf[x-8]>0)
          Curr_buf[x-8] -= 1;
          else Curr_buf[x-8]=9;
          Disp1Char(x-5,1,Curr_buf[x-8]) ;
          LocateXY(x-5,1);
          }
          }
          }

          }


          }

          /*============================================
          函數(shù)名稱:Init_port
          功 能:初始化I/O端口
          參 數(shù):無(wú)
          返回值 :無(wú)
          ==============================================*/
          void Init_port()
          {
          /*下面六行程序關(guān)閉所有的IO口*/
          P1DIR = 0XFF;P1OUT = 0XFF;
          P2DIR = 0XFF;P2OUT = 0XFF;
          P3DIR = 0XFF;P3OUT = 0XFF;
          P4DIR = 0XFF;P4OUT = 0XFF;
          P5DIR = 0XFF;P5OUT = 0XFF;
          P6DIR = 0XFF;P6OUT = 0XFF;
          P6DIR |= BIT2;P6OUT |= BIT2; //關(guān)閉電平轉(zhuǎn)換
          //定義液晶端口

          P4DIR = 0XFF; //數(shù)據(jù)口
          P4OUT = 0;
          //定義按鍵端口
          P1DIR =BIT6 + BIT7; //設(shè)置P1.0~P.3為輸入狀態(tài),P.7為輸出


          }
          /*============================================
          函數(shù)名稱:Init_SysClk
          功 能:初始化系統(tǒng)時(shí)鐘
          參 數(shù):無(wú)
          返回值 :無(wú)
          ==============================================*/

          void Init_SysClk()
          {

          unsigned int i;

          BCSCTL1 &= ~XT2OFF; // XT2= HF XTAL

          do
          {
          IFG1 &= ~OFIFG; // Clear OSCFault flag
          for (i = 0xFF; i > 0; i--); // Time for flag to set
          }
          while ((IFG1 & OFIFG)); // OSCFault flag still set?

          BCSCTL2 |= SELM_2; // MCLK= XT2 (safe),分頻椅子為1
          BCSCTL2 |= SELS; //SMCLK的時(shí)鐘源為T(mén)X2CLK,分頻因子為1

          }


          /*============================================
          函數(shù)名稱:Init_TimerB
          功 能:初始化定時(shí)器B,設(shè)定基準(zhǔn)時(shí)間500us
          參 數(shù):無(wú)
          返回值 :無(wú)
          ==============================================*/
          void Init_TimerB()
          {
          TBCTL |= TBSSEL1 +TBCLR; //MCLK ,8M
          TBCCTL0 = CCIE;
          TBCCR0 =4000; //定時(shí)500us
          TBCTL |= MC_1; // Start Timer_B in up mode
          }


          /*===========================================
          函數(shù)名稱:TimerB_ISR
          功 能:設(shè)定時(shí)間間隔
          參 數(shù):無(wú)
          返回值 :無(wú)
          =============================================*/
          // Timer B0 interrupt service routine
          #pragma vector=TIMERB0_VECTOR
          __interrupt void TimerB_ISR (void)
          {
          static uchar Flag_500us = 0;
          Flag_500us ++;
          if(Flag_500us ==20)
          {
          Key_Flag =1; //定時(shí)10ms
          Flag_500us=0;
          // TBCCTL0 = ~CCIE; //關(guān)中斷,單步調(diào)試時(shí)用,不然一直在中斷里


          }

          }


          //按鍵頭文件 key.h

          #ifndef MSP430_KEY_PROCESS_H
          #define MSP430_KEY_PROCESS_H
          /***************************************************
          程序功能:用定時(shí)掃描方式讀取6個(gè)行列式按鍵的鍵值
          ****************************************************/
          #include
          #include "lcd1602.h"

          #define keyin (P1IN & 0x0F)

          uchar KEY_BUFFER ;
          uchar KEY_BUFFER1 ;

          uchar KEY_DATA = 0x00;
          uchar Num=0;
          extern uchar Key_Flag;
          extern uchar Keyval;
          extern uchar Respond_Key_Flag;
          extern uchar Set_Confirm_Flag;

          /*******************************************
          函數(shù)名稱:Delay10us
          功 能:延時(shí)約10us
          參 數(shù):無(wú)
          返回值 :無(wú)
          ********************************************/
          void Delay10us(void)
          {
          uint i=10;
          while (i != 0)
          {
          i--;
          }
          }
          /*******************************************
          函數(shù)名稱:Key_Scan
          功 能:掃描按鍵值
          參 數(shù):無(wú)
          返回值 :Keyval
          ********************************************/
          uchar Key_Scan()
          {

          if(Key_Flag ==1 ) //10ms掃描一次
          {
          Key_Flag =0;
          //位處理,先用一個(gè)字節(jié)把八位按鍵的值讀出來(lái),然后再進(jìn)行判斷
          P1OUT =0X70;
          Delay10us();//給硬件響應(yīng)時(shí)間
          KEY_BUFFER =keyin;
          KEY_BUFFER =~KEY_BUFFER;
          KEY_BUFFER1 =KEY_BUFFER<<4;

          P1OUT =0XB0;
          Delay10us();
          KEY_BUFFER =keyin;
          KEY_BUFFER =~KEY_BUFFER;
          KEY_BUFFER &=0X0F; //屏蔽高四位
          KEY_BUFFER1 |=KEY_BUFFER ;

          if(KEY_BUFFER1 != KEY_DATA) //首先判斷是否有鍵按下
          {
          KEY_DATA =KEY_BUFFER1; //讀鍵值
          Num =0;
          }
          else //KEY_BUFFER1 = KEY_DATA的處理
          {
          Num ++;

          if(Num==4) //Num=4,讀4次有效,延時(shí)達(dá)到40ms
          {
          if(KEY_DATA==0x10) //判斷鍵值
          Keyval=1;
          else if(KEY_DATA==0x20)
          Keyval=2;
          else if(KEY_DATA==0x40)
          Keyval=3;
          else if(KEY_DATA==0x80)
          Keyval=4;
          else if(KEY_DATA==0x01)
          Keyval=5;
          else if(KEY_DATA==0x02)
          Keyval=6;
          else Keyval=0;

          }
          else // Num!=4 的處理
          {


          if( KEY_DATA == 0x00) //按鍵放開(kāi),允許響應(yīng)
          {
          Num=0;
          Respond_Key_Flag =1; //按鍵響應(yīng)標(biāo)志位
          }
          else //按鍵沒(méi)放開(kāi),連續(xù)按
          {

          if((KEY_DATA == 0x10)&&(Num >=100)) //1s,判斷是否為設(shè)置/確認(rèn)鍵
          {
          Num =0;
          Set_Confirm_Flag =1;

          }


          }

          }

          }

          }

          return Keyval;

          }
          #endif




          //液晶1602頭文件 lcd1602.h

          #ifndef MSP430_LCD1602_PROCESS_H
          #define MSP430_LCD1602_PROCESS_H
          //硬件連接 P4 數(shù)據(jù)口 P3.2---EN P3.1---RW P3.0----RS

          #include"msp430x14x.h"
          typedef unsigned int uint;
          typedef unsigned char uchar;
          //定義MCU與LCD的接口
          /**************宏定義***************/
          #define Busy 0x80
          #define CtrlDir P3DIR
          #define CLR_RS P3OUT&=~BIT0 //RS = P3.0
          #define SET_RS P3OUT|=BIT0
          #define CLR_RW P3OUT&=~BIT1//RW = P3.1
          #define SET_RW P3OUT|=BIT1
          #define CLR_EN P3OUT&=~BIT2//EN = P3.2
          #define SET_EN P3OUT|=BIT2
          /*******************************************
          函數(shù)名稱:Delay5ms
          功 能:延時(shí)約5ms
          參 數(shù):無(wú)
          返回值 :無(wú)
          ********************************************/
          void Delay5ms(void)
          {
          uint i=40000;
          while (i != 0)
          {
          i--;
          }
          }
          /*******************************************
          函數(shù)名稱:WaitForEnable
          功 能:等待1602液晶完成內(nèi)部操作
          參 數(shù):無(wú)
          返回值 :無(wú)
          ********************************************/
          void WaitForEnable(void)
          {
          P4DIR &= 0x00; //將P4口切換為輸入狀態(tài)

          CLR_RS;
          SET_RW;
          _NOP();
          SET_EN;
          _NOP();
          _NOP();

          while((P4IN & Busy)!=0); //檢測(cè)忙標(biāo)志

          CLR_EN;

          P4DIR |= 0xFF; //將P4口切換為輸出狀態(tài)
          }
          /*******************************************
          函數(shù)名稱:write_cmd
          功 能:向液晶模塊寫(xiě)入命令
          參 數(shù):com--命令,
          返回值 :無(wú)
          ********************************************/
          void write_cmd(unsigned char com)
          {
          WaitForEnable(); //等待液晶不忙
          CLR_RS ; //RS=0,RW=0,寫(xiě)指令
          CLR_RW;
          _NOP();
          P4OUT = com;
          _NOP();
          SET_EN ;
          _NOP();
          _NOP();
          CLR_EN;
          }

          /*******************************************
          函數(shù)名稱:write_data
          功 能:向液晶顯示的當(dāng)前地址寫(xiě)入顯示數(shù)據(jù)
          參 數(shù):data--顯示字符數(shù)據(jù)
          返回值 :無(wú)
          ********************************************/
          void write_data(unsigned char data)
          {
          WaitForEnable(); //等待液晶不忙
          SET_RS; //RS=1,RW=0,寫(xiě)數(shù)據(jù)
          CLR_RW;
          _NOP();
          P4OUT = data;
          _NOP();
          SET_EN ; //產(chǎn)生負(fù)脈沖
          _NOP();
          _NOP();
          CLR_EN ;
          }

          /*============================================
          函數(shù)名稱:Init_LCD
          功 能:初始化液晶
          參 數(shù):無(wú)
          返回值 :無(wú)
          ==============================================*/
          void Init_LCD()
          {
          CtrlDir |= 0x07; //控制線端口設(shè)為輸出狀態(tài)
          P4DIR = 0xFF; //數(shù)據(jù)端口設(shè)為輸出狀態(tài)

          write_cmd(0x38); //規(guī)定的復(fù)位操作
          Delay5ms();
          write_cmd(0x38);
          Delay5ms();
          write_cmd(0x38);
          Delay5ms();

          write_cmd(0x38);//16×2顯示,5×7點(diǎn)陣,8位數(shù)據(jù)接口
          write_cmd(0x08);//關(guān)閉顯示
          write_cmd(0x01);//清屏,數(shù)據(jù)指針=0,所有顯示=0
          write_cmd(0x06);//讀或?qū)懸粋€(gè)字符后地址指針加1 &光標(biāo)加1,整屏顯示不移動(dòng)
          write_cmd(0x0c);//開(kāi)顯示, 關(guān)光標(biāo),光標(biāo)所在位置的字符不閃爍

          }

          /*******************************************
          函數(shù)名稱:LocateXY
          功 能:向液晶寫(xiě)入顯示字符位置的坐標(biāo)信息
          參 數(shù):x--位置的列坐標(biāo)
          y--位置的行坐標(biāo)
          返回值 :無(wú)
          ********************************************/
          void LocateXY(uchar x,uchar y)
          {
          uchar temp;

          temp = x&0x0f;
          y &= 0x01;
          if(y) temp |= 0x40; //如果在第2行
          temp |= 0x80;

          write_cmd(temp);
          }
          /*******************************************
          函數(shù)名稱:Disp1Char
          功 能:在某個(gè)位置顯示一個(gè)字符
          參 數(shù):x--位置的列坐標(biāo)
          y--位置的行坐標(biāo)
          data--顯示的字符數(shù)據(jù)
          返回值 :無(wú)
          ********************************************/
          void Disp1Char(uchar x,uchar y,uchar data)
          {
          LocateXY( x, y );
          write_data( data );
          }

          /***********************************************
          函數(shù)名稱:DispStr
          功 能:讓液晶從某個(gè)位置起連續(xù)顯示一個(gè)字符串
          參 數(shù):x--位置的列坐標(biāo)
          y--位置的行坐標(biāo)
          ptr--指向字符串存放位置的指針
          返回值 :無(wú)
          ***********************************************/
          void DispStr(uchar x,uchar y,uchar *ptr)
          {
          uchar *temp;
          uchar i,n = 0;

          temp = ptr;
          while(*ptr++ != 看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();