一、硬件: 1、 launchpad开发板一块(板载MSP430G2553) 2、 LCD1602液晶屏一块(3.3V) 3、 DS1302数字时钟芯片 4、 32.768KHz晶振一枚 5、 按键两枚 6、 电位器一枚 7、 电容、导线等
二、要实现的功能: 1、 精确显示年月日时分秒 2、 闰年、二月自动调节时间 3、 两个按键控制调节时间日期等 4、 显示自定义的语句 5、 恋爱纪念日提醒,显示不一样的画面(We’ve been together for XX years!)
三、硬件电路图
四、整体思路
//设置P1口作为输出连接LCD1602的数据端D0-D7,P2.0为rs,P2.1为rw,P2.2为e(都配置为输出)作为LCD1602的控制端口。 //配置P2.3为SCLK,P2.4为SDA,P2.5为RST(都配置为输出)作为DS1302的控制端 //P2.6、P2.7接两个按键,配置为输入,下降沿中断,中断处理函数 void key_pro(),P2、6接key1(控制光标),P2.7接key2,控制调节 //grace配置中设置P2.0---P2.5为输出,MCLK=1MHz,关闭看门狗 //在做DS1302的硬件时应该特别注意:数据线RST、SCLK、SDA一定上拉电阻,晶振添加负载电容,连接线尽量短 先列写出主函数,是思路清晰点:
- void main (void)
- {
- CSL_init(); // 初始化单片机
- lsd1602_init(); // 初始化LCD1602
- ds1302_init(); //初始化DS1302
- while(1)
- {
- _DINT(); //关闭中断
- data_pro(); //从DS1302中读取并处理数据
- _EINT();
- if(month== 0x03 && date== 0x07)//3月7日是我们的纪念日
- jww(); //如果是3月7号则显示不同的画面(jww是处理函数)
- update_disbuf(); //更新LCD1602显示空间(在2553中开辟)
- display(); //控制LCD1602显示时间
- if(month== 0x03 && date== 0x07)//3月7日纪念日
- __delay_cycles(1000000);
- }
- }
就这样很简单的思路,全部使用了子程序调用,所以看起来清晰点,下面贴出来整个函数。注释的挺多了,有什么建议或者交流的直接回复帖子。 五、程序 说一下阅读方法,先看懂了上边的主函数,然后对应主函数调用的子函数,一个一个来看,逐个看懂,就很简单。(有一个难点,就是按键处理。因为只用了两个按键,key1每按一次会有全局变量i增加一,控制LCD1602光标的显示位置,另外一个按键调节时间)
- //设置P0作为输出连接LCD1602的数据端D0-D7,P2.3为SCLK,P2.4为SDA,P2.5为RST(都配置为输出)
- //P2.0为rs,P2.1为rw,P2.2为e(都配置为输出)
- //P2.67配置为输入,下降沿中断,中断处理函数 void key_pro(),P2。6接key1(控制光标),P2.7接key2,控制调节(增加)
- //grace配置中设置P2.345为输出,MCLK=1MHz,
- //本程序将数据用ASCII表示,方便LCD1602显示
- //在做DS1302的硬件时应该特别注意:数据线RST。SCLK、SDA一定上拉电阻,晶振添加负载电容,连接线尽量短
- //date代表日,day代表星期几
- #include <msp430.h>
- #include <ti/mcu/msp430/csl/CSL.h>
- //定义全局变量年月日时分秒
- char year,month,date,hour,minute,second,n;//n代表周几
- char love_years; //恋爱纪念年
- char day[7][3]={"MON","TUE","WED","THI","FRI","SAT","SUN"};
- char i=0; //用来记录key1按下的次数
- char dis_buf1[16]; //lcd上排显示缓冲区
- char dis_buf2[16]; //lcd下排显示缓冲区
- char weiwei1[16]={"weiwei: I love u"};
- char weiwei2[16]={"so much! by xuxu"};
- char love1[16]={"We've been toget"};
- char love2[16]={"her for years"};
- //LCD1602控制位
- #define rs_0 (P2OUT &= ~BIT0)
- #define rs_1 (P2OUT |= BIT0)
- #define rw_0 (P2OUT &= ~BIT1)
- #define rw_1 (P2OUT |= BIT1)
- #define e_0 (P2OUT &= ~BIT2)
- #define e_1 (P2OUT |= BIT2)
- //DS1302控制位
- #define SCLK_0 (P2OUT &= ~BIT3)
- #define SCLK_1 (P2OUT |= BIT3)
- #define SDA_0 (P2OUT &= ~BIT4)
- #define SDA_1 (P2OUT |= BIT4)
- #define RST_0 (P2OUT &= ~BIT5)
- #define RST_1 (P2OUT |= BIT5)
- #define SDA (P2IN &= BIT4)
- //宏定义DS1302数据地址
- #define write_second 0x80
- #define read_second 0x81
- #define write_minute 0x82
- #define read_minute 0x83
- #define write_hour 0x84
- #define read_hour 0x85
- #define write_date 0x86
- #define read_date 0x87
- #define write_month 0x88
- #define read_month 0x89
- #define write_year 0x8c
- #define read_year 0x8d
- #define write_day 0x8a
- #define read_day 0x8b
- #define write_protect 0x8e
- #define write_power 0x90
- //*******************以下为LCD1602的子函数************************//
- //***********************************************************//
- //查询是否忙碌(每次输入指令前都要判断液晶模块是否处于忙的状态)
- char busy(void)
- {
- char busyc;
- rs_0;
- rw_1;
- e_1;
- __delay_cycles(1000);
- P1DIR = 0x00; //P1口置为输入,读取LCD状态
- busyc = P1IN & BIT7; //从P1输入是否忙碌(D7高电平表示忙碌)
- P1DIR = 0xff;
- e_0;
- return busyc;
- }
- //向LCD1602写字节命令
- void write_command(char command)
- {
- while(busy()); //判断LCD是否忙碌
- rs_0;
- rw_0;
- P1OUT = command;
- __delay_cycles(1); //时间间隔MIN=30nS
- e_1;
- __delay_cycles(1); //MIN=150nS
- e_0;
- }
- //向LCD1602写数据命令
- void write_data(char data)
- {
- while(busy()); //判断LCD是否忙碌
- rs_1;
- rw_0;
- __delay_cycles(1);
- e_1;
- P1OUT=data;
- __delay_cycles(1);
- e_0;
- }
- //LCD1602初始化函数
- void lsd1602_init()
- {
- e_0;
- write_command(0x38);
- __delay_cycles(15000);
- write_command(0x0c);
- write_command(0x06);
- write_command(0x01);
- }
- void update_disbuf()
- {
- dis_buf1[0]='2';
- dis_buf1[1]='0';
- dis_buf1[2]=year/16 + 0x30;
- dis_buf1[3]=year%16 + 0x30;
- dis_buf1[4]='-';
- dis_buf1[5]=month/16 + 0x30;
- dis_buf1[6]=month%16 + 0x30;
- dis_buf1[7]='-';
- dis_buf1[8]=date/16 + 0x30;
- dis_buf1[9]=date%16 + 0x30;
- dis_buf1[10]=' ';
- dis_buf1[11]=' ';
- dis_buf1[12]=' ';
- dis_buf1[13]=day[n-1][0];
- dis_buf1[14]=day[n-1][1];
- dis_buf1[15]=day[n-1][2];
- dis_buf2[0]=' ';
- dis_buf2[1]='j';
- dis_buf2[2]='w';
- dis_buf2[3]='w';
- dis_buf2[4]='&';
- dis_buf2[5]='z';
- dis_buf2[6]='x';
- dis_buf2[7]=' ';
- dis_buf2[8]=hour/16 + 0x30;
- dis_buf2[9]=hour%16 + 0x30;
- dis_buf2[10]=':';
- dis_buf2[11]=minute/16 + 0x30;
- dis_buf2[12]=minute%16 + 0x30;
- dis_buf2[13]=':';
- dis_buf2[14]=second/16 + 0x30;
- dis_buf2[15]=second%16 + 0x30;
- }
- void display()
- {
- char t;
- write_command(0x80);
- for (t=0;t<=15;t++)
- {write_data(dis_buf1[t]);}
- write_command(0xc0);
- for (t=0;t<=15;t++)
- {write_data(dis_buf2[t]);}
- }
- //********************以下为DS1302的子函数************************//
- //***********************************************************//
- //向DS1302写一个字节的数据
- void ds1302_Wbyte(char dat)
- {
- char s,temp;
- temp = dat;
- for(s=0;s<8;s++)
- {if(temp & 0x01) //从低位开始传输数据
- {SDA_1;}
- else
- SDA_0;
- SCLK_1; //上升沿锁存数据
- temp = temp>>1; //数据右移一位为下次输出做准备
- SCLK_0; //为下一次做准备
- }
- }
- //从DS1302读取8位数据
- char ds1302_Rbyte()
- {
- char u,temp;
- P2DIR &= ~BIT4;
- for(u=8; u>0;u--)
- {
- temp=temp>>1;
- temp += (P2IN&BIT4)<<3;
- SCLK_1;
- SCLK_0;
- }
- P2DIR |= BIT4;
- return(temp);
- }
- //向DS1302写入地址然后读取数据
- char ds1302_Read(char cmd)
- {
- char dat;
- RST_0; //初始化RST为低
- SCLK_0; //SLK=0
- RST_1; //开始传输数据
- ds1302_Wbyte(cmd); //传输命令字,写入要读取的时间、日期地址
- dat = ds1302_Rbyte(); //读取八位数据
- RST_0; //结束数据传输
- SCLK_0; //拉高时钟线
- return(dat);
- }
- //向DS1302写入地址后写入数据
- void ds1302_Write(char cmd,char dat)
- {
- RST_0;
- SCLK_0; //在RST的上升沿,SCLK必须为0
- RST_1; //开始传输数据
- ds1302_Wbyte(cmd); //写入要修改的地址
- ds1302_Wbyte(dat); //写入数据
- SCLK_1; //拉高时钟线
- RST_0; //拉低RST
- }
- //初始化DS1302的程序
- void ds1302_init(void)
- {
- ds1302_Write(write_protect,0x00);//关闭写保护
- ds1302_Write(write_second,0x00); //初始化秒为00,不暂停时钟(BIT7)
- ds1302_Write(write_minute,0x59); //初始化分为00
- ds1302_Write(write_hour,0x23); //初始化时为23,设置为24小时制(BIT7)
- ds1302_Write(write_date,0x01); //初始化日期为01
- ds1302_Write(write_month,0x01); //初始化月为01
- ds1302_Write(write_year,0x12); //初始化年为(20)12
- ds1302_Write(write_day,0x07); //周日
- ds1302_Write(write_power,0x0a5); //一个二极管压降,电阻4K
- ds1302_Write(write_protect,0x80);//打开写保护
- }
- //DS1302数据处理函数,此函数将个位、十位分别用char表示,方便用数码管显示
- void data_pro(void)
- {
- ds1302_Write(write_protect,0x00);//关闭写保护
- date = ds1302_Read(read_date); //读取日
- if(date>0x29 && month==0x02) //如果调时时2月超过29
- {ds1302_Write(write_date,0x01);
- date = ds1302_Read(read_date);
- ds1302_Write(write_month,month + 1);
- }
- month = ds1302_Read(read_month);//读取月
- year = ds1302_Read(read_year); //读取年
- hour = ds1302_Read(read_hour); //读取时
- hour = hour & 0x3f; //屏蔽掉前两位
- minute = ds1302_Read(read_minute);//读取分
- second = ds1302_Read(read_second);//读取秒
- n = ds1302_Read(read_day);//读取星期
- ds1302_Write(write_protect,0x80);//打开写保护
- }
- //按键中断处理程序(使用grace配置)
- void key_pro(void)
- {
- char j; //用于复制自定义的显示计数(16个)
- __delay_cycles(8000); //延时去抖动
- if(!(P2IN & BIT6)) //判断是否有按键按下
- {
- i++;
- switch(i)
- {
- case 1:
- write_command(0x83); //显示光标到年
- write_command(0x0f);
- break;
- case 2:
- write_command(0x86); //显示光标到月
- write_command(0x0f);
- break;
- case 3:
- write_command(0x89); //显示光标到日
- write_command(0x0f);
- break;
- case 4:
- write_command(0x8f); //显示光标到周
- write_command(0x0f);
- break;
- case 5:
- write_command(0xc9); //显示光标到时
- write_command(0x0f);
- break;
- case 6:
- write_command(0xcc); //显示光标到分
- write_command(0x0f);
- break;
- case 7:
- write_command(0xcf); //显示光标到秒
- write_command(0x0f);
- break;
- default: break;
- }
- }
- if(i>7)
- {
- i=0;
- write_command(0x0c); //关闭光标显示
- }
- P2IFG=0; //软件复位标志
- while(!(P2IN & BIT6))
- {
- ds1302_Write(write_protect,0x00);//关闭写保护
- while(!(P2IN & BIT7)) //如果按键2被按下
- {
- switch(i) //根据i的值来确定某变量进行加1
- {case 0: //显示自定义的语句
- for(j=0;j<16;j++)
- {
- dis_buf1[j] = weiwei1[j];
- dis_buf2[j] = weiwei2[j];
- display();
- }
- break;
- case 1: //此事处理全局变量year
- year++; //year加1
- if(year>0x99) //如果year大于99则置0
- year=0;
- if((year & 0x0f)>0x09) //如果year低四位大于9(第四位BCD码表示个位),十位加1,个位置0
- {year +=0x10;
- year &=0xf0;
- }
- ds1302_Write(write_year,year);//将变化后的year写入DS1302
- year = ds1302_Read(read_year);//读出来year显示(使调节year时同步变化,为了人性化)
- update_disbuf(); //更新显示字符
- while(!(P2IN & BIT7))
- display();
- break;
- case 2: //此时处理全局变量month
- month++;
- if(month>0x12)
- month=1;
- if((month & 0x0f)>0x09)
- {month +=0x10;
- month &=0xf0;
- }
- ds1302_Write(write_month,month);
- month = ds1302_Read(read_month);
- update_disbuf(); //更新显示字符
- while(!(P2IN & BIT7))
- display();
- break;
- case 3: //此时处理全局变量date
- date++;
- if( (date>0x29 && month==0x02)
- || (month==0x04 || month==0x06 || month==0x09 || month==0x11)&& date>0x30
- || date>0x31 )
- date=0x01;
- if((date & 0x0f)>0x09)
- {date +=0x10;
- date &=0xf0;
- }
- ds1302_Write(write_date,date);
- date = ds1302_Read(read_date);
- update_disbuf(); //更新显示字符
- while(!(P2IN & BIT7))
- display();
- break;
- case 4: //此时处理全局变量day
- n++;
- if(n>0x07)
- n=1;
- ds1302_Write(write_day,n);
- n = ds1302_Read(read_day);
- update_disbuf(); //更新显示字符
- while(!(P2IN & BIT7))
- display();
- break;
- case 5: //此时处理全局变量hour
- hour++;
- if(hour>0x23)
- hour=0;
- if((hour & 0x0f)>0x09)
- {hour +=0x10;
- hour &=0xf0;
- }
- ds1302_Write(write_hour,hour);
- hour = ds1302_Read(read_hour);
- update_disbuf(); //更新显示字符
- while(!(P2IN & BIT7))
- display();
- break;
- case 6: //此时处理全局变量minute
- minute++;
- if(minute>0x59)
- minute=0;
- if((minute & 0x0f)>0x09)
- {minute +=0x10;
- minute &=0xf0;
- }
- ds1302_Write(write_minute,minute);
- minute = ds1302_Read(read_minute);
- update_disbuf(); //更新显示字符
- while(!(P2IN & BIT7))
- display();
- break;
- case 7: //此时处理全局变量second
- second++;
- if(second>0x59)
- second=0;
- if((second & 0x0f)>0x09)
- {second +=0x10;
- second &=0xf0;
- }
- ds1302_Write(write_second,second);
- second = ds1302_Read(read_second);
- update_disbuf(); //更新显示字符
- while(!(P2IN & BIT7))
- display();
- break;
- default: break;
- }
- }
- ds1302_Write(write_protect,0x80);//打开写保护
- }
- }
- //纪念日处理程序
- void jww(void)
- {char ww_xx;
- for(ww_xx=0;ww_xx<16;ww_xx++)
- {
- dis_buf1[ww_xx] = love1[ww_xx];
- dis_buf2[ww_xx] = love2[ww_xx];
- }
- love_years= year - 0x11; //减去2011年
- dis_buf2[8]=love_years/16 + 0x30;
- dis_buf2[9]=love_years%16 + 0x30;
- display();
- _DINT();
- __delay_cycles(2000000); //延时显示出来
- _EINT();
- }
- //主函数
- void main (void)
- {
- CSL_init(); // 初始化单片机
- lsd1602_init(); // 初始化LCD1602
- ds1302_init(); //初始化DS1302
- while(1)
- {
- _DINT();
- data_pro(); //读取并处理数据
- _EINT();
- if(month== 0x03 && date== 0x07)//3月7日纪念日
- jww();
- update_disbuf(); //更新显示字符
- display(); //显示时间
- if(month== 0x03 && date== 0x07)//3月7日纪念日
- __delay_cycles(1000000);
- }
- }
|