硬件连接:
P14~P10:手机MP3用5维导航按键,分别为RIGHT、DOWN、LEFT、MENU、UP键,采用下降沿中断
P37~P34:LED,置位则亮
外接32768Hz无源晶振
COM0~3、S0~S39外接160段LCD,4MUX,1/3BIAS,3.3V
P62:外接有源蜂鸣器,置位则响
//软件调试已通过,连续走秒12小时误差不超过1秒*
//*以CASIO G-SHOCK手表为准
//额定电压3.3~3.4V,过低的电压会导致走秒变慢
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "msp430x44x.h" | |
unsigned char place=2,buff=0,time_c=0,time_s=0; | |
unsigned char tab_time[3]={30,25,21},max_time[3]={59,59,23}; | |
#define sec tab_time[0] | |
#define min tab_time[1] | |
#define hrs tab_time[2] | |
const char tab_num[]= | |
{ | |
0xaf,0x06,0x6d,0x4f, | |
0xc6,0xcb,0xeb,0x0e, | |
0xef,0xcf,0xee,0xe3, | |
0x61,0x67,0xe9,0xe8, | |
}; | |
#define a 0x10 | |
#define b 0x20 | |
#define c 0x40 | |
#define d 0x80 | |
#define e 0x1 | |
#define f 0x2 | |
#define g 0x4 | |
#define h 0x8 | |
const char tab_asc[]= | |
{ | |
a+e+f+d+c, f, e+c+f+h+d, 0, c+f+h, 0, c+f+h+d, f, //abcd | |
a+e+c+f+h,0, a+e+c+f, 0, a+e+h+c+d, f, e+c+f+d, f, //efgh | |
d, f, d+h, f, d, f+e+h, e+f+h,0, //ijkl | |
e+f+a+d, f+a+b+c, e+f+b, b+c+h, c+f+h+d, 0, a+e+f+c, f, //mnop | |
a+e+d+c, f+d, d, a+f+b+g+h,a+e+c+d+h, 0, a+d, a+f, //qrst | |
e+f+h+d, f, e+f+g, e, e+f+h+d, f+d+b+c, b+g, e+h, //uvwx | |
b+d, e, c+g+h, 0 //yz | |
}; | |
void delay(unsigned int x) | |
{ | |
while(x--); | |
} | |
void clrlcd(void) | |
{ | |
unsigned char i; | |
for (i=0; i<20; i++)LCDMEM[i] = 0x00; // Clear LCD memory to clear display | |
} | |
void display_asc(char *str,unsigned char n) | |
{ | |
unsigned char i,k=8,temp; | |
if(n<=6) | |
for(i=0;i<n;i++) | |
{ | |
temp=(str[i]-'A')<<1; | |
LCDMEM[k++]=tab_asc[temp++]; | |
LCDMEM[k++]=tab_asc[temp]; | |
} | |
} | |
void main( void ) | |
{ | |
//系统初始化Sysyem Intialize | |
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer to prevent time out reset | |
FLL_CTL0 |= XCAP14PF; // Configure load caps | |
delay(10000); // Delay for 32 kHz crystal tostabilize | |
//液晶初始化LCD Initialize | |
//基本定时器初始化Basic Timer Initialize | |
LCDCTL = 0xFD; // 4-Mux LCD, segments S0-S39 | |
BTCTL = BTDIV+BTFRFQ1+BTIP2+BTIP0; //置位BTDIV让BTCNT1与BTCNT2联动 | |
//使用BTFRFQ设定LCD刷新频率;使用BTIP设定BT中断频率 | |
P5SEL = 0xFC; // Select P5.2-7 as Com and Rxx for LCD | |
clrlcd(); | |
//按键侦测初始化KEY Initialize | |
P1DIR &= 0xE0; //P10~P14输入 | |
P1IES = 0x1F; //下降沿中断 | |
P1IE = 0x1F; | |
P3OUT = 0xF0; P3DIR = 0xF0; | |
P6OUT = BIT2; P6DIR |= BIT2; | |
display_asc("HELLO",5); | |
delay(50000);delay(50000); | |
P6OUT = 0x00; P3OUT = 0x00; | |
//主程序开始MAIN PROGRAM BEGIN | |
clrlcd(); | |
LCDMEM[ 8]=0x90;LCDMEM[ 9]=0x12; //Display "TIME" | |
LCDMEM[10]=0x80;LCDMEM[11]=0x02; //显示“TIME” | |
LCDMEM[12]=0x93;LCDMEM[13]=0x72; | |
LCDMEM[14]=0x5B;LCDMEM[15]=0x94; | |
LCDMEM[7] = 0x0A; //显示时钟冒号 | |
_EINT(); //开启总中断 | |
IE2 |= BTIE; //开启BT中断 | |
loop: | |
if(time_s) //如果时间在走动 | |
{ | |
if(buff==BIT1)time_s ^= BIT0; //如果OK键按下,停止/继续走秒 | |
LCDMEM[7] ^= 0x0A; //时钟的冒号闪烁Blinking the ':' | |
if(time_c) //如果到每秒中断Every sec INT? | |
{ // | |
if(sec<59) //更新时间寄存器 | |
sec++; //change time rigister | |
else // | |
{ // | |
sec=0; // | |
if(min<59) // | |
min++; // | |
else // | |
{ // | |
min=0; // | |
if(hrs<23) // | |
hrs++; // | |
else // | |
hrs=0; // | |
} // | |
} // | |
LCDMEM[0]=tab_num[sec%10]; //时间刷新 | |
LCDMEM[1]=tab_num[sec/10]; //refresh time display | |
LCDMEM[2]=tab_num[min%10]; // | |
LCDMEM[3]=tab_num[min/10]; // | |
LCDMEM[4]=tab_num[hrs%10]; // | |
LCDMEM[5]=tab_num[hrs/10]; // | |
} // | |
} // | |
else //如果时间停止 | |
{ | |
if(time_c) //如果每秒中断,则清空当先设置位置的显示 | |
{ | |
LCDMEM[place*2] = 0x00; | |
LCDMEM[1+place*2] = 0x00; | |
} | |
else //如果半秒中断,则复原当前设置位置的显示 | |
{ //从而实现当先设置位置的闪烁 | |
LCDMEM[place*2] = tab_num[tab_time[place]%10]; | |
LCDMEM[1+place*2] = tab_num[tab_time[place]/10]; | |
} | |
switch(buff) | |
{ | |
case 0x01:tab_time[place]++; | |
if(tab_time[place]>max_time[place])tab_time[place]=0;break; | |
case 0x02:time_s ^= BIT0;break; | |
case 0x04:LCDMEM[place*2] = tab_num[tab_time[place]%10]; | |
LCDMEM[1+place*2] = tab_num[tab_time[place]/10]; //先善后,把当前位置数字显示 | |
place++;if(place==3)place=0;break; //再切换到高一位 | |
case 0x08:if(tab_time[place])tab_time[place]--; | |
else tab_time[place]=max_time[place];break; | |
case 0x10:LCDMEM[place*2] = tab_num[tab_time[place]%10]; //先善后,把当前位置数字显示 | |
LCDMEM[1+place*2] = tab_num[tab_time[place]/10]; //再切换到低一位 | |
if(place)place--;else place=2;break; | |
} | |
} | |
buff=0; //把键值复位,以免重复操作 | |
time_c ^=BIT0; //取反半秒/每秒中断标志 | |
LPM3; //进入LPM3休眠 | |
goto loop; | |
} | |
#pragma vector=BASICTIMER_VECTOR | |
__interrupt void btrefre(void) //每0.5秒中断一次 | |
{ | |
//IFG2 &= 0x7F; //BTIFG会被自动清零,无需软件清零 | |
LPM3_EXIT; | |
} | |
#pragma vector=PORT1_VECTOR | |
__interrupt void key(void) | |
{ | |
unsigned char temp; | |
P1IE ^= 0x1F; | |
P6OUT ^= BIT2; | |
delay(10000); //短暂延时防止抖动可能造成的重复中断 | |
buff=P1IN; //P1IN寄存器采样 | |
delay(500); //短暂延时后对P1IN寄存器重新采样 | |
temp=P1IN; //如果不一样说明存在抖动,本次按键忽略 | |
if((temp&0x1F)!=(buff&0x1F)){buff=0;goto error;} | |
buff ^= 0x1F; //后5位取反 | |
buff &= 0x1F; //只保留低5位 | |
delay(10000); //防止松开按键时的多次抖动,避免形成死循环或者中断嵌套 | |
for(temp=0;temp<20;temp++)while(P1IN<0x1F)delay(5000); | |
error: | |
P6OUT ^= BIT2; | |
P1IFG = 0x00; | |
P1IE ^= 0x1F; | |
LPM3_EXIT; | |
} |
没有评论:
发表评论