MSP430 矩阵键盘扫描
MSP430单片机应用中键盘的软件设计
按键设计在行、 列线交叉上, 行列线分别连接到按键开关 的两端。当行线通过上拉电阻接 +5V 时, 被钳位在高电平状 态。 键盘中有无按键按下是由列线送人全扫描字, 行线读人行 线状态来判断的。 其方法是:先给列线的所有 珊 线均置成低 电平, 然后将行线电平状态读人累加器 A 中。如果有键按下, 总会有一根行线电平被拉至电平, 从而使行输人不全为 1。 键 盘中哪一个键按下是由列线逐列置低电平, 检查输人状态。 其 方法是:依次给列线送低电平, 然后检查所有行线状态, 如果 全为 1, 则所按下之键不在此列。而且是在与 0 电平行线相交 点上的那个键。 (2)键盘工作方式的选择 一般在实践应用中,由于应用系统在工作时并不经常需 要按键输人 , 所以为了提高 CPU 的工作效率, 可采用中断扫 描工作方式,即只有在键盘有按键按下时,才发中断请求, CPU 响应中断请求后, 转到中断服务程序, 进行键盘扫描, 识 别键码。 具体应用程序举例:(下面程序经过调试验证正确)下 面介绍通过 MSP430 的 P1 口接的 4*4=16 个按键 ( 编号为
l
P10UTI=BIT7;
if(PI IN&BITI)
e lse
if(Pl IN&B1 T4)
x=7;
void Comm- Sent(unsigned char Byte) { unsigned char i, a[3]二 , '430";
{
for(i=O ;i<3;i++)
{ TXBUFO =aa[i]; while((UTCTLO &0x01)二 =0);
x=2;
e lse
{
int i;
BCSCTLI &=- X'IS ;
MSP430_按键的定时器扫描
MSP430_按键的定时器扫描//按键的定时器扫描:每1ms进入一次time中断,10ms进行一次按键检测。
#includechar Key_Pressed_Flag=0;//按键标志位char Key_Front=1, Key_Current=1;//上次按键值,本次按键值int Key_Det_1ms_Cnt=0;int main(void){WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗//配置系统时钟DCOCTL = 0;BCSCTL1 = CALBC1_1MHZ; // 设置 DCO为1MDCOCTL = CALDCO_1MHZ;//配置定时器P1DIR |=BIT0; // 2P1.0为输出P1OUT |=BIT0; //初始化CCTL0 = CCIE; // CCR0中断使能CCR0 = 1000; //设置定时器计数值TACTL = TASSEL_2 + MC_1; // SMCLK为定时器时钟,向上计数模式//配置按键P1SEL &= ~(BIT3); // 1设置P1.3为IO口P1DIR &= ~BIT3; // 2设置P1.3为输入P1REN |= BIT3; // 3使能SW2为上下拉 (P1.3)P1OUT |= BIT3; // 4设置SW2为上拉 (P1.3)//配置串口模块P1SEL |= BIT1 + BIT2 ; // 配置引脚P1SEL2|= BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TX UCA0CTL1 |= UCSSEL_2; // 模块时钟选择为SMCLK UCA0BR0 = 104; // 设置波特率UCA0BR1 = 0; // 1MHz/104=9600bpsUCA0MCTL = UCBRS0; // 调整波特率UCA0CTL1 &= ~UCSWRST; // **使能系统复位** IE2 |= UCA0RXIE; // 使能USCI_A0接收中断//使能全局中断_BIS_SR(GIE); // 使能中断while(1){//按键处理if(Key_Pressed_Flag){Key_Pressed_Flag=0;P1OUT ^=BIT0; //位的异或运算:使得输出改变}}}// Timer A0 interrupt service routine#pragma vector=TIMER0_A0_VECTOR__interrupt void Timer_A (void){//基于定时器的按键检测Key_Det_1ms_Cnt++;//计数器if(Key_Det_1ms_Cnt==10){Key_Det_1ms_Cnt=0;//计数器置0,为下一次计数做准备Key_Current=BIT3 & P1IN;if((Key_Current==0)&&(Key_Front>0))Key_Pressed_Flag=1;Key_Front=Key_Current;}}// Echo back RXed character, confirm TX buffer is ready first #pragma vector=USCIAB0RX_VECTOR__interrupt void USCI0RX_ISR(void){while (!(IFG2&UCA0TXIFG)); // 检测发送是否准备好UCA0TXBUF = UCA0RXBUF; // 将接收数据发送给主机}。
单片机矩阵键盘扫描的两种方式
单片机矩阵键盘扫描的两种方式单片机矩阵键盘扫描的两种方式矩阵键盘扫描方式:第一种:逐行扫描法,就是一行一行的扫描。
实现代码如下(键盘连接P2口):#define NO_KEY 0XFF#define KEY_LO() P2 &= 0XF0#define KEY_HI() P2 |= 0X0F#define KEY_L(i) P2 &= ~(1<<i)#define KEY_RD() ((P2>>4) & 0x0f)UINT8 OnceKey(void){UINT8 line = 0;UINT8 key = NO_KEY;//key valueKEY_LO();if (KEY_RD() == 0X0F){KEY_HI();return NO_KEY;}for (line=0; line<4; line ++){KEY_HI();KEY_L(line);key = KEY_RD();switch (key){case ROW_FIRST:key = 4*line + 0;break;case ROW_SECOND:key = 4*line + 1;break;case ROW_THIRD:key = 4*line + 2;break;case ROW_FOURTH:key = 4*line +3;break;default :key = 0x0f;break;}if (key < 0x10){return key;}}return NO_KEY;}第二种,线性反转法。
就是行和列分别读出。
实现代码如下:#define CVT(i) ((i)==(~1)&0x0f)? 0: ((i)==(~2)&0x0f)? 1: ((i)==(~4)&0x0f)? 2: ((i)==(~8)&0x0f)? 3: 4;#define KEY0_3HI() P2 |= 0X0F#define KEY0_3LO() P2 &= 0XF0#define KEY4_7HI() P2 |= 0XF0#define KEY4_7LO() P2 &= 0X0F#define KEY0_3RD() (P2 & 0X0F)#define KEY4_7RF() ((P2>>4) & 0X0F)UINT8 OnceKey(void){UINT8 line = NO_KEY;UINT8 row = NO_KEY;UINT8 key;KEY0_3HI();KEY4_7LO();line = KEY0_3RD();//读入行的值if (0x0f == line){key = NO_KEY;}else{KEY0_3LO();KEY4_7HI();row = KEY4_7RD();//读入列的值if (0x0f == row){key = NO_KEY;}else{key = CVT(line)*4 + CVT(row);}}KEY0_3HI();KEY4_7HI();return key; }。
msp430 按键控制LED 最基本程序
按键篇经过一短时间的学习,下面,亲自动手编写一下程序吧。
程序的目的是:按下按键,控制LED的亮和灭。
短按键,则小灯亮1秒,然后灭;长按键,小灯常亮。
首先,完成键盘的扫描程序。
第一点:如果是扫描,就要用到定时器。
我想设计定时器每隔10ms扫描一次按键。
定时器,我选用定时器A。
它的定时中断函数如下:函数名称:TimerA_ISR功能:定时器A的中断服务函数参数:无返回值:无********************************************/#pragma vector = TIMERA0_VECTOR__interrupt void TimerA_ISR(void){GetKey();}上面这个定时中断函数的意思就是:每当定时时间到了以后,就调用GetKey()函数一次。
GetKey()函数就是扫描键盘按键的函数了。
在GetKey()函数中,会根据按键类型(长按/短按)返回不同的数值。
根据返回的数值,做小灯亮法的操作。
那么,返回的这个值,我们需要保存在一个变量中,在这里定义一个变量ucharFlagLcd ;来保存返回值。
这个变量在全局变量中定义,以保证它的作用域。
那么定时函数就变为#pragma vector = TIMERA0_VECTOR__interrupt void TimerA_ISR(void){FlagLcd =GetKey();}定时器中断的时间间隔,我在主函数中定义。
这样写:CCTL0 = CCIE; //使能CCR0中断CCR0 = 40; //设定周期0.01STACTL = TASSEL_1 + ID_3 + MC_1; //定时器A的时钟源选择ACLK,增计数模式这样,定时器这块就算完工了。
那么,下面进行按键扫描程序。
按键的定义是这样的,根据我板子的按键原理图如下这是一个矩阵键盘。
其中KEY就是外部高电平3.3V。
我只想用其中的P1.0作为这次试验的按键。
行列式键盘扫描
实验二 行列式键盘扫描一. 实验内容与目的1. 实验内容利用行列式键盘,当按下键盘中的一个键子时会在数码管上显示出相应的键值,要求键盘有去抖功能,数码管显示的键值能进行移位。
2,实验目的学会行列式键盘扫描的原理与方法,进一步强化对MSP430I/O 口使用方法的掌握,加强msp430C 语言编程的能力。
二. 方法与结果键盘扫描:利用P3口进行键盘扫描,如图,令P3.0~P3.3为输出端口,P3.4~P3.7为输入端口,由于P3.4~P3,7接了上拉电阻,所以当没有键子按下时P3.4~P3.7都为‘1’,当有键子按下时P3.4~P3.7就有可能发生变化。
所以键盘扫描式先让P3.0~P3.3都为‘0’,当有键子按下时P3.4~P3.7就会有一个由‘1’变为‘0’,根据哪一个变为‘0’就能判断出相应的列有键子按下,再让P3.0~p3.3逐个变为‘1’判断出哪一行有键子按下进而确定出哪一个键子按下。
11221112221122311224112251122611227112281122911221122#1122*1122A 1122B1122C1122DR2510k R2610kR2710kR2810kP_30P_31P_32P_33P_34P_35P_36P_37P3.0~p3.3为‘0’P3.4~p3.7都为‘1’P3.4~P3.7不都为‘1’ 令P3.0~p3.3逐个为‘1’ 确定列确定行当P3.4~p3.7都为‘1’确定键值数码管显示:数码管位选与段选共用P1.0~P1.3,利用锁存器74HC373分时进行段选和位选,P6.1和P6.2控制74HC373,从而使相应数码管显示相应数。
电路图如下:e 1d 2d p3c 4g 546b 73829f 10a 11112seg4O E 1Q 02D 03D 14Q 15Q 26D 27D 38Q 39G N D 10L E11Q 412D 413D 514Q 515Q 616D 617D 718Q 719V C C 2074HC373_174HC373O E 1Q 02D 03D 14Q 15Q 26D 27D 38Q 39G N D 10L E11Q 412D 413D 514Q 515Q 616D 617D 718Q 719V C C 2074HC373_274HC373R19100R20100R21100R22100R2310k R2410k P_61P_62VCCVCCGND GNDGND GND GNDGNDP_10P_11P_12P_13P_14P_15P_16P_17三. 实验程序#include<msp430.h> void KEYSCAN(); void TUBESCAN();void KEYSLOVE( unsigned int key); unsigned char const table[]={0xff,0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //0~F 码值 unsigned int s1=0,s2=0,s3=0,s4=0; //s1~s4保存相应键值,进行显示 unsigned int key;void delay1(unsigned int i) {while(i--); }void main() {WDTCTL=WDTPW+WDTHOLD; P1DIR=0xff; P1SEL=0x00; P3SEL=0x00; P3DIR=0x0f;P6DIR=BIT1+BIT2; TUBESCAN(); P3OUT=0xf0; while(1)KEYSCAN();TUBESCAN();}}void KEYSCAN(){P3OUT=0xf0;if(P3IN!=0xf0){switch(P3IN){case (0xe0):P3OUT=0x01;if(P3IN==0xf1) {key=16;break;}P3OUT=0x02;if(P3IN==0xf2) {key=12;break;}P3OUT=0x04;if(P3IN==0xf4) {key=8;break;}P3OUT=0x08;if(P3IN==0xf8) {key=4;break;}case (0xd0):P3OUT=0x01;if(P3IN==0xf1) {key=15;break;}P3OUT=0x02;if(P3IN==0xf2) {key=11;break;}P3OUT=0x04;if(P3IN==0xf4) {key=7;break;}P3OUT=0x08;if(P3IN==0xf8) {key=3;break;}case (0xb0):P3OUT=0x01;if(P3IN==0xf1) {key=14;break;}P3OUT=0x02;if(P3IN==0xf2) {key=10;break;}P3OUT=0x04;if(P3IN==0xf4) {key=6;break;}P3OUT=0x08;if(P3IN==0xf8) {key=2;break;}case (0x70):P3OUT=0x01;if(P3IN==0xf1) {key=13;break;}P3OUT=0x02;if(P3IN==0xf2) {key=9;break;}P3OUT=0x04;if(P3IN==0xf4) {key=5;break;}P3OUT=0x08;if(P3IN==0xf8) {key=1;break;}}P3OUT=0xf0;KEYSLOVE(key);} //键盘扫描函数,得到相应的键值key }void KEYSLOVE( unsigned int key){delay1(200);if(P3IN!=0xf0){while(P3IN!=0xf0) TUBESCAN(); //键盘去抖,保证当手松开时读取键值if(s4==0)s4=s3;s3=s2;s2=s1;s1=key;}else{if(key==16){s1=0;s2=0;s3=0;s4=0;key=0;}}}} //将得到的键值进行处理:移位/重置void TUBESCAN(){P6OUT=0x02;P1OUT=table[s4];P6OUT=0x04;P1OUT=0x01;delay1(400);P6OUT=0x02;P1OUT=table[s3];P6OUT=0x04;P1OUT=0x02;delay1(400);P6OUT=0x02;P1OUT=table[s2];P6OUT=0x04;P1OUT=0x04;delay1(400);P6OUT=0x02;P1OUT=table[s1];P6OUT=0x04;P1OUT=0x08;delay1(400);} //数码管扫描,使数码管保持四.行列式键盘实验总结①做行列是键盘重点是键盘扫描确定键值,键盘扫描也有多种方式,要多思考确定最优方式,采用本实验中的键盘扫描方式当没有键子按下时不必执行键盘扫描的其他程序,将更多的时间给了数码管扫描,挺优的,在着手写程序之前一定要筹划如何去写,要寻求简单易行的方法,写程序规划挺重要的。
MSP430单片机 矩阵键盘与数码管实验(附原理图)
MSP430单片机矩阵键盘与数码管实验(附原理图)/************************************************************* *MSP430单片机矩阵键盘与数码管实验*功能:用共阳极数码管显示按键的键值*适用:MSP430各系列单片机*by:duyunfu1987*************************************************************/ #include "msp430x44x.h"#define ROW P2OUT //矩阵键盘的行宏定义#define COL P2IN //矩阵键盘的列宏定义#define DPYOUT P3OUT //数码管输出口宏定义unsigned char keyval; //键值//共“阳”极数码管的码表unsigned char LED7CA[] ={~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D, ~0x07,~0x7F,~0x6F,~0x77,~0x7C,~0x39,~0x5E,~0x79,~0x71,0xff};/********************************************************函数名称:keyscan()*功能:扫描4*3矩阵键盘,并返回键值*出口参数:若有按键则返回键值,若无按键返回15*4*3矩阵键盘:0 1 2 3* 4 5 6 7* 8 9 A b*******************************************************/ unsigned char keyscan(){int i=0;unsigned char key=0;ROW = 0x8f; //先置三行输出低电平if((COL & 0x0f)!= 0x0f) //是否有按键{do i++;while(i<3000); //消抖动延时ROW = 0xbf; //扫描第一行if((COL & 0x0f)== 0x0f){ ROW = 0xdf; //扫描第二行if((COL & 0x0f)== 0x0f){ ROW = 0xef; //扫描第三行if((COL & 0x0f)== 0x0f)key = 15;else key = ~((ROW & 0XF0)|(COL & 0X0F));}else key = ~((ROW & 0XF0)|(COL & 0X0F));}else key = ~((ROW & 0XF0)|(COL & 0X0F));if(key != 15)switch(key) //获取有效地键值{ case 0x48: key=0; break;case 0x44: key=1; break;case 0x42: key=2; break;case 0x41: key=3; break;case 0x28: key=4; break;case 0x24: key=5; break;case 0x22: key=6; break;case 0x21: key=7; break;case 0x18: key=8; break;case 0x14: key=9; break;case 0x12: key=10;break;case 0x11: key=11;break;default: key=15;}}else key = 15;keyval=key;return key;}void main( void ){// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;P3DIR |= 0xff;P3OUT = 0xff; //共阳极数码管输出口初始化P2DIR |= BIT4 +BIT5+BIT6; //先配置矩阵键盘的行(输出)//P2.6 第一行,P2.5 第二行,P2.4 第三行//P2.3 第一列,P2.2 第二列,P2.1 第三列,P2.0 第四列keyval=16;while(1){ keyscan();if(keyval != 15 && keyval<17)DPYOUT = LED7CA[keyval];//数码管显示键值}}。
矩阵键盘的三种扫描方法
矩阵键盘的三种扫描方法矩阵键盘是一种常见的输入设备,它由多个按键组成,并通过矩阵扫描的方式来检测用户的按键输入。
矩阵键盘的扫描方法可以分为三种:行扫描、列扫描和交错扫描。
下面将详细介绍这三种扫描方法。
1.行扫描行扫描是最简单的一种扫描方法。
它的原理是将矩阵键盘的每一行连接到一个IO口,通过轮询检测每一行的电平变化来获取用户的按键输入。
行扫描的工作流程如下:1)将矩阵键盘的每一行连接到一个IO口,并设置为输入模式。
2)逐个地将每一行的IO口设置为高电平,并检测列的电平状态。
3)如果其中一列的电平为低电平,说明该列有按键按下。
此时,记录下这个按键的位置(行号和列号)以及按键的值(键码或字符),然后将这个按键的位置和值传递给上层应用或处理器。
4)将当前行的IO口设置为低电平,然后继续下一行的检测,重复2)~3)步骤,直到所有行都被检测完毕。
行扫描的优点是实现简单,只需要一个IO口来检测按键的状态。
但是它的缺点是扫描速度较慢,因为需要逐个地检测每一行。
2.列扫描列扫描是一种比较常用的扫描方法。
它的原理是将矩阵键盘的每一列连接到一个IO口,通过轮询检测每一列的电平变化来获取用户的按键输入。
列扫描的工作流程如下:1)将矩阵键盘的每一列连接到一个IO口,并设置为输入模式。
2)逐个地将每一列的IO口设置为高电平,并检测行的电平状态。
3)如果其中一行的电平为低电平,说明该行有按键按下。
此时,记录下这个按键的位置(行号和列号)以及按键的值(键码或字符),然后将这个按键的位置和值传递给上层应用或处理器。
4)将当前列的IO口设置为低电平,然后继续下一列的检测,重复2)~3)步骤,直到所有列都被检测完毕。
列扫描的优点是速度较快,因为只需要逐个地检测每一列。
但是它的缺点是需要多个IO口来检测按键的状态。
3.交错扫描交错扫描是一种综合了行扫描和列扫描的扫描方法,它可以有效地减少扫描的时间。
交错扫描的原理是将矩阵键盘的行和列交错地连接到多个IO口,通过并行检测行和列的电平变化来获取用户的按键输入。
MSP430矩阵键盘程序源码
// 上一次按键值刷新
}
if (K_STOP_HV&key) key = K_STOP_HV;
} //***************************************************************************
//*************************************************************************** //***************************************************************************
shift<<=1;
}
//--------------------------------------------------------------------------
if (code_now == key_last)
{
if (++key_delay >= T_delay)
// 同一按键按住是否超过预定时间
{
key_delay = T_delay - T_dlyup; // 设置新值以使按键快输反应,
f_key = 1;
// 设置标志
f_key_all=1;
}
}
else
// 有新键按下
{
f_key = 1;
// 设置标志
key_delay = 0;
// 计数器复位
key = key_last = code_now;
#define BASE_T0 10
// T0 基本定时周期为 20ms,用于键盘定时扫描
#define T_dlyup (100/BASE_T0)
MSP430键盘与8位数码管显示应用
MSP430键盘与8位数码管显示应用作者:魏小龙南京航空航天大学硬件连接:1、4×4 扫描键盘连接在P1 端口,P10---P13 为行线,P14---P17 为列线,列线下拉到地。
2、8 只数码管的显示电路,通过164 串行移位输出8 位段码,138 位8 只数码管的位选信号。
也都连接在P1 端口上。
与键盘复用引脚。
如下图:软件分析:1、扫描显示。
扫描显示的原理在于利用人眼睛的视觉暂停,让每个数码管只显示一点时间,所有的数码管轮流显示,而人眼睛看起来就象所有的都在显示一样。
所以硬件上所有的数码管的段码端都连接在一起,而每一个数码管的公共端(地)不连接在一起,而由138 选中每个是数码管。
所以软件上,很明显,分几个步骤。
第一、将要显示的数码转换为段码。
可使用查表的方式。
比如要显示“1、2、3、4、5、6、7、8”分别在8 个数码管上,首先安排段码表,设置一个数组seg[]:unsigned char seg[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}则5 的段码为seg[5]。
第二、将要显示的段码输出,这里使用164 移位输出。
第三、每输出一个要显示的段码,则使用138 选中应该显示的数码管。
第四、延时一小段时间。
这个时间不能长,也不能短。
太长则8 只数码管看起来很抖动,太短则8 只数码管一片模糊。
第五、循环第一到第四。
2、扫描键盘。
本程序的目的在于知道那个键被按下了。
二实现此目的需要以下步骤。
第一、判断有没有键被按下。
第二、如果有,消除键盘的机械抖动。
这是必须的,抖动是机械键盘必然存在的。
第三、判断是哪个键被按下。
第四、等待按键松开。
这也是必须的,不然将会输出很多重复的按键值。
3、将按键的键值显示的数码管上。
调用键盘程序,调用显示程序即可。
基于MSP430G2553的按键测试程序
基于msp430G2系列的按键测试程序本程序有扫描和中断两种方式,代码均附后。
4、4×1独立按键实验(1)4×1键盘1:扫描数码管显示(2)4×1键盘2:xx数码管显示(3)4×1键盘3:控制LED(4)4×1键盘4:控制蜂鸣器5、4×4矩阵键盘实验(1)4×4键盘1:行列扫描数码管显示(2)4×4键盘2:行列扫描1602液晶显示3)4×4键盘3:控制LED蜂鸣器#include <msp430g2452.h>#defineBUTTONBIT3#defineLED_REDBIT0#defineLED_GREENBIT6#defineLED_DIRP1DIR#defineBUTTON_DIRP1DIR#defineBUTTON_OUTP1OUT#defineLED_OUTP1OUT#defineBUTTON_RENP1REN#defineBUTTON_ON(P1IN&BIT3)#defineBUTTON_OFF!(P1IN&BIT3)#defineLED_RED_ON()P1OUT|=BIT0#defineLED_RED_OFF()P1OUT&=~BIT0#defineLED_GREEN_ON()P1OUT|=BIT6#defineLED_GREEN_OFF()P1OUT&=~BIT6 volatile unsigned char i=0,flag=0;void main(void){WDTCTL = WDTPW + WDTHOLD; BUTTON_DIR &= ~BUTTON;LED_DIR|= LED_RED+LED_GREEN;BUTTON_REN |= BUTTON;BUTTON_OUT= BUTTON;while(1){/*通过按键改变选择标志位*/if(BUTTON_OFF){flag=!flag;while(BUTTON_OFF);}if(flag){LED_RED_ON();i=10;while(i--)_delay_cycles(500);LED_RED_OFF();LED_GREEN_ON();i=10;while(i--)_delay_cycles(500);LED_GREEN_OFF();}else{LED_OUT |= LED_RED+LED_GREEN;i=10;while(i--)_delay_cycles(500);LED_OUT ^= (LED_RED+LED_GREEN);i=10;while(i--)_delay_cycles(500);}}}/**************该版本编译后的代码与第一个版本是一致的,请看差别在哪儿************/#include <msp430g2452.h>#defineBUTTONBIT3#defineLED_REDBIT0#defineLED_GREENBIT6#defineLED_DIRP1DIR#defineBUTTON_DIRP1DIR#defineBUTTON_OUTP1OUT#defineLED_OUTP1OUT#defineBUTTON_RENP1REN#defineBUTTON_ON(P1IN&BIT3)#defineBUTTON_OFF!(P1IN&BIT3)#defineBIT_SET(x , y)x |= (y)#defineBIT_CLR(x , y)x &=~(y)volatile unsigned char i=0,flag=1;void main(void){WDTCTL = WDTPW + WDTHOLD;BIT_CLR(BUTTON_DIR , BUTTON);BIT_SET(LED_DIR , LED_RED+LED_GREEN);BIT_SET(BUTTON_REN , BUTTON);BIT_SET(BUTTON_OUT , BUTTON);/********************************************************/while(1){/*通过按键改变选择标志位*/if(BUTTON_OFF){flag=!flag;while(BUTTON_OFF);}/*********************************************** ******/if(flag){BIT_SET(LED_OUT , LED_RED);i=10;while(i--)_delay_cycles(500);BIT_CLR(LED_OUT , LED_RED);/*****************************************************/BIT_SET(LED_OUT , LED_GREEN);i=10;while(i--)_delay_cycles(500);BIT_CLR(LED_OUT ,LED_GREEN);}/*****************************************************/ else{BIT_SET(LED_OUT ,LED_RED+LED_GREEN);i=10;while(i--)_delay_cycles(500);/*****************************************************/BIT_CLR(LED_OUT , LED_RED+LED_GREEN);}}}i=10;while(i--)_delay_cycles(500);。
经典的矩阵键盘扫描程序
键盘是单片机常用输入设备,在按键数量较多时,为了节省I/O口等单片机资源,一般采取扫描的方式来识别到底是哪一个键被按下。
即通过确定被按下的键处在哪一行哪一列来确定该键的位置,获取键值以启动相应的功能程序。
4*4矩阵键盘的结构如图1(实物参考见万用板矩阵键盘制作技巧)。
在本例中,矩阵键盘的四列依次接到单片机的P1.0~P1.3,四行依次接到单片机的P1.4~P1.7;同时,将列线上拉,通过10K电阻接电源。
查找哪个按键被按下的方法为:一个一个地查找。
先第一行输出0,检查列线是否非全高;否则第二行输出0,检查列线是否非全高;否则第三行输出0,检查列线是否非全高;如果某行输出0时,查到列线非全高,则该行有按键按下;根据第几行线输出0与第几列线读入为0,即可判断在具体什么位置的按键按下。
下面是具体程序:1 / 2void Check_Key(void){unsigned char row,col,tmp1,tmp2;tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列{key_val =key_Map[ row*4 +col ]; // 获取键值,识别按键;key_Map为按键的定义表return; // 退出循环}tmp2*=2; // tmp2左移一位}}}} //结束这是一种比较经典的矩阵键盘识别方法,实现起来较为简单,程序短小精炼。
MSP430程序库七按键
MSP430程序库七按键msp430程序库按键键是单片机系统中最常用的输入设备之一;几乎只要需要交互式输入,就必须有键盘。
这个博客实现了一个通用键盘程序。
只要它提供一个读取键值(底部键值)的函数,程序就会完成一些列处理,比如去抖振、存储在队列中等等。
同时,本程序提供了最常用的4*4矩阵键盘程序和4键程序。
硬件介绍:本文主要实现了一个键盘的通用框架,可以很方便的改为不同的键盘函数,这里实现了两种按键4个单独按键和4*4行列扫描的键盘。
四个按键的工作原理如下:四个按键的一端接地,另一端连接上拉电阻,然后输入单片机0-P1的P1。
3个港口;这样,当按键时,单片机接收到一个低电平。
释放时,单片机输入信号具有上拉电阻,并固定在高电平。
4*4的按键:行输入信号配有桑拉电阻,无按键时默认电平高电平;列扫描信号线直接接到按键列线;读键时,列扫描信号由单片机给出低电平信号(按列逐列扫描),读取行信号,从而判断具体是哪个按键;电路图大概如下:在图中,In是键盘的列扫描线,out是键盘输出的行信号线。
扫描也可以按行扫描。
此时,in是行扫描行,out是键输出的列信号行。
我的程序按列扫描(行和列扫描的原理相同,但行和列是交换的)。
这里,同时实现了4*4按键的scanf函数的移植,同时,加入了之前实现的液晶的printf函数的移植,搭建了一个可以交互输入输出的完整的一个系统;液晶的printf又加入了函数,实现了退格;可以在输入错误数字的时候退格重新输入。
程序实现:首先,我们来谈谈这个项目的结构。
该程序实现了一个循环队列来存储按下的键值。
可以保存最新的四把钥匙,防止钥匙丢失;程序使用中断模式按键。
每16毫秒读取一次按键(使用看门狗的间隔中断),以判断按键值是否有效。
如果有效,将其放入队列并等待读取。
循环队列的实现:通过数组实现。
为了判断队列是否已满,数组的最后一个元素不需要存储密钥代码值:/**********************宏定义***********************/#definekeysize4//键码值队列#definelengthkeysize+1//队列数组元素个数/***************************************************//**********************键值队列*********************///可keysize(length-1)个键码循环队列占用一个元素空间charkey[length];入队函数:入队时,队满则出队一个,以保存最新的四个按键。
msp430矩阵键盘c代码
for(x=110;x;x--); } void IO_init() {
P3DIR=0x0f;
P3OUT=0x00; }
uchar key_putdown()
{
uchar putdown=0;
P3OUT=0x00;
while(1)
{
if((P3IN&0xf0)!=0xf0)
uchar key_jianzhi; //返回键值
switch(n)
{
case 0xee:key_jianzhi=0;break;
case 0xde:key_jianzhi=1;break;
case 0xbe:key_jianzhi=2;break;
case 0x7e:key_jianzhi=3;break;
case 0xed:key_jianzhi=4;break;
case 0xdd:key_jianzhi=5;break;
case 0xbd:key_jianzhi=6;break;
case 0x7d:key_jianzhi=7;break;
case 0xeb:key_jianzhi=8;break;
key=key_process(key_scan(key_putdown())); P1OUTtable[key]; } }
case 0xb7:key_jianzhi=14;break;
case 0x77:key_jianzhi=15;break;
}
return key_jianzhi;
//得到被按下的键的键值
}
void main() {
uchar table[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; uchar key; IO_init(); P1DIR=0xff; while(1) {
430学习程序.
1. LED 流水灯 ................................................... 1 2 4*4矩阵键盘扫描实验 ................................ 1 3 1602字符型液晶显示实验 .......................... 2 4 LCD128*64打点及采样波形 ...................... 4 5 DS1302实时时钟实验 ................................. 8 6 ADC12电压测量实验 .. (12)1. LED 流水灯#include "msp430x14x.h" #define uint unsigned int #define uchar unsigned char uchar LedData=0x80; //延时子程序void DelayMs(uint ms){ while(ms--){for(uint i=0;i<800;i++); } }//时钟初始化函数 void InitClock(void){BCSCTL1=RSEL2+RSEL1+RSEL0;//XT2开启 LFXT1工作在低频模式 ACLK 不分频 最高的标称频率 DCOCTL=DCO2+DCO1+DCO0;//DCO 为最高频率 do{IFG1&=~OFIFG;//清除振荡器失效标志 for(uint i=255;i>0;i--); }while(IFG1&OFIFG); //判断XT2是否起振 BCSCTL2=SELM1+SELS;//MCLK SMCLK 时钟源为TX2CLK 不分频}void main(){WDTCTL=WDTPW+WDTHOLD;//关闭看门狗 InitClock(); _DINT();//关闭中断P2SEL=0x00;//P2口所有引脚设置为一般的IO 口 P2DIR=0xFF;//P2口所有引脚设置为输出方向 while(1){//LedData>>=1;//右移一位 //if(LedData==0) LedData=0x80; P2OUT=LedData;//P2口输出数据 DelayMs(400); }}2 4*4矩阵键盘扫描实验功能:在数码管上显示输入的值#include "msp430x14x.h" #define uint unsigned int#define uchar unsigned char uchar KeyValue=0xFF; //共阳数码管编码表uchar Code[18]={0xC0,0xF9,0xA4,0xB0,//0,1,2,3 0x99,0x92,0x82,0xF8,//4,5,6,7 0x80,0x90,0x88,0x83,//8,9,A,b 0xC6,0xA1,0x86,0x8E,//C,d,E,F 0xBF,0xFF};//-,全灭uchar Bit[8]={16,16,16,16,16,16,16,16}; //数码管各位要显示的数字 //键值编码表uchar KeyCode[16]={0x77,0x7B,0x7D,0x7E,//0,1,2,3 0xB7,0xBB,0xBD,0xBE,//4,5,6,7 0xD7,0xDB,0xDD,0xDE,//8,9,A,b 0xE7,0xEB,0xED,0xEE};//C,d,E,F uchar BitCode=0x80; //数码管位码初值 //时钟初始化函数 void InitClock(void){BCSCTL1=RSEL2+RSEL1+RSEL0;//XT2开启 LFXT1工作在低频模式 ACLK 不分频 最高的标称频率 DCOCTL=DCO2+DCO1+DCO0;// DCO 为最高频率 do{IFG1&=~OFIFG;//清除振荡器失效标志 for(uint i=255;i>0;i--); }while(IFG1&OFIFG);//判断XT2是否起振BCSCTL2=SELM1+SELS;//MCLK SMCLK 时钟源为TX2CLK 不分频 }//端口初始化函数 void InitPort(void){P1SEL=0x00;//P1口所有引脚设置为一般的IO 口 P1DIR=0x0F;//P1.0 P1.1 P1.2 P1.3设置为输出方向 P1OUT=0x00;//P1口先输出低电平 P1IE=0xF0;//P1.4 P1.5 P1.6 P1.7中断允许 P1IES=0xF0;//P1.4 P1.5 P1.6 P1.7下降沿触发中断 P2SEL=0x00;//P2口所有引脚设置为一般的IO 口 P4SEL=0x00;//P4口所有引脚设置为一般的IO 口P2DIR=0xFF;//P2口所有引脚设置为输出方向 P4DIR=0xFF;//P4口所有引脚设置为输出方向 P2OUT=0x00;//P2口先输出低电平 P4OUT=0xFF;//P4口先输出低电平 P5SEL&=~BIT7;//P5.7设置为一般的IO 口 P5DIR|=BIT7;//P5.7设置为输出方向 P5OUT&=~BIT7;//P5.7输出低电平来使能74HC573来驱动数码管 }//延时子函数 void Delay(void){ for(uchar i=255;i>0;i--); }//按键分析程序 void KeyProcess(void){ uchar OutData=0x07;for(uchar i=0;i<4;i++){//扫描4列 OutData|=0xF0; P1OUT=OutData;if(P1IN!=OutData) KeyValue=P1IN; OutData>>=1; }P1OUT=0x00;//恢复原来的值 }//端口1中断处理程序#pragma vector=PORT1_VECTOR __interrupt void Port1INT(void){ Delay(); KeyProcess();P1IFG=0x00;//清除中断标志位 }//延时子程序void DelayMs(uint ms){ while(ms--){for(uint i=0;i<800;i++); } }//数码管扫描显示程序 void Display(void){for(uchar i=0;i<16;i++){//查找键值对应的数字 if(KeyValue==KeyCode[i]){Bit[0]=Bit[1]=Bit[2]=Bit[3]=Bit[4]=Bit[5]=Bit[6]=Bit[7]=i;//显示键值对应的数字break;}}for(uchar i=0;i<8;i++){ P4OUT=BitCode; //输出位码 P2OUT=Code[Bit[i]]; //输出段码 BitCode>>=1;//位码右移一位 if(BitCode==0) BitCode=0x80; DelayMs(1); //延时1msP2OUT=0xFF; } }void main(){WDTCTL=WDTPW+WDTHOLD;//关闭看门狗 InitClock(); InitPort();_EINT();//打开中断 while(1){ Display(); } }3 1602字符型液晶显示实验功能:在第一行显示 Model:WJ89S52 在第二行显示 #include "msp430x14x.h" #define uchar unsigned char #define uint unsigned int#define RS_HIGH P4OUT|=BIT0 //指令数据选择信号 #define RS_LOW P4OUT&=~BIT0 #define RW_HIGH P4OUT|=BIT1 //读写信号 #define RW_LOW P4OUT&=~BIT1 #define E_HIGH P4OUT|=BIT2 //使能信号 #define E_LOW P4OUT&=~BIT2 #define BUSY_OUT P2DIR|=BIT7 #define BUSY_IN P2DIR&=~BIT7 #define BUSY_DA TA P2IN&BIT7 uchar Data1[16]="V1= v,V2= v"; uchar Data2[16]="V3=V1+V2= v";uint data1;uint data2;//延时子程序DelayMS(uint ms){uint i;while(ms--){for(i=0; i<800;i++);}}// 测试LCD忙碌状态void LcdBusy(){RS_LOW;RW_HIGH;E_HIGH;_NOP();_NOP();BUSY_IN;while(BUSY_DA TA);BUSY_OUT;E_LOW;}//写入指令到LCDWriteCommand(uchar Command){LcdBusy();RS_LOW;RW_LOW;E_HIGH;_NOP();_NOP();P2OUT=Command;_NOP();_NOP();E_LOW;}//写入字符数据到LCDWriteData(uchar Data){LcdBusy();RS_HIGH;RW_LOW;E_HIGH;_NOP();_NOP();P2OUT=Data;_NOP();_NOP();E_LOW;}//LCD初始化设定LcdInit(){WriteCommand(0x38);//8位数据端口,2行显示,5*7点阵DelayMS(5);WriteCommand(0x0F);//开启显示, 无光标DelayMS(5);WriteCommand(0x06);//AC递增, 画面不动DelayMS(5);WriteCommand(0x01);//清屏DelayMS(5);}//时钟初始化函数void InitClock(void){BCSCTL1=RSEL2+RSEL1+RSEL0;//XT2开启LFXT1工作在低频模式ACLK不分频最高的标称频率DCOCTL=DCO2+DCO1+DCO0;//DCO为最高频率do{IFG1&=~OFIFG;//清除振荡器失效标志for(uint i=255;i>0;i--);}while(IFG1&OFIFG);//判断XT2是否起振BCSCTL2=SELM1+SELS;//MCLK SMCLK时钟源为TX2CLK 不分频}//端口初始化函数void InitPort(void){P2SEL=0x00;//P2口所有引脚设置为一般的IO口P4SEL=0x00;//P4口所有引脚设置为一般的IO口P2DIR=0xFF;//P2口所有引脚设置为输出方向P4DIR=0xFF;//P4口所有引脚设置为输出方向}//主程序main(){uchar i;uint sum;InitClock();WDTCTL=WDTPW+WDTHOLD;//关闭看门狗InitPort();LcdInit();//Lcd初始化_DINT();//关闭中断data1=643;data2=789;sum=data1+data2;Data1[3]=data1/100+'0';Data1[4]=data1%100/10+'0';Data1[5]=data1%10+'0';Data1[11]=data2/100+'0';Data1[12]=data2%100/10+'0';Data1[13]=data2%10+'0';Data2[9]=sum/1000+'0';Data2[10]=sum%1000/100+'0';Data2[11]=sum%100/10+'0';Data2[12]=sum%10+'0';while(1){WriteCommand(0x80);//定位在第一行第一个位置for(i=0;i<16;i++) WriteData(Data1[i]); /*DelayMS(1000);*/WriteCommand(0x80|0x40);//定位在第二行第一个位置for(i=0;i<16;i++) WriteData(Data2[i]);};}4 LCD128*64打点及采样波形#include "msp430x16x.h"#define uchar unsigned char#define uint unsigned int#define ulong unsigned long#define CD_HIGH P4OUT|=BIT1;#define CD_LOW P4OUT&=~BIT1;#define E_HIGH P4OUT|=BIT2;#define E_LOW P4OUT&=~BIT2;#define WR_HIGH P4OUT|=BIT4;#define WR_LOW P4OUT&=~BIT4;#define RD_HIGH P4OUT|=BIT5;#define RD_LOW P4OUT&=~BIT5; // ASCII 字模宽度及高度定义,ASCII 字模显示为8*16#define ASC_CHR_WIDTH 8#define ASC_CHR_HEIGHT 16uchar gCurRow,gCurCol;// 当前行列存储行高16 点列宽8点uchar INCOM;//状态字char turnf[8] = {7,6,5,4,3,2,1,0};#define TRUE 1#define FALSE 0//延时子程序void DelayMs(uint ms){while(ms--){for(uint i=0;i<800;i++);}}void delay(void){uchar i;for(i = 0;i < 15;i++)_NOP();}//时钟初始化函数void InitClock(void){BCSCTL1=RSEL2+RSEL1+RSEL0;//XT2开启LFXT1工作在低频模式ACLK不分频最高的标称频率DCOCTL=DCO2+DCO1+DCO0;//DCO为最高频率do{IFG1&=~OFIFG;//清除振荡器失效标志for(uint i=255;i>0;i--);}while(IFG1&OFIFG);//判断XT2是否起振BCSCTL2=SELM1+SELS;//MCLK SMCLK时钟源为TX2CLK 不分频}//端口初始化函数void InitPort(){P1SEL=0x00;//P1口所有引脚设置为一般的IO口P1DIR=0x00;//P1.2 P1.3 P1.4 P1.5 P1.6 P1.7设置为输出方向P1OUT=0xff;//P1口先输出高电平P1IE=0xFF;//P1.0 P1.1中断允许P1IES=0xFF;//P1.0 P1.1下降沿触发中断P2SEL=0x00;//P2口所有引脚设置为一般的IO口P4SEL=0x00;//P4口所有引脚设置为一般的IO口P2DIR=0xFF;//P2口所有引脚设置为输出方向P4DIR=0xFF;//P4口所有引脚设置为输出方向P2OUT=0x00;//P2口先输出低电平P4OUT=0xFF;//P4口先输出高电平P5DIR=0xFF;//P5口所有引脚设置为输出方向P5OUT=0x00;//P5口先输出低电平P3DIR=0xff;}/************************************************//* 读状态字*//************************************************/ void Lcdsta(){E_HIGH;P2DIR=0x00;CD_HIGH;RD_LOW;WR_HIGH;INCOM=P2IN;E_LOW;P2DIR=0xff;}/************************************************//* 状态位STA1,STA0判断读写指令和读写数据*//* 在读写数据或者写入命令前必须保证均为1 *//************************************************/ void STA01(){uchar i;for(i=10;i>0;i--){if((INCOM&0x03)==0x03) // 读取状态{break;}}}/********************************************//* 检查STA2,如果STA2=1 为自动读状态*//*****************************************/void STA2(){unsigned char i;for(i=10;i>0;i--){if((INCOM&0x04)==0x04){break;}}}/***********************************************/ /* 状态位STA3 判断STA3 = 1 数据自动写状态*//***********************************************/ void STA3(){unsigned char i;for(i=10;i>0;i--){if((INCOM&0x08)==0x08){break;}}}/************************************************/ /* 状态位STA6 判断STA6 =1 屏读/屏拷贝状态*//************************************************/ void STA6(){unsigned char i;for(i=10;i>0;i--){if((INCOM&0x40)==0x40){break;}}}/************************//* 写指令*//************************/void WriteCommand(uchar Command) {STA01();E_HIGH;CD_HIGH;WR_LOW;P2OUT=Command;E_LOW;}/************************//* 写数据*//************************/void fnPR13(uchar Data){STA01();E_HIGH;CD_LOW;WR_LOW;P2OUT=Data;E_LOW;}/************************//* 写双参数的指令*//************************/void fnPR1(char Cmd1,char Cmd2,char Dat) {fnPR13(Cmd1);fnPR13(Cmd2);WriteCommand(Dat);}/************************//* 写单参数的指令*//************************/void fnPR11(char Cmd,char Dat){fnPR13(Cmd);WriteCommand(Dat);}/************************//* 写无参数的指令*//************************/void fnPR12(char Dat){WriteCommand(Dat);}/************************************************//* 取当前行数据*/ // 当前行列存储行高16 点列宽8点/************************************************/uchar fnGetRow(){return(gCurRow);}/************************************************//* 取当前列数据*//************************************************/uchar fnGetCol(){return(gCurCol);}/************************//* 设置当前地址RAM里*//************************/void fnSetPos(char urow,char ucol){uint iPos;iPos = (int)urow * 30 + ucol; //图形、文本显示区宽度(30字节/行)fnPR1(iPos&0xFF,iPos/256,0x24);//地址指针位置(高字节iPos/256)?gCurRow = urow;gCurCol = ucol;}/**********************//* 设置当前显示行列*//**********************/void cursor(unsigned char uRow, unsigned char uCol){fnSetPos(uRow * 16, uCol);//文字显示,两个字节(两行——16)}/*********************/ /* 清屏 */ /*********************/ void cls() { int i;fnPR1(0x00,0x00,0x24); // 置地址指针为从零开始 fnPR12(0xB0); // 自动写for(i=0;i<240*128/8;i++) // 清一屏 {STA3();fnPR13(0x0); // 写数据实际使用时请将0x55 改成0x0 }fnPR12(0xB2); // 自动写结束fnPR1(0x00,0x00,0x24); // 重置地址指针 gCurRow = 0; // 置地址指针存储变量 gCurCol = 0; }/******************************/ /* 在col 行row 列显示内部字符dat*/ /******************************/ void printf(char col,char row,char dat) {uchar D1; D1=col*16+row; fnPR1(D1,0x00,0x24); // 置地址指针,d1代表从左至右第D1个字符(0~127),每个字符8*8点fnPR11(dat,0xc4);//地址不变,写数据,dat 为内部字符地址 }/************************/ /* LCD 初始化 */ /************************/ void fnLCMInit() {fnPR1(0x00,0x00,0x40); // 文本显示区首地址fnPR1(0x10,0x00,0x41); // 文本显示区宽度(30字节/行) fnPR1(0x00,0x00,0x42); // 图形显示区首地址fnPR1(0x1E,0x00,0x43); // 图形显示区宽度(30字节/行) fnPR12(0xA0|0x01); // 光标形状 fnPR12(0x80); // 显示方式设置 fnPR12(0x90|0x0c); // 显示开关设置 }/***********************************************/// 主函数/**********************************************/ void main(void) {int i,j;WDTCTL=WDTPW+WDTHOLD;//关闭看门狗 InitClock(); InitPort();fnLCMInit(); _DINT();//关闭中断 cls(); //cursor(0,0);for(i=0;i<8;i++) for(j=0;j<16;j++) printf(i,j,0x00); while(1) {printf(0,0,0x36);//V printf(0,1,0x41);//a printf(0,10,0x36);//V//电流显示printf(2,0,0x29);//I printf(2,1,0x41);//a printf(2,10,0x21);//Aprintf(3,0,0x29);//I printf(3,1,0x45);//e printf(3,10,0x21);//Aprintf(4,0,0x36);//V printf(4,1,0x4B);//k printf(4,10,0x36);//Vprintf(5,0,0x36);//V printf(5,1,0x5A);//z printf(5,10,0x36);//V}}5 DS1302实时时钟实验功能:在数码管上显示从DS1302读取的时间日期星期数据时间格式:时-分-秒日期格式:年月日-星期C键:选择显示时间还是日期D键:循环选择所要编辑的位E键:编辑的位的数值加1F键:编辑的位的数值减1#include "msp430x14x.h"#define uint unsigned int#define uchar unsigned char#define SCLK_HIGH P3OUT|=BIT3#define SCLK_LOW P3OUT&=~BIT3#define RST_HIGH P3OUT|=BIT1#define RST_LOW P3OUT&=~BIT1#define IO_HIGH P3OUT|=BIT2#define IO_LOW P3OUT&=~BIT2#define IO_OUT P3DIR|=BIT2#define IO_IN P3DIR&=~BIT2#define IO_DA TA P3IN&BIT2uchar num=100;uchar TimeFlag=1; //显示日期时间标志uchar EditFlag=0; //闪烁显示标志uchar KeyValue=0xFF;uchar DNum=0; //D键按的次数//共阳数码管编码表const uchar Code[18]={0xC0,0xF9,0xA4,0xB0,//0,1,2,30x99,0x92,0x82,0xF8,//4,5,6,70x80,0x90,0x88,0x83,//8,9,A,b0xC6,0xA1,0x86,0x8E,//C,d,E,F0xBF,0xFF};//-,全灭//键值编码表const uchar KeyCode[16]={0x77,0x7B,0x7D,0x7E,//0,1,2,30xB7,0xBB,0xBD,0xBE,//4,5,6,70xD7,0xDB,0xDD,0xDE,//8,9,A,b0xE7,0xEB,0xED,0xEE};//C,d,E,Fuchar DS1302[8]={0,0,0,0,0,0,0,0}; //秒,分,时,日,月,星期,年uchar DateBit[8]={0,0,0,0,0,0,16,0}; //日期各位显示的数值uchar TimeBit[8]={0,0,16,0,0,16,0,0}; //时间各位显示的数值uchar BitCode=0x80; //数码管位码初值//时钟初始化函数void InitClock(void){BCSCTL1=RSEL2+RSEL1+RSEL0;//XT2开启LFXT1工作在低频模式ACLK不分频最高的标称频率DCOCTL=DCO2+DCO1+DCO0;//DCO为最高频率do{IFG1&=~OFIFG;//清除振荡器失效标志for(uint i=255;i>0;i--);}while(IFG1&OFIFG);//判断XT2是否起振BCSCTL2=SELM1+SELS;//MCLK SMCLK时钟源为TX2CLK 不分频}//端口初始化函数void InitPort(void){P1SEL=0x00;//P1口所有引脚设置为一般的IO口P1DIR=0x0F;//P1.0 P1.1 P1.2 P1.3设置为输出方向P1OUT=0x00;//P1口先输出低电平P1IE=0xF0;//P1.4 P1.5 P1.6 P1.7中断允许P1IES=0xF0;//P1.4 P1.5 P1.6 P1.7下降沿触发中断P3SEL=0x00;//P3口所有引脚设置为一般的IO口P3DIR=0x0E;//P3.1 P3.2 P3.3设置为输出方向P2SEL=0x00;//P2口所有引脚设置为一般的IO口P4SEL=0x00;//P4口所有引脚设置为一般的IO口P2DIR=0xFF;//P2口所有引脚设置为输出方向P4DIR=0xFF;//P4口所有引脚设置为输出方向P2OUT=0x00;//P2口先输出低电平P4OUT=0xFF;//P4口先输出低电平P5SEL&=~BIT7;//P5.7设置为一般的IO口P5DIR|=BIT7;//P5.7设置为输出方向P5OUT&=~BIT7;//P5.7输出低电平来使能74HC573来驱动数码管}//ms级延时子程序void DelayMs(uint ms){while(ms--){for(uint i=0;i<800;i++);}}//数码管扫描显示程序void Display(void){for(uchar i=0;i<8;i++){if(EditFlag==1&&DNum>0){ //判断是否闪烁 if(TimeFlag==0){ //判断日期还是时间闪烁switch(DNum){ //根据D 按的次数判断日期那一位闪烁 case 1:P4OUT=BitCode&0x3F;break; case 2:P4OUT=BitCode&0xCF;break; case 3:P4OUT=BitCode&0xF3;break; case 4:P4OUT=BitCode&0xFE;break; } }else{switch(DNum){ //根据D 按的次数判断时间那一位闪烁 case 1:P4OUT=BitCode&0x3F;break; case 2:P4OUT=BitCode&0xE7;break; case 3:P4OUT=BitCode&0xFC;break; } } }else{P4OUT=BitCode; //输出位码 }if(TimeFlag==1) P2OUT=Code[TimeBit[i]];//判断显示时间还是日期 else P2OUT=Code[DateBit[i]]; BitCode>>=1;//位码右移一位 if(BitCode==0) BitCode=0x80; DelayMs(1); //延时1ms P2OUT=0xFF; } }//10us 级延时子程序 void Delayus(uint us){ while(us--){for(uint i=0;i<800;i++); } }//按键分析程序 void KeyProcess(void){ uchar OutData=0x07;for(uchar i=0;i<4;i++){//扫描4列 OutData|=0xF0; P1OUT=OutData;if(P1IN!=OutData) KeyValue=P1IN; OutData>>=1; }P1OUT=0x00;//恢复原来的值 }//端口1中断处理程序#pragma vector=PORT1_VECTOR __interrupt void Port1INT(void){ for(uint i=1000;i>0;i--); KeyProcess();P1IFG=0x00;//清除中断标志位 }//向DS1302写一字节数据,address 为命令字节 void WriteByte(uchar Command,uchar WriteData){ uchar j,k=1; RST_LOW; SCLK_LOW; RST_HIGH; for(j=0;j<=7;j++){if(Command&k) IO_HIGH; else IO_LOW; SCLK_HIGH; k<<=1; SCLK_LOW; }k=1;for(j=0;j<=7;j++){if(WriteData&k) IO_HIGH; else IO_LOW; SCLK_HIGH; k<<=1; SCLK_LOW; }RST_LOW; }//读取DS1302一字节数据,address 为命令字节 uchar ReadByte(uchar Command){ uchar i,k=1; RST_LOW; SCLK_LOW; RST_HIGH; for(i=0;i<8;i++){if(Command&k) IO_HIGH; else IO_LOW; SCLK_HIGH; k<<=1;if(i!=7) SCLK_LOW; } k=0;for(i=0;i<8;i++){k>>=1; SCLK_LOW; IO_IN;if(IO_DA TA) k|=0x80; IO_OUT; SCLK_HIGH; }RST_LOW; return(k); }//读取DS1302的秒,分,时,日,月,星期,年 void ReadDS1302(){ uchar i;for(i=0;i<=6;i++) DS1302[i]=ReadByte(0x80+2*i+1); //计算时间日期的各位要显示的数据 TimeBit[7]=DS1302[0]&0x0F; TimeBit[6]=DS1302[0]&0x70; TimeBit[6]>>=4;TimeBit[4]=DS1302[1]&0x0F; TimeBit[3]=DS1302[1]&0x70; TimeBit[3]>>=4;TimeBit[1]=DS1302[2]&0x0F; TimeBit[0]=DS1302[2]&0x30; TimeBit[0]>>=4;DateBit[5]=DS1302[3]&0x0F; DateBit[4]=DS1302[3]&0x30; DateBit[4]>>=4;DateBit[3]=DS1302[4]&0x0F; DateBit[2]=DS1302[4]&0x10; DateBit[2]>>=4;DateBit[7]=DS1302[5]&0x07; DateBit[1]=DS1302[6]&0x0F; DateBit[0]=DS1302[6]&0xF0; DateBit[0]>>=4; }//定时器A 初始化 void InitTimerA(void){ TACTL=TASSEL1+ID1+ID0+MC0+TACLR;//选择1/8SMCLK 增计数清除TARCCTL0=CCIE;//CCR0中断允许 比较模式 CCR0=10000;//时间间隔10ms }//定时器A 中断#pragma vector=TIMERA0_VECTOR__interrupt void TimerAINT(void){ num--; if(num==0){EditFlag=!EditFlag; //更新闪烁标志 num=50; } }//时间编辑程序void TimeEdit(uchar flag){ uchar Data,NowData; if(flag){ //判断加1还是减1switch(DNum){ //判断编辑时间的哪一位 case 1:{Data=ReadByte(0x85); //读取小时数据 NowData=Data+1;if((NowData&0x0F)>9) NowData=NowData+6; if(NowData>=0x24) NowData=0;WriteByte(0x84,NowData); //写入小时数据 break; } case 2:{Data=ReadByte(0x83); //读取分数据 NowData=Data+1;if((NowData&0x0F)>9) NowData=NowData+6; if(NowData>=0x60) NowData=0; WriteByte(0x82,NowData); //写入分数据 break; } case 3:{Data=ReadByte(0x81); //读取秒数据 NowData=Data+1;if((NowData&0x0F)>9) NowData=NowData+6; if((NowData&0x7F)>=0x60) NowData=0;WriteByte(0x80,(NowData&0x7F)|(Data&0x80)); //写入秒数据 break; } }}else{ switch(DNum){ //判断编辑时间的哪一位 case 1:{Data=ReadByte(0x85); //读取小时数据 if(Data==0){ NowData=0x23; }else{NowData=Data-1;if((NowData&0x0F)>9) NowData=NowData-6;}WriteByte(0x84,NowData); //写入小时数据break;}case 2:{Data=ReadByte(0x83); //读取分数据if(Data==0){NowData=0x59;}else{NowData=Data-1;if((NowData&0x0F)>9) NowData=NowData-6;}WriteByte(0x82,NowData); //写入分数据break;}case 3:{Data=ReadByte(0x81); //读取秒数据if(Data==0){NowData=0x59;}else{NowData=Data-1;if((NowData&0x0F)>9) NowData=NowData-6;}WriteByte(0x80,(NowData&0x7F)|(Data&0x80)); //写入秒数据break;}}}}//日期编辑程序void DateEdit(uchar flag){uchar Data,NowData;if(flag){ //判断加1还是减1switch(DNum){ //判断编辑日期的哪一位case 1:{ //年加1Data=ReadByte(0x8d); //读取年数据NowData=Data+1; //年加1if((NowData&0x0F)>9) NowData=NowData+6; //BCD调整if(NowData>=0xA0) NowData=0; //年>=100时,年=0 WriteByte(0x8c,NowData); //年写入DS1302break;} case 2:{Data=ReadByte(0x89); //读取月数据NowData=Data+1; //月加1if((NowData&0x0F)>9) NowData=NowData+6; //BCD调整if(NowData>=0x13) NowData=1; //月>=13,月=1 WriteByte(0x88,NowData); //月写入DS1302break;}case 3:{Data=ReadByte(0x87); //读取日数据NowData=Data+1; //日加1if((NowData&0x0F)>9) NowData=NowData+6; //BCD调整if(NowData>=0x32) NowData=1; //日>=32,日=1 WriteByte(0x86,NowData); //日写入DS1302break;}case 4:{Data=ReadByte(0x8B); //读取星期数据NowData=Data+1; //星期加1if(NowData>=8) NowData=1; //星期>=8,星期=1 WriteByte(0x8A,NowData); //星期写入DS1302break;}}}else{switch(DNum){case 1:{ //年减1Data=ReadByte(0x8d); //读取年数据if(Data==0){NowData=0x99; //如果年=0,减1则为99}else{NowData=Data-1; //年减1if((NowData&0x0F)>9) NowData=NowData-6; //BCD调整}WriteByte(0x8c,NowData); //年写入DS1302break;}case 2:{Data=ReadByte(0x89); //读取月数据NowData=Data-1; //月减1if((NowData&0x0F)>9) NowData=NowData-6; //BCD调整if(NowData==0) NowData=0x12; //月=0,月=12 WriteByte(0x88,NowData); //月写入DS1302break;}case 3:{Data=ReadByte(0x87); //读取日数据NowData=Data-1; //日减1if((NowData&0x0F)>9) NowData=NowData-6; //BCD调整if(NowData==0) NowData=0x31; //日=0,日=31WriteByte(0x86,NowData); //日写入DS1302break;}case 4:{Data=ReadByte(0x8B); //读取星期数据NowData=Data-1; //星期减1if(NowData==0) NowData=7; //星期=0,星期=7WriteByte(0x8A,NowData); //星期写入DS1302break;}}}}//按钮功能函数void KeyFun(void){switch(KeyValue){case 0xE7:{//C键按下切换显示日期还是时间TimeFlag=!TimeFlag;DNum=0;KeyValue=0xFF;break;}case 0xEB:{ //D键按下,DNum加1DNum++;if((TimeFlag==0)&&(DNum>=5)) DNum=0; //如果当前编辑的是日期并且DNum>=5,则编辑完毕,返回正常状态if((TimeFlag==1)&&(DNum>=4)) DNum=0; //如果当前编辑的是时间并且DNum>=4,则编辑完毕,返回正常状态KeyValue=0xFF;break;}case 0xED:{ //E键按下,所选位加1if(TimeFlag==1) TimeEdit(1); //判断编辑日期还是时间else DateEdit(1);KeyValue=0xFF;break;}case 0xEE:{ //F键按下,所选位减1 if(TimeFlag==1) TimeEdit(0); //判断编辑日期还是时间else DateEdit(0);KeyValue=0xFF;break;}}}void main(){WDTCTL=WDTPW+WDTHOLD;//关闭看门狗InitClock();InitPort();InitTimerA();_EINT();//打开中断WriteByte(0x80,ReadByte(0x81)&0x7F); //启动DS1302while(1){KeyFun();ReadDS1302();Display();}}6 ADC12电压测量实验功能:在数码管上显示P6.0输入的电压参考电压为外部#include "msp430x14x.h"#define uint unsigned int#define uchar unsigned char#define ulong unsigned long//共阳数码管编码表uchar Code[18]={0xC0,0xF9,0xA4,0xB0,//0,1,2,30x99,0x92,0x82,0xF8,//4,5,6,70x80,0x90,0x88,0x83,//8,9,A,b0xC6,0xA1,0x86,0x8E,//C,d,E,F0xBF,0xFF};//-,全灭uchar Bit[8]={0,0,0,0,0,0,0,0}; //数码管各位显示的数字uchar BitCode=0x80; //数码管位码初值uint ADCBuf[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//保存采集到的数据ulong Sum=0;//20个数据的和ulong VBuf=0;//电压扩大10000000的值uchar Count=0;//时钟初始化函数void InitClock(void){BCSCTL1=RSEL2+RSEL1+RSEL0;//XT2开启LFXT1工作在低频模式ACLK不分频最高的标称频率DCOCTL=DCO2+DCO1+DCO0;//DCO为最高频率do{IFG1&=~OFIFG;//清除振荡器失效标志for(uint i=255;i>0;i--);}while(IFG1&OFIFG);//判断XT2是否起振BCSCTL2=SELM1+SELS;//MCLK SMCLK时钟源为TX2CLK不分频}//端口初始化函数void InitPort(void){P2SEL=0x00;//P2口所有引脚设置为一般的IO口P4SEL=0x00;//P4口所有引脚设置为一般的IO口P2DIR=0xFF;//P2口所有引脚设置为输出方向P4DIR=0xFF;//P4口所有引脚设置为输出方向P2OUT=0x00;//P2口先输出低电平P4OUT=0xFF;//P4口先输出低电平P5SEL&=~BIT7;//P5.7设置为一般的IO口P5DIR|=BIT7;//P5.7设置为输出方向P5OUT&=~BIT7;//P5.7输出低电平来使能74HC573来驱动数码管}//ms级延时子程序void DelayMs(uint ms){while(ms--){for(uint i=0;i<800;i++);}}//数码管扫描显示程序void Display(void){for(uchar i=0;i<8;i++){P4OUT=BitCode; //输出位码if(i==0){ //输出段码,如果第三位显示小数点P2OUT=Code[Bit[i]]&0x7F;}else{P2OUT=Code[Bit[i]];}BitCode>>=1;//位码右移一位if(BitCode==0) BitCode=0x80; DelayMs(1); //延时1msP2OUT=0xFF;}}//ADC12初始化void InitADC12(void){P6SEL=0x01;//P6.0为模拟输入ADC12CTL0&=~ENC;//ENC设置为0从而修改ADC12寄存器ADC12MCTL0=INCH_0+SREF_2+EOS;//参考电压为VeREF+和A Vss 输入通道A0ADC12CTL1=CSTARTADD_0+SHP+CONSEQ_2+ADC12SSEL_0+ ADC12DIV_0;//起始地址ADCMEM0,采样脉冲由采样定时器产生,单通道多次转换,内部时钟源不分频ADC12CTL0=MSC+ADC12ON;//采样信号由SHI仅首次触发,打开ADC12模块}//计算电压值void GetV(void){for(uchar i=0;i<20;i++) Sum+=ADCBuf[i];VBuf=Sum/20.0*((2.5*10000000)/4095.0);//计算电压并扩大10000000倍2.5为外部参考电压可用R4调节Sum=0;//计算数码管各位要显示的数值Bit[0]=VBuf/10000000;Bit[1]=VBuf%10000000/1000000;Bit[2]=VBuf%1000000/100000;Bit[3]=VBuf%100000/10000;Bit[4]=VBuf%10000/1000;Bit[5]=VBuf%1000/100;Bit[6]=VBuf%100/10;Bit[7]=VBuf%10;}//定时器A初始化void InitTimerA(void){TACTL=TASSEL1+ID1+ID0+MC0+TACLR;//选择1/8SMCLK 增计数清除TARCCTL0=CCIE;//CCR0中断允许比较模式CCR0=20000;//时间间隔20ms}//定时器A中断#pragma vector=TIMERA0_VECTOR__interruptvoid TimerAINT(void) {ADC12CTL0&=~ENC; ADCBuf[Count]=ADC12MEM0; Count++; if(Count==20) { GetV(); Count=0; }ADC12CTL0|=ENC+ADC12SC;//使能ADC 转换 }void main(){WDTCTL=WDTPW+WDTHOLD;//关闭看门狗 InitClock(); InitPort(); InitTimerA(); InitADC12(); _EINT();//打开中断 while(1){ Display(); } }7 128*64图形液晶显示实验(RT12864) 功能:交替显示一幅图像和文字 #include "msp430x14x.h" #define uchar unsigned char #define uint unsigned int #define ulong unsigned long #define DELAY _NOP();_NOP();_NOP();_NOP();_NOP();_NOP();_NOP();_NOP();_NOP();_NOP();#define CD_HIGH P4OUT|=BIT1;DELAY; #define CD_LOW P4OUT&=~BIT1;DELAY; #define E_HIGH P4OUT|=BIT2;DELAY; #define E_LOW P4OUT&=~BIT2;DELAY; #define WR_HIGH P4OUT|=BIT4;DELAY; #define WR_LOW P4OUT&=~BIT4;DELAY; #define RD_HIGH P4OUT|=BIT5;DELAY; #define RD_LOW P4OUT&=~BIT5;DELAY;// ASCII 字模宽度及高度定义 #define ASC_CHR_WIDTH 8 #define ASC_CHR_HEIGHT 16 // ASCII 字模显示为8*16uchar gCurRow,gCurCol;// 当前行列存储行高16 点列宽8点 uchar KEY1=1,KEY2=0; uchar INCOM;uchar uPowArr[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};char turnf[8] = {7,6,5,4,3,2,1,0}; uchar ImageX[64*16]={};//一幅图像数据 //汉字数据*char ASC_MSK[1];typedef struct // 汉字字模数据结构 {char Index[2]; char Msk[32]; }typFNT_GB16; typFNT_GB16 GB_16[]= {};/************************************************/ /* 取当前行数据*/ // 当前行列存储行高16 点列宽8点 /************************************************/ uchar fnGetRow() {return(gCurRow); }/************************************************/ /* 取当前列数据*//************************************************/uchar fnGetCol(){return(gCurCol); }//延时子程序 void DelayMs(uint ms) {while(ms--) {for(uint i=0;i<800;i++); }}//时钟初始化函数 void InitClock(void) {BCSCTL1=RSEL2+RSEL1+RSEL0;//XT2开启 LFXT1工作在低频模式ACLK 不分频 最高的标称频率DCOCTL=DCO2+DCO1+DCO0;//DCO 为最高频率 do{IFG1&=~OFIFG;//清除振荡器失效标志 for(uint i=255;i>0;i--);}while(IFG1&OFIFG);//判断XT2是否起振 BCSCTL2=SELM1+SELS;//MCLK SMCLK 时钟源为TX2CLK 不分频}//端口初始化函数 void InitPort() {P1SEL=0x00;//P1口所有引脚设置为一般的IO 口P1DIR=0xFC;//P1.2 P1.3 P1.4 P1.5 P1.6 P1.7设置为输出方向 P1OUT=0xff;//P1口先输出高电平 P1IE=0x03;//P1.0 P1.1中断允许 P1IES=0x03;//P1.0 P1.1下降沿触发中断P2SEL=0x00;//P2口所有引脚设置为一般的IO 口 P4SEL=0x00;//P4口所有引脚设置为一般的IO 口 P2DIR=0xFF;//P2口所有引脚设置为输出方向 P4DIR=0xFF;//P4口所有引脚设置为输出方向 P2OUT=0x00;//P2口先输出低电平 P4OUT=0xFF;//P4口先输出高电平 }void KeyProcess() {if(P1IN|BIT0==0) KEY1=1; if(P1IN|BIT1==0) KEY2=1; }//端口1中断处理程序#pragma vector=PORT1_VECTOR __interrupt void Port1INT(void){ DelayMs(5); KeyProcess();P1IFG=0x00;//清除中断标志位 }//读状态字 void Lcdsta() {E_HIGH; P2DIR=0x00; CD_HIGH; RD_LOW; WR_HIGH; INCOM=P2IN; E_LOW; P2DIR=0xff; }/************************************************/ /* 状态位STA1,STA0判断读写指令和读写数据*/ /* 在读写数据或者写入命令前必须保证均为1 */ /************************************************/ void STA01() {uchar i; for(i=10;i>0;i--) {if((INCOM&0x03)==0x03) // 读取状态 {break; } } }/********************************************/ /* 检查STA2,如果STA2=1 为自动读状态*/ /*****************************************/ void STA2() {unsigned char i; for(i=10;i>0;i--) {if((INCOM&0x04)==0x04) {break; } } }/***********************************************//* 状态位STA3 判断STA3 = 1 数据自动写状态*//***********************************************/ void STA3(){unsigned char i;for(i=10;i>0;i--){if((INCOM&0x08)==0x08){break;}}}/************************************************/ /* 状态位STA6 判断STA6 =1 屏读/屏拷贝状态*//************************************************/ void STA6(){unsigned char i;for(i=10;i>0;i--){if((INCOM&0x40)==0x40){break;}}}/************************//* 写指令*//************************/void WriteCommand(uchar Command){STA01();E_HIGH;CD_HIGH;WR_LOW;P2OUT=Command;DELAY;E_LOW;}/************************//* 写数据*//************************/ void fnPR13(uchar Data){STA01();E_HIGH;CD_LOW;WR_LOW;P2OUT=Data;DELAY;DELAY;E_LOW;}/************************//* 写双参数的指令*//************************/void fnPR1(char Cmd1,char Cmd2,char Dat) {fnPR13(Cmd1);fnPR13(Cmd2);WriteCommand(Dat);}/************************//* 写单参数的指令*//************************/void fnPR11(char Cmd,char Dat){fnPR13(Cmd);WriteCommand(Dat);}/************************//* 写无参数的指令*//************************/void fnPR12(char Dat){WriteCommand(Dat);}/************************//* 设置当前地址RAM里*//************************/void fnSetPos(char urow,char ucol){。
msp430g2553的矩阵按键程序
IAR环境下的程序!矩阵按键在单片机设计中经常见到,下面给大家几个程序!如果有需求可以看看!矩阵按键,扫描下面程序是淘来的!#include<msp430g2553.h>/***************全局变量***************/unsigned char Key_Val;//存放键值void CtrlKey(unsigned char sw); //控制键盘开关//sw=0关sw=1开/*******************************************函数名称:Init_Keypad功能:初始化扫描键盘的IO端口参数:无返回值:无********************************************/void Init_Keypad(void){P1DIR = 0x0f;//P1.0~P1.3设置为输出状态,P1.4~P1.7输入状态(上拉H)P1OUT=0;P1IES =0xf0;//P1.7允许中断P1IE=0xf0;//P1.4~P1.7下降沿触发中断P1IFG=0;//中断标志清0Key_Val = 0;}/*******************************************函数名称:Check_Key功能:扫描键盘的IO端口,获得键值参数:无返回值:无********************************************/ //p14\5\6\7接上拉电阻/***************************************key_Val对应键值列:[p14][p15][p16][p17]↓↓↓↓行:[p13]→1234[p12]→5678[p10]→***************************************/void Check_Key(void){unsigned char row ,col,tmp1,tmp2;unsigned char keymap[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};//设置键盘逻辑键值tmp1 = 0x08;for(row = 0;row < 4;row++)//行扫描{P1OUT = 0x0f;//P1.0~P1.3输出全1P1OUT -= tmp1;//P1.0~p1.3输出四位中有一个为0tmp1 >>=1;if((P1IN & 0xf0)<0xf0)//是否P1IN的P1.4~P1.7中有一位为0{tmp2 = 0x10;// tmp2用于检测出哪一位为0for(col = 0;col < 4;col++)//列检测{if((P1IN & tmp2) == 0x00)//是否是该列,等于0为是{Key_Val = keymap[row*4 + col];//获取键值return;//退出循环}tmp2 <<= 1;// tmp2右移1位}}}}/*******************************************函数名称:delay延时约15ms,完成消抖功能参数:无返回值:t= tmp*5*clk根据使用时钟调整tmp值********************************************/void delay(void){unsigned int tmp;for(tmp = 12000;tmp > 0;tmp--);}/*******************************************函数名称:Key_Event功能:检测按键,并获取键值参数:无返回值:无********************************************/void Key_Event(void){unsigned char tmp;P1OUT =0;//设置P1OUT全为0,等待按键输入tmp = P1IN;//获取p1INif((tmp & 0xf0) < 0xf0)//如果有键按下{delay();//消除抖动Check_Key();//调用check_Key(),获取键值}}/***************************************************************** ****控制打开或者关闭键盘中断SW= 0:关闭;ELSE:打开***************************************************************** ****/void CtrlKey(unsigned char sw){if(sw==0)P1IE =0;//关闭端口中断elseP1IE =0xf0; //打开端口中断}/*端口1按键中断*/#pragma vector=PORT1_VECTOR__interrupt void Port(void){if((P1IFG&0xf0)!=0){Key_Event();if(Key_Val!=0)//键值!=0有键按下{CtrlKey(0);//关键盘中断}}P1IFG=0;P1OUT=0;//清中断标志}下面的程序是自己改了下,端口发生了变化!按键矩阵也发生了变化!/***************************************************************** ********************************************************************* *********************/#include<msp430g2553.h>/***************全局变量***************/unsigned char Key_Val;//存放键值void main(){WDTCTL=WDTPW+WDTHOLD;Init_Keypad();_BIS_SR(LPM3_bits + GIE); //最低功耗睡眠while(1);}/*******************************************函数名称:Init_Keypad功能:初始化扫描键盘的IO端口参数:无返回值:无********************************************/ void Init_Keypad(void){P1DIR = 0x38; //P1.0~P1.3设置为输出状态,P1.4~P1.7输入状态(上拉H)P1OUT=0;P1IES =0xC0;//P1.4~P1.7允许中断P1IE=0xC0;//P1.4~P1.7下降沿触发中断P1IFG=0;//中断标志清0Key_Val = 0;}/*******************************************函数名称:Check_Key功能:扫描键盘的IO端口,获得键值参数:无返回值:无********************************************/ //p13\14\15接上拉电阻/***************************************key_Val对应键值列:[p13][p14][p15]↓↓↓行:[p17]→123[p16]→456***************************************/void Check_Key(void){unsigned char row ,col,tmp1,tmp2;unsigned char keymap[] = {1,2,3,4,5,6};//设置键盘逻辑键值tmp1 = 0x08;//从(xx1xxx相左移)for(row = 0;row < 3;row++)//列扫描{P1OUT = 0x38;//P1.3~P1.5输出全1P1OUT -= tmp1;//P1.3~p1.5输出四位中有一个为0tmp1 <<=1;if((P1IN & 0xC0)<0xC0)//是否P1IN的P1.4~P1.7中有一位为0{tmp2 = 0x80;// tmp2用于检测出哪一位为0for(col = 0;col < 2;col++)//行检测{if((P1IN & tmp2) == 0x00)//是否是该列,等于0为是{Key_Val = keymap[row*4 + col];//获取键值return;//退出循环}tmp2 >>= 1;// tmp2右移1位}}}}/*******************************************函数名称:delay功能:延时约15ms,完成消抖功能参数:无返回值:t= tmp*5*clk根据使用时钟调整tmp值********************************************/void delay(void){unsigned int tmp;for(tmp = 12000;tmp > 0;tmp--);}/*******************************************函数名称:Key_Event功能:检测按键,并获取键值参数:无返回值:无********************************************/ void Key_Event(void){unsigned char tmp;P1OUT =0;//设置P1OUT全为0,等待按键输入tmp = P1IN;//获取p1INif((tmp & 0xf0) < 0xf0)//如果有键按下{delay();//消除抖动Check_Key();//调用check_Key(),获取键值}}#pragma vector=PORT1_VECTOR__interrupt void Port(void){delay();if((P1IN&0XC0)<0XC0){Check_Key();switch(Key_Val){case 1:{;自己接相应按键的功能break;}case 2:{;自己接相应按键的功能break;}case 3:{;自己接相应按键的功能break;}case 4:{;自己接相应按键的功能break;}case 5:{;自己接相应按键的功能break;}case 6:{;自己接相应按键的功能break;}default:break;}}P1IFG=0;//清中断标志}下面这个按键用了数组了,存放按键的值,可以应用于密码锁之类的应用!为网上淘来/********************************************************************* ********************************************************************* ******************///此示例程序为中断方式,得到键盘的键值,存放在队列keybuff[10]中//此示例程序没有显示,//键盘的按键按下引起P1口的中断服务程序,得到键盘的键值,保存到键值队列//在其他的中断服务程序中通过键值队列中的数据引导程序的流程#include <msp430x14x.h>unsigned char keybuff[10];unsigned char keypoint=0;void delay(int v){while(v!=0)v--;}unsigned char key(void){unsigned char x=0xff;P1DIR=0X0F;P1OUT=0X01;//扫描第一行if((P1IN&0X70)==0X10)x=0;elseif((P1IN&0X70)==0X20)elseif((P1IN&0X70)==0x40)x=2;else{P1OUT=0X2;//扫描第二行if((P1IN&0X70)==0X10)x=3;elseif((P1IN&0X70)==0X20)x=4;elseif((P1IN&0X70)==0x40)x=5;else{P1OUT=0X4;//扫描第三行if((P1IN&0X70)==0X10)x=6;elseif((P1IN&0X70)==0X20)x=7;elseif((P1IN&0X70)==0x40)else{P1OUT=8;//扫描第四行if((P1IN&0X70)==0X10)x=9;elseif((P1IN&0X70)==0X20)x=10;elseif((P1IN&0X70)==0x40)x=11;}}}return(x);}unsigned char keyj(void){unsigned char x;P1DIR=0x0f;P1OUT=0x0f;//键盘硬件:P10--P13为行线,最上面一根为P10x=(P1IN&0X70);//P14--P16为列线,最左边一根为P14,列线下拉return(x);//无按键,返回0?;有按键返回非0}interrupt[PORT1_VECTOR] voidport1key(void){if(keyj()!=0X00){delay(300);//消抖动if(keyj()!=0X0){keybuff[keypoint]=key();//按键见键值保存到队列keypoint++;//if(keypoint==10)keypoint=0;}}P1OUT=0X0F;P1IFG=0X0;//清除中断标志}void main(void){WDTCTL = WDTPW + WDTHOLD;/*// Stop WDT */P1DIR=0XF;P1OUT=0XF;P1IES=0X0;P1IE=0X70;//列线上升沿允许P1中断_EINT();/*/ Enable interrupts*/while(1){LPM0;_NOP();}}这个是单个按键是,输入端的P1REN要设为1。
MSP430按键输入和led点阵显示解读
第4章键盘和显示器的应用在单片机应用系统中,键盘和显示器是非常重要的人机接口。
人机接口是指人与计算机系统进行信息交互的接口,包括信息的输入和输出。
常用输入设备主要是键盘,常用输出设备包括发光二极管、数码管和液晶显示器等。
4.1 键盘输入键盘用于实现单片机应用系统中的数据信息和控制命令的输入,按结构可分为编码键盘和非编码键盘。
编码键盘上闭合键的识别由专用的硬件编码器实现,并产生相应的键码值,如计算机键盘。
非编码键盘是通过软件的方法产生键码,不需要专用的硬件电路。
为了减少电路的复杂程度,节省单片机的I/O口,在单片机应用系统中广泛使用非编码键盘,主要对象是各种按键或开关。
这些按键或开关可以独立使用(称之为独立键盘),也可以组合使用(称之为矩阵式键盘)。
4.1.1 按键电路与按键抖动处理按键电路连接方法非常简单,如图4.1所示。
此电路用于通过外力使按键瞬时接通开关的场合,如单片机的RESET电路中,通过按键产生一个瞬时的低电压,CPU感知这个低电压后重启。
图4.1 按键复位电路由于按键的闭合与断开都是利用其机械弹性实现的,当机械触点断开、闭合时,会产生抖动,这种抖动操作用户感觉不到,但对CPU来说,其输出波形则明显发生变化,如图4.2所示。
图4.2 按键开、闭时的电压抖动波形按键按下和释放时的抖动时间一般为10~20ms ,按键的稳定闭合期由操作用户的按键动作决定,一般为几百毫秒到几秒,而单片机CPU的处理速度在微秒极,因此,按键的一次闭合,有可能导致CPU的多次响应。
为了避免这种错误操作,必须对按键电路进行去抖动处理。
常用的去抖动方法有硬件方式和软件方式两种。
使用硬件去抖动的方式,需要在按键连接的硬件设计上增加硬件去抖电路,比如将按键输出信号经过R-S 触发器或 RC 积分电路后再送入单片机,就可以保证按一次键只发出一个脉冲。
软件方式去抖动的基本原理是在软件中采用时间延迟,对按键进行两次测试确认,即在第一次检测到按键按下后,间隔 10ms 左右,再次检测该按键是否按下,只有在两次都测到按键按下时才最终确认有键按下,这样就可以避开抖动时间段,消除抖动影响。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
TACTL = TASSEL_2+TACLR;
CCTL0 = CCIE;
CCR0 = 8000;
TACTL |= MC_2;
BTCTL = 0x00; //不配置就总复位
clr_lcdmem();
_EINT();
{
WDTCTL = WDTPW + WDTHOLD;
LCDCTL= 0X5D;
P5SEL = 0XFD;
SCFI0 |= FN_2;
FLL_CTL0 = XCAP14PF;
SCFQCTL = 30;
case 0xBC:key_buff=8; key_cnt[key_buff]++;break;
case 0xDC:key_buff=9; key_cnt[key_buff]++;break;
case 0xEC:key_buff=11;key_cnt[key_buff]++;break;
LCDMEM[6]=lcd_table[key_buff];
LCDMEM[5]=0x04;
LCDMEM[0]=lcd_table[key_cnt[key_buff]%10];
LCDMEM[1]=lcd_table[(key_cnt[key_buff]-(key_cnt[key_buff]-(key_cnt[key_buff]%100)))/10];
default:clr_lcdmem();break;
}
key_display();
}
CCR0 += 8000;
}
//---------------------------------------------------------//
// K 1 2 3 # # 0 *
// K 4 5 6 0 3 6 9
// K 7 8 9 * 2 5 8
case 0xE6:key_buff=10;key_cnt[key_buff]++;break;
case 0x7A:key_buff=4; key_cnt[key_buff]++;break;
case 0xBA:key_buff=5; key_cnt[key_buff]++;break;
// 端口定义
// LCD显示型号:7位半48段 矩阵键盘4x3
// P1. 7 6 5 4 3 2 1
// in/out in/out in/out in/out out/in out/in out/in
// 备 注: 调用了键盘扫描,键值翻译,键值显示子程序。
//---------------------------------------------------------//
#pragma vector = TIMERA0_VECTOR
__interrupt void Timer_A (void)
// K 1 4 7
//
// S 0 1 2 ~ 14
// out out out out
static unsigned char flag;
static unsigned char key_buff,buffer,buffer1,buffer2,kb1,kb2;
static unsigned int key_cnt[12]={0,0,0,0,0,0,0,0,0,0,0,0};
while(1);
}
//---------------------------------------------------------//
// 功 能:TimerA溢出中断
// 入口参数: /
// 出口参数: /
// 全局变量: buffer、buffer1、buffer2、key_buff、key_cnt。
// 功 能:延时函数
// 入口参数:延时长度:m。
// 出口参数:/
// 全局变量:/
// 备 注:/
//---------------------------------------------------------//
void Delay(int m)
{
while(m-->0);
// s0 s1 s2 ~ s14
//
//com 0 1 2 3
// out out out out
// com0 com1 com2 com3
// 备 注:flag:0.2s标志 key_buff:显示键值 buffer:实际键值
// 备 注:buffer1:低四位键值 buffer2:高四位键值
// 备 注:kb1:按键按下标志1 kb2:按键按下标志2
//---------------------------------------------------------//
{
case 0x76:key_buff=1; key_cnt[key_buff]++;break;
case 0xB6:key_buff=2; key_cnt[key_buff]++;break;
case 0xD6:key_buff=3; key_cnt[key_buff]++;break;
}
//---------------------------------------------------------//
// 功 能:LCD清屏
// 入口参数: /
// 出口参数: /
// 全局变量: /
// 备 注: 初始化时使用。
//---------------------------------------------------------//
const unsigned char lcd_table[12]={
0x7B, // "0";2"
0x1F, // "3"
0x36, // "4"
0x3D, // "5"
0x7D, // "6"
0x13, // "7"
LCDMEM[4]=lcd_table[(key_cnt[key_buff]-(key_cnt[key_buff]-(key_cnt[key_buff]%100000)))/10000];
}
//---------------------------------------------------------//
LCDMEM[2]=lcd_table[(key_cnt[key_buff]-(key_cnt[key_buff]-(key_cnt[key_buff]%1000)))/100];
LCDMEM[3]=lcd_table[(key_cnt[key_buff]-(key_cnt[key_buff]-(key_cnt[key_buff]%10000)))/1000];
// 功 能:翻线法获取键值
// 入口参数: /
// 出口参数: /
// 全局变量: kb1、kb2、buffer1、buffer2.
// 备 注: 矩阵键盘扫描
//---------------------------------------------------------//
{
flag++;
if (flag==100)
{
flag=0;
scan_key();
buffer=buffer1|buffer2;
switch (buffer)
// 出口参数: /
// 全局变量: /
// 备 注: MCLK=DCO倍频至1MHz SMCLK=XT2=4MHz TimerA连续模式
//---------------------------------------------------------//
void main(void)
void clr_lcdmem(void)
{
int i;
for(i = 0;i<7;i++)
{
LCDMEM[i] = 0x00;
}
}
//---------------------------------------------------------//
// 功 能:键值、按键次数显示
#include "msp430x44x.h"
void Delay(int m);
void clr_lcdmem(void);
void key_display (void);
void scan_key(void);
//=========================================================//
// 入口参数: /
// 出口参数: /
// 全局变量: key_buff、key_cnt。
// 备 注:
//---------------------------------------------------------//
void key_display (void)
{
LCDMEM[7]=0x00;
//=========================================================//