MSP430程序库<七>按键

2019-10-10来源: eefocus关键字:MSP430  程序库  按键

按键是单片机系统最常用的输入设备之一;几乎是只要需要交互输入,就必须有键盘。这篇博客实现了一个通用的键盘程序,只要提供一个读取键值的函数(底层键值),程序将完成消抖、存入队列等一些列处理。同时本程序提供最常用的4*4矩阵键盘的程序,和4个按键的程序。


硬件介绍:

本文主要实现了一个键盘的通用框架,可以很方便的改为不同的键盘函数,这里实现了两种按键4个单独按键和4*4行列扫描的键盘。


4个按键的是这样的:四个按键分别一端接地,另一端接上拉电阻后输入单片机的P1.0-P1.3口;这样,按键按下时,单片机接到低电平,松开时单片机输入信号有上拉电阻固定为高电平。


4*4的按键:行输入信号配有桑拉电阻,无按键时默认电平高电平;列扫描信号线直接接到按键列线;读键时,列扫描信号由单片机给出低电平信号(按列逐列扫描),读取行信号,从而判断具体是哪个按键;电路图大概如下:


image

图中,IN是键盘的列扫描线,OUT是键盘的输出的行信号线。扫描是也可以按行扫描,这时IN是行扫描线,OUT的按键输出的列信号线。我的程序是按列扫描的(行列扫描原理一样,只是行列进行了交换)。


这里,同时实现了4*4按键的scanf函数的移植,同时,加入了之前实现的液晶的printf函数的移植,搭建了一个可以交互输入输出的完整的一个系统;液晶的printf又加入了函数,实现了退格;可以在输入错误数字的时候退格重新输入。


程序实现:

先说一下程序的结构,程序实现了一个循环队列,用来存放已按下的键值,可以保存最新的四个按键,可以防止按键丢失;程序使用的是中断的方式进行按键,每16ms(用的是看门狗的间隔中断)读一次按键,进行判断键值是否有效,有效则放入队列,等待读取。


循环队列的实现:用数组实现,为判断队满,数组的最后一个元素不用于存储键码值:


/**********************宏定义***********************/

#define KeySize     4           //键码值队列

#define Length      KeySize+1   //队列数组元素个数

/***************************************************/


/**********************键值队列*********************/

//可KeySize(Length-1)个键码循环队列占用一个元素空间

char Key[Length];

入队函数:入队时,队满则出队一个,以保存最新的四个按键。


void AddKeyCode(char keyCode)

{

    if((rear+1)%Length==front)      //队满

    {

        front=(front+1)%Length;     //出队一个

    }

    Key[rear] = keyCode;

    rear=(rear+1)%Length;

}

出队函数:出队函数即是读取按键的函数,以供其他需要的地方调用。


char ReadKey()

{

    char temp;

    //if(rear==front) return '';    //无按键

    while(rear==front);

    temp = Key[front];

    front=(front+1)%Length;

    return temp;

}

KeyProcess:这个函数即是键盘处理函数,需要被每10ms-20ms的时间调用一次的函数,在这里把它放入了看门狗定时器16ms的中断中;函数流程图和函数内容如下:


image


void KeyProcess()

{

    static char keyValue = 0xff;    //按键标识,键值

    static char addedFlag = 0;      //加入队列标志

    char keyVal = GetKey();

    if(keyVal==0xff)                //无按键

    {

        keyValue = 0xff;

        addedFlag = 0;

        return;

    }

    if(keyValue==0xff)              //之前状态无按键

    {

        keyValue = keyVal;

        return;

    }

    if(keyValue!=keyVal)            //和前次按键不同

    {

        keyValue = keyVal;          //保存新按键值

        return;

    }

    if(addedFlag==1)                //已加入队列

    {

        return;

    }

    addedFlag = 1;

    AddKeyCode(KeyCode[keyVal]);

}

这个函数完成按键的判断,并和上次的比较,从而判断是否是有效按键,再根据是否已经入队保存,去判断是否要保存,入队列保存按键。


