历史上的今天
返回首页

历史上的今天

今天是: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;

推荐阅读

史海拾趣

Bipolarics Inc公司的发展小趣事

Bipolarics Inc成立之初,专注于研发新型双极性晶体管技术。在经历了数年的实验室研究后,公司成功开发出一种性能卓越、功耗更低的新型晶体管。这一技术突破使得Bipolarics Inc的产品在市场上迅速获得了认可,公司开始扩大生产规模,满足不断增长的市场需求。随着市场份额的逐渐扩大,Bipolarics Inc逐渐成为了双极性晶体管领域的领军企业。

Cornell Dubilier公司的发展小趣事

面对日益激烈的市场竞争和不断变化的客户需求,Cornell Dubilier公司积极引进智能化生产设备和解决方案。例如,公司部署了Rethink Robotics的智能协作机器人,显著提高了生产效率和质量。通过与机器人技术的结合,Cornell Dubilier公司在电力电容制造领域取得了显著的成绩,实现了生产过程的自动化和智能化。

Gruner AG公司的发展小趣事
不同的光耦合器型号在CTR值、额定电压和电流、封装形式等方面可能有所不同,因此需要根据具体需求选择合适的型号。
CAMBION公司的发展小趣事

CAMBION公司自成立以来,始终将技术创新作为核心驱动力。在早期,公司研发团队成功开发了一款具有革命性的芯片技术,显著提升了电子设备的处理速度和能效。这一技术迅速在行业内引起关注,为CAMBION赢得了大量订单和合作伙伴。随着技术的不断完善和应用范围的扩大,CAMBION逐渐在电子行业中崭露头角。

Changzhou Galaxy Century Microelectronics Co.,Ltd公司的发展小趣事

在发展过程中,银河微电积极寻求与行业内外的合作伙伴建立战略合作关系。通过与晶通半导体(深圳)有限公司等企业的合作,银河微电在技术研发、市场拓展等方面取得了显著成效。这些战略合作不仅提升了公司的综合实力,还为公司的未来发展奠定了坚实的基础。

Aearo Technologies公司的发展小趣事

尽管Aearo Technologies在行业中享有盛誉,但近年来也面临了一些挑战。公司生产的一款名为“Combat Arms”的军用耳塞被指存在设计缺陷和质量问题,导致部分使用者听力受损。这一事件引发了广泛的关注和诉讼。面对这一挑战,Aearo Technologies积极应对,与相关部门合作进行调查,并采取了一系列措施改进产品质量和确保用户安全。

问答坊 | AI 解惑

可为汽车电子系统提供网络联系的灵活平台

由于汽车需要面对多种不同的路面及驾驶情况,因此车内的电子系统必须采用多种不同的网络标准,才可满足不同的性能要求。为了更好地满足不同网络标准的要求,车内电子系统的互连网络便一直朝着网中网模式的路向发展。网中网模式基本上以远程信息控制 ...…

查看全部问答>

pads2007

求PADS2007 layout 教程…

查看全部问答>

platform builder 5.0与win7兼容吗?

我想在win7上装platform builder 5.0,请问它能在win7下正常运行吗?…

查看全部问答>

wince 5.0 之最小系统裁剪

目前系统已经能够正常挂载和失败BINFS分区,当BINFS分区中只有一个文件时(比如放置NORFLASH驱动),系统能够启动且正确加载NORFLASH驱动。下面是启动日志 Booting kernel with clean memory configuration: Memory Sections: [0] : start: 8e78 ...…

查看全部问答>

求教Mipsel USB功能控制器模拟PL2303串口芯片的问题

问题如题: 现象如下: USB 功能控制器有数据发出, 但主机串口助手无法接收到数据, 也就是说PL2303的驱动层在进行转换时不能完成这个功能, 收发的PIPE与PL2303一至, 配置也基本一致。 以下是模拟芯片与PL2303芯片的实际捕获的数据。 …

查看全部问答>

小弟调查一下现在大家都用哪种PLC软件

大家好,小弟想调查一下现在画梯形图哪种PLC软件用得多啊?西门子?三菱?还是欧姆龙啊?哪个年龄段用的哪 种软件啊? 分别都是用于哪方面的控制? 谢谢了!…

查看全部问答>

WiLink 7.0 很强大!

WiLink 7.0 单芯片 WLAN、GPS、蓝牙和 FM 解决方案 做个手持设备很不错   …

查看全部问答>

富士通FM3的多功能串口(MFS)示例代码

        富士通FM3的多功能串口(MFS)功能很强,应用也很灵活,具体可看我前面的帖子《MB9B506R多功能串行接口》。        功能强,应用灵活带来的负面因素就是软件复杂。 ...…

查看全部问答>

菜鸟学习LaunchPad小结

我这一个月学习LaunchPad的小结,虽然很菜。。。但是,带新人入门啊~~~哈啊哈~~~…

查看全部问答>