热度 22
2013-9-4 14:57
1623 次阅读|
3 个评论
指针实际上只是一个寄存器,只保存指向内存的地址非实际需要的数值。一般使用它都是需要有一个实际保存内容的变量,一般是用结构体,使用指针主要是方便操作,如下Key 键值读取,直接操作寄存器地址,同时运用宏定义,简化使用。 msOS 通过扫描方式实现了矩阵键盘值读取同时也实现了长按与短按键功能,通过注册函数KeySystemTickService 来收集与检测按键信息供其他函数使用。 按键实现机理,从原理图来分析,原理图设计已经做了特如处理,按键处接了vdd3.3V 和 电阻 1K,默认状况是接按键 的5个IO口都是低电平,若是有按键按下,其中相应的IO口为输入高电平。 扫描函数(ScandPin)中通过改变了行按键 输出值, (ScandPin01 = 0;ScandPin00 = 1),通过判断列的IO口状况,输出自己定义的按键值。 长按与短按及去抖动实现原理:是在 KeySystemTickService 函数中进行计数 ScandCounter 及 JitterCounter,此函数被SysTick_Handler 函数调用,sysTick 为系统CPU 节拍时钟,即所谓心跳函数。每隔100个tick 进行运行一次KeySystemTickService 函数。 一个Tick 时间由如下函数得到 SysTick_Config(SystemCoreClock / 10000);长按短按判断依据是在每执行一次KeySystemTickService 函数时候,若是有按键之后读到的值为invalid,JitterCounter--,去抖动,若是无松开则ScandCounter++,判断第二次值是否一样,若是不一样丢掉按键信息即是去抖原理,一样按键值,ScandCounter++ 继续增加,当超过设定的最长按键时间(ScandCounter = LongInterval)之后抛出按键消息。 精彩绝妙的宏定义及指针使用,直接操作寄存器。 //IO口操作,只对单一的IO口!确保n的值小于16! #define BIT_BAND(addr, bitnum) ((addr 0xF0000000)+0x2000000+((addr 0xFFFFF)5)+(bitnum2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BIT_BAND(addr, bitnum)) #define PaIn(n) BIT_ADDR(GPIOA_IDR_ADDR,n) #define PaOut(n) BIT_ADDR(GPIOA_ODR_ADDR,n) #define PbIn(n) BIT_ADDR(GPIOB_IDR_ADDR,n) #define PbOut(n) BIT_ADDR(GPIOB_ODR_ADDR,n) #define ScandPin00 PbOut(4) #define ScandPin01 PbOut(5) #define ScandPin10 PcIn(10) #define ScandPin11 PcIn(11) #define ScandPin12 PcIn(12) #define ScandPin13 PbIn(3) #define ShortInterval 3 /*短按按键间隔*/ #define LongInterval 40 /*长按按键间隔*/ #define JitterInterval 10 /*防误动按键间隔*/ 详细操作函数如下:(函数名字很直观表达函数内容) static byte RemapKey(byte scandValue) //重新定义短按键键值 { switch(scandValue) { case 0xEF: return(0); case 0xDF: return(1); 。。。 default: return(invalid); } } static byte RemapLongKey(byte scandValue) //重新定义长按键键值 { switch(scandValue) { case 0xEF: return(0x30); case 0xDF: 。。。 default: return(invalid); } } static byte ScandPin(void) // 扫描方式检测按键 { byte scandValue; scandValue = invalid; if(ScandPin13 == 0) scandValue = 0x7F; if(ScandPin12 == 0) scandValue = 0xBF; if(ScandPin11 == 0) scandValue = 0xDF; if(ScandPin10 == 0) scandValue = 0xEF; ScandPin00 = 0; ScandPin01 = 1; DelayUs(1); if(ScandPin13 == 0) scandValue = 0xF7; if(ScandPin12 == 0) scandValue = 0xFB; if(ScandPin11 == 0) scandValue = 0xFD; if(ScandPin10 == 0) scandValue = 0xFE; ScandPin01 = 0; ScandPin00 = 1; return(scandValue); } void KeySystemTickService(void) // 注册机制,检测是否有按键,发送KeyMessageType 类型的PostMessageQueue 消息。 { byte scandValue; scandValue = ScandPin(); .... if (ScandCounter == LongInterval) { PostMessageToLogicTask(KeyMessageType, RemapLongKey(ScandValueSave)); } else if (ScandCounter ShortInterval) { PostMessageToLogicTask(KeyMessageType, RemapKey(ScandValueSave)); } ScandCounter = 0; ScandValueSave = invalid; JitterCounter = JitterInterval; } ..... } void SysTick_Handler(void) { static unsigned char Counter = 0; 。。。。 switch(Counter) { 。。。。。。 case 15: SystemTick100RegisterPointBlock (); break; case 97: RtcSystemTickService(); break; case 99: KeySystemTickService(); break; default: break; } AdcSystemTickService(); // System.Device.Io.SetBeep(true); CheckstationSystemTickService(); } 硬件图如下: 欢迎各位与我一起学习ARM 技术,我的E-MIAL:timeisours@163.com,web:www.51buddy.com,QQ:158377757