历史上的今天
今天是:2025年03月01日(星期六)
2020年03月01日 | msp430使用OLED实现数字钟
2020-03-01 来源:eefocus
本次实验使用msp430及一块扩展板实现数字钟系统,扩展板上有一块OLED屏幕与4x4矩阵键盘,此外还有一些led指示灯,如下图所示:

最终实现的效果如下图所示:

可以看到有一个动态的开机界面,细心的同学还会发现右上角是一个月亮图案,白天可是会变成太阳哦~

系统采用了层级设置界面的方式,使用状态标志记录当前显示界面。将显示与数据运算分层,使代码逻辑清晰易懂。



main函数代码如下:
#include #include "libinterfacePaint.h" #include "libinit.h" #include "liboledoled.h" #include "liboledbmp.h" void Key_Head(); void run_time(); void run_date(); void make_date_legal(); int time_d = 0;//分频计数器 int h = 23, m = 59, s = 50;//时分秒 int y = 2017, mon = 12, d = 31;//出生日期为该天,计算多少天后的天数只需要用 (年-2018)+月天数+日天数 即可 //闹钟存储数组,5个闹钟, //分别存储 h,m,s,off(0)/on(1)s int alarms[5][4] = { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} }; //界面字符串缓存,init时即初始化,闹钟设置选择界面使用 char set_alarm_string[25] = "1OFF 2OFF 3OFF 4OFF 5OFF"; int alarm_on = 0; int alarm_count = 0; //状态标志:0:走钟;1:设置;2:时间设置界面;3:日期设置界面;4:闹钟设置选择界面;41~45:第x个闹钟设置界面 unsigned int state = 0; int time_mode = 1; // 12/24显示模式切换,1:表示24小时,0:表示12小时 int row_max = 1;//最大行数,移动行时使用 int choice_row = 1;//标志行,设置是标志位置使用 int key_delay = 0;//按键消抖,每10ms扫描键盘,一旦按键,计时开始,150ms后恢复 int reading = 0;//是否按下键 int scount = 0;//动画移动计数 unsigned char clearbmp[768]={0}; void main(void) { WDTCTL = WDTPW+WDTHOLD; //测试时钟频率使用 P1DIR |= BIT1; P1OUT |= BIT1; init_clock_XT2(); init_timerA(); init_keyboard(); init_led(); init_oled(); //初始化显示日期,因为日期刷新不频繁,故需要在此、在返回主界面、设置完毕、run_date()后执行 show_date(y, mon, d); //使时间与日期同时出现 show_time(h,m,s); OLED_DrawBMP(0, 1, 98, 24, clouds); if(h<6 || h>21) OLED_DrawBMP(110, 0, 126, 16, moon); else OLED_DrawBMP(110, 0, 126, 16, sun); _enable_interrupts(); LPM0; //while(1); } //timer_a定时器中断,中断时间是0.001s #pragma vector = TIMER0_A0_VECTOR __interrupt void TIMER0_A0_ISR(void){ //动画效果 if(state == 0 && time_d%21 == 0){ if(scount == 20){ scount=0; OLED_DrawBMP(0, 1, 98, 24, clouds); OLED_DrawBMP(98, 0, 130, 24, clearbmp); if(h<6 || h>21) OLED_DrawBMP(110, 0, 126, 16, moon); else OLED_DrawBMP(110, 0, 126, 16, sun); }else{ OLED_DrawBMP(0+scount, 1, 98+scount, 24, clouds); if(h<6 || h>21) OLED_DrawBMP(110, 0, 126, 16, moon); else OLED_DrawBMP(110, 0, 126, 16, sun); } scount++; } //1s计时器 if(time_d == 100){ run_time(); switch(state){ case 0://时钟界面 if(time_mode) show_time(h,m,s); else show_time12(h,m,s); break; case 1:setting_glisten(choice_row);break;//设置界面,闪烁选中行 case 2:time_set_glisten(choice_row,h,m,s);break;//时间设置界面,闪烁选中数字 case 3:date_set_glisten(choice_row,y,mon,d);break;//日期设置界面,闪烁选中数字 case 4:show_alarm_set_glisten(choice_row);break;//闹钟设置选择界面 case 41:case 42:case 43:case 44: case 45: alarm_set_glisten(choice_row, alarms, state); break; default:break; } if(h==0 && m==0 && s==0){ run_date(); if(state == 0) show_date(y, mon, d); } if(alarms[0][3] && alarms[0][0] == h && alarms[0][1] == m && alarms[0][2] == s){ alarm_on = 1; alarm_count = 0; } if(alarms[1][3] && alarms[1][0] == h && alarms[1][1] == m && alarms[1][2] == s){ alarm_on = 2; alarm_count = 0; } if(alarms[2][3] && alarms[2][0] == h && alarms[2][1] == m && alarms[2][2] == s){ alarm_on = 3; alarm_count = 0; } if(alarms[3][3] && alarms[3][0] == h && alarms[3][1] == m && alarms[3][2] == s){ alarm_on = 4; alarm_count = 0; } if(alarms[4][3] && alarms[4][0] == h && alarms[4][1] == m && alarms[4][2] == s){ alarm_on = 5; alarm_count = 0; } time_d = 0; //测试时钟频率使用 P1OUT ^= BIT1; } //闹钟闪烁 if(alarm_on != 0 && time_d%50 == 0){ alarm_count++; switch(alarm_on){ case 1:P6OUT ^= BIT0;break; case 2:P6OUT ^= BIT1;break; case 3:P6OUT ^= BIT2;break; case 4:P6OUT ^= BIT3;break; case 5:P6OUT ^= BIT4;break; default:break; } if(alarm_count == 120){ alarm_count = 0;//计数清零 alarm_on = 0;//关闭闪烁 P6OUT |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7;//熄灯 } } //每10ms扫描键盘,但读取后等待200ms后才能重新读取 if(key_delay > 20){ key_delay=0; reading = 0;} //键盘扫描 ,f=100Hz Key_Head(); if(reading == 1) key_delay++; //分频计数器 time_d++; } volatile unsigned char KeyVal; //键值 volatile unsigned char CF[4], Cont[4]; const unsigned char KeyOut[4] = { 0xef, 0xdf, 0xbf, 0x7f }; //4X4按输出端控制 void Key_Head() { static unsigned int ReadData[4]; unsigned int i; for (i = 0; i < 4; i++) { P4OUT = KeyOut[i] | 0x0f; //忽略低4位 ReadData[i] = (P4IN | 0xf0) ^ 0xff; if(key_delay == 0){//按键消抖 reading=1;//按下标志 /*按键设置: * A:前移 10 * B:后移 11 * C:停止闹钟 12 * D:12/24切换、闹钟on/off切换 13 * E:确认(进入设置界面) 14 * F:返回 15 * 其他:数字输入 */ KeyVal = (ReadData[i]&0x01)*0 + (ReadData[i]&0x02)/2 + (ReadData[i]&0x04)/2 + (ReadData[i]&0x08)/8*3 + i*4; if(ReadData[i]){ switch(KeyVal){ case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9: if(state == 2){//设置时间 switch(choice_row){ case 1: if(KeyVal>2) KeyVal=2; h=h%10+KeyVal*10; break; case 2: if(h/10 == 2 && KeyVal > 3) KeyVal=3; h=h/10*10+KeyVal; break; case 3: if(KeyVal>5) KeyVal=5; m=m%10+KeyVal*10; break;
史海拾趣
|
由于汽车需要面对多种不同的路面及驾驶情况,因此车内的电子系统必须采用多种不同的网络标准,才可满足不同的性能要求。为了更好地满足不同网络标准的要求,车内电子系统的互连网络便一直朝着网中网模式的路向发展。网中网模式基本上以远程信息控制 ...… 查看全部问答> |
|
目前系统已经能够正常挂载和失败BINFS分区,当BINFS分区中只有一个文件时(比如放置NORFLASH驱动),系统能够启动且正确加载NORFLASH驱动。下面是启动日志 Booting kernel with clean memory configuration: Memory Sections: [0] : start: 8e78 ...… 查看全部问答> |
|
求教Mipsel USB功能控制器模拟PL2303串口芯片的问题 问题如题: 现象如下: USB 功能控制器有数据发出, 但主机串口助手无法接收到数据, 也就是说PL2303的驱动层在进行转换时不能完成这个功能, 收发的PIPE与PL2303一至, 配置也基本一致。 以下是模拟芯片与PL2303芯片的实际捕获的数据。 … 查看全部问答> |
|
大家好,小弟想调查一下现在画梯形图哪种PLC软件用得多啊?西门子?三菱?还是欧姆龙啊?哪个年龄段用的哪 种软件啊? 分别都是用于哪方面的控制? 谢谢了!… 查看全部问答> |
|
富士通FM3的多功能串口(MFS)功能很强,应用也很灵活,具体可看我前面的帖子《MB9B506R多功能串行接口》。 功能强,应用灵活带来的负面因素就是软件复杂。 ...… 查看全部问答> |