这个函数需要每10ms-20ms中断运行一次:


#pragma vector=WDT_VECTOR

__interrupt void WDT_ISR()

{

    KeyProcess();

}

这是430看门狗的间隔定时中断,设置的是每16ms中断一次:


    WDTCTL=WDT_ADLY_16;   //看门狗内部定时器模式16ms

    IE1 |= WDTIE;         //允许看门狗中断

KeyProcess里调用了GetKey函数,这个函数需要用户提供,以满足特殊的按键需求,这里提供了两个实例:4个按键和4*4矩阵键盘。


4个按键的getkey函数:


char GetKey()

{

    if((P1IN&0X0F)==0x0E)

    {

        return 0;

    }

    if((P1IN&0X0F)==0x0D)

    {

        return 1;

    }

    if((P1IN&0X0F)==0x0B)

    {

        return 2;

    }

    if((P1IN&0X0F)==0x07)

    {

        return 3;

    }

    return 0xff;

}

这里根据每个按键,输出按键原始键值,没有按键则输出0xff;当自己提供getkey函数时,也需要这样,无按键时返回0xff


把对应原始键值翻译成所需键码,用数组KeyCode:


char KeyCode[] = "0123";    /*4个按键时*/

这里把它转化成ASCII码输出,需要的话可以自行更改。


4*4矩阵键盘:getkey:


char GetKey()

