历史上的今天
返回首页

历史上的今天

今天是:2025年02月03日(星期一)

2020年02月03日 | MSP430学习笔记7-4*4键盘的对应数码管显示

2020-02-03 来源:eefocus

这个例程也是开发板上面的一个经典例程,我对程序的框架进行了修改,更适合以后的调用。具体的4*4键盘扫描原理较为基础这里不再赘述,这里我认为比较重要的是要养成一个良好的写程序的习惯,想4*4键盘扫描这样的函数可以写成一个固定的C或者H文件,便于以后调用。先看看主程序:

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

程序功能:扫描4X4键盘并将键值在数码管上显示


------------------------------------------------

测试说明:按动K1~K16按键,观察数码管显示

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

#include

#include "Keypad.C"


//数码管7位段码:0--f

unsigned char scandata[16] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,

                              0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};

//记录显示位数的全局变量

unsigned char cnt = 0;

//显示缓存

unsigned char Dispbuf[2];


//引用外部变量的声明

extern unsigned char key_Pressed;      

extern unsigned char key_val;         

extern unsigned char key_Flag; 



/********************主函数********************/

void main(void)

{

    /*下面六行程序关闭所有的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;  //关闭电平转换      

    WDTCTL = WDT_ADLY_1_9;        //设置内部看门狗工作在定时器模式,1.9ms中断一次

    IE1 |= WDTIE;                 //使能看门狗中断

  

    _EINT();                      //打开全局中断

    Init_Keypad();

    while(1)

    {

        Key_Event();

    

        if(key_Flag == 1)

        {

            key_Flag = 0;

            Dispbuf[1] = key_val / 10;

            Dispbuf[0] = key_val % 10;

            

        }

    }

}

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

函数名称:watchdog_timer

功    能:看门狗中断服务函数,在这里输出数码管的

          段选和位选信号

参    数:无

返回值  :无

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

#pragma vector=WDT_VECTOR

__interrupt void watchdog_timer(void)

    P4OUT = 0xff;

    P5OUT = scandata[Dispbuf[cnt]];         //输出段选信号

    P4OUT &= ~(1 << (cnt+2));               //输出位选信号

  

    cnt++;                                  //位计数变量在0~1之间循环

    if(cnt == 2) cnt = 0;

}


主程序较为简单,具体的原理参见上一个笔记,在主程序中与键盘扫描相关的函数被击中在Keypad.C中,需要说明的是在主函数中需要对Keypad.C的部分变量做声明,这样才能使用Keypad.C中的变量。Keypad.C代码如下:

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

4*4键盘扫描函数

作者:孙浩

修改时间:2010.8.2

程序说明:

此程序以开发板的例程做部分修改,更方便程序调用。

在调用之前需要注意需要在主函数中对程序中使用的变量做外部变量声明

需要在主函数中声明的变量如下:

//引用外部变量的声明

extern unsigned char key_Pressed; //按键是否被按下:1--是,0--否     

extern unsigned char key_val;     //存放键值    

extern unsigned char key_Flag;    //按键是否已放开:1--是,0--否

另外对应的键值可以在本文件的全局变量中修改,只需要对应修改

数组uchar key_Map[]的对应的值即可。

调用示例如下:

Init_Keypad();        //先进行初始化

    while(1)

    {

        Key_Event();  //在死循环中进行键值扫描

    

        if(key_Flag == 1)//用来判断有无按键按下,从而读取键值进行操作

        {

            key_Flag = 0;//key_Flag需要手动清零

        }

    }

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

#include 

//相应的函数声明

void Init_Keypad(void);//键盘初始化

void Check_Key(void);

void delay();

void Key_Event(void);//读取键盘函数,在使用时通过此函数进行键盘扫描


//选择对应的端口

#define KEYOUT P1OUT

#define KEYIN P1IN

#define KEYDIR P1DIR


typedef unsigned char uchar;

typedef unsigned int  uint;


/***************全局变量***************/

uchar key_Pressed;      //按键是否被按下:1--是,0--否

uchar key_val;          //存放键值

uchar key_Flag;         //按键是否已放开:1--是,0--否

//设置键盘逻辑键值与程序计算键值的映射

uchar key_Map[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};


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

函数名称:Init_Keypad

功    能:初始化扫描键盘的IO端口

参    数:无

返回值  :无

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

void Init_Keypad(void)

{     

    KEYDIR = 0xf0;       //KEY.0~KEY.3设置为输入状态, KEY.4~KEY.7设置为输出状态

    KEYOUT |= 0xf0;      // KEY.4~KEY.7输出高电平

    key_Flag = 0;       

    key_Pressed = 0;   

    key_val = 0;

}

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

* Check_Key(),检查按键,确认键值

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

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

函数名称:Check_Key

功    能:扫描键盘的IO端口,获得键值

参    数:无

返回值  :无

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

void Check_Key(void)

{

    uchar row ,col,tmp1,tmp2;

    

    tmp1 = 0x80;

    for(row = 0;row < 4;row++)              //行扫描

    {

        KEYOUT = 0xf0;                      //KEY.4~KEY.7输出全1

        KEYOUT -= tmp1;                      //KEY.4~p1.7输出四位中有一个为0

        tmp1 >>=1;                              

        if ((KEYIN & 0x0f) < 0x0f)           //是否KEYIN的KEY.0~KEY.3中有一位为0

        {                       

            tmp2 = 0x01;                         // tmp2用于检测出那一位为0  

            for(col = 0;col < 4;col++)              // 列检测 

            {          

                if((KEYIN & tmp2) == 0x00)           // 是否是该列,等于0为是

                {          

                    key_val = key_Map[row * 4 + col];  // 获取键值

                    return;                         // 退出循环

                }

                tmp2 <<= 1;                        // tmp2右移1位 

            }

        }

    }      

}

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

函数名称:delay

功    能:延时约15ms,完成消抖功能

参    数:无

返回值  :无

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

void delay()

{

    uint tmp;

     

    for(tmp = 12000;tmp > 0;tmp--);

}

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

函数名称:Key_Event

功    能:检测按键,并获取键值

参    数:无

返回值  :无

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

void Key_Event(void)

{     

    uchar tmp;

     

    KEYOUT &= 0x00;              // 设置KEYOUT全为0,等待按键输入

    tmp = KEYIN;                 // 获取 p1IN

    if ((key_Pressed == 0x00)&&((tmp & 0x0f) < 0x0f)) //如果有键按下

    {                     

        key_Pressed = 1;        // 如果有按键按下,设置key_Pressed标识

        delay();                //消除抖动

        Check_Key();            // 调用check_Key(),获取键值 

    }     

    else if ((key_Pressed == 1)&&((tmp & 0x0f) == 0x0f)) //如果按键已经释放

    {                     

        key_Pressed = 0;        // 清除key_Pressed标识

        key_Flag    = 1;        // 设置key_Flag标识

    }

    else 

    {

        _NOP();

    }     

}


具体的注意提防都已经在注释中做了说明,在原来的程序中这个文件是分为Keypad.C和Keypad.h两个文件,键盘扫描函数的声明单独为一个头文件,我觉得并不是特别需要。源程序中全局变量是单独列为一个头文件gdata.h的。这样在全局变量比较多的情况下可以使程序更有条理可以参考。

推荐阅读

史海拾趣

冠西电子(COSMO)公司的发展小趣事

进入21世纪,冠西电子不断加大在研发方面的投入,成功突破了一系列技术难题,特别是在光耦合器和继电器领域取得了显著成果。这些技术突破不仅提升了冠西电子产品的竞争力,也为其赢得了更多国际大厂的信赖。同时,冠西电子积极拓展市场,其产品广泛应用于电源、互联网设备、电脑系统和相关系统、家电、工业、安防系统等领域,为全球客户提供优质的产品和服务。

Global Communications公司的发展小趣事
由于环境温度的频繁变化可能导致电路中的元件参数发生变化,从而影响补偿电路的稳定性和准确性。因此,在电路设计中需要选择稳定性好的元件,并采取适当的保护措施来确保电路的稳定性。
Essentra Components公司的发展小趣事

Essentra Components公司一直将客户服务放在首位,通过提供优质的售前咨询、售中支持和售后服务,赢得了客户的广泛赞誉。公司不仅为客户提供了丰富的产品选择,还根据客户的具体需求提供定制化的解决方案。此外,公司还建立了完善的物流配送体系,确保产品能够及时、准确地送达客户手中。这些努力使得Essentra Components在客户中树立了良好的口碑,为公司的发展奠定了坚实的基础。

Flambeau公司的发展小趣事

在追求经济效益的同时,Flambeau公司始终不忘履行社会责任和环保使命。公司积极响应全球可持续发展号召,将环保理念融入产品研发、生产和销售的各个环节。通过采用环保材料、优化生产工艺、推广循环经济等措施,Flambeau有效降低了产品生命周期中的环境影响。此外,公司还积极参与环保公益活动和社会责任项目,为推动电子行业的绿色可持续发展贡献力量。

Blaze Display Technology Co Ltd公司的发展小趣事

在国内市场取得一定成绩后,Blaze公司开始积极拓展国际市场。通过与全球知名企业的合作,公司成功将产品打入国际市场,并赢得了良好的口碑。此外,公司还积极参加国际电子展会和交流活动,与全球同行建立了广泛的合作关系,为公司的进一步发展奠定了坚实的基础。

Chipcera Technology Co Ltd公司的发展小趣事

随着技术实力的不断增强,Chipcera开始将目光投向更广阔的市场。公司通过参加国际电子展会、与知名厂商合作等方式,积极推广自家产品。同时,公司还加大了对品牌建设的投入,通过提升产品质量、优化售后服务等措施,树立了良好的品牌形象。这些努力使得Chipcera的产品逐渐打入国际市场,成为行业内的佼佼者。

问答坊 | AI 解惑

利用运算放大器实现的混频器

混频器常常用一个二极管桥式电路(diodebridge)或一个Gilbert单元(Gilbertcell)来实现。这两类混频器都使用了一个本地振荡器(LO)来跳转射频输入的极性。   当LO为正时,RF输入被混频转换为中频(IF)输出时极性不改变。当LO为负时,RF输入转换为IF时极 ...…

查看全部问答>

关于TAPI的lineInitializeEx的困惑

Windows Embedded CE 6.0帮助文档中介绍,Establishing a Modem Connection的流程如下: lineInitializeEx      ↓ lineOpen      ↓ lineMakeCall      ↓ lineGetMessage & ...…

查看全部问答>

subproject的问题

用windows ce 的template建了个pda的os project 想在这个project下面加一个 subproject 来播放一个 test16bit.wav的文件 这个文件 我是从project property的custom build actions里面加入目录relase的 这个subproject我是这么写的 #include # ...…

查看全部问答>

虚拟网卡动态修改mac

    本人目前维护一个虚拟网卡的微端口驱动程序,代码已经由别人完成,且已经商品化,公司要求我增加一项功能,功能是驱动能够动态的修改虚拟网卡的mac地址。      虚拟网卡mac地址的初始化是通过读一个TXT文件,然 ...…

查看全部问答>

串口输出 程序调试

#include #include void main() { int i=7,j=2; float f=(float)i/j; SCON = 0x50; TMOD |= 0x20; TH1 = 0xf3; TR1 = 1; TI = 1; printf(\"%f\",f); while(1) {} } 这个程序为什么在运行的时候 在串口输入串口 没看到东西啊 ...…

查看全部问答>

一个让人纠结的结果

最近玩单片机的时候谢了一个小代码,但是实在不知道出错在哪里。代码如下         ORG 0000H         ;程序从000H地址开始运行         LJMP        ...…

查看全部问答>

求教!新手求指点

若我有一台17KW  600V的无刷电机,控制器的驱动部分因该选用哪种IGBT和驱动芯片呀,求个型号以供参考,谢谢了…

查看全部问答>

LPCXpresso-CN在IAR下怎么开发,选什么仿真器啊

驱动应该装好了,用lpcxpresso IDE开发无能 板子后面写了IAR,应该可以用IAR来开发 导入了一个IAR里自带的LPC1114的例程 编绎有一警告,无错误 仿真器选择那个呢,我一个个试好像都不行啊, 是不是有其他的选项要设置…

查看全部问答>

Z-Stack中SimpleApp开关结点加入网络流程

(1)开关结点初始化    这时选择的节点类型是终端节点,所以使用f8wEndev.cfg文件,所以在Zglobals.h文件中,我们可以得到下面的定义#define ZG_DEVICETYPE_ENDDEVICE        0x02#define DEVICE_LO ...…

查看全部问答>