#include "msp430x44x.h"
#include "string.h"
//定义键值
//*****************************
#define cKB_1 0x12 //1
#define cKB_2 0x13 //2
#define cKB_3 0x14 //3
#define cKB_4 0x15 //4
#define cKB_5 0x16 //5
#define cKB_6 0x17 //6
#define cKB_7 0x18 //7
#define cKB_8 0x21 //8
#define cKB_9 0x22 //9
char table[]={
0x00,0xf8,0x48,0x48,0x48,0x48,0xff,0x48,
0x48,0x48,0x48,0xfc,0x08,0x00,0x00,0x00,
0x00,0x07,0x02,0x02,0x02,0x02,0x3f,0x42,
0x42,0x42,0x42,0x47,0x40,0x70,0x00,0x00};
char table1[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x42,0x42,0x42,0x47,0x40,0x70,0x00,0x00,
0x00,0xf8,0x48,0x48,0x48,0x48,0xff,0x48,
0x48,0x48,0x48,0xfc,0x08,0x00,0x00,0x00
};
static char page, col;
/////////////////////////////////////////////////////////////////////////////////////////
//本函数用于向LCD写一个字节数据
// 依赖性:无
// 前提条件:1。LCD有3片列驱动,由CS来选择,0≤ROW≤63时CS=1; 64≤Row≤127时CS=2; 128≤Row≤191时CS=3
// 2。LCD工作正常,能正确返回状态信息,否则程序会挂死
// 参数:CS为列驱动片选;DAT为待写入的数据
// 返回值:无
void WDAT (unsigned int cs,unsigned int dat)
{
char chip,RState;
switch(cs)
{
case 1:{
chip = 0x00|(P6OUT & 0xfc);
break;
}
case 2:{
chip = 0x01|(P6OUT & 0xfc);
break;
}
case 3:{
chip = 0x02|(P6OUT & 0xfc);
break;
}
}
RState = 0xFF;
P1OUT &= ~0x80; //E=0
P1OUT &= ~0x40; //RS=0
P6OUT = chip;
P2OUT |= 0x01; //R/W=1
P2OUT &=~0x04; //245 enable
P1OUT &= ~0x04; //DIR=0
P5DIR &= ~0xFF;
while((0x80 & RState)==0x80)
{
P1OUT |= 0x80; //E=1
RState = P5IN;
P1OUT &= ~0x80; //E=0
}
P1OUT |= 0x40; //RS=1
P2OUT &= ~0x01; //R/W=0
P1OUT |= 0x80; //E=1
P5OUT = dat;
P5DIR |= 0xFF;
P1OUT |= 0x04; //DIR=1
P1OUT &= ~0x80; //E=0
P6OUT |= 0x03; //no CS
P1OUT |= 0x80; //E=1
}
/////////////////////////////////////////////////////////////////////////////////////////
//本函数用于向LCD写一个命令字
// 依赖性:无
// 前提条件:1。LCD有3片列驱动,由CS来选择,0≤ROW≤63时CS=1; 64≤Row≤127时CS=2; 128≤Row≤191时CS=3
// 2。LCD工作正常,能正确返回状态信息,否则程序会挂死
// 参数:CS为列驱动片选;COM为待写入的命令字
// 返回值:无
void WCOM(unsigned int CS,unsigned int COM)
{
char RState;
char chip;
switch(CS)
{
case 1:{
chip = 0x00|(P6OUT & 0xfc);//1111 1100 第一片
break;
}
case 2:{
chip = 0x01|(P6OUT & 0xfc);//1111 1110 第三片
break;
}
case 3:{
chip = 0x02|(P6OUT & 0xfc);//1111 1101第二片
break;
}
}
RState = 0xFF;
P1OUT &= ~0x80; //E=0
P1OUT &= ~0x40; //RS=0
P6OUT = chip; //CS
P2OUT |= 0x01; //R/W=1 READ
P2OUT &=~0x04; //245 enable
P1OUT &= ~0x04; //DIR=0 B__A INPUT
P5DIR &= ~0xFF;
while((0x80 & RState)==0x80)
{
P1OUT |= 0x80; //E=1
RState = P5IN;
P1OUT &= ~0x80; //E=0
}
P2OUT &= ~0x01; //R/W=0 WRITE
P1OUT |= 0x80; //E=1
P5OUT = COM;
P5DIR |= 0xFF;
P1OUT |= 0x04; //DIR=1 A__B OUTPUT
P1OUT &= ~0x80; //E=0
P6OUT |= 0x03; // no CS
P1OUT |= 0x80; //E=1
}
//延时函数,这个随便写个循环就成,DelayTime即为延时的时间
void Delay(unsigned int DelayTime)
{
unsigned int i;
for (i = 0;i < DelayTime;i++);
}
//根据cScanVal的值获取按键的列号,cScanVal为ScanKeyboard()后获得的值
char LocateKeyRow(unsigned int cScanVal)
{
char RowCode;
switch (cScanVal) //键盘为5*8哦
{
case 0x7F: //0111 1111第一个为低,说明此行第一列的键被按下,以下雷同
{
RowCode = 0x01; //row1
break;
}
case 0xBF: //1011 1111
{
RowCode = 0x02; //row2
break;
}
case 0xDF:
{
RowCode = 0x03; //row3
break;
}
case 0xEF:
{
RowCode = 0x04; //row4
break;
}
case 0xF7:
{
RowCode = 0x05; //row5
break;
}
case 0xFB:
{
RowCode = 0x06; //row6
break;
}
case 0xFD:
{
RowCode = 0x07; //row7
break;
}
case 0xFE:
{
RowCode = 0x08; //row8
break;
}
case 0xFF: //没有键按下
{
RowCode = 0;
break;
}
default: //多健同时按下
{
RowCode = 0xFF;
break;
}
}
return RowCode; //返回列号
}
//扫描行 ,因为键盘为5*8,所以扫描5行,pLineArray存储扫描到的行信息
void ScanKeyboard(char *pLineArray)
{
//设置扫描键盘所需的硬件端口状态
P5DIR = 0; //P5端口设置为输入状态
P3DIR |= 0xe0; //设置P3.5、P3.6、P3.7设置为输出状态
P2DIR |= 0x02; //P2.1为键盘所用的245的Enable端(由于P2.1仅用于此目的,所以不需要考虑恢复状态)
P2OUT &= ~0x02; //使能总线驱动245
P3OUT = 0x60; //向HC138输出011使之在Y3上输出低电平
*pLineArray++ = P5IN;
P3OUT = 0x80; //向HC138输出100使之在Y4上输出低电平
*pLineArray++ = P5IN;
P3OUT = 0xa0; //向HC138输出101使之在Y5上输出低电平
*pLineArray++ = P5IN;
P3OUT = 0xc0; //向HC138输出110使之在Y6上输出低电平
*pLineArray++ = P5IN;
P3OUT = 0xe0; //向HC138输出111使之在Y7上输出低电平
*pLineArray++ = P5IN;
P2OUT |= 0x02; //关闭245 key 总线驱动
}
//根据ScanKeyboard和LocateKeyRow获得的行列值,组合成 cFirstKey;高四位为行值,低四位为列值;并返回
char ReadKeyboard()
{
char cTemp,cFirstKey;
char cLineStatus[5]; //记录五行值
cFirstKey = 0;
while(1)
{
memset(cLineStatus,0,5);
ScanKeyboard(cLineStatus);//扫描后,cLineStatus中记录了每一行的按键信息
cLineStatus[0] = LocateKeyRow(cLineStatus[0]);//扫描每一行,看所在行是否有键按下,并获得列值
cLineStatus[1] = LocateKeyRow(cLineStatus[1]);//同上
cLineStatus[2] = LocateKeyRow(cLineStatus[2]);
cLineStatus[3] = LocateKeyRow(cLineStatus[3]);
cLineStatus[4] = LocateKeyRow(cLineStatus[4]);
for (cTemp = 0;cTemp < 5;cTemp++)//因为是5行,所以...
{
//从LocateKeyRow中可知只有一行中有多个键被同时按下才会返回0xff
if (cLineStatus[cTemp] == 0xff)
continue;
if (cLineStatus[cTemp] != 0)
{
if (cFirstKey == 0)
cFirstKey = ((cTemp + 1) << 4) | cLineStatus[cTemp];
}
}
return cFirstKey;
}
}
//根据行列获得自定义键值
char SwitchKeyValue(void)
{
char NewKey, RetKeyVal;
NewKey = ReadKeyboard(); // 得到行列值,高四位为行值,低四位为列值
switch(NewKey)
{
case 0x47:
{
RetKeyVal = cKB_1; //1
break;
}
case 0x42:
{
RetKeyVal = cKB_2; //2
break;
}
case 0x46:
{
RetKeyVal = cKB_3; //3
break;
}
case 0x37:
{
RetKeyVal = cKB_4; //4
break;
}
case 0x32:
{
RetKeyVal = cKB_5; //5
break;
}
case 0x36:
{
RetKeyVal = cKB_6; //6
break;
}
case 0x27:
{
RetKeyVal = cKB_7; //7
break;
}
case 0x22:
{
RetKeyVal = cKB_8; //8
break;
}
case 0x26:
{
RetKeyVal = cKB_9; //9
break;
}
default: RetKeyVal = 0xFF; break;
}
return RetKeyVal;
}
void Display(char *word)
{
WCOM(1,page);
WCOM(1,col);
for(int i=0;i<32;i++)
{
WDAT(1,table[i]);
if(i==15)
{
page++;
WCOM(1,page);
WCOM(1,col);
}
}
page--;
col=col+16;
if((col-0x40)%64==0) {col = 0x40; page=page+2;}
}
void InitLCD ()
{
P5OUT |= 0xFF;
P5DIR |= 0xFF; //DB0_DB7 P5为LCD的输入端
P1OUT |= 0x04;
P1DIR |= 0x04; //P1.2__245DIR=1 A__B OUTPUT
P1OUT &= ~0x40;
P1DIR |= 0x40; //P1.6__RS=0 instruction code
P1OUT |= 0x80;
P1DIR |= 0x80; //P1.7__E=1 unable
P2OUT &= ~0x01;
P2DIR |= 0x01; //P2.0__R/W=0 write
P2OUT &= ~0x04;
P2DIR |= 0x04; //P2.2__245 OE=0 enable
P6OUT &= ~0x00;
P6DIR |= 0x03; //作为片选,11为没有CS,disable any block of LCD
WCOM(1,0xC0); //0xC0 设置列起始位置
WCOM(2,0xC0);
WCOM(3,0xC0);
WCOM(1,0x3F); //设置起始页 参见上一篇说明书哦
WCOM(2,0x3F);
WCOM(3,0x3F);
P2OUT |= 0x0E; //display 245 unable
}
void ClearScreen(void)
{
page=0xb8;
col=0x40;
for(int i=0;i<8;i++)
{
for(int j=0;j<192;j++)
{
if(j<64)
{
if(j==0)
{
WCOM(1,page);
WCOM(1,col);
}
WDAT(1,0x00);
}
else if(j<128)
{
if(j==64)
{
WCOM(3,page);
WCOM(3,col);
}
WDAT(3,0x00);
}
else
{
if(j==128)
{
WCOM(2,page);
WCOM(2,col);
}
WDAT(2,0x00);
}
}
page++;
col=0x40;
}
}
void main(void)
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
P2OUT |= 0x0E; //P2.1 245key ;P2.2 245DIS; P2.3 245PRN
P2DIR |= 0x0E; // three 245 unable
//本函数用于初始化LCD
InitLCD();
P3DIR |= 0xE0; // p3.5 p3.6 p3.7 3-8 DECODER
P3OUT |= 0xE0;
P1DIR |= BIT1; //设置p1.2为输出,接蜂鸣器
TACCTL0 |= CCIE;//使能比较中断
TACTL|=TASSEL0+MC_1;//选择时钟源ACLK(32768HZ)
_EINT();
ClearScreen();
page = 0xb8;
col = 0x40;
while(1)
{
switch(SwitchKeyValue())
{
case cKB_1: P1DIR|=BIT1;TACCR0=31;Display(table);Delay(30000);break; //dao
case cKB_2: P1DIR|=BIT1;TACCR0=28;Display(table);Delay(30000);break; //re
case cKB_3: P1DIR|=BIT1;TACCR0=25;Display(table);Delay(30000);break; //mi
case cKB_4: P1DIR|=BIT1;TACCR0=23;Display(table);Delay(30000);break; //fa
case cKB_5: P1DIR|=BIT1;TACCR0=21;Display(table);Delay(30000);break; //sao
case cKB_6: P1DIR|=BIT1;TACCR0=19;Display(table);Delay(30000);break; //la
case cKB_7: P1DIR|=BIT1;TACCR0=17;Display(table);Delay(30000);break; //xi
case cKB_8: P1DIR|=BIT1;TACCR0=16;Display(table);Delay(30000);break; //gao dao
default: P1DIR &= ~BIT1; break;
}
}
}
//定时器A中断服务程序
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A(void)
{
P1OUT^=BIT1;//取反,产生方波反
}