{

    P1DIR |= 0XF0;                  //高四位输出

    for(int i=0;i<4;i++)

    {

        P1OUT = 0XEF << i;

        for(int j=0;j<4;j++)

        {

            if((P1IN&(0x01<

            {

                return (i+4*j);

            }

        }

    }

    return 0xff;

}

这里是按列扫描,可以随意改成其他扫描方式,只要获取原始键值即可,无按键是须返回0xff。


KeyCode,翻译成ASCII码:


char KeyCode[] = "0123456789ABCDEF"

到这里,正常的键盘程序结束,调用时只需加入Key.c,包含Key.h即可使用,先调用KeyInit后,就可以正常的读键了。这里不再细说。


scanf移植:scanf移植时,需要的是ASCII码字符型设备,利用ASCII码输入数据还必须要有回车键,只有这样,才能用scanf输入数据,这里为了输入数据错误时,可以退格修改,按键还有一个退格键。


键盘结构:

image.png

保留键用字符’’,回车’n’退格’b’


所以:KeyCode:


char KeyCode[] = "123b45600789000r"; /* 4*4,scanf移植*/

在字符串里,后面是数字时,必须用’00’否则,c语言编译器认为和后面的数字组合为一个字符。


scanf的移植,需要实现getchar函数,这里和之前的getchar函数类似,把它放到了Getchar.c文件里,内容如下:


#include

#include "Key.h"


#define LINE_LENGTH 20          //行缓冲区大小,决定每行最多输入的字符数


/*标准终端设备中,特殊ASCII码定义,请勿修改*/

#define InBACKSP 0x08           //ASCII  <--  (退格键)

#define InDELETE 0x7F           //ASCII (DEL 键)

#define InEOL 'r'              //ASCII   (回车键)

#define InLF 'n'                 //ASCII   (回车)

#define InSKIP '3'             //ASCII control-C

#define InEOF 'x1A'            //ASCII control-Z


#define OutDELETE "x8 x8"     //VT100 backspace and clear

#define OutSKIP "^Cn"          //^C and new line

#define OutEOF "^Z"             //^Z and return EOF


int getchar()

{

    static char inBuffer[LINE_LENGTH + 2];      //Where to put chars

    static char ptr;                            //Pointer in buffer

    char c;

    

    while(1)

    {

        if(inBuffer[ptr])                       //如果缓冲区有字符

            return (inBuffer[ptr++]);           //则逐个返回字符

        ptr = 0;                                //直到发送完毕,缓冲区指针归零

        while(1)                                //缓冲区没有字符,则等待字符输入

        {

[1] [2]
关键字:MSP430  程序库  按键 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic476704.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:MSP430程序库<八>DAC12的使用
下一篇:MSP430程序库<六>通过SPI操作AD7708

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

MSP430程序库<十一>定时器TA的PWM输出
;          //TA PWM输出程序库头文件void main(){    // Stop watchdog timer to prevent time out reset    WDTCTL = WDTPW + WDTHOLD;    ClkInit();        TAPwmInit('A',1,'P','P');   //将定时器TA初始化成为PWM发生器   
发表于 2019-10-09
MSP430程序库<十一>定时器TA的PWM输出
MSP430程序库<十二>SVS(电源电压监控器)模块
电源电压监控对于单片机来说,也是经常要用的模块。当需要稳定的工业级产品时,经常要对电源电压监控,以保证单片机系统工作于正常环境或范围中。MSP430F16x提供了一个现成的电源电压监控器模块SVS,方便检测电源电压或者是外部电压,可以设置为电压过低时复位 或置标志位。本程序即完成SVS的设置使用的程序库(msp430f14x没有此模块)。硬件介绍:MSP430单片机含有的SVS模块可以很方便的监控电源电压或外部电压。电源电压监控器(SVS)是用于监控AVCC电源电压或外部电压。 SVS的可配置当电源电压或外部电压下降到低于用户选择的电压级别时设置一个标志,或产生POR复位。SVS模块有以下特点:可以监控AVCC电压;可选择产生
发表于 2019-10-09
MSP430程序库<十二>SVS(电源电压监控器)模块
MSP430程序库<十三>硬件乘法器使用
;/***************************************************************************** 名    称:main主程序* 功    能:硬件乘法器程序库使用演示* 入口参数:无* 出口参数:无****************************************************************************/void main( void ){    // Stop watchdog timer to prevent time out reset    WDTCTL = WDTPW + WDTHOLD; 
发表于 2019-10-09
MSP430程序库<十三>硬件乘法器使用
MSP430程序库<十四>DMA程序库
;     case 2: DMA2CTL |= DMAREQ;  break;      //2通道    }}这个和上个函数类似:仅仅设置一个控制位,函数很简单,不再解释啦。程序实现就这么多了,有关详细内容可以下载附件里的程序库,程序的注释很详细。使用示例:使用这个程序时,步骤和原来的相同:工程中加入DMA.c文件,然后源文件中包含DMA.h头文件即可。示例程序主要如下:#include <msp430x16x.h>#include "DMA.h"unsigned int
发表于 2019-10-09
MSP430程序库<十四>DMA程序库
MSP430程序库<十五>Flash控制器
一般,在单片机中的Flash存储器用于存放程序代码,属于只读型存储器。而在MSP430些列的单片机中,都可以通过内置的Flash控制器擦除或改写任何一段的内容。另外,msp430的单片机内部还专门留有一段Flash区域(information memory),用于存放掉电后需要永久保存的数据。利用430内部的Flash控制器,可以完成较大容量的数据记录、用户设置参数在掉电后的保存等功能。硬件介绍:要对Flash读写,首先要了解MSP430的存储器组织。430单片机的存储器组织结构采用冯诺依曼结构,RAM和ROM统一编址在同一寻址空间中,没有代码空间和数据空间之分。一般430的单片机都统一编址在0-64k地址范围中,只有少数高端
发表于 2019-10-09
MSP430程序库<十五>Flash控制器
MSP430程序库<十>ADC12模块
;   ADC12CTL0 &=~ ENC;                      //停止转换        i=0;    }}该程序实现的是多次A0-A2 32次转换,把结果存入results数组。单次时,仅仅采样一次(A0-A2)可用自己更改处理函数。程序部分就完成了,调用时注意要自己实现处理逻辑或存储逻辑。使用示例: 本程序使用方式还是加入C文件,包含H文件;不过和之前的程序不同的是要自己实现中断处理逻辑。使用示例参见程序库中
发表于 2019-10-09
MSP430程序库<十>ADC12模块
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved