1、20180824电气43 陈振斌 孙鹏程西安交通大学2017-5-20闹钟提示 1、 整体系统框图S3、S4、S5键组合实现校正整点S2键切换显示S1键切换模式数码管闪烁报时报温温度显示日历校正定闹功能日历显示时钟显示时钟校正2、 系统工作原理基于单片机STC89C52与开发平台KEIL软件,利用C语言设计相关程序。期间配合使用DS1302时钟芯片实现走时功能,使用温度传感器件DS18B20实现室温测量功能,使用ISD1760语音芯片实现录放音功能以及配合动态显示数码将相关功能以可视形式呈现,并通过按键配合实现切换显示、校时、定闹等额外功能。S1、S2键执行模式及显示切换功能及S5确认/关闭闹
2、钟功能时钟、日历校正及定闹模块(S3、S4、S5组合)闹钟提示(数码管闪烁)定时中断部分循环程序主程序循环时钟、日历显示模块整点报时报温功能温度显示循环(关闭定时器)3、 软件框图开始各变量及时钟、语音芯片初始化 4、 系统使用介绍:电路板上电后,初始状态数码管显示时钟;S1键切换模式,模式0为正常显示模式,模式1为校正模式,并且取决于按下按键之前显示部分依次进入:时钟校正、日历校正、闹钟定时模块;S2键切换显示,依次为:时钟、日历、温度;S3键在进入校正模式有效,用于选择校正位;S4键在进入校正模式有效,用于对当前校正位进行数值改变,即“加1”功能;S5键在校正模式时,用于确认校正,在闹钟闪
3、烁时,按下可关闭闹钟;S6为电路板重置键,终止程序;RST键为语音芯片重置键,中断语音芯片工作。5、 已知部分缺陷及非完美解决方案:问题描述:进入校正模式时,会出现数据读取错乱,使得数码显示09以外的数字,如A、B、C、D等;在确认校正时同样会有几率出现该问题。推测原因:DS1302走时程序中数据会有过渡性变化,使得display_buffer数组的数据在读取和置入时产生问题。或置数时有数据错误。 解决方案:对显示错乱部分重新进行校时,该处将置零。此后可正常校正。6、 软件编写与调试时所遇到的问题及解决方案:l 按键按下时程序多次执行:利用“miaomiao”系列变量作为判定条件保证只执行一次
4、程序;l 对显示变量display_buffer直接进行加一操作进位产生错乱:引入buffer_temp数组,替代校正;l 语音芯片不能连续播放多段语音:每段播放后延时适当时间;l 为使得”on”、” off” 的右下角显示小数点时对SEGMENT直接进行“位与”操作只能显示o8.”、” of8”. 等:引入变量s过渡;l 整点报时会连续两次播放语音:只在分钟显示为“59”时使得miaomiao_play变量为一,播放后置为零,保证只播放一次;l 报温时可能读取到设定工作温度上限(39摄氏度)的温度值且实际此时温度在上限之内:在tmread()函数里增加循环读取部分直至读到正常数值;l 其他组
5、组员(于晨曦同学)提出的建议与提示:温度读取时间较长不宜加入定时中断显示;每次显示前对位码或段码(取决于置数顺序)先置零,以解决数码管残影问题。7、 PCB板原理图及接线图见验收文件夹PPT,由于打印问题在此不作展示。8、 源程序代码#include #include #include #include #define SEGMENT XBYTE0xdfff#define BIT_LED XBYTE0xbfff#define fosc 11.0592#define time0 2500#define uint unsigned int#define SEGMENT XBYTE0xdfff#de
6、fine BIT_LED XBYTE0xbfff/语音部分定义开始unsigned char bdata SR0_L;unsigned char bdata SR0_H;unsigned char bdata SR1;unsigned char APCL=0,APCH=0;unsigned char PlayAddL=0,PlayAddH=0;unsigned char RecAddL=0,RedAddH=0;sbit CMD=SR0_L0;sbit FULL=SR0_L1;sbit PU=SR0_L2;sbit EOM=SR0_L3;sbit INTT=SR0_L4;sbit RDY=SR1
7、0;sbit ERASE=SR11;sbit PLAY=SR12;sbit REC=SR13;unsigned char ISD_SendData(unsigned char dat);void ISD_PU(void);void ISD_Rd_Status(void);void ISD_WR_APC2(unsigned char apcdatl,apcdath);void ISD_SET_PLAY(unsigned char Saddl,Saddh,Eaddl,Eaddh);sbit SS=P14;sbit SCK=P17;sbit MOSI=P15;sbit MISO=P16;void I
8、SD_Init(void);void delay(unsigned int t);unsigned char get_address(unsigned char k);/快速获取部分语音地址函数/语音部分定义结束/温度部分定义开始sbit TMDAT=P34;void dmsec(unsigned int count);void tmreset(void);void tmstart(void);void tmdisplay(void);void tmread(void);/温度读取函数unsigned char tmrtemp(void);unsigned char code seg_code
9、=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00;unsigned char code tran_code=0,1,2,3,4,5,6,7,8,9; /类型转换数组unsigned char last;int last_shi=2,last_ge=6;/温度部分定义结束/时间部分定义开始unsigned char data display_bit,display_buffer8,display_buffer18,ring8=1,5,0,0,0,1,0,0;unsigned
10、char data time0_h,time0_1,TEMP;unsigned int idata time0_times;unsigned char get_code(unsigned char i);void display(void);void initial_ds1302();unsigned char read_ds1302(char command);void open_write_bit();void close_write_bit();void read_time();void set_time();void reset_time();/校正确认功能函数void read_da
11、te();sbit SCL_DS1302=P20;sbit IO_DS1302=P21;sbit RST_DS1302=P22;unsigned char bdata data_ds1302;sbit bit_data0=data_ds13020;sbit bit_data7=data_ds13027;unsigned char bdata x;sbit x0=x0;sbit x7=x7;/时间部分定义结束/功能部分定义开始sbit key1=P10;/切换功能unsigned char modecg;/工作模式指示变量sbit key2=P11;/切换显示unsigned char disp
12、laycg;/切换显示指示变量sbit key3=P12;/切换校正位unsigned char time_ajflag;/时钟校正位指示变量unsigned char time_bitadjust;/时钟校正位显示变量unsigned char date_ajflag;/日历校正位指示变量unsigned char date_bitadjust;/日历校正位显示变量unsigned char ring_ajflag;/闹钟校正位指示变量unsigned char ring_bitadjust;/闹钟校正位显示变量sbit key4=P13;/加位键sbit key5=P32;/确认或关闭闹钟
13、键unsigned char miaomiao_1,miaomiao_2,miaomiao_3,miaomiao_4,miaomiao_5,miaomiao_play;/防止多次执行步骤指示变量unsigned char j,s;/j为部分程序循环指示变量,s为为解决on off的加小数点显示问题而定义的SEGMENT过渡变量int time_t=400;/数码管闪烁计数变量unsigned char buffer_temp8,play_adr8,wendu_shi,wendu_ge;/分别为校正功能过渡变量数组、语音播报地址变量、温度十位类型过渡变量及温度个位类型过渡变量/功能部分定义结束m
14、ain() modecg=0; displaycg=0; BIT_LED=0; date_ajflag=0; ring_ajflag=0; time_ajflag=0; miaomiao_1=1; miaomiao_2=1; miaomiao_3=1; miaomiao_4=1; miaomiao_5=1; miaomiao_play=1;/以上为各新定义变量的初始化 TEMP=TMOD; TEMP=TEMP&0XF0; TMOD=TEMP|0X01; time0_times=-time0*fosc/12; time0_h=(time0_times/256); time0_1=(time0_t
15、imes%256); TH0=time0_h;TL0=time0_1; initial_ds1302(); display_bit=0x01; display_buffer5=0x05; display_buffer4=0x03; display_buffer3=0x09; display_buffer2=0x05; display_buffer1=0x01; display_buffer0=0x02; display_buffer17=0x06; display_buffer16=0x00; display_buffer15=0x05; display_buffer14=0x00; disp
16、lay_buffer13=0x07; display_buffer12=0x01; display_buffer11=0x00; display_buffer10=0x02; set_time(); ISD_Init(); dmsec(1); tmread(); TR0=EA=ET0=1; do if(key1=0) if(miaomiao_1) modecg+;modecg=modecg%2;/切换工作模式:0:显示模式;1:校正、定闹模式 miaomiao_1=0; if(displaycg=0&modecg=1) for(j=0;j8;j+) buffer_tempj=display_b
17、ufferj;if(displaycg=2&modecg=1) for(j=0;j8;j+) buffer_tempj=display_buffer1j;if(displaycg=1&modecg=1) ET0=1;/从主程序的温度显示进入定时中断 for(j=0;j8;j+) buffer_tempj=ringj; else miaomiao_1=1; if(key2=0) if(miaomiao_2) displaycg+;displaycg=displaycg%3;/切换显示部分:0:时钟;1:温度/定闹;2:日历 miaomiao_2=0;if(displaycg=0&modecg=1
18、) for(j=0;j8;j+) buffer_tempj=display_bufferj;/每次切换对buffer_temp赋予当前的变量值if(displaycg=2&modecg=1) for(j=0;j8;j+) buffer_tempj=display_buffer1j; if(displaycg=1&modecg=1) for(j=0;j200) BIT_LED=0x00; SEGMENT=0x00; time_t-; else display(); time_t-;if(time_t=0) time_t=400; else display(); /时间部分开始unsigned c
19、har get_code(unsigned char i) unsigned char p; switch(i) case 0: p=0x3F; break; case 1: p=0x06; break; case 2: p=0x5B; break; case 3: p=0x4F; break; case 4: p=0x66; break; case 5: p=0x6D; break; case 6: p=0x7D; break; case 7: p=0x07; break; case 8: p=0x7F; break; case 9: p=0x67; break; case 10: p=0x
20、77; break; case 11: p=0x7C; break; case 12: p=0x39; break; case 13: p=0x5E; break; case 14: p=0x79; break; case 15: p=0x71; break; default: break; return(p);unsigned char get_address(unsigned char k) unsigned char p; switch(k) case 0x00: p=1; break; case 0x01: p=7; break; case 0x02: p=13; break; cas
21、e 0x03: p=19; break; case 0x04: p=25; break; case 0x05: p=31; break; case 0x06: p=37; break; case 0x07: p=43; break; case 0x08: p=49; break; case 0x09: p=55; break; default: break; return(p);void display(void) unsigned char i; /由于时钟和日历部分显示差别,故使用不同的display_bit与i的对应函数 if(displaycg=2) switch(display_bi
22、t) case 1: i=0; break; case 2: i=1; break; case 4: i=2; break; case 8: i=3; break; case 16: i=4; break; case 32: i=5; break; case 64: i=6; break; case 128: i=7; break; default: break; else switch(display_bit) case 1: i=0; break; case 2: i=1; break; case 4: i=2; break; case 8: i=2; break; case 16: i=
23、3; break; case 32: i=3; break; case 64: i=4; break; case 128: i=5; break; default: break; /时钟显示开始 if(modecg=0&displaycg=0) BIT_LED=0;/每次显示对位码置零,以消除显示残影问题,下同 if(display_bit=0x04|display_bit=0x20) SEGMENT=0x40; /此为时钟显示时加“-”的判定 else SEGMENT=get_code(display_bufferi); BIT_LED=display_bit; if(display_bit
24、=64) display_bit=display_bit*2; else display_bit=0x01; /时钟显示结束/日历显示开始if(modecg=0&displaycg=2) BIT_LED=0; SEGMENT=get_code(display_buffer1i); BIT_LED=display_bit; if(display_bit0x09) buffer_temp3=0x00; buffer_temp2+; if(buffer_temp25) buffer_temp2=0; if(time_bitadjust=0x02) buffer_temp1+;if(buffer_te
25、mp10x09) buffer_temp1=0x00; buffer_temp0+; if(buffer_temp0=2&buffer_temp13)|(buffer_temp02)/如此判定条件是为了消除从display_buffer中读取到的buffer_temp可能得到超出范围数字的bug,下同 buffer_temp0=0; buffer_temp1=0; miaomiao_4=0; else miaomiao_4=1; BIT_LED=0; if(display_bit=0x04|display_bit=0x20) SEGMENT=0x40; else if(display_bit=
26、time_bitadjust) SEGMENT=get_code(buffer_tempi)+0x80;/被选择到的校正位右下角小数点开启显示else SEGMENT=get_code(buffer_tempi); BIT_LED=display_bit; if(display_bit0x09) buffer_temp7=0x00; buffer_temp6+; if(buffer_temp6=3&buffer_temp71)|(buffer_temp6)3) buffer_temp6=0; buffer_temp7=1; if(date_bitadjust=0x20) buffer_temp
27、5+;if(buffer_temp50x09) buffer_temp5=0x00; buffer_temp4+; if(buffer_temp4=1&buffer_temp52)|(buffer_temp41) buffer_temp5=1; buffer_temp4=0; if(date_bitadjust=0x08) buffer_temp3+;if(buffer_temp30x09) buffer_temp3=0x00; if(date_bitadjust=0x04) buffer_temp2+;if(buffer_temp20x09) buffer_temp2=0x00; miaomiao_4=0; else miaomiao_4=1; BIT_LED=0; if(display_bit=date_bitadjust) SEGMENT=get_code(buffer_tempi)+0x80;else SEGMENT=get_code(buffer_tempi); BIT_LED=display_bit; if(display_bi