• 单片机按键处理框架

    2019-08-10 11:21:00
    写过一段时间单片机程序,也看了一些单片机程序,书上的,网上的,基本都是非常原始的读取按键,延时判断,这些按键相关代码穿插于整个程序,着实不够美观,最重要的是不能复用,so俺就想做个按键框架,只需提供按键...

    写过一段时间单片机程序,也看了一些单片机程序,书上的,网上的,基本都是非常原始的读取按键,延时判断,这些按键相关代码穿插于整个程序,着实不够美观,最重要的是不能复用,so俺就想做个按键框架,只需提供按键处理代码即可,言归正传,先简介一下几个文件,ringfifo.c提供了一个简单的环形缓冲队列,用以通知按键消息,key.c 实现的按键的框架处理(读取按键,调用按键处理函数),key_port.c 需提供底层硬件接口及用户的按键处理函数,目前支持的按键消息类型有4类:keyDown,keyRelease,longPress, double click.

    key.h中提供了4个函数:InitKey()为初始化, KeyProc() 须在主循环中调用,KeyScan()须定时(10-20ms)调用,SetKeyHandler()用来设置按键处理函数

     1 #ifndef __KEY_H__
     2 #define __KEY_H__
     3 
     4 #define NULL 0
     5 
     6 typedef enum{
     7     KEY_EVENT_DOWN = 0,
     8     KEY_EVENT_UP,
     9     KEY_EVENT_LONGPRESS,
    10     KEY_EVENT_DOUBLECLICK,
    11     KEY_EVENT_COMBO_KEYDOWN,
    12 }KeyEventType;
    13 
    14 typedef void (*pKeyEventCB)(void *para);
    15 
    16 typedef struct _tagKeyInfo
    17 {
    18     unsigned char keyCode;
    19     unsigned char keyStatus;
    20     unsigned char comboKeyFlag;
    21     unsigned int keyDbClickTime;    
    22     unsigned int keyDownTime;
    23     unsigned int keyRepeatTime;
    24     pKeyEventCB FuncCB[5]; 
    25     void * para[5];    
    26 }KeyInfo;
    27 
    28 typedef struct _tagMessageInfo
    29 {
    30     unsigned int keyEvent;
    31     unsigned int keyCode;
    32     KeyInfo* pContext;
    33 }MessageInfo;
    34 
    35 
    36 
    37 void InitKey(void);        // 
    38 
    39 void KeyProc(void);// call this func in main loop
    40 
    41 void KeyScan(void);    // call it in timer service, 20ms
    42 
    43 pKeyEventCB SetKeyHandler(unsigned char key,KeyEventType event,pKeyEventCB pFunc,void *para);
    44 
    45 #endif
    key.h
      1 #include "key_port.h"
      2 #include "key.h"
      3 #include "ringfifo.h"
      4 #include <string.h>
      5 
      6 #define KEY_STATE_UP 0X0
      7 #define KEY_STATE_DOWN 0X3
      8 #define KEY_STATE_LONGRESS 0XF
      9 #define KEY_STATE_RELEASE 0XC
     10 
     11 static KeyInfo kInfo[KEY_AMOUNT];
     12 static RingFifo MsgQ;
     13 
     14 
     15 void PostMessage(MessageInfo* pMsg)
     16 {
     17     PushFifo(&MsgQ,pMsg);    
     18 }
     19 
     20 unsigned char GetMessage(MessageInfo*pMsg)
     21 {
     22     return PopFifo(&MsgQ,pMsg);
     23 }
     24 
     25 // call it in timer service
     26 void KeyScan(void)
     27 {
     28     int i = 0;
     29     unsigned char c = 0;
     30     KeyInfo * pInfo = kInfo; 
     31     MessageInfo Msg;
     32     for(i=0;i<KEY_AMOUNT;++i)
     33     {
     34         Msg.pContext = pInfo;
     35         Msg.keyCode = pInfo->keyCode;
     36         c = ReadKeyStatus(Msg.keyCode);    //
     37         pInfo->keyStatus |= c;
     38         pInfo->keyStatus &= 0xF;
     39         switch(pInfo->keyStatus)
     40         {
     41             case KEY_STATE_UP:
     42                     pInfo->keyDownTime = 0;
     43                     break;
     44             case KEY_STATE_DOWN:
     45                     Msg.keyEvent = KEY_EVENT_DOWN;
     46                     PostMessage(&Msg);                                    // post event
     47                     break;
     48             case KEY_STATE_LONGRESS:
     49                     if(pInfo->keyDownTime < KEY_LONGPRESS_TIME /POLLING_INTERVAL)
     50                     {
     51                         pInfo->keyDownTime++;
     52                     }
     53                     else
     54                     {
     55                         if(pInfo->keyRepeatTime <  KEY_LONGPRESS_REPEAT_INTERVAL/POLLING_INTERVAL)
     56                         {
     57                             ++pInfo->keyRepeatTime;
     58                         }
     59                         else
     60                         {
     61                             pInfo->keyRepeatTime = 0;
     62                             Msg.keyEvent = KEY_EVENT_LONGPRESS;
     63                             PostMessage(&Msg);    // post event
     64                         }
     65                     }
     66                     break;
     67             case KEY_STATE_RELEASE:
     68                     Msg.keyEvent = KEY_EVENT_UP;                            
     69                     PostMessage(&Msg);                                        // post event
     70                     if(pInfo->keyDbClickTime)    //double click 
     71                     {
     72                         Msg.keyEvent = KEY_EVENT_DOUBLECLICK;
     73                         PostMessage(&Msg);                                        // post event
     74                     }
     75                     pInfo->keyDbClickTime = KEY_DBCLICK_TIME /POLLING_INTERVAL;
     76                     break;
     77         }
     78         if(pInfo->keyDbClickTime)pInfo->keyDbClickTime--;
     79         pInfo->keyStatus <<= 1;
     80         ++pInfo;
     81     }
     82     
     83 }
     84 
     85 
     86 
     87 // call this func in main()
     88 void KeyProc(void)
     89 {
     90     KeyInfo * pInfo = 0;
     91     int k = 10;
     92     MessageInfo msg;
     93     while(GetMessage(&msg) &&(k--))
     94     {
     95         pInfo = msg.pContext;
     96         if(pInfo->FuncCB[msg.keyEvent])
     97         {
     98             pInfo->FuncCB[msg.keyEvent](pInfo->para[msg.keyEvent]);
     99         }
    100     }
    101 }
    102 
    103 pKeyEventCB SetKeyHandler(unsigned char key,KeyEventType event,pKeyEventCB pFunc,void *para)
    104 {
    105     pKeyEventCB pf = NULL;
    106     int i = 0;
    107     for(i = 0;i<KEY_AMOUNT;++i)
    108     {
    109         if(key == kInfo[i].keyCode)
    110         {
    111             pf = kInfo[i].FuncCB[event];
    112             kInfo[i].FuncCB[event] = pFunc;
    113             kInfo[i].para[event] = para;
    114             break;
    115         }
    116     }
    117     return pf;
    118 }
    119 
    120 void InitKey(void)
    121 {
    122     int i = 0;
    123     InitFifo(&MsgQ);
    124     memset(kInfo,0,sizeof(kInfo));
    125     for(i = 0;i<KEY_AMOUNT;++i)
    126     {
    127         kInfo[i].keyCode = KeyCodeTable[i];
    128     }
    129     
    130     RegisterKeyHandler();
    131 }
    key.c
     1 #ifndef __RINGFIFO_H__
     2 #define __RINGFIFO_H__
     3 
     4 #include "key.h"
     5 
     6 #define FIFO_SIZE 10
     7 
     8 typedef  MessageInfo ElemDataType;
     9 
    10 typedef struct _tagFifo
    11 {
    12     ElemDataType data[FIFO_SIZE];        // message 
    13     unsigned char read;                    //
    14     unsigned char write;                //
    15 }RingFifo;
    16 
    17 void InitFifo(RingFifo * pFifo);
    18 unsigned char PopFifo(RingFifo * pFifo,ElemDataType * pMsg);
    19 unsigned char PushFifo(RingFifo * pFifo,ElemDataType * pMsg);
    20 unsigned char PeekFifo(RingFifo * pFifo,ElemDataType * pMsg);
    21 
    22 #endif
    RingFifo.h
     1 #include "RingFifo.h"
     2 #include <string.h>
     3 //#include <assert.h>
     4 
     5 #define assert(x)
     6 
     7 void InitFifo(RingFifo * pFifo)
     8 {
     9         assert(pFifo);
    10         memset(pFifo,0,sizeof(RingFifo));
    11 }
    12 
    13 unsigned char PopFifo(RingFifo * pFifo,ElemDataType * pMsg)
    14 {
    15         assert(pFifo&&pMsg);
    16         if(pFifo->read == pFifo->write)
    17         {
    18             return 0;
    19         }
    20         else
    21         {
    22             memcpy(pMsg,pFifo->data+pFifo->read,sizeof(ElemDataType));
    23             pFifo->read = (pFifo->read+1)%FIFO_SIZE;
    24             return 1;
    25         }
    26     
    27 }
    28 
    29 unsigned char PushFifo(RingFifo * pFifo,ElemDataType * pMsg)
    30 {
    31     assert(pFifo&&pMsg);
    32     memcpy(pFifo->data+pFifo->write,pMsg,sizeof(ElemDataType));
    33     pFifo->write = (pFifo->write + 1) % FIFO_SIZE;
    34     return 1;
    35 }
    36 
    37 unsigned char PeekFifo(RingFifo * pFifo,ElemDataType * pMsg)
    38 {
    39     assert(pFifo&&pMsg);
    40     if(pFifo->read == pFifo->write)
    41     {
    42         return 0;
    43     }
    44     else
    45     {
    46         memcpy(pMsg,&pFifo->data[pFifo->read],sizeof(ElemDataType));
    47         return 1;
    48     }
    49 }
    RingFifo.c

    key_port.h中, KEY_AMOUNT代表能识别的按键个数,      用户需实现ReadKeyStatus(),RegisterKeyHandler()这2个函数,其中

    ReadKeyStatus()用来读取硬件按键状态,具体可参见key_port.c示例

    RegisterKeyHandler()用来设置按键处理函数。

     1 #ifndef __KEY_PORT_H__
     2 #define __KEY_PORT_H__
     3 
     4 #define KEY_AMOUNT 6
     5 
     6 #define KEY_LONGPRESS_TIME 3000                        //   3S
     7 #define KEY_DBCLICK_TIME 500    
     8 #define POLLING_INTERVAL 20                                //timer interval
     9 #define KEY_LONGPRESS_REPEAT_INTERVAL 500
    10 extern unsigned char KeyCodeTable[KEY_AMOUNT];
    11 unsigned char ReadKeyStatus(unsigned char key);
    12 void RegisterKeyHandler(void);
    13 
    14 #endif
    Key_Port.h
      1 #include "key_port.h"
      2 #include "key.h"
      3 #include "stm32f10x.h"
      4 #include "timer.h"
      5 #include "stepper.h"
      6 
      7 #define KEY_1  1
      8 #define KEY_2  2
      9 #define KEY_3  3
     10 #define KEY_4  4
     11 #define KEY_5  5
     12 #define KEY_6  6
     13 
     14 unsigned char KeyCodeTable[KEY_AMOUNT]=
     15 {
     16     KEY_1,
     17     KEY_2,
     18     KEY_3,
     19     KEY_4,
     20     KEY_5,
     21     KEY_6
     22 };
     23 
     24 void startStateMachine(void);
     25 void key1handler(void *p)    //
     26 {
     27    startStateMachine();
     28 }
     29 
     30 void key2handler(void *p)    //reset
     31 {
     32    
     33 }
     34 
     35 
     36 void key3handler(void *p)    // reserve
     37 {
     38    
     39         
     40 }
     41 
     42 void key3handler_up(void *p)    // 
     43 {
     44     
     45 }
     46 
     47 void key4handler(void *p)
     48 {
     49 
     50 }
     51 
     52 void key5handler(void *p)
     53 {
     54 
     55 }
     56 
     57 void key6handler(void *p)
     58 {
     59 
     60 }
     61 
     62 // get key status,return 1 if key down ,
     63 unsigned char ReadKeyStatus(unsigned char key)
     64 {
     65     unsigned char c = 0;
     66     switch(key)
     67     {
     68         case KEY_1:
     69             c = !GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5);
     70             break;
     71         case KEY_2:
     72             c = !GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15);
     73             break;
     74         case KEY_3:
     75             c = GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_4);
     76             break;
     77         case KEY_4:
     78             
     79             c = 0;
     80             break;
     81         case KEY_5:
     82             
     83             c= 0;
     84             break;
     85         case KEY_6:
     86             c= 0;
     87             break;
     88     }
     89     return c;
     90 }
     91 
     92 void RegisterKeyHandler(void)
     93 {
     94     // Add you key event func here
     95     SetKeyHandler(KEY_1,KEY_EVENT_DOWN,key1handler ,0);
     96     SetKeyHandler(KEY_2,KEY_EVENT_DOWN,key2handler ,0);
     97     SetKeyHandler(KEY_3,KEY_EVENT_DOWN,key3handler ,0);
     98     SetKeyHandler(KEY_3,KEY_EVENT_UP,key3handler_up ,0);
     99     SetKeyHandler(KEY_4,KEY_EVENT_DOWN,key4handler ,0);
    100     SetKeyHandler(KEY_5,KEY_EVENT_DOWN,key5handler ,0);
    101     SetKeyHandler(KEY_6,KEY_EVENT_UP,key6handler ,0);
    102 }
    Key_Port.c

    在key_port.c中,提供了一个示例,分别设置了3个按键key_1,key_2,key_3的keydown处理函数,同时设置了key_3的keyUp处理函数。

    转载于:https://www.cnblogs.com/mayitbe/p/3914743.html

    展开全文
  • 之前的电子钟程序中,用的按键消抖处理方法是10ms的延时,这种方法效率比较低 所以现在利用状态机原理重写一下,效率很高啊   4个独立按键中用到3个, keys5用于切换对时分秒等状态,keys2是减小数值,keys3是增加...

    之前的电子钟程序中,用的按键消抖处理方法是10ms的延时,这种方法效率比较低

    所以现在利用状态机原理重写一下,效率很高啊

     

    4个独立按键中用到3个,

    keys5用于切换对时分秒等状态,keys2是减小数值,keys3是增加数值

     

    同时可以判断按键的"短按,长按,连发"等功能

    小于2秒视为短按,

    大于2秒视为长按,

    在长按状态下每0.2秒自动连发一次, 这样对时的时候就不用按N次了

     

    欢迎一起交流,qq 102351263   验证码 iteye

    程序分很多个文件 ,Keil uVision4 打包



     

     

    #include "MY51.H"
    #include "keyScan.h"
    #include "smg.h"
    #include "myClock.h"
    
    void show();   //数码管显示
    
    extern s8  shi;   
    extern s8  fen;
    extern s8  miao;
    extern u8  changeTimeFlag;
    extern u8  timeMultipleFlag;
    
    void main() 	
    {
    	startT0(10,100);  //开T0启定时器	 10毫秒*100=1秒
    	while(1)
    	{
    		show();		
    	}	
    }
    	
    void T0_Work()  //T0定时器调用的工作函数
    {
    	u8 key_stateValue;
    	u8* pKeyValue;
    	*pKeyValue=0;
    	key_stateValue=read_key(pKeyValue);
    	if(timeMultipleFlag)	 //到1秒了
    	{
    		timeMultipleFlag=0;	 //标志清零
    		clock();			 //走时,秒++
    	}
    
    	if( (return_keyPressed==key_stateValue)&&(*pKeyValue==KEYS5_VALUE) )
    	{	   //短按keyS5时改变对时状态
    			changeTimeState(); //改变changeTimeFlag的3种状态,分别修改时或分或秒
    	}
    
    	if((return_keyPressed==key_stateValue)||(key_stateValue&return_keyAuto) )
    	{	//短按s2或s3可加减响应数值,长按keyS2或keyS3时每0.1秒加减一次数值
            if(changeTimeFlag)				//changeTimeFlag不为0时,允许修改
            {
                if(KEYS2_VALUE == *pKeyValue)
                {
    			   changeTime(TRUE);	   //KEYS2,秒++
                }
                
                if(KEYS3_VALUE == *pKeyValue)
                {
    			   changeTime(FALSE);	   //KEYS3,秒--
                }
            }
    	}
    }
    
    
    
    void show()  //显示时钟
    {
    	u8 oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela; //oneWela是最左边的数码管
    	sixWela =miao%10;
    	fiveWela=miao/10;	
    	foreWela=fen%10;
    	threeWela=fen/10;
    	twoWela=shi%10;
    	oneWela=shi/10;
    	displaySMG(oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela,0xf5); //0xf5是小数点的位置
    }
    
    
    
    
    

     

     

     

     

     

     

     

     

    #ifndef _MY51_H
    #define _MY51_H
    #include <reg52.h>
    #include <math.h>
    #include <intrins.h>
    #include "mytype.h"
    
    
    #define high	1   //高电平
    #define low		0   //低电平
    
    #define led P1    	//灯总线控制
    sbit led0=P1^0;     //8个led灯,阴极送低电平点亮
    sbit led1=P1^1;
    sbit led2=P1^2;
    sbit led3=P1^3;
    sbit led4=P1^4;
    sbit led5=P1^5;
    sbit led6=P1^6;
    sbit led7=P1^7;
    
    sbit lcdEN=P3^4; 	//液晶通讯使能端en,高脉冲有效
    sbit lcdRS=P3^5; 	//液晶第4脚,RS,低电平是指令模式,高电平是数据模式
    //sbit lcdR/W    	//液晶第5脚,低电平是写入模式,因为我们只写不读,所以接地
    
    sbit csda=P3^2;  	//DAC0832模数转换cs口
    sbit adwr=P3^6; 	//ADC0804这个同DAC0832
    sbit dawr=P3^6;
    sbit adrd=P3^7;  	//ADC0804
    sbit beep=P2^3;     //蜂鸣器
    
    void delayms(u16 ms);
    void T0_Work();
    void startT0(u32 ms,u16 t_multiple);
    ///////////////////////////////////////////////////////////////////////////
    
    /////////////////////////////////////////////////////////////////////////////
    
    
    #endif

     

    #include "MY51.h"
    
    u8   TH0Cout=0 ;	     //初值	
    u8   TL0Cout=0 ;	   
    u16  T0IntCout=0;     	 //中断计数
    u16  timeMultiple=0;     //中断复用时间的倍数
    u8   timeMultipleFlag=0; //中断时间复用置位标志
    
    void delayms(u16 ms)     //软延时函数
    {
    	u16 i,j;
    	for(i=ms;i>0;i--)
    	{
            for(j=113;j>0;j--)
            {}
    	}
    }
    
    
    //开启定时器,定时完成后需要手动关闭TR0,否则将循环定时
    //参数一是定时的毫秒数,参数二是定时的倍率数(定时复用)
    void startT0(u32 ms,u16 t_multiple)  	 //定时器初始化设定
    {	
    	u32   N=11059.2*ms/12; 				 //定时器总计数值
    
    	TH0Cout =(65536-N)/256;      	 	 //装入计时值零头计数初值
    	TL0Cout =(65536-N)%256;
    
    	timeMultiple=t_multiple;
    
    	TMOD=TMOD | 0x01; 					 //设置定时器0的工作方式为1
    	
    	EA =OPEN;   		//打开总中断
    	ET0=OPEN;   		//打开定时器中断
    
    	TH0=TH0Cout;  		//定时器装入初值
    	TL0=TL0Cout;
    	TR0=START;	 		//启动定时器
    }
    
    /*	 方法二,此方法用于长时间的定时,以利于减少中断次数,减小误差
    void startT0(u32 one_ms,u16 two_multiple)  
    {	
    	u32    	    N=11059.2*one_ms/12; 		//定时器总计数值
    
    	TH0Cout =(65536-N%65536)/256;      	 	//装入计时值零头计数初值
    	TL0Cout =(65536-N%65536)%256;
    	T0IntCountAll=(N-1)/65536+1;			 //总中断次数
    	T0IntCountAll2=T0IntCountAll*two_multiple;
    
    	TMOD=TMOD | 0x01; 						 //设置定时器0的工作方式为1
    	
    	EA =OPEN;   //打开总中断
    	ET0=OPEN;   //打开定时器中断
    
    	TH0=TH0Cout;  //定时器装入初值
    	TL0=TL0Cout;
    	TR0=START;	 //启动定时器
    }*/
    
    void T0_times() interrupt 1 //T0定时器中断函数
    {
    	TH0=TH0Cout;   	
    	TL0=TL0Cout;
    	T0IntCout++;
    	if(T0IntCout==timeMultiple)  //复用定时器
    	{	
    		T0IntCout=0; 		 	 //中断次数清零,重新计时
    		timeMultipleFlag=1;
    	}
    	T0_Work();     				//调用工作函数
    }
    
    
    
    

     

     

    #ifndef   _MYTYPE_H
    #define   _MYTYPE_H
    
    /////////////////////////////////////////////
    
    typedef float                             f32   ;
    typedef double		                  d64  ;
    typedef float  const                   fc32 ;
    typedef double  const               dc64  ;
    typedef volatile float                vf32   ;
    typedef volatile double             vd64  ;
    //typedef volatile float     const   vfc32   ;
    //typedef volatile double  const   vdc64  ;
    //////////////////////////////////////////////
    
    
    typedef signed long  s32;
    typedef signed short s16;
    typedef signed char   s8;
    
    
    typedef signed long  const sc32;  /* Read Only */
    typedef signed short const sc16;  /* Read Only */
    typedef signed char  const sc8;   /* Read Only */
    
    typedef volatile signed long  vs32;
    typedef volatile signed short vs16;
    typedef volatile signed char  vs8;
    
    //typedef volatile signed long  const vsc32;  /* Read Only */
    //typedef volatile signed short const vsc16;  /* Read Only */
    //typedef volatile signed char  const vsc8;   /* Read Only */
    
    
    typedef unsigned long  u32;
    typedef unsigned short u16;
    typedef unsigned char  u8;
    
    typedef unsigned long  const uc32;  /* Read Only */
    typedef unsigned short const uc16;  /* Read Only */
    typedef unsigned char  const uc8;   /* Read Only */
    
    typedef volatile unsigned long  vu32;
    typedef volatile unsigned short vu16;
    typedef volatile unsigned char  vu8;
    
    //typedef volatile unsigned long  const vuc32;  /* Read Only */
    //typedef volatile unsigned short const vuc16;  /* Read Only */
    //typedef volatile unsigned char  const vuc8;   /* Read Only */
    
    typedef enum {FALSE = 0, TRUE = !FALSE} bool;
    
    typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
    
    typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
    ////////////////////////////////////////////////////////////////////////////////////////////
    typedef enum {CLOSE = 0, OPEN = !CLOSE} OPEN_CLOSE;
    typedef enum {GND = 0, VCC = !GND} GND_VCC;
    typedef enum {NO = 0, YES = !NO} YES_NO;
    typedef enum {STOP = 0, START = !STOP} START_STOP;
    ////////////////////////////////////////////////////////////////////////////////////////////
    #define U8_MAX     ((u8)255)
    #define S8_MAX     ((s8)127)
    #define S8_MIN     ((s8)-128)
    #define U16_MAX    ((u16)65535u)
    #define S16_MAX    ((s16)32767)
    #define S16_MIN    ((s16)-32768)
    #define U32_MAX    ((u32)4294967295uL)
    #define S32_MAX    ((s32)2147483647)
    #define S32_MIN    ((s32)-2147483648)
    
    #endif

     

    #ifndef _KEYSACN_H
    #define _KEYSACN_H
    #include <reg52.h>
    #include "mytype.h"
    
    #define state_keyUp         0       //初始状态,未按键
    #define state_keyDown       1       //键被按下
    #define state_keyLong       2       //长按
    #define state_keyTime       3       //按键计时态
    
    #define return_keyUp        0x00    //初始状态
    #define return_keyPressed   0x01    //键被按过,普通按键
    #define return_keyLong      0x02    //长按
    #define return_keyAuto      0x04    //自动连发
    
    #define key_down             0      //按下
    #define key_up              0xf0    //未按时的key有效位键值
    #define key_longTimes       200     //10ms一次,200次即2秒,定义长按的判定时间
    #define key_autoTimes       20      //连发时间定义,20*10=200,200毫秒发一次
    
    sbit keyS2=P3^4; 	//4个独立按键
    sbit keyS3=P3^5;
    sbit keyS4=P3^6;
    sbit keyS5=P3^7;
    
    #define KEYS2_VALUE              0xe0 			   //keyS2 按下
    #define KEYS3_VALUE              0xd0 			   //keyS3 按下
    #define KEYS4_VALUE              0xb0 			   //keyS4 按下
    #define KEYS5_VALUE              0x70 			   //keyS5 按下
    
    
    //void KeyInit(void);        //初始化,io口未复用时可省略此步
    static u8 getKey(void);      //获取P口的连接key的io值,其他io位屏蔽为0
    u8 read_key(u8* pKeyValue);  //返回按键的各种状态,pKeyValue保存键值
    
    
    #endif
    
    ////////////////////////////////////////////////////////////////
    

     

    #include "keyScan.h"
    #include <reg52.h>
    
    /*按键初始化,若io没有复用的话可以省略此步骤
    void KeyInit(void) 
    { 
        keyS2 = 1 ; 
        keyS3 = 1 ; 
        keyS4 = 1 ; 
        keyS5 = 1 ;
    	//即P3|=0xf0;             
    }*/
    
    static u8 getKey(void) 		   //获取P3口值
    { 
        if(key_down == keyS2)
    	{
    		return KEYS2_VALUE ; 
    	}
    
        if(key_down == keyS3 )
    	{
    	  return KEYS3_VALUE ; 
    	}
    
        if(key_down == keyS4 )
    	{
    		return KEYS4_VALUE ;
    	}
    	 
        if(key_down == keyS5 )
    	{
    		return KEYS5_VALUE ; 
    	}
    
        return key_up ;    //0xf0  没有任何按键
    }
    
    //函数每10ms被调用一次,而我们弹性按键过程时一般都20ms以上
    //所以每次按键至少调用本函数2次
    u8 read_key(u8* pKeyValue)			   
    {
        static u8  s_u8keyState=0;        //未按,普通短按,长按,连发等状态
        static u16 s_u16keyTimeCounts=0;  //在计时状态的计数器
    	static u8  s_u8LastKey = key_up ; //保存按键释放时的P3口数据
    
        u8 keyTemp=0;          		//键对应io口的电平
        s8 key_return=0;        	//函数返回值
        keyTemp=key_up & getKey();  //提取所有的key对应的io口
    
        switch(s_u8keyState)           //这里检测到的是先前的状态
        {
            case state_keyUp:   //如果先前是初始态,即无动作
            {
                if(key_up!=keyTemp) //如果键被按下
                {
                    s_u8keyState=state_keyDown; //更新键的状态,普通被按下 
                }
            }
            break;
            
            case state_keyDown: //如果先前是被按着的
            {
                if(key_up!=keyTemp) //如果现在还被按着
                {
                    s_u8keyState=state_keyTime; //转换到计时态
                    s_u16keyTimeCounts=0;
    				s_u8LastKey = keyTemp;     //保存键值
                }
                else
                {
                    s_u8keyState=state_keyUp; //键没被按着,回初始态,说明是干扰
                }
            }
            break;
            
            case state_keyTime:  //如果先前已经转换到计时态(值为3)
            {  //如果真的是手动按键,必然进入本代码块,并且会多次进入
                if(key_up==keyTemp) //如果未按键
                {
                    s_u8keyState=state_keyUp; 
                    key_return=return_keyPressed;    //返回1,一次完整的普通按键
                    //程序进入这个语句块,说明已经有2次以上10ms的中断,等于已经消抖
                    //那么此时检测到按键被释放,说明是一次普通短按
                }
                else  //在计时态,检测到键还被按着
                {
                    if(++s_u16keyTimeCounts>key_longTimes) //时间达到2秒
                    {
                        s_u8keyState=state_keyLong;  //进入长按状态
                        s_u16keyTimeCounts=0; 		 //计数器清空,便于进入连发重新计数
                        key_return=return_keyLong;   //返回state_keyLong
                    }
                    //代码中,在2秒内如果我们一直按着key的话,返回值只会是0,不会识别为短按或长按的
                }
            }
            break;
            
            case state_keyLong:  //在长按状态检测连发  ,每0.2秒发一次
            {
                if(key_up==keyTemp) 
                {
                   s_u8keyState=state_keyUp; 
                }
                else //按键时间超过2秒时
                {
                    if(++s_u16keyTimeCounts>key_autoTimes)//10*20=200ms
                    {
                        s_u16keyTimeCounts=0;
                        key_return=return_keyAuto;  //每0.2秒返回值的第2位置位(1<<2)
                    }//连发的时候,肯定也伴随着长按
                }
                key_return |= return_keyLong;  //0x02是肯定的,0x04|0x02是可能的
            }
            break;
            
            default:
            break;
        }
    	*pKeyValue = s_u8LastKey ; //返回键值
        return key_return;
    }

     

    #ifndef _51SMG_H_
    #define _51SMG_H_
    
    #include <reg52.h>
    #include "mytype.h"
    sbit dula =P2^6;  		//段选锁存器控制  控制笔段
    sbit wela =P2^7;  		//位选锁存器控制  控制位置
    
    #define dark	0x11  	//在段中,0x11是第17号元素,为0是低电平,数码管不亮
    #define dotDark 0xff 	//小数点全暗时
    
    
    
    void displaySMG(u8 one,u8 two,u8 three,u8 four,u8 five,u8 six,u8 dot); 	//数码管显示函数
    
    #endif

     

     

    #include "smg.h"
    #include "my51.h"
    
    u8 code table[]= { 			//0~F外加小数点和空输出的数码管编码
    	0x3f , 0x06 , 0x5b , 0x4f , // 0 1 2 3
    	0x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 7
    	0x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B
    	0x39 , 0x5e , 0x79 , 0x71 , // C D E F
    	0x80 , 0x00 ,0x40           // . 空  负号    空时是第0x11号也就是第17号元素
     };
    
    u8 code dotTable[]={		   //小数点位置
        0xff ,                 //全暗
    	0xfe , 0xfd , 0xfb ,   //1 2 3
    	0xf7 , 0xef , 0xdf     //4 5 6                    
    };
    
    //数码管显示
    void displaySMG(u8 oneWela,u8 twoWela,u8 threeWela,u8 fourWela,u8 fiveWela,u8 sixWela,u8 dot)
    {	
        //控制6位数码管显示函数,不显示的位用参数dark,保留ADC0804的片选信号
        u8 csadState=0x80&P0;  				//提取最高位,即ADC0804的片选信号
        u8 tempP0=((csadState==0)?0x7f:0xff); //数码管位选初始信号,阴极全置高电平
        P0=tempP0;		//0x7f表示数码管不亮,同时ADC0804片选有效
        wela=1;			//注:wela和dula上电默认为1
        P0=tempP0;
        wela=0;
    
        P0=0;			    //由于数码管是共阴极的,阳极送低电平,灯不亮,防止灯误亮
        dula=1;
        P0=0;
        dula=0;	 		    //段选数据清空并锁定
    //////////////////////////oneWela
        {  //消除叠影,数码管阴极置高电平,并锁存
            P0=tempP0;
            wela=1;			
            P0=tempP0;
            wela=0;
        }
        P0=0;       	//低电平送到数码管阳极,避免数码管误亮
        dula=1;
        P0=table[oneWela]|((0x01&dot)?0x00:0x80);   //送段数据,叠加小数点的显示
        dula=0;
        
    
        P0=tempP0;          //送位数据前关闭所有显示,并保持csad信号
        wela=1;
        P0=tempP0 & 0xfe;   //0111 1110最高位是AD片选,低6位是数码管位选,低电平有效
        wela=0;
        delayms(1);
    
    /////////////////////////twoWela
        {  //消除叠影
            P0=tempP0;
            wela=1;			
            P0=tempP0;
            wela=0;
        }
        P0=0;
        dula=1;
        P0=table[twoWela]|((0x02&dot)?0x00:0x80);
        dula=0;
        
        P0=tempP0;
        wela=1;
        P0=tempP0 & 0xfd;    //0111 1101
        wela=0;
        delayms(1);
    
    /////////////////////////threeWela
        {  //消除叠影
            P0=tempP0;
            wela=1;			
            P0=tempP0;
            wela=0;
        }
        P0=0;
        dula=1;
        P0=table[threeWela]|((0x04&dot)?0x00:0x80);
        dula=0;
    
        P0=tempP0;
        wela=1;
        P0=tempP0 & 0xfb;    //0111 1011
        wela=0;
        delayms(1);
    
    /////////////////////////fourWela
        {  //消除叠影
            P0=tempP0;
            wela=1;			
            P0=tempP0;
            wela=0;
        }
        P0=0;
        dula=1;
        P0=table[fourWela]|((0x08&dot)?0x00:0x80);
        dula=0;
    
        P0=tempP0;
        wela=1;
        P0=tempP0 & 0xf7;   //0111 0111
        wela=0;
        delayms(1);
    
    /////////////////////////fiveWela
        {  //消除叠影
            P0=tempP0;
            wela=1;			
            P0=tempP0;
            wela=0;
        }
        P0=0;
        dula=1;
        P0=table[fiveWela]|((0x10&dot)?0x00:0x80);
        dula=0;
    
        P0=tempP0;
        wela=1;
        P0=tempP0 & 0xef; 		//0110 1111
        wela=0;
        delayms(1);
    
    /////////////////////////sixWela
        {  //消除叠影
            P0=tempP0;
            wela=1;			
            P0=tempP0;
            wela=0;
        }
        P0=0;
        dula=1;
        P0=table[sixWela]|((0x20&dot)?0x00:0x80);
        dula=0;
    
        P0=tempP0;
        wela=1;
        P0=tempP0 & 0xdf;   //0101 1111
        wela=0;
        delayms(1);
    }
    

     

    #ifndef		_MYCLOCK_H   
    #define		_MYCLOCK_H
    #include "mytype.h"
    #include "my51.h"
    
    void clock(void);			  		//走时
    void changeTimeState(void);   		//改变对时状态
    void changeTime(bool add_or_sub);   //修改时间,true为增加,false为减少
    #endif

     

    #include "myClock.h"
    
    u8  changeTimeFlag=0;
    s8  shi=22;   //对时
    s8  fen=45;
    s8  miao=0;
    void clock(void)
    {
    	if(!changeTimeFlag)   //不在对时状态
    	{
    		miao++;
    		if(miao>59)
    		{
    			miao=0;
    			fen++;
    		}
    	
    		if(fen>59)
    		{
    			fen=0;
    			shi++;
    		} 
    		
    		if(shi>23)
    		{
    			shi=0;
    		}
    	}
    }
    
    void changeTimeState(void)		 //在满足条件时改变对时状态,时或分或秒,同时改变指示灯
    {
    	changeTimeFlag=(++changeTimeFlag)%4;
    	switch(changeTimeFlag)
    	{
    		case 0:
    		{
    		    led=0xff;			                       
    		}
    		break;
    		
    		case 1:
    		{
    		    led=0xff;
    		    led7=0;
    			                       
    		}
    		break;
    		
    		case 2:
    		{
    		     led=0xff;
    		     led5=0;
    		}
    		break;
    		
    		case 3:
    		{
    		     led=0xff;
    		     led3=0;
    		}
    		break;
    		
    		default:
    		break;
    	}
    }
    
    void changeTime(bool add_or_sub)	 //修改时分秒
    {
    	if(add_or_sub)
    	{
            switch(changeTimeFlag)
            {
                case 1:
                {
                    shi++;
                    if(shi>23)
                    {
                        shi=0;
                    }  				                       
                }
                break;
        
                case 2:
                {
                    fen++;
                    if(fen>59)
                    {
                        fen=0;
                    }
                }
                break;
        
                case 3:
                {
                    miao++;
                    if(miao>59)
                    {
                        miao=0;
                    }
                }
                break;
        
                default:
                break;
            }
    	}
    	else
    	{
    	    switch(changeTimeFlag)
    	    {
    	        case 1:
    	        {
    	            shi--;
    	            if(shi<0) 
    	            {
    	                shi=23;
    	            } 				                       
    	        }
    	        break;
    	
    	        case 2:
    	        {
    	            fen--;
    	            if(fen<0)
    	            {
    	                fen=59;
    	            }
    	        }
    	        break;
    	
    	        case 3:
    	        {
    	            miao--;
    	            if(miao<0)
    	            {
    	                miao=59;
    	            }
    	        }
    	        break;
    	
    	        default:
    	        break;
    	    }	
    	}
    }
    

     

    展开全文
  • 分享一个按键液晶多级菜单设计方法 typedef struct {  uchar KeyStateIndex ; / / 当前状态索引号  uchar KeyDnState ; / / 按下“向下”键时转向的状态索引号  uchar Key

    http://www.amobbs.com/forum.php?mod=viewthread&tid=4001689

    分享一个按键液晶多级菜单设计方法


    typedef struct

    {
     uchar  KeyStateIndex ;   / / 当前状态索引号
     uchar  KeyDnState ;   / / 按下“向下”键时转向的状态索引号
     uchar  KeyUpState ;   / / 按下“向上”键时转向的状态索引号
     uchar  KeyCrState ;   / / 按下“回车”键时转向的状态索引号
     uchar  KeyBackState ;   / / 按下“退回”键时转向的状态索引号
     void   (*CurrentOperate)( ) ;   / / 当前状态应该执行的功能操作
    }  KbdTabSt ruct ;
    # define SIZE - OF KEYBD - MENU 55   / / 菜单总长度
    KbdTabSt ruct code KeyTab[ SIZE - OF - KEYBD - MENU ] =
    {
     {0 ,0 ,0 ,1 ,0 , MainJob1 } ,
     {1 ,7 ,2 ,8 ,0 , Dsp Point} ,   / / 第一层
     {2 ,1 ,3 ,8 ,0 , DspCurve},   / / 第一层
     {3 ,2 ,4 ,36 ,0 ,Dsp Kout} ,   / / 第一层
     {4 ,3 ,5 ,50 ,0 , DisCloseDown } ,   / / 第一层


     {5 ,4 ,6 ,8 ,0 ,  ModifyPoint} ,   / / 第一层
     {6 ,5 ,7 ,52 ,0 , SetCloseDown } ,   / / 第一层
     {7 ,6 ,1 ,0 ,0 , Cancel} ,   / / 第一层
     …
     …
     {52 ,53 ,53 ,0 ,1 ,  OkSetCloseDown1} ,
     {53 ,52 ,52 ,0 ,1 , OkSetCloseDown2} ,
     {54 ,0 ,0 ,0 ,0 , Disable} ,
      …
      …
    } ;
     void Get Keylnput (void)
    {
     switch ( status &0xf0)
      {
      case 0xe0 :/ / 回车键,找出新的菜单状态编号
       …
            KeyFuncIndex = KeyTab[ KeyFuncIndex ] . KeyCrState ;
       …
       break ;
      case 0xb0 :/ / 向下键,找出新的菜单状态编号
       …
        KeyFuncIndex = KeyTab [ KeyFuncIndex ] . KeyDn2State ;
       …
      break ;
       case 0xd0 :/ / 向上键,找出新的菜单状态编号


       …
        KeyFuncIndex = KeyTab [ KeyFuncIndex ] . KeyUp2State ;
       …
       break ;
      case 0x70 :/ / 回退键,找出新的菜单状态编号
       …
        KeyFuncIndex = KeyTab [ KeyFuncIndex ] . KeyBack2State ;
       …
       break ;
      case 0 ;
        return ;   / / 错误的处理
        break ;
       }
      KeyFuncPt r = KeyTab[ KeyFuncIndex ] . CurrentOperate ;
      ( * KeyFuncPt r) () ;   / / 执行当前按键的操作
    }


    以上是框架结构,下面是应用此方法的应用。
    平台,AT91RM9200,LINUX2.6.13,arm-linux-gcc3.3.2


    按键接线图 (原文件名:按键接线图.jpg)


    液晶接线图 (原文件名:液晶接线图.jpg)

    按键驱动程序ourdev_549702.rar(文件大小:10K) (原文件名:keyboard.rar)
    320*240液晶驱动程序,RA8835控制器(完全兼容SED1335)ourdev_549703.rar(文件大小:10K) (原文件名:LCD320_240.rar)
    液晶应用程序ourdev_549718.rar(文件大小:36K) (原文件名:ui.rar)


    OURDEV让我成长了不少,所以,以后有好东西一定会和大家分享。

    顺便借此机会向阿莫致歉,曾经发帖发了几句牢骚,没有恶意,都是年轻惹的祸,请见谅。

    第一次在OURDEV上发技术性的帖子,不知道这样够不够详细,如有疑问,请指出,定补充
    展开全文
  • STM32按键程序

    2018-12-29 14:29:54
    //按键按松开标志 if(mode)key_up=1; //支持连按 if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1)) { delay_ms(10);//去抖动 key_up=0; if(KEY0==0)return 1; else if(KEY1==0)return
    u8 KEY_Scan(u8 mode)
    {
    			static u8 key_up=1;//按键按松开标志
    			if(mode)key_up=1; //支持连按
    			if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1))
    		{
    				delay_ms(10);//去抖动
    				key_up=0;
    				if(KEY0==0)return 1;
    				else if(KEY1==0)return 2;
    				else if(KEY2==0)return 3;
    				else if(KEY3==1)return 4;
    		}else if(KEY0==1&&KEY1==1&&KEY2==1&&KEY3==0)key_up=1;
    		return 0;// 无按键按下
    }
    

    static是静态变量只会执行一次
    if(key_up&&(KEY00||KEY10||KEY20||KEY31))这句意思是如果keyup为1,同时key0123中有一个按键被按下,那么if为真,执行取值操作,作为返回值付给主函数的t,
    else if(KEY01&&KEY11&&KEY21&&KEY30)key_up=1;这个意思是如果上面的if为假,那么如果key0123没有一个被按下,那么keyup置1,
    我们来分析如果不支持连按的情况,mode为0,
    一开始你没按按键那么if(key_up&&(KEY00||KEY10||KEY20||KEY31))为假不执行后面的语句执行elseif应为keyup没变过,所以没什么用。
    假设你按的是key0,那么KEY00||KEY10||KEY20||KEY31为真,执行后面的语句,把keyup置0后,取出按键值,作为函数返回值送会给t,
    如果你继续按着当下次按键扫描时到来时,static u8 key_up=1,这个只执行一次,同时mode又为0,那么keyup还是0,
    然后执行到if(key_up&&(KEY00||KEY10||KEY20||KEY31))这句,由于keyup是0所以不会执行if语句,执行elseif,但是你此时有有一个按键是被按下的,所以elseif里的keyup=1也不会被执行,因为elseif也是假的。然后返回值还是0,这就达到了不支持连按的目的
    如果你按过之后送手了那么再看,if(key_up&&(KEY00||KEY10||KEY20||KEY31))这条语句为假应为keyup为0执行elseif,此时由于你没有按按钮,所以会执行keyup=1这条语句,当下次扫描按钮来临时又恢复到了最初的情况。
    同理可以分析出mode为1时的支持连按的情况

    展开全文
  • 51单片机PWM控制电机

    2015-01-04 13:29:13
    小时候玩的四驱车,给直流马达接通电源就嗤嗤的跑出去了。电机种类众多,就属控制直流电机最简单,只要对调正负极就能改变电机的转向。另外,直流电机负载能力强,适合做越野车的驱动电机。为了做可调速的越野车,就...

        小时候玩的四驱车,给直流马达接通电源就嗤嗤的跑出去了。电机种类众多,就属控制直流电机最简单,只要对调正负极就能改变电机的转向。另外,直流电机负载能力强,适合做越野车的驱动电机。为了做可调速的越野车,就有了这篇文章。

        电源电压输出是固定的,电机的转速也因此是固定的,为了调节电机的转速,就得改变电源电压的输出(为嘛要改变电机转速?举个简单的列子,双电机驱动小车-一边一个电机-如何实现转向?让两边轮胎上的速度不同即可)。how?用PWM调制的方法,把恒定的直流电源电压调制成频率一定宽度可变的脉冲电压序列,从而可以改变平均输出电压的大小,以调节电机的转速。电源电压在此处就是51MCU的引脚输出,4.5-5V,只要在引脚上产生频率可调的波形即可。假设在一个周期内,就10ms吧,前5ms引脚输出高电平,后5ms引脚输出低电平,周而复始,引脚上输出50%占空比的稳定方波;再改改,前2ms输出高电平,后8ms输出低电平,引脚上输出20%占空比的稳定方波。

        MCU产生周期性事件很简单,用定时器定时产生中断即可。一般差不多一下形式:

    void Isr01() interrupt 1
    {
        static unsigned int cnt;
        cnt++;
        if(cnt==40)
        {
            cnt=0;
        }
    }
    假设每250us产生一次中断,以上中断函数统计40次中断,即10ms。
    为了完成"可改变占空比的方波"这个命题,来试试给这个函数增加一些统计事件,在一个统计事件中做一些事,另一个统计事件中做其他的事。

    unsigned int condition=20;
    void Isr01() interrupt 1
    {
        static unsigned int cnt;
        cnt++;
        //一个周期
        if(cnt==40)
        {
            cnt=0;
        }
        //事件1
        if(cnt<condition)
        {
        //do sth
        }
        //事件2
        else
        {
        //do other thing
        }
    }
    condition就是新增加的统计事件,前半个周期为一个事件,后半个周期为另一个事件。这里,当cnt小于5ms,输出高电平,当cnt大于输出低电平,合在一起生成一个50%占空比的方波。

    unsigned int condition=20;
    void Isr01() interrupt 1
    {
        static unsigned int cnt;
        cnt++;
        //一个周期
        if(cnt==40)
        {
            cnt=0;
        }
        if(cnt<condition)
        {
        //前半个周期do sth
        pin=0x00;
        }
        else
        {
        //后半个周期do other thing
        pin=0x01;
        }
    }
    为了改变占空比,只要在ISR外修改condition即可,贴出最终的代码:

    #include <REG52.H>   
    #include <INTRINS.H>  
      
    sbit P2_0 = P2^0;  
    sbit P2_1 = P2^1;
    #define MakeByte(target, Hi,Lo) \  
    do{ \  
        target |= (((Hi)<<4)|(Lo)); \   
    }while(0); \  
      
    #define SetTH(n,val) \  
    do{ \  
        TH##n = val; \  
    }while(0); \  
      
    #define SetTL(n,val)  \  
    do{ \  
        TL##n = val; \  
    }while(0); \  
      
    #define EnableET(n) \  
    do{ \  
        ET##n = 0x01; \  
        IE |= 0x80; \  
    }while(0); \ 
    
    enum KEYSTAT
    {
    	KEYDOWN=0,KEYUP,
    };
    
    unsigned char iterator = 0x00;
    
    void DelayMs(unsigned int ms)
    {
    	int i=0,j=0;
    	for(;i<ms;i++)
    	{
    		for(j=0;j<1000;j++)
    		{
    			_nop_();
    		}
    	}
    }
    
    void OnKeyDown()
    { 
    	if(iterator == 0x28)
    		iterator = 0x00;
    	else
    		iterator += 0x04;
    }
    
    OnKeyUp()
    {}
    
    int main()
    {
    	unsigned char curKeyStat = KEYUP;
    	unsigned char preKeyStat = KEYUP;
    
    	SetTH(0,0x06);
    	SetTL(0,0x06);
    	MakeByte(TMOD,0x02,0x02);
    	EnableET(0);
    	TR0 = 0x01;
    
    	while(1)
    	{
    		while(1)
    		{
    			curKeyStat = P2_1;
    			switch(curKeyStat)
    			{
    			case KEYDOWN:
    				if(curKeyStat == preKeyStat)
    				{
    					//确实按下键
    					OnKeyDown();
    				}
    				else
    				{
    					//两次按键不同 状态待定
    				}
    				preKeyStat = curKeyStat;
    				break;
    			case KEYUP:
    				if(curKeyStat == preKeyStat)
    				{
    					//确实松开键
    					OnKeyUp();
    				}
    				else
    				{
    					//两次按键不同 状态待定
    				}
    				preKeyStat = curKeyStat;
    				break;
    			}
    			DelayMs(200);	
    		}
    	}
    
    	return 0;
    }
    
    void IsrT0() interrupt 1
    {
    	static unsigned int enterIsr = 0;
    	TR0 = 0x00;
    	//每250us进入isr
    	enterIsr++;
    	//10ms一个周期
    	if(enterIsr == 0x28)
    	{
    		enterIsr = 0x00;
    		P2_0 = 0x0;	
    	}
    	if(enterIsr<=iterator)
    	{
    		P2_0 = 0x00;
    	}
    	else
    	{
    		P2_0 = 0x01;
    	}
    	TR0 = 0x01;	
    }
    在主函数中,通过判断按下键来改变condition。


    结尾部分,贴上仿真图和仿真结果:

    1)占空比100%:

    2)差不多55%占空比:


    3)0%的占空比,电机休息了:


    展开全文
  • static u8 keyup=1; //防止检测多次 if(keyup&&(KEY0==0||KEY1==0||KEY3==0)) { delay_ms(50);//去抖 if(KEY0==0||KEY1==0||KEY3==0) { keyup=0; if (KEY0==0) return KE
  • 短按(按下持续时间小于3s)一次数码管显示加1,同时流水灯计数加1。 长按(按下持续时间大于3s)时,数码管显示每500ms加1,同时流水灯每500ms计数加1。 #include typedef unsigned char uchar;...
  • 按键扫描是每个工程师都会用到的,它就像一个零部件,存在于每个程式系统中。而如何把它写得高效、省空间也是需要一定的技巧。 下面我介绍一下我接触到的一些按键扫描的写法。其实也都是站在巨人的肩膀上,再加上...
  • 4.STM32F407ZG按键输入

    2018-09-10 21:34:57
    2.按键扫描:首先,按键输入这一从高电平变为低电平的动作才能任为按键按下,并不只是检测到有按键输入就是按键按下。其次,这里需要考虑按键一直处于按下状态时的情况。最后,需要对按键按下进行防抖确认。 3.针对...
  • 单片机基础学-按键

    2010-09-19 00:13:00
    按键总结篇  作者:HouZuping 在所有智能产品中,按键是最为常用的,所以按键程序的好坏很重要。以前我们在学校里学的按键检测方法都是不适用,很浪费时间,减少了CPU的效率。在大家的不断努力下,...
  • 这两天完成了一个stm32的工程,在解决按键时写出了一个独立按键的扫描函数,应该有前辈已经出来了,的其实质就是普通的扫描方式修改的,优点是将按键相关参数封装为一个结构体,每加一个按键都不需要在函数中增加...
  • 这一灵感来源于定时器计数的方法,最后可以实现的效果跟咱们电脑键盘按键的效果一样!我先来介绍下基本原理吧! 采用定时器中断的方法,比如定时器终端我们设置为5ms,我们需要按键按下超过40ms时才算有按键按下,...
  • 51单片机电子琴C代码

    2015-10-30 18:57:15
    #include #include #include #include #include #define uchar unsigned char typedef unsigned char  uint8;    // 无符号8位整型变量 typedef signed char  int8;      // 有符号8位整型变量 ty
  • 项目需要 摇杆 控制机器,但是在家里调试 摇杆机构不...监控窗体按键信息的代码如下,本来打算用keyup keydown 事件的,发现不行,必须重写 PreTranslateMessage 函数 BOOL Ckey2comDlg::PreTranslateMessage(MSG* pMSG) {
  • 单片机实现多级菜单

    2016-09-20 22:01:51
    单片机实现多级菜单 1、首先定义一个机构体如下 typedef struct  {  uchar current;  uchar up;//上键  uchar down;//下键  uchar enter;//确认键  void (*current_operation)();  } key_table;...
  • 摘要:  介绍了在C 语言环境下,在LCD 液晶显示屏上实现多级嵌套菜单的一... 单片机; C 语言; LCD  中图分类号:TP311. 1 文献标识码:B  收稿日期:2005 - 11 - 21 0 引言  由于C 语言的结构性和模块化,采用C 语
  • 今天学习了下矩阵键盘, 4*4, 分别代表0~F这16个数字 我们按了哪个键就显示到数码管上   看完郭老师讲解原理后就自己动手写了,郁闷的是 在keil软件中,我在switch-case语句中 少了个冒号,竟然编译通过!...
  • 51单片机实战之野外求生手电前言材料清单设计目标主要电路图主要程序pid部分程序多级菜单与按键部分程序一些效果图片 前言 第一次写博客,肯定有很多写的不好的地方,希望大家有疑问或者好的建议可以提出来。我就先...
  • 基于单片机环境监测温湿度PM2.5系统设计,实时检测环境中的温湿度值,并检测控制的PM2.5颗粒,同时可以设定报警范围值,也可以通过led灯指示当前的控制各参数的状态。 #define uchar unsigned char // 以后...
1 2 3 4 5
收藏数 86
精华内容 34