PIC16F877A数字时钟时钟程序
基于PIC16F887单片机的温度、时钟显示以及闹钟功能

基于PIC16F887单片机的温度、时钟显示以及闹钟功能一、课程设计的目的《PIC 单片机课程设计》是电气工程及其自动化专业及相近专业的一门重要的专业实践课,本课程在《PIC 单片机》课程的基础上,通过硬件设计与软件编程与调试的实践,进一步掌握PIC 单片机的应用方法,熟练PIC 单片机的C 程序的编写与调试,是毕业设计前的一次重要的实践,为今后走上工作岗位打下坚实的单片机应用基础。
二、设计内容1 Proteus 线路图绘制根据所设计的线路图,绘制与之一致的,能用于仿真的Proteus 线路图。
要求所绘的线路图美观、紧凑,参数要与课设一致。
2、软件编制与调试根据所设计的线路图制相应的单片机C 程序,要求所制的程序符合C 语言格式并加上注解。
每编一段即进行译,有错及时修改,并先在Proteus 上仿真,基本正确后再用PICkit3 在线调试,最后应脱机运行。
三、设计目标1该设计包括数字钟及数字温度计:按键的使用.LCD.蜂鸣器时钟芯片DS1307和温度传感器TC74。
2功能;此设计可以感测环境的温度,显示当前的时间,及闹钟。
温度与时间都显示在LCD显示屏上,以及如何调整闹钟界面四硬件设计及说明1复位按键2时钟芯片DS1307及附属接线时钟芯片DS1307用于产生时间,它提供了秒、分、时、日、年、和星期等数据,能算只瑞年2100年,时钟的晶振是典型的32.768Hz。
(1)其引脚作用如下:2(2)DS1307的读写如下;1写DS1307 的步骤如下:a) 发送启始位;b) 发送DS1307 的7位地址+0 (写),即0b11010000;c) 发送要写入DS1307 的地址,地址见图16,如要修改分,此值为1;d) 发送要写入DS1307 的数,如要把分修改为十进制数37,则此数为0x37;e) 发送停止位;2读DS1307 的步骤如下:a) 发送启始位;b) 发送DS1307 的7位地址+0 (写),即0b11010000;c) 发送要读的DS1307 的起始地址,如要从秒读起,为0;d) 发送停止位;e) 发送重新开始位;f) 发送DS1307 的7位地址+1 (读),即0b11010001;g) 发送读使能位,接收一个数据,单片机发送应答位;h) 发送读使能,接收下一个数据(地址会自动+1),单片机发送应答位,直到读数完成,接收最后一个数时单片机不发送应答位;i) 发送停止位;注意在DS1307仿真的时候七位地址为0b1001101 而实际为0b1001000 ;(3)功能是;提供时间通过pic16F877送入LCD中显示。
PIC16F877A功能及其编程

4.1.1 端口A
因此,在使用RA口时,除了要设置TRISA外,有 时相关寄存器也要设置。
注意:在上电复位时,与AN有关的端口的默认 设置是作为模拟端口,即ADCON1(见4.6)中默认 值为0b00xx0000,这个值的设置结果是除RA4外的所 有的RA引脚都作为模拟输入。
信的时钟线; RC7/RX/DT:IO引脚、异步串行通信的接收、同步串行通
信的数据线。
4.1.4 端口D
端口D有8个引脚,它除了作为普通IO口外, 还能作为并行从动口使用。
4.1.5 端口E 端口E只有3个引脚,它们都可以作为AD转换
的模拟电压输入口,功能如下:
RE0/RD/AN5:IO引脚、并行从动口的读控制、 模拟电压输入通道AN5;
➢ 中断的特点:可返回性。中断处理结束后必须能 回到原先的程序,并且能继续运行原先的程序,
这就需要在中断时能进行现场保护与恢复。
中断的执行过程
➢ 中断发生:程序执行到某行,突然事件(能够产 生中断的事件)发生,产生中断。
➢ 断点保护:CPU自动将中断时刻即将要执行的下 一条指令的地址压入堆栈。
➢ 中断响应:CPU自动将PC强制设为0X0004,且GIE =0。执行中断服务程序(自动完成现场保护与恢 复,手动清中断标志位)。
将被调试系统占用,因此在调试时此二个引脚暂 不能使用。
3、8个引脚具有内部弱上拉使能控制 由OPTION_REG寄存器的第7位RBPU控制,如果弱 上拉使能,作为输入的RB口在端口悬空时将被上拉 到高电平。以RB0为例,如下图所示:
4、RB0/INT具有外部中断功能。
5、RB的的高4位还具有电平变化中断功能
ADIE
基于PIC16F887单片机的数字钟完整c程序代码

#include <pic.h>__CONFIG (0x20F1);__CONFIG (0x3FFF); //调试用#define LCD_E RD6 //LCD E 读写使能控制#define LCD_RW RD5 //LCD 读(1)/写(0)控制线#define LCD_RS RD4 //LCD 寄存器选择数据(1)指令(0)//RD4-RD7分别接DB4-DB7,RD7为忙标志#define COM 0 //在LCD_WRITE()中的第2参数为0表示写命令#define DAT 1 //在LCD_WRITE()中的第2参数为1表示写数据#define mod RB3//模式选择(时间、闹钟、温度、秒表)#define set RB0//选择按键#define add RB1//加按键#define miu RB2//减按键#define RTR 0b00000000 //TC74的读温度命令#define TC74_ADD 0b1001101 //TC74的7位地址#define LINE1 0b10000000#define LINE2 0b11000000signed char hourt,mint,sect;//闹钟设置位int f;//闹钟显示清零判断char flag=0;//按键标志位char WW,QW,BW,SW,GW,M;char table[]="Mon Tue Wed Thu Fri Sat Sun ";//星期signed char year,month,day,week,hour,min,sec,a,T;bank1 char DD[16]; //一行LCD显示数据暂存char A[7];//DS1307读数//====LCD程序void CSH(void); //初始化void LCD_CSH(void); //LCD初始化void LCD_BUSY(void); //检测LCD是否忙char LCD_READ(void); //读LCD,忙检测用void LCD_WRITE(char,char); //LCD写1字节,命令或数据void LCD_WRITE_4(char,char); //LCD写半字节void DISP_C(char); //在指定行中显示字符,字符在数组DD中void DISP_MENU(const char *); //由常数数组显示整屏字符void DELAY_US(char);void DELAY(unsigned int);void delaynms(unsigned int);//===DS1307void IIC_SEND(char);void IIC_CSH(void);void READ_DS1307(char addr,char n);void write_DS1307(char addr,char data);void DS1307_CSH(void);//DS1307初始化void MENU_DS1307(void);//==温度void DISP_T(signed char R1); //温度在R1 signed char READ_T(void);void clock();//闹钟void set_time(void);//按键void bcd_dec(char adr,char R);char dec_bcd(char dec);void BCD(unsigned int R1);void guangbiao(void);//光标//========主程序void main(){CSH();READ_DS1307(0,7);//读DS1307if(A[0]&0x80)DS1307_CSH();//判断是否初始化while(1){clock();set_time();//按键检测delaynms(50);if(flag==0){ READ_DS1307(0,7);//读DS1307MENU_DS1307();//显示DS1307T=READ_T();//读温度DISP_T(T);//显示温度}}}//========初始化端口void CSH(void){TRISD=0b00000000; //控制LCD1604,全为输出RD7=1; //背光TRISB=0x0FF;RBPU=0;WPUB=0x0FF;ANSELH=0;PORTB=0x00;//===PWM设置TRISC1=0; //RC1为输出RC1=0;PR2=124; //周期为1msCCPR2L=0x32;CCP2CON=0b00000000;//关闭PWMT2CON=0b00000110; //TMR2预分频1:16,开始工IIC_CSH();LCD_CSH();}//LCD模块初始化void LCD_CSH(void){ DELAY(20); //延时20msLCD_WRITE_4(0b0011,COM); //发送控制序列DELAY_US(10); //延时100usLCD_WRITE_4(0b0011,COM); //发送控制序列DELAY_US(10); //延时100usLCD_WRITE_4(0b0011,COM); //发送控制序列DELAY_US(10); //延时100usLCD_WRITE_4(0b0010,COM); //4位数据格式LCD_BUSY(); //LCD忙检测LCD_WRITE(0b00101000,COM); //4位数据格式,2行,5×7点阵LCD_WRITE(0b00001100,COM); //D(d2)=1:打开显示,C(d1)=1:光标打开,B(d0)=1:光标不闪烁LCD_WRITE(0b00000001,COM); //清除显示DELAY(2); //延时2msLCD_WRITE(0b00000110,COM); //输入模式,I/D(d1)=1:地址加1,S(d0)=1:显示移位关闭}//========读LCD状态char LCD_READ(void){ unsigned char R1;TRISD|=0X0F; //LCD数据线为输入LCD_RS=0; //寄存器选择LCD_RW=1;NOP(); //读为1LCD_E=1;NOP(); //使能R1=0; //短延时R1=(PORTD<<4 )& 0xF0; //读数据的高4位给R1高四位LCD_E=0;NOP(); //读数据结束LCD_E=1;NOP(); //使能R1 |= (PORTD & 0x0F); //读PORTD的低4位,R1的高4位不变!LCD_E=0;NOP(); //读数据结束LCD_RW=0;return (R1);}//写一字节数R1,FLAG为写命令或数据选择,0为写命令,1为写数据//写之前先检查是否忙,写完后延时100us,分二次写4位数据/命令void LCD_WRITE(char R1,char FLAG){ char R2;TRISD&=0XF0;LCD_BUSY();R2=R1 & 0xF0; //低4位清0R2=R2>>4; //取高4位LCD_WRITE_4(R2,FLAG); //先写高4位R2=(R1 & 0x0F); //高4位清0,取低4位LCD_WRITE_4(R2,FLAG); //再送低4位DELAY_US(10); //延时100us}//写R1的低4位,FLAG为寄存器选择,1为命令,0为数据void LCD_WRITE_4(char R1,char FLAG){ TRISD&=0XF0;LCD_RW=0;NOP(); //写模式LCD_RS=FLAG;NOP(); //寄存器选择PORTD &= 0xF0;NOP(); //RD低4位先清0LCD_E=1;NOP(); //使能R1=(R1&0x0F); //R1低4位送至低4位PORTD |=R1;NOP(); //送4位LCD_E=0;NOP(); //数据送入有效,下降沿送入LCD_RS=0;NOP();PORTD &= 0xF0; //RD低4位清0}//========检测LCD是否忙void LCD_BUSY(void){ unsigned char R1;while(1){ R1=LCD_READ(); //读寄存器if ((R1 & 0x80)==0x00) //最高位为忙标志位break;};}//======延时(n)msvoid DELAY(unsigned int n){unsigned int j;char k;for (j=0;j<n;j++)for (k=246;k>0;k--) NOP();}//======延时(n)msvoid delaynms(unsigned int n){unsigned int j;char k;for (j=0;j<n;j++)for (k=246;k>0;k--) NOP();}//======延时(n×10)usvoid DELAY_US(char n){ char j;for (j=0;j<n;j++){NOP();NOP();}}//=======DS1307有关子程序//===DS1307初始化void DS1307_CSH(){write_DS1307(0x00,0X00);//秒钟设置write_DS1307(0x01,0x01);//分钟设置write_DS1307(0x02,0x01);//小时设置write_DS1307(0x03,0X01);//星期天设置write_DS1307(0x04,0x01);//日月设置write_DS1307(0x05,0x05);//月设置write_DS1307(0x06,0x12);//年设置write_DS1307(0x07,0x70);//7脚方波允许,输出1HZ}//==IIC初始化void IIC_CSH(){ TRISC =0b00011000; //SDA,SCL设置为输入SSPCON=0b00101000; //同步串口使能(SSPEN),主控方式SMP=0; //使能高速模式(400 kHz) 的压摆率控制SSPADD=4; //主控模式为波特率值,每位时间T=(SSPADD+1)/Tcy=5us }//发送数R并等待发送完成,收到从机的应答信号void IIC_SEND(char R){ SSPBUF=R; //发送while (RW==1); //在主动模式下,判断发送是否完成while (SSPIF==0); //等待发送完成while (ACKSTA T==1); //等待从机发送应答信号NOP();}//====读写DS1307程序void write_DS1307(char addr,char data){SEN=1; //发送起始位while(SEN==1); //检测起始位完成IIC_SEND(0b11010000); //送DS1307的七位地址和写功能IIC_SEND(addr); //发送要写入的地址IIC_SEND(data); //发送要写入的数PEN=1; //发送停止位while (PEN==1); //检查停止位结束}//===读DS1307void READ_DS1307(char addr,char n){char i;SEN=1; //产生起始位while (SEN==1); //检测起始位完成IIC_SEND(0b11010000); //送DS1307的7位地址IIC_SEND(addr); //此值为DS1307要读的地址PEN=1; //发送停止位while (PEN==1);//检查停止位结束NOP();RSEN=1; //发送重新启始位while(RSEN==1); //检测重新起始位完成IIC_SEND(0b11010001); //读数据for (i=0;i<n;i++) //读字节个数{ RCEN=1;while (RCEN==1);A[i]=SSPBUF; //读1字节if (i<n-1){ ACKDT=0;ACKEN=1;while (ACKEN==1);}else{ ACKDT=1;ACKEN=1;while (ACKEN==1);} //最后一字节不应答}PEN=1;while (PEN==1);}//=====显示DS1307void MENU_DS1307(void){ LCD_WRITE(0b00001100,COM); //D(d2)=1:打开显示,C(d1)=1:光标打开,B(d0)=1:光标不闪烁char i;LCD_WRITE(LINE1,COM); //DDRAM地址,第1行的第1个字符LCD_WRITE(' ',DAT);LCD_WRITE('2',DAT);LCD_WRITE('0',DAT);LCD_WRITE((A[6]>>4)+0x30,DA T);LCD_WRITE((A[6]&0x0F)+0x30,DA T);LCD_WRITE('-',DAT);LCD_WRITE((A[5]>>4)+'0',DA T);LCD_WRITE((A[5]&0x0F)+'0',DAT);LCD_WRITE('-',DAT);LCD_WRITE((A[4]>>4)+'0',DA T);LCD_WRITE((A[4]&0x0F)+'0',DAT);LCD_WRITE(' ',DAT);i=A[3]&0x07;LCD_WRITE(table[(i-1)*4],DA T);LCD_WRITE(table[(i-1)*4+1],DAT);LCD_WRITE(table[(i-1)*4+2],DAT);LCD_WRITE(table[(i-1)*4+3],DAT);//LCD_WRITE(' ',DAT);LCD_WRITE(LINE2,COM); //DDRAM地址,第2行的第1个字符LCD_WRITE(' ',DAT);LCD_WRITE((A[2]>>4)+'0',DA T);LCD_WRITE((A[2]&0x0F)+'0',DAT);LCD_WRITE(0x3A,DA T);LCD_WRITE((A[1]>>4)+'0',DA T);LCD_WRITE((A[1]&0x0F)+'0',DAT);LCD_WRITE(0x3A,DA T);LCD_WRITE((A[0]>>4)+'0',DA T);LCD_WRITE((A[0]&0x0F)+'0',DAT);LCD_WRITE(' ',DAT);}char dec_bcd(char dec){char bcd;bcd= 0;while(dec >= 10){dec -= 10;bcd++;}bcd <<= 4;bcd |= dec;return (bcd);}void bcd_dec(char adr,char R) {SW=A[adr]>>4;GW=A[adr]&0x0F;while(SW>0){R=R+10;SW--;}R+=GW;}//====按键程序void set_time(){if(mod==0){delaynms(30);if(mod==0){while(!mod);//等待M++;if(M==3){ M=0;flag=0;f=0;a=0;}}}if(M==1)//设置时间{if(set==0){delaynms(30);if(set==0){while(!set);a++;if(a==8)a=0;}}guangbiao();//光标定位,闪烁if(a==1){if(add==0){delaynms(30);if(add==0){while(!add);bcd_dec(0,sec);sec++;if(sec==60)sec=0;write_DS1307(0,dec_bcd(sec));}}if(miu==0){delaynms(30);if(miu==0){while(!miu);bcd_dec(0,sec);sec--;if(sec==-1)sec=59;write_DS1307(0,dec_bcd(sec));}}}if(a==2){if(add==0){delaynms(30);if(add==0){while(!add);bcd_dec(1,min);min++;if(min==60)min=0;write_DS1307(1,dec_bcd(min));}}if(miu==0){delaynms(30);if(miu==0){while(!miu);bcd_dec(1,min);min--;if(min==-1)min=59;write_DS1307(1,dec_bcd(min));}}}if(a==3){if(add==0){delaynms(30);if(add==0){while(!add);bcd_dec(2,hour);hour++;if(hour==24)hour=0;write_DS1307(2,dec_bcd(hour));}}if(miu==0){delaynms(30);if(miu==0){while(!miu);bcd_dec(2,hour);hour--;if(hour==-1)hour=23;write_DS1307(2,dec_bcd(hour));}}}if(a==4){if(add==0){delaynms(30);if(add==0){while(!add);bcd_dec(3,week);week++;if(week==8)week=1;write_DS1307(3,dec_bcd(week));}}if(miu==0){delaynms(30);if(miu==0){while(!miu);bcd_dec(3,week);week--;if(week==0)week=7;write_DS1307(3,dec_bcd(week));}}}if(a==5){if(add==0){delaynms(30);if(add==0){while(!add);bcd_dec(4,day);day++;if(day==32)day=1;write_DS1307(4,dec_bcd(day));}}if(miu==0){delaynms(30);if(miu==0){while(!miu);bcd_dec(4,day);day--;if(day==0)day=31;write_DS1307(4,dec_bcd(day));}}}if(a==6){if(add==0){delaynms(30);if(add==0){while(!add);bcd_dec(5,month);month++;if(month==13)month=1;write_DS1307(5,dec_bcd(month));}}if(miu==0){delaynms(30);if(miu==0){while(!miu);bcd_dec(5,month);month--;if(month==0)month=12;write_DS1307(5,dec_bcd(month));}}}if(a==7){if(add==0){delaynms(30);if(add==0){while(!add);bcd_dec(6,year);year++;if(year==99)year=0;write_DS1307(6,dec_bcd(year));}}if(miu==0){delaynms(30);if(miu==0){while(!miu);year--;if(year==-1)year=99;bcd_dec(6,year);write_DS1307(6,dec_bcd(year));}}}READ_DS1307(0,7);//读DS1307}//====闹钟按键设置else if(M==2){f++;flag=1;if(f==1){a=0;LCD_WRITE(LINE2+1,COM);//显示上次闹铃时间BCD(hourt);LCD_WRITE(SW+'0',DAT);LCD_WRITE(GW+'0',DAT);LCD_WRITE(LINE2+4,COM);BCD(mint);LCD_WRITE(SW+'0',DAT);LCD_WRITE(GW+'0',DAT);LCD_WRITE(LINE2+7,COM);BCD(sect);LCD_WRITE(SW+'0',DAT);LCD_WRITE(GW+'0',DAT);}if(set==0) //设置时间{delaynms(30);if(set==0){while(!set);a++;if(a==4)a=0;}}guangbiao();//光标定位,闪烁if(a==1){if(add==0){delaynms(30);if(add==0){while(!add);sect++;if(sect==60)sect=0;BCD(sect);LCD_WRITE(LINE2+7,COM);LCD_WRITE(SW+0x30,DAT); //显示十位LCD_WRITE(GW+0x30,DAT); //显示个位}}if(miu==0){delaynms(30);if(miu==0){while(!miu);sect--;if(sect==-1)sect=59;BCD(sect);LCD_WRITE(LINE2+7,COM);LCD_WRITE(SW+0x30,DAT); //显示十位LCD_WRITE(GW+0x30,DAT); //显示个位}}}if(a==2){if(add==0){delaynms(30);if(add==0){while(!add);mint++;if(mint==60)mint=0;BCD(mint);LCD_WRITE(LINE2+4,COM);LCD_WRITE(SW+0x30,DAT); //显示十位LCD_WRITE(GW+0x30,DAT); //显示个位}}if(miu==0){delaynms(30);if(miu==0){while(!miu);mint--;if(mint==-1)mint=59;BCD(mint);LCD_WRITE(LINE2+4,COM);LCD_WRITE(SW+0x30,DAT); //显示十位LCD_WRITE(GW+0x30,DAT); //显示个位}}}if(a==3){if(add==0){delaynms(30);if(add==0){while(!add);hourt++;if(hourt==24)hour=0;BCD(hourt);LCD_WRITE(LINE2+1,COM);LCD_WRITE(SW+0x30,DAT); //显示十位LCD_WRITE(GW+0x30,DAT); //显示个位}}if(miu==0){delaynms(30);if(miu==0){while(!miu);hourt--;if(hourt==-1)hourt=23;BCD(hourt);LCD_WRITE(LINE2+1,COM);LCD_WRITE(SW+0x30,DAT); //显示十位LCD_WRITE(GW+0x30,DAT); //显示个位}}}}}//====光标定位void guangbiao(void){switch(a){case(1):LCD_WRITE(0b11001000,COM);LCD_WRITE(0b00001111,COM);break;//定位秒,光标打开,B(d0)=1:光标闪烁case(2):LCD_WRITE(0b11000101,COM);LCD_WRITE(0b00001111,COM);break;//定位分,光标打开,B(d0)=1:光标闪烁case(3):LCD_WRITE(0b11000010,COM);LCD_WRITE(0b00001111,COM);break;//定位时,光标打开,B(d0)=1:光标闪烁case(4):LCD_WRITE(0b10001110,COM);LCD_WRITE(0b00001111,COM);break;//定位星期,光标打开,B(d0)=1:光标闪烁case(5):LCD_WRITE(0b10001010,COM);LCD_WRITE(0b00001111,COM);break;//定位日,光标打开,B(d0)=1:光标闪烁case(6):LCD_WRITE(0b10000111,COM);LCD_WRITE(0b00001111,COM);break;//定位月,光标打开,B(d0)=1:光标闪烁case(7):LCD_WRITE(0b10000100,COM);LCD_WRITE(0b00001111,COM);break;//定位秒,光标打开,B(d0)=1:光标闪烁case(8):LCD_WRITE(0b10000010,COM);LCD_WRITE(0b00001111,COM);break;//定位秒,光标打开,B(d0)=1:光标闪烁}}//=====读TC74的温度值signed char READ_T(void){ signed char R1;SEN=1; //开始条件while (SEN==1); //检测开始条件是否完成?IIC_SEND(TC74_ADD<<1); //送TC74地址(写)IIC_SEND(RTR); //写RTR命令(写)RSEN=1; //重新开始条件while (RSEN==1); //等待重新开始条件结束IIC_SEND((TC74_ADD<<1)+1);//发送TC74地址(读)RCEN=1; //接收使能while (RCEN==1); //等待接收完成R1=SSPBUF; //接收数据存入R1PEN=1; //停止位while(PEN==0);return(R1);}//从R1双字节数转换为十进制数万位-个位:WW,QW,BW,SW,GW void BCD(unsigned int R1){ WW=0;QW=0;BW=0;SW=0;GW=0;while(R1>=10000){R1-=10000;WW++;}while(R1>=1000){R1-=1000;QW++;}while(R1>=100){R1-=100;BW++;}while(R1>=10){R1-=10; SW++;}GW=R1;}//===温度显示void DISP_T(signed char R1) //温度在R1{ char R2;if (R1>=0)BCD(R1);else{ R2=~(R1)+1;BCD(R2);}if (R1<0){LCD_WRITE(LINE2+10,COM); //DDRAM地址,第1行的第5个字符LCD_WRITE('-',DAT);}if (R1>=0) //只在温度为正时才显示百位LCD_WRITE(BW+0x30,DAT); //显示百位,数字加上0x30即为相应的ASCII码,下同LCD_WRITE(SW+0x30,DAT); //显示十位LCD_WRITE(GW+0x30,DAT); //显示个位LCD_WRITE(0xDF,DA T); //°LCD_WRITE('C',DAT);LCD_WRITE(' ',DAT);}//====闹钟void clock(){ if(!mod||!set||!add||!miu){delaynms(30);if(!mod||!set||!add||!miu);CCP2CON=0b00000000; //关PWM模式}BCD(sect);if(SW==(A[0]>>4)&&GW==(A[0]&0x0F)){BCD(mint);if(SW==(A[1]>>4)&&GW==(A[1]&0x0F)){BCD(hourt);if(SW==(A[2]>>4)&&GW==(A[2]&0x0F))CCP2CON=0b00001100; //开PWM模式}}}。
基于PIC16F877A单片机的温度,时间显示

基于PIC16F877A单片机的温度,时间显示以及闹钟设置,硬件和软件配备一,硬件图#include<pic.h>__CONFIG(0x3B31);#define rs RD0#define rw RD1#define en RD2#define BEEP RD3 #define s1 RA0#define s2 RA1#define s3 RA2#define s4 RA3#define uint unsigned int#define uchar unsigned charsigned char set_time[7]={0,58,23,6,1,5,12};//秒分时星期日月年signed char read_time[7]={0,0,0,0,0,0,0};signed char shi=7,fen=15,alarm_time=1,reapeat_fen=2,cent;//闹钟时,闹钟分,闹铃响分钟,闹铃响间隔uchar s1_num,s2_num;const uchar alarm[]={"ALARM TIME:"};const uchar mode[]={"MODE:"};const uchar rpt[]={"RPT:"};const uchar min[]={"min"};void PORT_INIT(){TRISA=0xff;//A口设置为输入ADCON1=0x06;//RA口上电复位为模拟输入口TRISC3=1;//SCL和SDA设置为输入TRISC4=1;TRISD=0x00;//D口设置为输出}void IIC_INIT(){SSPCON=0x28;STAT_SMP=0;SSPADD=4;}void delayms(uint z)//延时函数{uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void delayus(uint k){while(k--);}void write_byte_low(uchar R1,uchar flag0)//写一个字节的低4位,flag0为指令/数据选择位{ //,0为写指令,1为写数据uchar low;rs=flag0;low=R1&0x0f;low=low<<4;PORTD&=0x0f;NOP();PORTD|=low;NOP();//写指令的低4位en=1;delayus(20);en=0;}void lcd_write(uchar dat,uchar flag1)//写指令/数据到1602{uchar dat_high,dat_low;dat_high=dat>>4;write_byte_low(dat_high,flag1);dat_low=dat&0x0f;write_byte_low(dat_low,flag1);NOP();}void write_string(uchar address,uchar const *str)//往指定的地址写字符串{uchar i=0;lcd_write(address,0);while(str[i]!='\0'){lcd_write(str[i],1);delayus(5);i++;}}void LCD_INIT()//初始化函数{rw=0;en=0;delayms(20);write_byte_low(0b0011,0);delayms(1);write_byte_low(0b0011,0);delayus(10);write_byte_low(0b0011,0);delayus(10);write_byte_low(0b0010,0);delayms(1);lcd_write(0x28,0);delayms(5);lcd_write(0x0c,0);delayms(5);lcd_write(0x01,0);delayms(5);lcd_write(0x06,0);delayms(5);}void naoling(){uchar i;for(i=0;i<20;i++){BEEP=1;delayus(5);BEEP=0;delayus(5);}}void IIC_SEND(uchar num){SSPBUF=num;while(STAT_RW==1);//等待发送结束while(SSPIF==0);while(ACKSTAT==1);//等待应答}signed char read_temp()//读温度{signed char temp;SEN=1;while(SEN==1);IIC_SEND(0b10011010);IIC_SEND(0);RSEN=1;while(RSEN==1);IIC_SEND(0b10011011);RCEN=1;while(RCEN==1);// SSPIF=0;// while(SSPIF==0);//等待接收结束temp=SSPBUF;PEN=1;while(PEN==1);return temp;}void dispose()//BCD数据处理{uchar i,temp1,temp2;for(i=0;i<7;i++){temp1=set_time[i]/10;temp2=set_time[i]%10;set_time[i]=temp1*16+temp2;}}void time_csh()//时间初始化{uchar i;dispose();for(i=0;i<7;i++){SEN=1;//起始信号while(SEN==1);//检测起始信号是否已完成IIC_SEND(0xd0);IIC_SEND(i);IIC_SEND(set_time[i]);PEN=1;//停止信号while(PEN==1);}}void read_ds1307()//读时间{uchar k;for(k=0;k<8;k++){SEN=1;//起始信号while(SEN==1);IIC_SEND(0xd0);IIC_SEND(k);PEN=1;//停止信号while(PEN==1);RSEN=1;//重新启动while(RSEN==1);IIC_SEND(0xd1);SSPIF=0;RCEN=1;while(SSPIF==0);//等待接收结束read_time[k-1]=SSPBUF;NOP();NOP();PEN=1;//停止信号while(PEN==1);}}void display_time(){lcd_write(0x80,0);lcd_write(0x32,1);lcd_write(0x30,1);lcd_write(0x30+read_time[6]/16,1);//年lcd_write(0x30+read_time[6]%16,1);lcd_write('-',1);lcd_write(0x30+read_time[5]/16,1);//月lcd_write(0x30+read_time[5]%16,1);lcd_write('-',1);lcd_write(0x30+read_time[4]/16,1);//日lcd_write(0x30+read_time[4]%16,1);lcd_write(0x80+0x0d,0);switch(read_time[3]){case 1:lcd_write('M',1);lcd_write('O',1);lcd_write('N',1);break;case 2:lcd_write('T',1);lcd_write('U',1);lcd_write('E',1);break;case 3:lcd_write('W',1);lcd_write('E',1);lcd_write('D',1);break;case 4:lcd_write('T',1);lcd_write('H',1);lcd_write('U',1);break;case 5:lcd_write('F',1);lcd_write('R',1);lcd_write('I',1);break;case 6:lcd_write('S',1);lcd_write('A',1);lcd_write('T',1);break;case 7:lcd_write('S',1);lcd_write('U',1);lcd_write('N',1);break;lcd_write(0x80+0x40,0);lcd_write(0x30+read_time[2]/16,1);//时lcd_write(0x30+read_time[2]%16,1);lcd_write(':',1);lcd_write(0x30+read_time[1]/16,1); //分lcd_write(0x30+read_time[1]%16,1);lcd_write(':',1);lcd_write(0x30+read_time[0]/16,1); //秒lcd_write(0x30+read_time[0]%16,1);NOP();NOP();cent=read_temp();lcd_write(0x80+0x4b,0);lcd_write(0x30+cent/10,1);lcd_write(0x30+cent%10,1);lcd_write(0xdf,1);lcd_write('C',1);if((shi==(read_time[2]/16*10+read_time[2]%16))&&(fen<=(read_ti me[1]/16*10+read_time[1]%16))&&((read_time[1]/16*10+read_time[1] %16)<(fen+alarm_time)))naoling();}if((shi==(read_time[2]/16*10+read_time[2]%16))&&(fen+reapeat_fe n<=(read_time[1]/16*10+read_time[1]%16))&&((read_time[1]/16*10+re ad_time[1]%16)<(fen+alarm_time+reapeat_fen))){naoling();}if((shi==(read_time[2]/16*10+read_time[2]%16))&&(fen+2*reapeat _fen<=(read_time[1]/16*10+read_time[1]%16))&&((read_time[1]/16*10 +read_time[1]%16)<(fen+alarm_time+2*reapeat_fen))){naoling();}if((shi==(read_time[2]/16*10+read_time[2]%16))&&(fen+3*reapeat _fen<=(read_time[1]/16*10+read_time[1]%16))&&((read_time[1]/16*10 +read_time[1]%16)<(fen+alarm_time+3*reapeat_fen))){naoling();}if((shi==(read_time[2]/16*10+read_time[2]%16))&&(fen+4*reapeat_fen<=(read_time[1]/16*10+read_time[1]%16))&&((read_time[1]/16*10 +read_time[1]%16)<(fen+alarm_time+4*reapeat_fen))){naoling();}}void setting_time(){uchar l,s2_value,setting_flag;if(s2==0){delayms(10);if(s2==0){s2_value++;setting_flag = 1;while(s2==0);//松手检测for(l=0;l<7;l++)//存储当前时间数据//年星期月日时分秒{set_time[l]=read_time[l]/16*10+read_time[l]%16;}while(setting_flag){if(s2==0){delayms(5);if(s2==0){s2_value++;while(s2==0);//松手检测}}if(s2_value==1){lcd_write(0x83,0);//指向年份lcd_write(0x0f,0);//显示游标并闪烁if(s3==0){delayms(5);if(s3==0){set_time[6]++;if(set_time[6]==100){set_time[6]=0;}lcd_write(0x82,0);lcd_write(0x30+set_time[6]/10,1);lcd_write(0x30+set_time[6]%10,1);lcd_write(0x83,0);//指向年份while(s3==0);}}if(s4==0){delayms(5);{set_time[6]--;if(set_time[6]==-1){set_time[6]=99;}lcd_write(0x82,0);lcd_write(0x30+set_time[6]/10,1);lcd_write(0x30+set_time[6]%10,1);lcd_write(0x83,0);//指向年份while(s4==0);}}}if(s2_value==2){lcd_write(0x86,0);//指向月份if(s3==0){delayms(5);{set_time[5]++;if(set_time[5]==13){set_time[5]=1;}lcd_write(0x85,0);lcd_write(0x30+set_time[5]/10,1);lcd_write(0x30+set_time[5]%10,1);lcd_write(0x86,0);//指向月份while(s3==0);}}if(s4==0){delayms(5);if(s4==0){set_time[5]--;{set_time[5]=12;}lcd_write(0x85,0);lcd_write(0x30+set_time[5]/10,1);lcd_write(0x30+set_time[5]%10,1);lcd_write(0x86,0);//指向月份while(s4==0);}}}if(s2_value==3){lcd_write(0x89,0);//指向日if(s3==0){delayms(5);if(s3==0){set_time[4]++;{set_time[4]=1;}lcd_write(0x88,0);lcd_write(0x30+set_time[4]/10,1);lcd_write(0x30+set_time[4]%10,1);lcd_write(0x89,0);//指向日while(s3==0);}}if(s4==0){delayms(5);if(s4==0){set_time[4]--;if(set_time[4]==0){set_time[4]=31;lcd_write(0x88,0);lcd_write(0x30+set_time[4]/10,1);lcd_write(0x30+set_time[4]%10,1);lcd_write(0x89,0);//指向日while(s4==0);}}}if(s2_value==4){lcd_write(0x8f,0);//指向星期if(s3==0){delayms(5);if(s3==0){set_time[3]++;if(set_time[3]==8)set_time[3]=1;}switch(set_time[3]){case1:lcd_write(0x8d,0);lcd_write('M',1);lcd_write('O',1);lcd_write('N',1);bre ak;case2:lcd_write(0x8d,0);lcd_write('T',1);lcd_write('U',1);lcd_write('E',1);brea k;case3:lcd_write(0x8d,0);lcd_write('W',1);lcd_write('E',1);lcd_write('D',1);bre ak;case4:lcd_write(0x8d,0);lcd_write('T',1);lcd_write('H',1);lcd_write('U',1);brea k;case5:lcd_write(0x8d,0);lcd_write('F',1);lcd_write('R',1);lcd_write('I',1);break ;case6:lcd_write(0x8d,0);lcd_write('S',1);lcd_write('A',1);lcd_write('T',1);break;case7:lcd_write(0x8d,0);lcd_write('S',1);lcd_write('U',1);lcd_write('N',1);brea k;}lcd_write(0x8f,0);//指向星期while(s3==0);}}if(s4==0){delayms(5);if(s4==0){set_time[3]--;if(set_time[3]==0){set_time[3]=7;}switch(set_time[3])case1:lcd_write(0x8d,0);lcd_write('M',1);lcd_write('O',1);lcd_write('N',1);bre ak;case2:lcd_write(0x8d,0);lcd_write('T',1);lcd_write('U',1);lcd_write('E',1);brea k;case3:lcd_write(0x8d,0);lcd_write('W',1);lcd_write('E',1);lcd_write('D',1);bre ak;case4:lcd_write(0x8d,0);lcd_write('T',1);lcd_write('H',1);lcd_write('U',1);brea k;case5:lcd_write(0x8d,0);lcd_write('F',1);lcd_write('R',1);lcd_write('I',1);break ;case6:lcd_write(0x8d,0);lcd_write('S',1);lcd_write('A',1);lcd_write('T',1);brea k;case7:lcd_write(0x8d,0);lcd_write('S',1);lcd_write('U',1);lcd_write('N',1);brea k;lcd_write(0x8f,0);//指向星期while(s4==0);}}}if(s2_value==5){lcd_write(0x80+0x41,0);//指向小时if(s3==0){delayms(5);if(s3==0){set_time[2]++;if(set_time[2]==24){set_time[2]=0;}lcd_write(0x80+0x40,0);lcd_write(0x30+set_time[2]/10,1);lcd_write(0x30+set_time[2]%10,1);lcd_write(0x80+0x41,0);//指向小时while(s3==0);}}if(s4==0){delayms(5);if(s4==0){set_time[2]--;if(set_time[2]==-1){set_time[2]=23;}lcd_write(0x80+0x40,0);lcd_write(0x30+set_time[2]/10,1);lcd_write(0x30+set_time[2]%10,1);lcd_write(0x80+0x41,0);//指向小时while(s4==0);}}}if(s2_value==6){lcd_write(0x80+0x44,0);//指向分钟if(s3==0){delayms(5);if(s3==0){set_time[1]++;if(set_time[1]==60){set_time[1]=0;}lcd_write(0x80+0x43,0);lcd_write(0x30+set_time[1]/10,1);lcd_write(0x30+set_time[1]%10,1);lcd_write(0x80+0x44,0);//指向分钟while(s3==0);}}if(s4==0){delayms(5);if(s4==0){set_time[1]--;if(set_time[1]==-1){set_time[1]=59;}lcd_write(0x80+0x43,0);lcd_write(0x30+set_time[1]/10,1);lcd_write(0x30+set_time[1]%10,1);lcd_write(0x80+0x44,0);//指向分钟while(s4==0);}}}if(s2_value==7){lcd_write(0x80+0x47,0);//指向秒if(s3==0){delayms(5);if(s3==0){set_time[0]++;if(set_time[0]==60){set_time[0]=0;}lcd_write(0x80+0x46,0);lcd_write(0x30+set_time[0]/10,1);lcd_write(0x30+set_time[0]%10,1);lcd_write(0x80+0x47,0);//指向分钟while(s3==0);}}if(s4==0){delayms(5);if(s4==0){set_time[0]--;if(set_time[0]==-1){set_time[0]=59;}lcd_write(0x80+0x46,0);lcd_write(0x30+set_time[0]/10,1);lcd_write(0x30+set_time[0]%10,1);lcd_write(0x80+0x47,0);//指向分钟while(s4==0);}}}if(s2_value==8)//这里注意?{s2_value=0;lcd_write(0x0c,0);setting_flag=0;time_csh();}}}}}void naozhong(){write_string(0x80,alarm);lcd_write(0x30+shi/10,1);lcd_write(0x30+shi%10,1);lcd_write('-',1);lcd_write(0x30+fen/10,1);lcd_write(0x30+fen%10,1);write_string(0x80+0x40,mode);lcd_write(0x30+alarm_time,1);write_string(0x80+0x47,rpt);lcd_write(0x30+reapeat_fen/10,1);lcd_write(0x30+reapeat_fen%10,1);write_string(0x80+0x4d,min);}uchar s1_scan(){if(s1==0){delayms(5);if(s1==0){s1_num++;if(s1_num==2){s1_num=0;s2_num=0;lcd_write(0x0c,0);}while(s1==0);lcd_write(0x01,0);if(s1_num==1){naozhong();lcd_write(0x0f,0);}}}return s1_num;}void setting_naozhong(){if(s2==0){delayms(5);if(s2==0){s2_num++;if(s2_num==4){s2_num=0;}while(s2==0);}}switch(s2_num){case 0:{lcd_write(0x8c,0);if(s3==0){delayms(5);if(s3==0){shi++;if(shi==24){shi=0;}lcd_write(0x8b,0);lcd_write(0x30+shi/10,1);lcd_write(0x30+shi%10,1);lcd_write(0x8c,0);//指向小时while(s3==0);}}if(s4==0){delayms(5);if(s4==0){shi--;if(shi==-1){shi=23;}lcd_write(0x8b,0);lcd_write(0x30+shi/10,1);lcd_write(0x30+shi%10,1);lcd_write(0x8c,0);//指向小时while(s4==0);}}break;}case 1:{lcd_write(0x8f,0);if(s3==0){delayms(5);if(s3==0){fen++;if(fen==60){fen=0;}lcd_write(0x8e,0);lcd_write(0x30+fen/10,1);lcd_write(0x30+fen%10,1);lcd_write(0x8f,0);//指向小时while(s3==0);}}if(s4==0){delayms(5);if(s4==0){fen--;if(fen==-1){fen=59;}lcd_write(0x8e,0);lcd_write(0x30+fen/10,1);lcd_write(0x30+fen%10,1);lcd_write(0x8f,0);//指向小时while(s4==0);}}break;}case 2:{lcd_write(0x80+0x45,0);if(s3==0){delayms(5);if(s3==0){alarm_time++;if(alarm_time==10){alarm_time=1;}lcd_write(0x30+alarm_time,1);lcd_write(0x80+0x45,0);//指向小时while(s3==0);}}if(s4==0){delayms(5);if(s4==0){alarm_time--;if(alarm_time==0){alarm_time=9;}lcd_write(0x30+alarm_time,1);lcd_write(0x80+0x45,0);//指向小时while(s4==0);}}break;}case 3:{lcd_write(0x80+0x4c,0);if(s3==0){delayms(5);if(s3==0){reapeat_fen++;if(reapeat_fen==60){reapeat_fen=0;}lcd_write(0x80+0x4b,0);lcd_write(0x30+reapeat_fen/10,1);lcd_write(0x30+reapeat_fen%10,1);lcd_write(0x80+0x4c,0);//指向小时while(s3==0);}}if(s4==0){delayms(5);if(s4==0){reapeat_fen--;if(reapeat_fen==-1){reapeat_fen=59;}lcd_write(0x80+0x4b,0);lcd_write(0x30+reapeat_fen/10,1);lcd_write(0x30+reapeat_fen%10,1);lcd_write(0x80+0x4c,0);//指向小时while(s4==0);}}break;}default:break;}}void main(){PORT_INIT();LCD_INIT();IIC_INIT();time_csh();while(1){switch(s1_scan()){case 0:read_ds1307();display_time();setting_time();break;case 1:setting_naozhong();break;default:break;}} }。
用C语言写的一个PIC16F877的时闹钟程序

用C语言写的一个PIC16F877的时闹钟程序单片机用16F877,主时钟用20MHz,用32768作定时时间。
可以实现2路定闹,每一路都可分别设置和开关,采用4x4键盘,16x2的字符型LCD显示。
连线在程序开头有说明。
程序的功能:(1)上电后LCD背光打开,并显示倒计时5秒,然后时钟开始工作。
(2)用模式键(*)切换模式,如显示时间、日期、闹钟1、闹钟2等,并且可以用上、下键控制加1、减1或是闹钟的On、Off。
(3)原程序有16个键,包括0~9数字键,可以直接输入要设置的时间值,但后来将数字键取消了,你仍然可以通过修改程序的部分注释恢复此功能。
(4)闹钟有2路,时间到后闹2分钟,可按任意键取消本次闹钟。
闹钟响时有2种音调,是用PIC的PWM实现的。
(5)按任意键可打开背光,1分钟后自动关闭背光。
(6)RA0~RA3为按键扫描输入,应接下拉电阻。
主程序// FileName: Main.c// MCU: Microchip PIC16F877// Tool: CCS-C compiler// Author: KingEDA, MSN:kingeda@, skype:kingeda, E-mail:kingeda@// Website: // Description:// A timer program// Ver 0.1: 2003-03-31, all clock function with date display, 2 way alarm.// Ver 0.2: 2003-05-05, (1) Alarm default is on,modify alarm1 time to 7:00:00,// and alarm2 to 13:30:00.// (2) Backlight will be enabled when alarming.// (3) Automatic adjust day(28,30,31).// (4) Automatic move cursor to next location when set item.// PIN Connection:// RC0~1 : 32768Hz crystal// RC2 : Buzzer// RC3 : LCD Back Light,drive a PNP BJT// RD0~RD7 : to LCD DB0~DB7// RA0~RA3 : keypad col in// RC4~RC7 : keypad line out// 7 8 9 #// 4 5 6 ↑// 1 2 3 ↓// 0 ←→*// RE0 : LCD RS// RE1 : LCD RW// RE2 : LCD E#include "my16f877.h"#device ICD=true//#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT #use delay(clock = 24000000)//#use fast_io(C)#use fast_io(E)#define lcd_busy (lcd_read_addr()&0x80) == 0x80#define time_start_addr 0x80+0x04#define time_hourh_addr time_start_addr#define time_hourl_addr time_start_addr+1#define time_minuteh_addr time_start_addr+3#define time_minutel_addr time_start_addr+4#define time_secondh_addr time_start_addr+6#define time_secondl_addr time_start_addr+7#define key_0 0x11#define key_1 0x21#define key_2 0x22#define key_3 0x24#define key_4 0x41#define key_5 0x42#define key_6 0x44#define key_7 0x81#define key_8 0x82#define key_9 0x84#define key_left 0x12#define key_right 0x14#define key_up 0x48#define key_down 0x28#define key_mode 0x18#define key_cancel 0x88char StrPower1[] = " * Power on * ";char StrSetTime[] = " * Adjust time* ";char StrSetDate[] = " * Adjust date* ";char StrAlarm1[] = " * Set alarm 1* ";char StrAlarm2[] = " * Set alarm 2* ";unsigned char PORTC_MAP;#bit BackLightEn = PORTC_MAP.3unsigned char BackLightTimer;int1 led;#bit lcd_rs = PORTE.0#bit lcd_rw = PORTE.1#bit lcd_e = PORTE.2#byte lcd_bus = PORTD#byte lcd_dir = TRISD#define PWM_on 0x0c#define PWM_off 0x00#define PWM_period 200#define PWM_DC 100unsigned char lcd_addr;unsigned char KeyLine;unsigned char KeyOld;unsigned char KeyNew;struct mTime {unsigned char hourh; // hour,0~23unsigned char hourl;unsigned char minuteh; // minute,0~59unsigned char minutel;unsigned char secondh; // second,0~59unsigned char secondl;};struct mTime CurrentTime = {1,2,0,0,0,0};struct mTime AlarmTime1 = {0,7,0,0,0,0}; // 07:00:00 struct mTime AlarmTime2 = {1,3,3,0,0,0}; // 13:30:00 unsigned char AlarmStatus;#bit Alarm1Enable = AlarmStatus.0#bit Alarm2Enable = AlarmStatus.1#bit Alarm1Alarm = AlarmStatus.2#bit Alarm2Alarm = AlarmStatus.3unsigned char Alarm1Cnt; // alarm1 second count unsigned char Alarm2Cnt;unsigned char CurrentMode;#define mode_time 0#define mode_set_time 1#define mode_set_date 2#define mode_set_alarm1 3#define mode_set_alarm2 4unsigned char adjust_item;struct mDate {unsigned char year1; //unsigned char year2;unsigned char year3;unsigned char year4;unsigned char monthh;unsigned char monthl;unsigned char dayh;unsigned char dayl;};struct mDate CurrentDate = {2,0,0,3,0,1,0,1}; unsigned char *pStr;// ------------------------------------------------------- unsigned char lcd_read_addr(){unsigned char ch;lcd_dir = 0xff; // read from lcdlcd_rs = 0;lcd_rw = 1; // instlcd_e = 1;#asmnopnopnop#endasmch = lcd_bus;lcd_e = 0;lcd_dir = 0x00; // set write to lcdreturn ch;}// ------------------------------------------------------- unsigned char lcd_write_data(unsigned char ch) {while (lcd_busy){ restart_wdt(); }lcd_rs = 1; // datalcd_rw = 0; // writelcd_bus = ch; // write outlcd_e = 1;#asmnopnopnop#endasmlcd_e = 0;return 'Y';}// ------------------------------------------------------- unsigned char lcd_write_inst(unsigned char ch) {while (lcd_busy){ restart_wdt(); }lcd_rs = 0; // instlcd_rw = 0; // writelcd_bus = ch;lcd_e = 1;#asmnopnopnop#endasmlcd_e = 0;return 'Y';}// ------------------------------------------------------- unsigned char lcd_read_data(){unsigned char ch;while (lcd_busy){ restart_wdt(); }lcd_dir = 0xff; // read from lcdlcd_rs = 1; // datalcd_rw = 1; // readlcd_e = 1;#asmnopnopnop#endasmch = lcd_bus; // read inlcd_e = 0;lcd_dir = 0x00; // set write to lcdreturn ch;}// ------------------------------------------------------- void lcd_init(){unsigned char Tempch;lcd_addr = 0;delay_ms(100);Tempch = 0x38; // 1-line mode,5x8 dotslcd_write_inst(Tempch); // Function setTempch = 0x0f; // lcd on,cursor on,blink onlcd_write_inst(Tempch); // Display on/offTempch = 0x06; // Increment mode,Entire shift offlcd_write_inst(Tempch);Tempch = 0x01; // clear displaylcd_write_inst(Tempch);delay_ms(3);}// -------------------------------------------------------//#int_timer1//void timer1_interrupt(void)#int_ccp2void ccp2_interrupt(void){//TMR1H = 0x80;if (CurrentTime.secondl==9){CurrentTime.secondl=0;if (CurrentTime.secondh==5){CurrentTime.secondh=0;if (CurrentTime.minutel==9){CurrentTime.minutel=0;if (CurrentTime.minuteh==5){CurrentTime.minuteh=0;if (CurrentTime.hourl==9){CurrentTime.hourl=0;CurrentTime.hourh++;}else if((CurrentTime.hourl==3) && (CurrentTime.hourh==2)){CurrentTime.hourl=0;CurrentTime.hourh=0;if ((((CurrentDate.dayl == 8) || (CurrentDate.dayl == 9)) && (CurrentDate.dayh == 2) && (CurrentDate.monthl == 2) && (CurrentDate.monthh == 0)) ||((CurrentDate.dayl == 0) && (CurrentDate.dayh == 3) && ((((CurrentDate.monthl == 4) || (CurrentDate.monthl == 6)|| (CurrentDate.monthl == 9)) && (CurrentDate.monthh == 0)) || ((CurrentDate.monthl == 1) && (CurrentDate.monthh == 1)))) ||((CurrentDate.dayl == 1) && (CurrentDate.dayh == 3))){CurrentDate.dayl=1;CurrentDate.dayh=0;if ((CurrentDate.monthl == 2) && (CurrentDate.monthh == 1)){CurrentDate.monthl = 1;CurrentDate.monthh = 0;if (CurrentDate.year4 == 9){CurrentDate.year4 = 0;if (CurrentDate.year3 == 9){CurrentDate.year3 = 0;if (CurrentDate.year2 == 9){CurrentDate.year2 = 0;CurrentDate.year1++;}elseCurrentDate.year2++;}elseCurrentDate.year3++;}elseCurrentDate.year4++;}else if(CurrentDate.monthl == 9){CurrentDate.monthl = 0;CurrentDate.monthh++;}elseCurrentDate.monthl++;}else if(CurrentDate.dayl == 9){CurrentDate.dayl=0;CurrentDate.dayh++;}elseCurrentDate.dayl++;}elseCurrentTime.hourl++;}elseCurrentTime.minuteh++;}elseCurrentTime.minutel++;}elseCurrentTime.secondh++;}elseCurrentTime.secondl++;if ((Alarm1Alarm == false) & (Alarm2Alarm == false)){led = 0;CCP1CON = PWM_off;}else{if (led == 1){led = 0;PR2 = PWM_period; // set pwm periodCCPR1L = PWM_DC; // set pwm duty cycle//CCP1CON = PWM_on;}else{led = 1;PR2 = PWM_period/2; // set pwm periodCCPR1L = PWM_DC/2; // set pwm duty cycle//CCP1CON = PWM_off;}}Alarm1Cnt++;Alarm2Cnt++;if (BackLightEn == 0)if (((BackLightTimer++)>=60) & (Alarm1Alarm == false) & (Alarm1Alarm == false))BackLightEn = 1; // disable backlight PORTC = PORTC_MAP;//TMR1IF = 0;//PIR1 = PIR2 = 0x00;CCP2IF = 0;}// ------------------------------------------------------- unsigned char get_key(void){unsigned char key_in,tmp;TRISC = 0x03;KeyLine = 0xf0;PORTC = KeyLine | PORTC_MAP;#asmnopnopnop#endasmif ((PORTA & 0x0f) != 0){tmp = 0x10;for (KeyLine = tmp;KeyLine!=0;KeyLine = tmp){PORTC = KeyLine | PORTC_MAP;tmp = KeyLine <<1;#asmnopnopnop#endasmkey_in = PORTA & 0x0f;if (key_in != 0){return (key_in | KeyLine);}}return 0;}elsereturn 0;}// -------------------------------------------------------void set_mode(void){if (CurrentMode == mode_set_alarm2)CurrentMode = mode_time;else{CurrentMode++;adjust_item = 0;}lcd_write_inst(0x01); // clear LCD displaylcd_write_inst(time_start_addr); // set LCD line1 if (CurrentMode == mode_set_time){lcd_write_data(CurrentTime.hourh + '0');lcd_write_data(CurrentTime.hourl + '0');lcd_write_data(':');lcd_write_data(CurrentTime.minuteh + '0');lcd_write_data(CurrentTime.minutel + '0');lcd_write_data(':');lcd_write_data(CurrentTime.secondh + '0');lcd_write_data(CurrentTime.secondl + '0');pStr = StrSetTime;}else if(CurrentMode == mode_set_date){lcd_write_data(CurrentDate.year1 + '0');lcd_write_data(CurrentDate.year2 + '0');lcd_write_data(CurrentDate.year3 + '0');lcd_write_data(CurrentDate.year4 + '0');lcd_write_data('/');lcd_write_data(CurrentDate.monthh + '0');lcd_write_data(CurrentDate.monthl + '0');lcd_write_data('/');lcd_write_data(CurrentDate.dayh + '0');lcd_write_data(CurrentDate.dayl + '0');pStr = StrSetDate;}else if(CurrentMode == mode_set_alarm1){lcd_write_data(AlarmTime1.hourh + '0');lcd_write_data(AlarmTime1.hourl + '0');lcd_write_data(':');lcd_write_data(AlarmTime1.minuteh + '0');lcd_write_data(AlarmTime1.minutel + '0');lcd_write_data(':');lcd_write_data(AlarmTime1.secondh + '0');lcd_write_data(AlarmTime1.secondl + '0');lcd_write_data(' ');lcd_write_data('O');if (Alarm1Enable){lcd_write_data('n');}else{lcd_write_data('f');lcd_write_data('f');}pStr = StrAlarm1;Alarm1Cnt =0;}else if(CurrentMode == mode_set_alarm2) {lcd_write_data(AlarmTime2.hourh + '0');lcd_write_data(AlarmTime2.hourl + '0');lcd_write_data(':');lcd_write_data(AlarmTime2.minuteh + '0');lcd_write_data(AlarmTime2.minutel + '0');lcd_write_data(':');lcd_write_data(AlarmTime2.secondh + '0');lcd_write_data(AlarmTime2.secondl + '0');lcd_write_data(' ');lcd_write_data('O');if (Alarm2Enable){lcd_write_data('n');}else{lcd_write_data('f');lcd_write_data('f');}pStr = StrAlarm2;Alarm2Cnt = 0;}lcd_write_inst(0xc0); // set LCD line2 if (CurrentMode != mode_time){for (;*pStr!=0;pStr++){ // write hint messagelcd_write_data(*pStr);}lcd_write_inst(0x0f); // LCD cursor onlcd_write_inst(time_start_addr); // move cursor to start }else // time mode,write date to second line{lcd_write_inst(0x0c); // LCD sursor off/* lcd_write_inst(0xc0 + 3); // set date start address lcd_write_data(CurrentDate.year1 + '0');lcd_write_data(CurrentDate.year2 + '0');lcd_write_data(CurrentDate.year3 + '0');lcd_write_data(CurrentDate.year4 + '0');lcd_write_data('/');lcd_write_data(CurrentDate.monthh + '0');lcd_write_data(CurrentDate.monthl + '0');lcd_write_data('/');lcd_write_data(CurrentDate.dayh + '0');lcd_write_data(CurrentDate.dayl + '0');*/ }if (CurrentMode == mode_set_time){lcd_write_inst(time_start_addr); // move cursor to start }else if (CurrentMode == mode_set_date){lcd_write_inst(time_start_addr); // move cursor to start }else if (CurrentMode == mode_set_alarm1){lcd_write_inst(time_secondl_addr+3);adjust_item = 6;}else if (CurrentMode == mode_set_alarm2){lcd_write_inst(time_secondl_addr+3);adjust_item = 6;}else{lcd_write_inst(0x0c); // LCD cursor off}}// ------------------------------------------------------- void set_date(void){if (adjust_item == 0) // adjust year{if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year1 = KeyNew;lcd_write_data(CurrentDate.year1 + '0');//lcd_write_inst(time_start_addr);adjust_item ++;}else if (KeyNew == key_left){adjust_item = 7;lcd_write_inst(time_start_addr + 9);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 1);}}else if(adjust_item == 1){if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year2 = KeyNew;lcd_write_data(CurrentDate.year2 + '0');//lcd_write_inst(time_start_addr + 1);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 0);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 2);}}else if(adjust_item == 2){if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year3 = KeyNew;lcd_write_data(CurrentDate.year3 + '0');//lcd_write_inst(time_start_addr + 2);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 1);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 3);}}else if(adjust_item == 3){if ((KeyNew >=0) & (KeyNew <= 9)){CurrentDate.year4 = KeyNew;lcd_write_data(CurrentDate.year4 + '0');//lcd_write_inst(time_start_addr + 3);adjust_item ++;lcd_write_inst(time_start_addr + 5);}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 2);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 5);}}else if(adjust_item == 4)if (((CurrentDate.monthl>2) & (KeyNew == 0)) | ((CurrentDate.monthl == 0) & (KeyNew == 1))| (((CurrentDate.monthl == 1) | (CurrentDate.monthl == 2)) & (KeyNew <2))) {CurrentDate.monthh = KeyNew;lcd_write_data(CurrentDate.monthh + '0');//lcd_write_inst(time_start_addr + 5);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 3);}else if (KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 6);}}else if(adjust_item == 5){if (((CurrentDate.monthh == 3) & (KeyNew <2)) | ((CurrentDate.monthh != 3) & (KeyNew >=0) & (KeyNew <=9))){CurrentDate.monthl = KeyNew;lcd_write_data(CurrentDate.monthl + '0');//lcd_write_inst(time_start_addr + 6);adjust_item ++;lcd_write_inst(time_start_addr + 8);}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 5);}else if (KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 8);}}else if(adjust_item == 6)if (((CurrentDate.dayl>1) & ((KeyNew == 1) | (KeyNew == 2))) | ((CurrentDate.dayl == 0) & (KeyNew >0) & (KeyNew<4))| ((CurrentDate.dayl == 1) & (KeyNew <4))){CurrentDate.dayh = KeyNew;lcd_write_data(CurrentDate.dayh + '0');//lcd_write_inst(time_start_addr + 8);adjust_item ++;}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 6);}else if (KeyNew == key_right){adjust_item ++;lcd_write_inst(time_start_addr + 9);}}else if(adjust_item == 7){if (((CurrentDate.dayh == 3) & (KeyNew <2)) | ((CurrentDate.dayh != 3) & (KeyNew >=0) & (KeyNew <=9))){CurrentDate.dayl = KeyNew;lcd_write_data(CurrentDate.dayl + '0');//lcd_write_inst(time_start_addr + 9);adjust_item ++;lcd_write_inst(time_start_addr + 0);}else if (KeyNew == key_left){adjust_item --;lcd_write_inst(time_start_addr + 8);}else if (KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_start_addr + 0);}}}// -------------------------------------------------------void set_time(void){if (adjust_item == 0) // set hourh{if (((CurrentTime.hourl <4) & (KeyNew < 3)) | ((CurrentTime.hourl >3) & (KeyNew <2))){CurrentTime.hourh = KeyNew;lcd_write_data(CurrentTime.hourh + '0'); // refresh hourh//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item = 5;lcd_write_inst(time_secondl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_hourl_addr);}}else if (adjust_item == 1) // set hourl{if (((CurrentTime.hourh == 2) & (KeyNew < 4)) | ((CurrentTime.hourh < 2) & (KeyNew <=9))){CurrentTime.hourl = KeyNew;lcd_write_data(CurrentTime.hourl + '0'); // refresh hourl//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minuteh_addr);}}else if (adjust_item == 2) // set minuteh{if (KeyNew <6){CurrentTime.minuteh = KeyNew;lcd_write_data(CurrentTime.minuteh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minutel_addr);}}else if (adjust_item == 3) // set minutel{if ((KeyNew >=0) & (KeyNew <=9)){CurrentTime.minutel = KeyNew;lcd_write_data(CurrentTime.minutel + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondh_addr);}}else if (adjust_item == 4) // set secondh{if (KeyNew <6){CurrentTime.secondh = KeyNew;lcd_write_data(CurrentTime.secondh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;&nb, sp; lcd_write_inst(time_minutel_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr);}}else if (adjust_item == 5) // set secondl{if ((KeyNew >=0) & (KeyNew <=9)){CurrentTime.secondl = KeyNew;lcd_write_data(CurrentTime.secondl + '0');//lcd_write_inst(0x10); // move cursor backadjust_item = 0;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_hourh_addr);}}}// -------------------------------------------------------void set_alarm1(void){if (adjust_item == 0) // set hourh{if (((AlarmTime1.hourl <4) & (KeyNew < 3)) | ((AlarmTime1.hourl >3) & (KeyNew <2))){AlarmTime1.hourh = KeyNew;lcd_write_data(AlarmTime1.hourh + '0'); // refresh hourh//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item = 6;lcd_write_inst(time_secondl_addr + 3);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_hourl_addr);}}else if (adjust_item == 1) // set hourl{if (((AlarmTime1.hourh == 2) & (KeyNew < 4)) | ((AlarmTime1.hourh < 2) & (KeyNew <=9))){AlarmTime1.hourl = KeyNew;lcd_write_data(AlarmTime1.hourl + '0'); // refresh hourl//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minuteh_addr);}}else if (adjust_item == 2) // set minuteh{if (KeyNew <6){AlarmTime1.minuteh = KeyNew;lcd_write_data(AlarmTime1.minuteh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minutel_addr);}}else if (adjust_item == 3) // set minutel{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime1.minutel = KeyNew;lcd_write_data(AlarmTime1.minutel + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondh_addr);}}else if (adjust_item == 4) // set secondh{if (KeyNew <6){AlarmTime1.secondh = KeyNew;lcd_write_data(AlarmTime1.secondh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minutel_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr);}}else if (adjust_item == 5) // set secondl{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime1.secondl = KeyNew;lcd_write_data(AlarmTime1.secondl + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondl_addr+3);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr+3);}}else if (adjust_item == 6) // set on/off{if ((KeyNew == key_up) | (KeyNew == key_down)){if (Alarm1Enable){Alarm1Enable =false; // disable alarm1lcd_write_data('f');lcd_write_data('f');}else{Alarm1Enable =true; // enable alarm1lcd_write_data('n');lcd_write_data(' ');}//lcd_write_inst(time_secondl_addr+3);adjust_item = 0;lcd_write_inst(time_hourh_addr);Alarm1Cnt = 0;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondl_addr);}else if(KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_hourh_addr);}}}// -------------------------------------------------------void set_alarm2(void){if (adjust_item == 0) // set hourh{if (((AlarmTime2.hourl <4) & (KeyNew < 3)) | ((AlarmTime2.hourl >3) & (KeyNew <2))){AlarmTime2.hourh = KeyNew;lcd_write_data(AlarmTime2.hourh + '0'); // refresh hourh//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item = 6;lcd_write_inst(time_secondl_addr+3);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_hourl_addr);}}else if (adjust_item == 1) // set hourl{if (((AlarmTime2.hourh == 2) & (KeyNew < 4)) | ((AlarmTime2.hourh < 2) & (KeyNew <=9))){AlarmTime2.hourl = KeyNew;lcd_write_data(AlarmTime2.hourl + '0'); // refresh hourl//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minuteh_addr);}}else if (adjust_item == 2) // set minuteh{if (KeyNew <6){AlarmTime2.minuteh = KeyNew;lcd_write_data(AlarmTime2.minuteh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_hourl_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_minutel_addr);}}else if (adjust_item == 3) // set minutel{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime2.minutel = KeyNew;lcd_write_data(AlarmTime2.minutel + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minuteh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondh_addr);}}else if (adjust_item == 4) // set secondh{if (KeyNew <6){AlarmTime2.secondh = KeyNew;lcd_write_data(AlarmTime2.secondh + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_minutel_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr);}}else if (adjust_item == 5) // set secondl{if ((KeyNew >=0) & (KeyNew <=9)){AlarmTime2.secondl = KeyNew;lcd_write_data(AlarmTime2.secondl + '0');//lcd_write_inst(0x10); // move cursor backadjust_item ++;lcd_write_inst(time_secondl_addr+3);}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondh_addr);}else if(KeyNew == key_right){adjust_item ++;lcd_write_inst(time_secondl_addr+3);}}else if (adjust_item == 6) // set on/off{if ((KeyNew == key_up) | (KeyNew == key_down)){if (Alarm2Enable){Alarm2Enable =false; // disable alarm2lcd_write_data('f');lcd_write_data('f');}else{Alarm2Enable =true; // enable alarm2lcd_write_data('n');lcd_write_data(' ');}//lcd_write_inst(time_secondl_addr+3);adjust_item = 0;lcd_write_inst(time_hourh_addr);Alarm2Cnt = 0;}else if(KeyNew == key_left){adjust_item --;lcd_write_inst(time_secondl_addr);}else if(KeyNew == key_right){adjust_item = 0;lcd_write_inst(time_hourh_addr);}}}// -------------------------------------------------------void main(void){unsigned char cnt;TRISC = 0x03; // PORTC.3 drive led,low activePORTC_MAP = 0x00;led = 0;BackLightEn = 0;BackLightTimer = 0;PORTC = PORTC_MAP;TRISA = 0xff; // low half byte as keyscan inTRISE = 0x00;ADCON0 = 0x00;ADCON1 = 0x06; // all digital I/Oslcd_init();INTCON = 0x00;lcd_write_inst(0x80); // set lcd ddram addressfor (pStr = StrPower1;*pStr!=0;pStr++){lcd_write_data(*pStr);}lcd_write_inst(0x0c); // LCD cursor offPIR1 = PIR2 = 0x00;T1CON = 0x0f; // T1CON: -- T1CKPS1 T1CPS0 T1OSCEN /T1SYNC TMR1CS TMR1ONTMR1H = 0x80;TMR1L = 0x00;。
毕业设计-基于PIC16F877A单片机字符液晶显示数字时钟设计

贵港职业学院毕业设计(论文)姓名:覃正杨学号:200930112126专业班级:电机系09级应用电子技术班论文题目:基于PIC16F877A字符液晶数字时钟指导教师:------二零一一年六月基于PIC16F877A单片机字符液晶显示数字时钟摘要近年来,随着电子产品的发展,人们对数字钟的要求越来越高,针对人们的这一需求设计了一种有单片机控制的智能化数字时钟,功能强大,界面友好,更好的满足了人们对它的智能化要求。
本文设计并实现了一款基于字符液晶显示的单片机数字钟,详细叙述了系统硬件、软件的具体实现过程。
论文重点阐述了数字钟硬件模块、时钟模块和相关控制模块等的模块化设计与制作;软件同样采用模块化的设计,包括读取模块、显示模块、时间调整模块设计,并采用汇编言语编写实现。
本设计实现了年、月、日和时间的显示功能、日期和时间修改功能。
设计方案已通过仿真软件验证,证明了设计的合理性。
关键词:单片机;数字钟;液晶显示;仿真目录目录 (3)引言 (4)第一章方案对比与选择 (5)方案1 (5)方案2 (5)方案选择 (5)第二章16F877A单片机概述 (6)2.1 单片机的用途与发展 (6)2.2 PIC16F877A单片机的结构与特点 (6)2.2.1 PIC16F877A单片机引脚结构 (6)2.2.2 PIC16F877A的内部结构 (7)2.2.3单片机的特点 (7)本章小结 (8)第三章LCD 1602A字符液晶显示说明 (9)3.1 LCD 1602A字符液晶显示的优势 (9)3.2 LCD 1602A字符液晶引脚说明 (9)本章小结 (9)第四章整体设计方案 (10)4.1 硬件选择 (10)4.3 PIC16F877A单片机电路 (10)4.4 LCD 1602A字符液晶显电路 (11)4.5 电源电路 (11)4.6 轻触按键电路 (11)4.7 整体电路图 (12)4.8 程序主流程图 (12)4.9 LCD 1602A字符液晶程序流程图 (13)本章小结 (13)第五章在线调式 (14)5.1 MPLAB ICD 2 在线调试器 (14)5.2 使用ICD 2 进行调试 (14)5.4 ICD2在线调式结果 (15)本章小结 (15)第六章结束语 (16)参考文献 (17)致谢 (17)附录字符液晶数字时钟程序 (18)引言现在是一个知识爆炸的新时代。
PIC16F877A TIMER1计数操作

0 = Oscillator isshut-off
bit2 T1SYNC:Timer1ExternalClock Input Synchronization Control bit
when TMR1CS =1
1= Do not synchronizeexternal clock input
1 = Externalclock from pin RC0/T1OSO/T1CKI
0 = Internal clock
bit0 TMR1ON:Timer1on bit
1 = enables timer1
0=stopstimer1说明:作用在TMR1的计数状态,计数信号从RC0/T1CKI
输入,当来一个上升沿时,采集到一个有效的信号,计数到TMR1L,TMR1H中。
0= Synchronize externalclock input
when TMR1CS =0
This bit isignored .Timer1uses the internal clock when TMR1CS = 0.
bit1 TMR1CS:Timer1 ClockSource Select bit
voidinterruptISR(void){TMR1L=(65536-1)%256;//重新赋值TMR1H=
(65536 - 1)/256; if(TMR1IE && TMR1IF) { TMR1IF = 0;PORTD= ~PORTD;}}
tips:感谢大家的阅读,本文118分频TMR1时钟为晶振时钟/(4*8)TMR1是16位宽度的TMR1由
2个8位的可读写的寄存器TMR1H和TMR1L组成。
pic16f877a程序

实验二程序清单:(1)编写程序使8个LED实现双跳灯显示//===========led程序===========#include <pic.h>//===========变量定义==========void delay(int z);//===========主程序============main(){TRISD=0x00;while(1){PORTD=0x03;delay(200);PORTD=0x0c;delay(200);PORTD=0x30;delay(200);PORTD=0xc0;delay(200);}}void delay(int z){int x,y;for(x=z;x>0;x--)for(y=120;y>0;y--);}(2)编写程序实现8个LED灯高四位和低四位交替点亮//===========led程序===========#include <pic.h>//===========变量定义==========void delay(int z);//===========主程序============main(){TRISD=0x00;while(1){PORTD=0xf0;delay(500);PORTD=0x0f;delay(500);}}void delay(int z){int x,y;for(x=z;x>0;x--)for(y=120;y>0;y--);}(3)编写程序使第一次按下按键时单双星闪(1、3、5、7个 LED灯与2、4、6、8个LED交替点亮),第二次按下按钮时高四位的LED和低四位的LED交替点亮,这两种显示方式依次循环#include <pic.h>//===========变量定义==========void delay(int z);void KEYSCAN();#define shuru RB0unsigned int i,j;//===========主程序============ main(){TRISD=0x00;TRISB=0X01;//设置RB0为输入i=0;PORTD=0XFF;while(1){KEYSCAN();if(i%2==1){PORTD=0xaa;delay(500);PORTD=0x55;delay(500);}if(i%2==0){PORTD=0xf0;delay(500);PORTD=0x0f;delay(500);}}}void delay(int z){int x,y;for(x=z;x>0;x--)for(y=120;y>0;y--);}void KEYSCAN(){while(1){if(shuru==1)break;} /*等待有键按下*/delay(10); /*软件延时*/if(shuru==1)i++; /* 如果仍有键按下,则调用键服务子程序*/}实验三程序清单:(1)4*4键盘扫描#include<pic.h> //包含单片机内部资源预定义const charLEDCODE[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7c,0x 39,0x5e,0x79,0x71};int result;void delay(); //delay函数申明void init(); //I/O口初始化函数申明void scan(); //按键扫描程序申明void display(int x); //显示函数申明//---------------------------------------------------//主程序void main(){while(1) //循环工作{init(); //调用初始化子程序scan(); //调用按键扫描子程序display(result); //调用结果显示子程序}}//---------------------------------------------------//初始化函数void init(){TRISD=0X0f; //设置C口高4位为输入,低4位为输出TRISC=0X00; //设置D口为输出PORTC=0X00;PORTD=0X00; //先清除所有显示}//按键扫描程序void scan(){PORTD=0XEF; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0xE0; //否,加上低4位0x07,做为按键扫描的结果return;}PORTD=0XDF; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0xD0; //否,加上低4位0x07,做为按键扫描的结果return;}PORTD=0XBF; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0xB0; //否,加上低4位0x07,做为按键扫描的结果return;}PORTD=0X7F; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0x70; //否,加上低4位0x07,做为按键扫描的结果return;}}//显示程序void display(int x){switch(result){case 0xee:PORTC= LEDCODE[0];delay();break; case 0xed:PORTC= LEDCODE[1];delay();break; case 0xeb:PORTC= LEDCODE[2];delay();break; case 0xe7:PORTC= LEDCODE[3];delay();break;case 0xde:PORTC= LEDCODE[4];delay();break;case 0xdd:PORTC= LEDCODE[5];delay();break; case 0xdb:PORTC= LEDCODE[6];delay();break; case 0xd7:PORTC= LEDCODE[7];delay();break;case 0xBE:PORTC= LEDCODE[8];delay();break;case 0xbd:PORTC= LEDCODE[9];delay();break; case 0xBb:PORTC= LEDCODE[10];delay();break; case 0xb7:PORTC= LEDCODE[11];delay();break; case 0x7E:PORTC= LEDCODE[12];delay();break; case 0x7d:PORTC= LEDCODE[13];delay();break; case 0x7b:PORTC= LEDCODE[14];delay();break;case 0x77:PORTC= LEDCODE[15];delay();break;}}//延时程序void delay() //延时程序{int i; //定义整形变量for(i=0x100;i--;); //延时}(2)数码管显示#include<pic.h> //包含单片机内部资源预定义// __CONFIG(0x1832);//芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关,加密,4M晶体HS振荡void delay(); //delay函数申明void init(); //I/O口初始化函数申明char TABLE[]={0,1,2,3,4}; //定义常数0-5的数据表格const charLEDCODE1[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};//共阴码void main(){init(); //调用初始化函数while(1) //死循环,让数码管持续{PORTC=0X01; //点亮第1位数码管PORTD=~LEDCODE1[TABLE[0]]; //D口输出数据表格第1个数据0 delay();PORTD=0xFF; //延时一定时间,保证数码管亮度PORTC= 0x02;PORTD=~LEDCODE1[TABLE[1]]; //显示数据1delay();PORTD=0xFF;PORTC= 0x04;PORTD=~LEDCODE1[TABLE[2]]; //显示数据2delay();PORTD=0xFF;PORTC= 0x08;PORTD=~LEDCODE1[TABLE[3]]; //显示数据3delay();PORTD=0xFF;}}void init() //I/O口初始化函数{TRISC=0X00; //设置A0输出,其他输入TRISD=0X00; //设置D口输出PORTC=0x00;PORTD=0x00; //先熄灭所有显示}void delay() //延时程序{int i; //定义整形变量for(i=0xF000;i--;); //延时 //0x400for(i=0xff;i--;);}void display(){int i ;unsigned char DISPBIT;DISPBIT=0x01;for (i=0;i<=3;i++){PORTC=DISPBIT; //点亮第1位数码管PORTD=~LEDCODE1[TABLE[i]]; //D口输出数据表格第1个数据0 delay();PORTD=0xFF;DISPBIT=DISPBIT<<1;}}实验四程序清单:(1)方波发生器#include<pic.h>sbit P1_0=P1^0;void timer0(void){P1_0=!P1_0;TH0=-(1000/256); /*计数初值重装*/TL0=-(1000%256);}void main(void){TMOD=0x01; /*T0工作在定时器方式1*/P1_0=0;TH0=-(1000/256); /*预置计数初值*/TL0=-(1000%256);EA=1; /*CPU开中断*/ET0=1; /*T0开中断*/TR0=1; /*启动T0*/do{}while(1);}(2)程序说明:P1口输出,低电平有效#include<pic.h>#define uchar unsigned char //定义无符号字符#define uint unsigned int //定义无符号整数void Delayms(uint x){ //定义延时函数uint i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}void main(){uint i;uchar temp;while(1){temp=0x01; //8个流水灯逐个闪动for(i=0;i<8;i++){P1=~temp;Delayms(300);temp<<=1;}temp=0x80; //8个流水灯反向逐个闪动for(i=0;i<8;i++){P1=~temp;Delayms(300);temp>>=1;}temp=0xfe; //8个流水灯依次全部点亮for(i=0;i<8;i++){P1=temp;Delayms(300);temp<<=1;}temp=0x7f; //8个流水灯依次反向全部点亮for(i=0;i<8;i++){P1=temp;Delayms(300);temp>>=1;}}}实验六程序清单:(1) U1发送部分程序清单#include<pic.h>unsigned tran[10]={0,2,4,6,8,1,3,5,7,9};unsigned char k,x;int i=0;const chartable[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xD8,0x80,0x90,0x88,0x83,0x c6,0xa1,0x86,0x8c,0x7f,0xbf,0x89,0xff};void sciint(){SPBRG=0x19;TXSTA=0x04;RCSTA=0x80;TRISC6=1;TRISC7=1;TRISB=0x00;}void delay(){for(i=0x1FFF;i>0;i--) {;}}void display(){for(k=0;k<10;k++) { x=tran[k];PORTB=table[x];delay();}}main(){sciint();di();TXEN=1;CREN=1;for(k=0;k<10;k++){ TXREG=k;while(1){if(TXIF==1)break;}while(1){if(RCIF==1)break;}RCREG=RCREG;}display();while(1){;}}(2) U2接收部分程序清单#include<pic.h>unsigned rece[10];unsigned char k,x;int i=0;const chartable[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xD8,0x80,0x90,0x88,0x83,0x c6,0xa1,0x86,0x8c,0x7f,0xbf,0x89,0xff};void sciint(){SPBRG=0x19;TXSTA=0x04;RCSTA=0x80;TRISC6=1;TRISC7=1;TRISB=0x00;}void delay(){for(i=0x1FFF;i>0;i--){;}}void display(){for(k=0;k<10;k++) { x=rece[k];PORTB=table[x]; delay();}}main(){sciint();di();CREN=1;TXEN=1;for(k=0;k<10;k++){ while(1){if(RCIF==1)break;}rece[k]=RCREG; TXREG=rece[k];while(1){if(TXIF==1)break;}}display();while(1){;}}实验七程序清单:(1)单路显示#include<pic.h>unsigned int i;unsigned int a,b,c;static inttable[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xD8,0x80,0x90,0x88,0x83,0x c6,0xa1,0x86,0x8c,0x7f,0xbf,0x89,0xff};void initial() //初始化{TRISB=0x00; //定义为输出PORTB=0x13; //数码管全灭TRISC=0x00;PORTC=0x13;a=0;b=0;c=0;}void ADC() //A/D转换初始化{ADCON0=0x41; //0100 0001 选择转换时钟8Tosc,选择A/D通道为RA0,//打开A/D转换器。
PIC16F877A万年历程序

PIC16F877A万年历程序时间:2009-03-05 来源: 作者:Wujieflash 点击:1639 字体大小:【大中小】为了把KS0108系列的液晶吃透,特别制作了这款万年历,感觉效果还是不错的.希望大家分享我的喜悦,毕竟有了更多志同道合的朋友支持,我才能更进一步提高.一,原理介绍说明:1.单片机还是采用PIC中最经典的PIC16F877A,端口多,功能全,特别是他有8K的ROM,这是我选择的主要原因,因为储存液晶的字库需要很大的空间.2.液晶显示还是用的KS0108系列,主要是他性价比高,指令简单,特别是公司也在用.3.时钟/日历芯片用的DALLOS的DS1302芯片,他可以储存从2000-2099年的日历,及实时时钟,可以方便的读写.4.温度测量还是用的DS18B20,这在我上一实例中已经用过,有兴趣可以查阅.5.本万年历可以显示实时时钟,精确到秒,年,月,日,星期,阴历,温度,生肖等,显示的信息量大. 6,可以通过按键自由设定时钟及日历,按"设置"键可以在秒,分,时,日,月,星期,年之间来回切换,要设置的单元以闪烁提醒.通过"+"."-"按键可以把要设置的单元设定到预想状态.二,程序说明:本程序有许多小的模块,现分列如下:1.主程序/**************************************************** 标题:万年历** 作者:Wujieflash ** 日期:2008年1月13日** 说明:包含文件***************************************************/ #include#include "ziku.h"#include "lcd_init.h"#include "ds1302.h"#include "ds18b20.h"#include "keyscan.h"#include "yinli.h"//子程序//LCD显示空白边框子程序void LCDShowTable(){uch i;SlectScreen(1); //写左半屏SetLine(0); //起使页SetColumn(0); //起使列for(i=0;i//显示固定字符子程序void LCDShowGudingWord(){Show8X16_2(0,24,s0);Show8X16_2(0,32,s0);Show8X16(2,1,s0);Show8X16(2,9,s0);Show16X16_3(6,40,ri);Show16X32(2,24,ss0);Show16X32(2,40,ss0);Show8X16_2(0,64,s0);Show8X16_2(0,72,s0);Show8X16_2(0,80,maohao);Show8X16_2(0,88,s0);Show8X16_2(0,96,s0);Show8X16_2(0,104,maohao);Show8X16_2(0,112,s0);Show8X16_2(0,119,s0);Show8X16(2,80,s0);Show8X16(2,88,s0);Show16X16_2(4,64,shiyi);Show16X16_2(4,80,yue);Show16X16_2(4,95,chu);Show16X16_2(4,111,yi);Show16X16_3(6,72,sheng);Show16X16_3(6,88,xiao);Show16X16_3(6,104,shu);Show16X16_2(0,40,nian);Show16X16(4,2,yue);Show16X16_3(6,8,xing);Show16X16_3(6,24,qi);Show16X16(2,96,danwei1);Show8X16_2(0,8,s2);Show8X16_2(0,16,s0);}/*----------------------------------------------------------*/ //TRM1初始化子程序void TMR1init(){//TRM1 INITIALT1CON=0X30; //8分频TMR1IF=0; //清中断标志TMR1IE=1; //使能定时器1中断TMR1L=0XDB; //初始值(定时0.5S)TMR1H=0X0B;TMR1ON=1; //开定时器1}//冒号闪烁子程序void FlashMaohao(){static uch timecount=0;if(TMR1IF==1){TMR1ON=0;TMR1IF=0;TMR1L=0XDB; //重新付初值TMR1H=0X0B;flag++;flag=flag%2; //闪烁标志在0-1间翻转TMR1ON=1;timecount++;if(timecount==120)//1分钟采样一次温度{timecount=0;get_temp(); //温度转换子程序}}if(flag==0){Show8X16_2(0,80,maohao);Show8X16_2(0,104,maohao);}if(flag==1){Show8X16_2(0,80,noshu);//清除Show8X16_2(0,104,noshu);}}//主程序void main(){TMR1init(); //定时器1初始化keyinit(); //键盘初始化LCDinit(); //LCD操作初始化LCDShowTable(); //显示空白表格LCDShowGudingWord(); //显示固定字符//Set1302(DisCash); //设置初始时间(默认写入我写程序的时间) get_temp(); //读取温度while(1){v_Get1302(clock); //读取时间、日历display();YangToYin(clock[6]/16*10+clock[6]&0x0f,clock[4]/16*10+clock[4]&0x0f,clock[3]/16*1 0+clock[3]&0x0f);FlashMaohao(); //冒号闪烁KeyScan(); //键盘扫描}}2.测温程序:/**************************************************** 标题:DS18B20测温** 作者:Wujieflash ** 日期:2008年1月13日** 说明:使用DS18B20芯片测温****************************************************/# define DQ RC3 //定义18B20数据端口# define DQ_DIR TRISC3 //定义18B20D口方向寄存器# define DQ_HIGH() DQ_DIR =1 //设置数据口为输入# define DQ_LOW() DQ = 0; DQ_DIR = 0 //设置数据口为输出unsigned char TLV=0 ; //采集到的温度高8位unsigned char THV=0; //采集到的温度低8位unsigned char TZ=0; //转换后的温度值整数部分//------------------------------------------------//延时函数//系统初始化函数void init(){ADCON1=0X07; //设置A口为普通数字口TRISA=0X00; //设置A口方向为输出//TRISC3=0; //设置D口方向为输出}//-----------------------------------------------//复位DS18B20函数reset(void){char presence=1;while(presence){DQ_LOW() ; //主机拉至低电平delay(2,90); //延时503usDQ_HIGH(); //释放总线等电阻拉高总线,并保持15~60us delay(2,8); //延时70usif(DQ==1) presence=1; //没有接收到应答信号,继续复位else presence=0; //接收到应答信号delay(2,70); //延时430us}}//-----------------------------------------------//写18b20写字节函数void write_byte(uch val){uch i;uch temp;for(i=8;i>0;i--){temp=val&0x01; //最低位移出DQ_LOW();NOP();NOP();NOP();NOP();NOP(); //从高拉至低电平,产生写时间隙if(temp==1) DQ_HIGH(); //如果写1,拉高电平delay(2,7); //延时63usDQ_HIGH();NOP();NOP();val=val>>1; //右移一位}}//------------------------------------------------//18b20读字节函数uch read_byte(void){uch i;uch value=0; //读出温度static bit j;for(i=8;i>0;i--){value>>=1;DQ_LOW();NOP();NOP();NOP();NOP(); //6usDQ_HIGH(); //拉至高电平NOP();NOP();NOP(); //4usj=DQ;if(j) value|=0x80;delay(2,7); //63us}return(value);}//-------------------------------------------------//启动温度转换函数void get_temp(){int i;DQ_HIGH();reset(); //复位等待从机应答write_byte(0XCC); //忽略ROM匹配write_byte(0X44); //发送温度转化命令for(i=10;i>0;i--){delay(201,132); //调用多次延迟函数,确保温度转换完成所需要的时间}reset(); //再次复位,等待从机应答write_byte(0XCC); //忽略ROM匹配write_byte(0XBE); //发送读温度命令TLV=read_byte(); //读出温度低8THV=read_byte(); //读出温度高8位DQ_HIGH(); //释放总线TZ=(TLV>>4)|(THV<<4);}3.日历显示程序/*************************************************** * 标题:DS1302读写** 作者:Wujieflash ** 日期:2008年1月14日** 说明:日历显示范围:2000年--2099年****************************************************/ #define RST RC0#define SCLK RC1#define IO RC2uch flag=0;uch second=1,minute=1,hour=1,year=1,month=1,date=1,day=1; uch clock[]={0};uch DisCash[]={0x00,0x30,0x09,0x16,0x01,0x03,0x09};/////往1302写入1Byte数据////////////////////////void RTInputByte(uch d){uch i;TRISC=0x00;for(i=8; i>0; i--){IO = d&0x01; //取最低位SCLK = 1; //上升沿发送SCLK = 0; //恢复d = d >> 1;}}///////从1302读取1Byte数据////////////////////////uch RTOutputByte(void){uch i,val=0;TRISC2=1; //设置为输入for(i=8; i>0; i--){val = val >>1;if(IO)val=val|0x80;// 从最低位开始接收SCLK = 1; //下降沿接收SCLK = 0;}return(val);}///////先写地址,后写命令/数据////////////////////////// void W1302(uch ucAddr, uch ucDa){RST = 0;SCLK = 0;RST = 1; //打开DS1302RTInputByte(ucAddr); // /* 地址,命令*/RTInputByte(ucDa); // /* 写1Byte数据*/SCLK = 1;RST = 0; //关闭DS1302}///////先写地址,后读命令/数据////////////////////////uch R1302(uch ucAddr){uch ucData;RST = 0;SCLK = 0;RST = 1;RTInputByte(ucAddr); // /* 地址,命令*/ucData = RTOutputByte(); // /* 读1Byte数据*/ SCLK = 1;RST = 0;return(ucData);}/////////向1302写入秒分时日月星期年*/////////////void Set1302(uch *pClock){uch i;uch ucAddr = 0x80; //起使地址W1302(0x8e,0x00); ///* 控制命令,WP=0,允许写操作*/ for(i =7; i>0; i--){W1302(ucAddr,*pClock); ///* 秒分时日月星期年*/ pClock++;ucAddr +=2; //写地址加2}W1302(0x8e,0x80); // /* 控制命令,WP=1,写保护*/}////////从1302读出秒分时日月星期年*////////////////// void v_Get1302(unsigned char ucCurtime[]){unsigned char i;unsigned char ucAddr = 0x81;for(i=0;i/////////与LCD的显示接口//////////////////////void display(){uch i;for(i=0;i4.按键扫描与服务程序/*************************************************** * 标题:按键扫描和服务** 作者:Wujieflash ** 日期:2008年1月17日** 说明:当按键按下,选中的单元就会闪烁****************************************************/ uch k=0;//键盘初始化子程序void keyinit(){TRISD0=1;TRISD0=1;TRISD0=1;}/*----------------------------------------------------------*/ //键盘扫描子程序void KeyScan(){int d;if(RD0==0) //设置键按下{k++; //选定入口值k=k%8;}while(1){if(RD0==1)break;//等待按键松开}switch(k)//键盘服务入口{case 1://设置秒{d=R1302(0x81);//读取秒d=d/16*10+d%16;//转换为16进制second=flag; //设置秒的闪烁标志minute=1; //其余变量不闪烁hour=1;year=1;month=1;date=1;day=1;if(second==0) //闪烁{Show8X16_2(0,111,noshu);Show8X16_2(0,119,noshu);}if(RD1==0) //秒数值加1{d++;if(d>0x3b)d=0;//大于59就为0 d=d/10*16+d%10;W1302(0x80,d);//写入DS1302 while(1){if(RD1==1)break;//等待键松开}}if(RD2==0)//数值减1{d--;if(d0x3b)d=0;d=d/10*16+d%10;W1302(0x82,d);while(1){if(RD1==1)break;}}if(RD2==0){d--;if(d0x17)d=0;d=d/10*16+d%10;W1302(0x84,d);while(1){if(RD1==1)break;}}if(RD2==0){d--;if(d0x1f)d=1;d=d/10*16+d%10;W1302(0x86,d); while(1){if(RD1==1)break; }}if(RD2==0){d--;if(d0x0c)d=1;d=d/10*16+d%10; W1302(0x88,d); while(1){if(RD1==1)break; }}if(RD2==0){d--;if(d0x07)d=1;d=d/10*16+d%10; W1302(0x8a,d); while(1){if(RD1==1)break; }}if(RD2==0){d--;if(d0x63)d=0;d=d/10*16+d%10; W1302(0x8c,d); while(1){if(RD1==1)break;}}if(RD2==0){……5.液晶显示程序/**************************************************** 标题:LCD操作** 作者:Wujieflash ** 日期:2008年1月12日** 说明:KS0108系列液晶不带字库****************************************************/#include#define E RA0 //液晶使能端#define RW RA1 //读写控制端#define DI RA2 //数据/指令通道#define CSA RA5 //片选#define CSB RA3 //片选#define nop() asm("nop")////////////////////////基本子函数/////////////////////////延时void delay(char x,char y){char z;do{z=y;do{;}while(--z);}while(--x);}//其指令时间为:7+(3*(Y-1)+7)*(X-1)如果再加上函数调用的call 指令、页面设定、传递参数花掉的7 个指令。
(完整word版)基于PIC16F877A的数字钟设计

电子工程系项目考核(报告)项目名称:数字时钟项目姓名班级学号课程名称一、项目要求:数码管默认显示00:00。
数码管1,2 表示小时,数码管3,4 表示分钟。
如此,实现时钟功能.要求能够整点报时、闹钟提示;并附带有秒表功能。
按键可以调整时钟时间、切换显示页面和设定闹钟时间等。
二、项目原理分析在项目用的单片机开发板上单片机的IO 口接四位数码管的各段。
同时开发板共阴数码管的阴极由138 译码器的输出端控制。
在该项目中我采用了数码管的动态显示,即每位数码管点亮2ms 时间左右,由于人的视觉暂留现象及发光二极管的余辉效应,只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O 端口,而且功耗更低。
在实现了数码管的动态显示的基础上在主程序中通过计算定时器1的中断次数,从而得到计时时间和秒表时间的基准时间。
同时在主程序中添加按键处理程序,实现时钟的开始、中断和校时,同时实现闹钟定时和切换显示等功能,还有秒表计时功能。
三、硬件电路图以及原理3。
1 硬件电路图如下:3。
2硬件原理:该项目中,主要的功能模块有:数码管显示模块;按键模块;蜂鸣器模块。
数码管显示模块主要是由芯片PIC16F877A内部的定时器1的定时中断实现数码管的动态显示.按键模块主要利用矩阵式按键实现多按键功能,矩阵式按键原理是在一端加高电平,然后检测另一端是否为高电平来判断按键是否按下,通过不同的定义可以让按键实现不同的功能。
蜂鸣器模块通过三极管的开关作用和驱动作用由芯片控鸣叫与否。
四、程序说明以及程序流程图该时钟默认显示页面为时钟计时页面,按键SW1 控制时钟、秒表的开始和中断,按按键SW1一次,如果数码管在显示秒表,则开始计秒功能;否则,开始正常计时;再按一次SW1则实现中断功能.按键SW2实现是数码管的选位,从第一个数码管开始,按一次就选中下一位数码管,循环选择。
SW3实现的是加1功能,每按一次就在SW2选中的位上加1。
pic16f877a和ds1302时钟在LCD12864的显示

#include<pic.h> //包含单片机内部资源预定义__CONFIG(0xFF32); //芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关,加密,4M晶体HS振荡#define lcd_data PORTD //RDx并行通信引脚:D0-D7#define rs RA5 //RS接RA5#define rw RA4 //RW接RA4#define en RA3 //E接RA3#define rst RA1 //RST接RA1#define psb RA2 //PSB接RA2#define psb_dir TRISA2#define uint unsigned int#define uchar unsigned char#define i_o RC4 //定义DS1302的数据口#define i_o_dir TRISC4#define sclk RC3 //定义DS1302的时钟口#define rst1 RC2 //定义DS1302的复位口unsigned char time_rx @ 0x30; //定义接收寄存器static volatile bit time_rx7 @ (unsigned)&time_rx*8 + 7; //接收寄存器的最高位void port_init(); //申明引脚初始化函数void ds1302_init(); //申明DS1302初始化函数void set_time(); //申明设置时间函数void get_time_date(); //申明读取时间函数void zhaunhuan(); //申明显示函数void time_write_1(unsigned char time_tx); //申明写一个字节函数unsigned char time_read_1(); //申明读一个字节函数//定义待设置的时间:秒、分、时、日、月、星期、年、控制字const char table[] = {0x00, 0x00, 0x13, 0x28, 0x8, 0x04, 0x14, 0x00};//定义读取时间和日期存放表格char table1[7];//定义0-9的显示代码const unsigned char TABLE[10] = {0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, 0x6f} ; //,0x77,0x7c,0x39,0x5e,0x79,0x71};char time[20];char date[20];void port_init(){ADCON1 = 0X07; //设置A口为普通I/O口// TRISB = 0X0F; //设置B口低4位为输入//高四位为输出TRISA = 0x00; //porta 输出PORTA = 0x00; //先关闭所有显示TRISD = 0x00; //portd 输出PORTD = 0x00;TRISC = 0X00; //rc输出}void ds1302_init(){sclk = 0; //拉低时钟信号rst1 = 0; //复位DS1302rst1 = 1; //使能DS1302time_write_1(0x8e); //发控制命令time_write_1(0); //允许写DS1302rst1 = 0; //复位}void set_time(){int i; //定义循环变量rst1 = 1; //使能DS1302time_write_1(0xbe); //时钟多字节写命令for (i = 0;i < 8;i++) //连续写8个字节数据{time_write_1(table[i]); //调用写一个字节函数}rst1 = 0; //复位}void time_write_1(unsigned char time_tx)// 入口参数:unsigned char time_tx 待写数据{int j; //设置循环变量for (j = 0;j < 8;j++) //连续写8bit{i_o = 0; //先设置数据为0sclk = 0; //时钟信号拉低if (time_tx&0x01) //判断待发送的数据位是0或1{i_o = 1; //待发送数据位是1}time_tx = time_tx >> 1; //待发送的数据右移1位sclk = 1; //拉高时钟信号}sclk = 0; //写完一个字节,拉低时钟信号}void get_time_date(){int i; //设置循环变量rst1 = 1; //使能DS1302time_write_1(0xbf); //发送多字节读取命令for (i = 0;i < 7;i++) //连续读取7个字节数据{table1[i] = time_read_1(); //调用读取1个字节数据的函数}rst1 = 0; //复位DS1302zhaunhuan(); //调用显示函数}unsigned char time_read_1(){int j; //设置循环变量i_o_dir = 1; //设置数据口方向为输入for (j = 0;j < 8;j++) //连续读取8bit{sclk = 0; //拉低时钟信号time_rx = time_rx >> 1; //接收寄存器右移1位time_rx7 = i_o; //把接收到的数据放到接收寄存器的最高位sclk = 1; //拉高时钟信号}i_o_dir = 0; //恢复数据口方向为输出sclk = 0; //拉低时钟信号return (time_rx); //返回读取到的数据}void zhaunhuan(){time[7]= (table1[0] & 0x0f)+0x30; //求秒的个位time[6]= ((table1[0] & 0xf0)>>4)+0x30; //求秒的十位time[5]= 0x3a;time[4]= (table1[1] & 0x0f)+0x30; //求分的个位time[3]= ((table1[1] & 0xf0)>>4)+0x30; //求分的十位time[2]= 0x3a;time[1]= (table1[2] & 0x0f)+0x30; //求时的个位time[0]= ((table1[2] & 0xf0)>>4)+0x30; //求时的十位time[8]='\0';date[1]= (table1[6] & 0x0f)+0x30; //求年的个位date[0]= ((table1[6] & 0xf0)>>4)+0x30; //求年的十位date[2]= '/';date[4]= (table1[4] & 0x0f)+0x30; //求月的个位date[3]= ((table1[4] & 0xf0)>>4)+0x30; //求月的十位date[5]= '/';date[7]= (table1[3] & 0x0f)+0x30; //求日的个位date[6]= ((table1[3] & 0xf0)>>4)+0x30; //求日的十位date[8]='\0';}/***************LCD显示部分**************************/void delayms(unsigned char ms) //80MHZ系统及外围设备时钟电路,延时MS ms{ //精确延时1munsigned char i; //100ms延时误差-1.8mswhile(ms--) //50ms延时误差-0.1ms{ //10ms延时误差-0.2msfor(i=0;i<121;i++) //200ms延时误差-3.8msNOP();}}void busy_check(void) //LCD与MCU通信“判忙”函数{unsigned char lcd_status;while(1){rs=0; //指令寄存器rw=1; //读en=0; //使能低电平,为使能高电平读数据做准备delayms(1);lcd_status=PORTD;delayms(1);en=1; //使能高电平,读操作是在高电平时完成的// delayms(50);while(lcd_status&0x80); //等待忙碌状态结束break;}}void wr_data(unsigned char wrdata) //写数据函数{busy_check(); //“判忙”rs=1; //数据寄存器rw=0; //写en=1; //使能高电平delayms(1);lcd_data=wrdata;en=0; //准备写入if(wrdata&0x80){PORTD=0;}else NOP();//使能低电平,产生下降沿,完成写操作// delayms(100);}void wr_cmd(unsigned char cmd) //写指令函数{busy_check(); //判忙rs=0; //指令寄存器rw=0; //写en=1; //使能高电平,为产生下降沿做准备delayms(1);lcd_data=cmd; //准备写入delayms(1);en=0;if(cmd&0x80){PORTD=0;}//使能低电平,产生下降沿,指令写入// delayms(100);}void display(uchar x,uchar y,uchar *seg) //LCD显示位置的确定{ //第X行,第Y列uchar i=0;uchar t=0;switch(x){case 1:i=0x80;break; //第1行case 2:i=0x90;break; //第2行case 3:i=0x88;break; //第3行case 4:i=0x98;break; //第4行default:break;}i=i+y-1; //确定最后的显示位置:第x行,第y列wr_cmd(i); //写入显示位置// delayms(100);while(seg[t]!='\0') //写入要显示的数据{// delayms(100);wr_data(seg[t]);// delayms(100);t++;}}void lcd_init(void) //lcd初始化{delayms(20);psb=1;// delayms(20);rst=1; //置为高电平,结束重置// delayms(20);rst=0; //重置(低电平有效)// delayms(20);rst=1; //置为高电平,结束重置// delayms(20);wr_cmd(0x30); //显示格式命令// delayms(20);wr_cmd(0x30); //2次输入,无需判忙// delayms(20);wr_cmd(0x0c); //游标向右,显示光标,关闭反白// delayms(20);wr_cmd(0x01); //清屏// delayms(50);wr_cmd(0x06); //数据读取写入时,光标右移,显示右移// delayms(20);}void main(){port_init(); //调用引脚初始化函数lcd_init();ds1302_init(); //调用DS1302初始化函数// set_time(); //调用设置时间函数while (1){get_time_date(); //调用取时间函数display(1,1,date);display(2,1,time);}}。
毕业设计——基于PIC16F877的智能电子钟设计

基于PIC16F877的智能电子钟设计1 引言随着电子技术产业结构调整,生产工艺的飞速发展,人们生活水平的不断提高,家用电器逐渐普及,而随着人们对周围环境便利程度的要求,市场对于智能时钟控制系统的需求也越来越大。
智能钟应实现的主要功能为:能实现二十四小时制的时分秒显示,具有快速手动校时电路,具有整点报时功能,具有闹钟表功能(可设置时分),具有倒计时功能。
2 设计原理及方案2.1 设计原理单片机是一门技术性、应用性很强的学科,实践教学是它的一个极为重要的环节。
不论是硬件扩展、接口应用还是编程方法、程序调试,都离不开实践。
本次设计的目的是通过完成一个涉及PIC单片机都种资源应用并具有综合功能的小系统目标板的设计与编程应用,能够对电子电路、电子元器件、印制电路板等方面的知识进一步加深认识,同时在软件编程、排版调试、焊接技术、相关仪器设备的使用技能等方面得到较全面的锻炼和提高,为今后能够独立进行某些单片机应用系统的开发设计工作打下一定的基础。
该电子时钟不但具有显示时、分、秒的作用,而且用按键还可以实现时间的调整和闹铃的设定。
本次综合实践完成了在单片机数据采集与定时系统的硬件电路设计后的基础上,焊接制作电路板,完成该系统的软件设计与调试。
待仿真成功后,再将程序烧写入单片机中。
2.2 设计方案系统结构整个电子时钟系统电路可分为五大部分:中央处理单元(CPU)、电源电路部分、显示部分、键盘输入部分。
系统由PIC16F877、LED 数码管、按键、发光二极管等部分构成,能实现时间的调整、定时时间的设定,输出等功能。
系统的功能选择由SB0、SB1、SB2、SB3、SB4 完成。
其中SB0 为时间校对,定时器调整功能键,按SB 0 进入调整状态。
SB1 为功能切换键。
第一轮按动 SB1 依次进入一路、二路、三路定时时间设置提示程序,按SB3 进入各路定时调整状态。
定时时间到,二极管发亮。
到了关断时间后灭掉。
如果不进入继续按SB1 键,依次进入时间年位校对、月位校对、日位校对、时位校对、分位校对、秒位校对状态。
lcd1602_pic16f877a_程序_代码

uint i;
uchar j;
for(i=0;i<2;i++)
{
j&=0x00;
j|=(dat&0xf0);
PORT=j;
PORT&=0x0f;//清高四位
PORT|=(dat&0xf0);//写高四位
if(x==1)
RS=1;
else
RS=0;
delay(3);
EN=1;
delay(3);
EN=0;
lcd_write(0x01,0);//显示清零,数据指针d location(uint x,uint y)
{
if(x==1)
{
lcd_write(0x80+y,0);
}
if(x==2)
{
lcd_write(0xc0+y,0);
}
}
void lcd_prins(uint x,uint y,uint z)//这里不能用uchar z,否则当z=6578,即四位或五位数时,放不下而导致出错
//lcd_single_prins(uint x,uint y,uint z);
////
//2013,01,07 //
/***********************************************/
#define uchar unsigned char
#define uint unsigned int
void delay(uint x);
void lcd_write(uchar dat,uchar x);
//延时函数
void delay(uint x)
{
PIC16F877A数字时钟时钟程序(优推内容)

;Digit clock;-----------------------------------------------;DA TE :20101205;Author:Tang HS;M C U :PIC16F877A;FileName : ClockPIC.ASM;-----------------------------------------------------------;Date: {2010/12/07.14:35}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义;------------------------------------------------------------;-----------------------------------------------------------;Date: {2010/12/07.22:15}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY;------------------------------------------------------------;Date: {2010/12/09.18:06}-V er02--CS-ICD:0xAFCE---ISP:0xef0e----;************************************************************;Date: {2010/12/10.00:47}-V er03--CS-ICD:0xb08d---ISP:0xfaa7----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY 都OK ; 3.MOVLW 纠正MOVV REG,1 引起的SUB_不良;;--------------------------------------------------------------;Date: {2010/12/10.13:10}-V er03.1--CS-ICD:0xb08b---ISP:0xfaa4----; 4.时差。
基于PIC16F877A时钟程序实验C程序

TMR1CS=0;
T1CKPS1=1;
T1CKPS0=1;
TMR1H=0x0B;
TMR1L=0xE9;
T1SYNC=0Βιβλιοθήκη TMR1ON=1; TMR1IF=0;
TMR1IE=1;
PEIE=1;
GIE=1;
while(1)
U5C=0; //U5A=1,U5B=1,U5C=0,选通数码管的个位进行显示
PORTD=LED[j%10];
}
}
}
》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《
{
U5A=0; //U5A=0,U5B=1,U5C=0,选通数码管的十位进行显示
U5B=1; //U5A=0,U5B=1,U5C=0,选通数码管的十位进行显示
U5C=0; //U5A=0,U5B=1,U5C=0,选通数码管的十位进行显示
PORTD=0x00;
PORTB=0x00;
TMR1CS=0;
T1CKPS1=1;
T1CKPS0=1;
TMR1H=0x0B;
TMR1L=0xE9;
T1SYNC=0;
TMR1ON=1;
TMR1IF=0;
TMR1IE=1;
PEIE=1;
GIE=1;
while(1)
{
PORTD=0x00; //关一次显示,以免显示出鬼影
if(j>59)j=0;
if(++d>3) d=1;
if(d==2) //如果d=2,显示十位
PIC16F877A时钟程序

STRSET3 EQU 38H
STRSET4 EQU 39H
ALARMMARK EQU 3AH
ALARM_MM1 EQU 3BH
ALARM_MM2 EQU 3CH
NOP
NOP
NOP
DECFSZ TIME500MS2,1
GOTO T500_LOOP2
DECFSZ TIME500MS1
GOTO T500_LOOP1
RETURN
END
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RETLW 0X4F ;3
RETLW 0X66 ;4
RETLW 0X6D ;5
RETLW 0X7D ;6
RETLW 0X07 ;7
RETLW 0X7F ;8
RETLW 0X6F ;9
RETLW 0X3F ;0
SUBLW 0X4F
BTFSC STATUS,2
GOTO CLRFDD2
MOVF DATECOUNT3,0
PIC16F877A数字时钟时钟程序

;Digit clock;-----------------------------------------------;DA TE :20101205;Author:Tang HS;M C U :PIC16F877A;FileName : ClockPIC.ASM;-----------------------------------------------------------;Date: {2010/12/07.14:35}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义;------------------------------------------------------------;-----------------------------------------------------------;Date: {2010/12/07.22:15}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY;------------------------------------------------------------;Date: {2010/12/09.18:06}-V er02--CS-ICD:0xAFCE---ISP:0xef0e----;************************************************************;Date: {2010/12/10.00:47}-V er03--CS-ICD:0xb08d---ISP:0xfaa7----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY 都OK ; 3.MOVLW 纠正MOVV REG,1 引起的SUB_不良;;--------------------------------------------------------------;Date: {2010/12/10.13:10}-V er03.1--CS-ICD:0xb08b---ISP:0xfaa4----; 4.时差。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
;Digit clock;-----------------------------------------------;DA TE :20101205;Author:Tang HS;M C U :PIC16F877A;FileName : ClockPIC.ASM;-----------------------------------------------------------;Date: {2010/12/07.14:35}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义;------------------------------------------------------------;-----------------------------------------------------------;Date: {2010/12/07.22:15}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY;------------------------------------------------------------;Date: {2010/12/09.18:06}-V er02--CS-ICD:0xAFCE---ISP:0xef0e----;************************************************************;Date: {2010/12/10.00:47}-V er03--CS-ICD:0xb08d---ISP:0xfaa7----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY 都OK ; 3.MOVLW 纠正MOVV REG,1 引起的SUB_不良;;--------------------------------------------------------------;Date: {2010/12/10.13:10}-V er03.1--CS-ICD:0xb08b---ISP:0xfaa4----; 4.时差。
50ms原来计数20次改为19次;250us原来计数200次改为197次;---------------------------------------------------------------;Date: {2010/12/10.17:30}-V er03.2--CS-ICD:0x296B---ISP:0x7387----; 5.在Set_ini中--增加CALL SET_Flag;指定Flag,1=1;标志位----解决Ver03.1-第一次按SET键时不能调HourL&HourH的问题;------------------------------------------------------------;************************************************;程序清单;**************************************************__CONFIG 3F39H;设置配置位中振荡方式为XT,其它全部禁止或关闭;************************************************;-----------------------------------------------include P16F877A.INC;-----------------------------------------------;-----------------ram varable------------------------------HourH equ 20H ;HourL equ 21H ;MinH equ 22H ;MinL equ 23H ;SecH equ 24h ;SecL equ 25h ; B'0010 0101';N250us equ 26h ;250us*200=50ms;N50ms equ 27h ;50ms*20=1000ms;Nsec equ 28h ;data1 equ 29h ;定义一个廷时变量寄存器data2 equ 2Ah ;定义另一个廷时变量寄存器keyvalue EQU 2Bh ;FlagKey EQU 2Ch ;W_STK equ 2Dh ;----------------STA TUS_STK equ 2Eh ;PCLATH_STK equ 2Fh ;FSR_STK equ 30h ;---------------COUNT0 equ 31h ; DELAY use 0011 0000COUNT1 equ 32h ;COUNT2 equ 33h ;Flag equ 34h ;---Adjust.Time---------N250us equ 35h ;250us*200=50msN50ms equ 36h ;50ms*20=1000msNsec equ 37h ;;------------------Counstant------------------------------n1 equ d'1';d'13' ;定义一个外层循环廷时常数d'13'(10ms) n2 equ 0ffh ;定义一个内层廷时常数RBCOUNST equ 0x1f ;rb0~rb4读取后异或常数;------------------bit1-----------------------------c equ 0 ;定义进位标志位位地址rp0 equ 5 ;定义状态寄存器的页选位RP0NOT_RBPU equ 7 ;定义选择寄存器RB的上拉电阻位RBPU z equ 2 ;定义0状态位的位地址F_release EQU 0 ;F_pressed equ 1 ;;--------------FlagKey---bit2----------------------------;#define F_release FlagKey,0 ;按键释放标志位;#define F_pressed FlagKey,1 ;按键闭合标志位;-------------Flag ----------------------------------;Flag,0 ; 时间调整标志位;Flag,1 ; FSR=21H=HourL;Flag,2 ; FSR=23H=MinL;Flag,3 ; FSR=25H=SecL;************************************************************** ;-------------------------------------------------------------ORG 0000HNOP ;放置一条ICD必需的空操作指令GOTO MAINORG 0004HGOTO ISR_TMR0 ;ORG 0008H;******************************************************;NAME : CONMERT1 数码管位码查表子程序;-------------------------------------------------CONVERT1 ;取数码管位码ADDWF PCL,1 ;地址偏移量加当前PC值TABLE1RETLW 0FDH ;第一位数码管RETLW 0FEH ;第二位数码管RETLW 0F7H ;第三位数码管RETLW 0FBH ;第四位数码管RETLW 0DFH ;第五位数码管RETLW 0EFH ;第六位数码管;********************************************************;NAME : CONVERT 数码管段码查表子程序;-----------------------------------------------------CONVERT ;取数码管段码ADDWF PCL,1 ;地址偏移量加当前PC值TABLERETLW 0C0H ;0RETLW 0F9H ;1RETLW 0A4H ;2RETLW 0B0H ;3RETLW 99H ;4RETLW 92H ;5RETLW 82H ;6RETLW 0F8H ;7RETLW 80H ;8RETLW 98H ;9RETLW 7FH ;.retlw 00h ;11;************************************************************* ; ///////////--Main program --///////////////////////////////;----------------------------------------------------------;***********************************************************; return ;;----------------------------------------------------------MAINCALL Sys_ini;CALL Clear_RAM;BSF INTCON,GIE ; 打开全局中断,启动定时器CALL RAM_ini ;LOOP_DISCALL Display_led;NOP;bcf STATUS,RP0;BTFSC PORTB,0 ; RB0=0? 键按下否?GOTO LOOP_DIS ; noCALL Display_led ; YesCALL Display_led;BTFSC PORTB,0 ; RB0=0? 再次确认键按下否?GOTO LOOP_DIS ; noCALL Set_in;CALL keyscan;LoopENDGOTO LOOP_DIS;;**************************************************** Set_inBSF Flag,0 ; Set1闪烁显示处理放在中断进行MOVLW 0x21 ; HourL->FSRMOVWF FSR ;;CALL SET_Flag;BSF Flag,1; 1BCF Flag,2; 0BCF Flag,3; 0keyscanRealase0 ; 按键释放,子程序名CALL Display_led ;movf PORTB,W ;读取RB口数据到W(d=0)andlw 0x1f ;屏蔽高4位bcf STATUS,Z ;xorlw 0x1f ;btfss STATUS,Z ;goto keyscanRealase0 ;Z=0有键按下;call delay ;Z=1无键按下CALL Display_led;CALL Display_led;movf PORTB,W ;读取RB口数据到W(d=0)andlw 0x1f ;屏蔽高4位bcf STATUS,Z ;xorlw 0x1f ;btfss STATUS,Z ;goto keyscanRealase0 ;Z=0有键按下,waitting for release;Z=1无键按下exit;------------RETURN ;;----------------------------;----------------------------KEY0_SUB ;SET_KEYINCF FSR,1 ;21-23-25hINCF FSR,1 ;MOVF FSR,W ;SUBLW 0x27 ;----27>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>- BTFSS STATUS,Z ; FSR=27H?GOTO $+3 ;MOVLW 0x21;MOVWF FSR;CALL SET_Flag;RETURN;KEY1_SUB ;ADD_KEYINCF INDF,1;CALL ArrangTime ;RETURN;KEY2_SUB ;SUB_KEY;MOVF INDF,1;;BTFSS STATUS,Z ; INDF=0?;GOTO $+4 ;NO:Jump to 'DECF INDF,1;';MOVLW .9 ;=Yes:Re-setup REGF;MOVF INDF,1 ;=Yes: 9->REGF;GOTO $+2 ;=Yes:and jump to 'CALL Time_sub;';DECF INDF,1;CALL Time_sub;RETURN;KEY3_SUB ;EXIT_KEY ;CALL Set_outBCF Flag,0 ; Clear 0MOVLW 0x00 ; HourL->FSRMOVWF FSR ;RETURN ;;-------------------------------------;*******************************************keyscan ;--1--按键闭合-----------------------BTFSS Flag,0 ; 1 继续按键处理goto keyscan_end ; 0 退出按键处理CALL ArrangTime ;CALL Display_led ;MOVF PORTB,W ;读取RB口数据到W(d=0)ANDLW 0x1f ;屏蔽高4位RBCOUNST A^1=~ABCF STATUS,Z ;将z清0XORLW 0x1f ;即RA与0x0f作异或运算,若两数相同,结果为0,Z置1;若两数相异,结果非0,Z=0BTFSC STATUS,Z ;0jump keycloseGOTO keyscan ; Z=1无键按下退出按键扫描;call delay ; Z=0有键按下,延时按键去抖动CALL Display_led ;CALL Display_led ;;--2----------------------MOVF PORTB,W ;读取RB口数据到W(d=0)ANDLW 0x1f ;屏蔽高4位MOVWF keyvalue ;保存键值到keyvalueBCF STATUS,Z ;将z清0XORLW 0x1f ;即RA与0x0f作异或运算,若两数相同,结果为0,Z置1;若两数相异,Z=0不相同BTFSC STATUS,Z ;0jump keycloseGOTO keyscan ; Z为1退出按键扫描;incf portc,1 ;key fuction sub.;********************************************KEY0BTFSC keyvalue,0 ; KEY0?GOTO KEY1;CALL KEY0_SUB;goto Adjust_Time;KEY1BTFSC keyvalue,1 ; KEY1?GOTO KEY2;CALL KEY1_SUB;goto Adjust_Time;KEY2BTFSC keyvalue,2 ; KEY2?GOTO KEY3;CALL KEY2_SUB;goto Adjust_Time;KEY3BTFSC keyvalue,3 ; KEY3?GOTO Adjust_Time ;KEY1;CALL KEY3_SUB;ADJ_OUT;----------------------------------------------Adjust_Time;CALL ArrangTime ;;--------------------------------------------keyscanRealase ; 按键释放,子程序名CALL Display_led ;movf PORTB,W ;读取RB口数据到W(d=0)andlw 0x1f ;屏蔽高4位bcf STATUS,Z ;xorlw 0x1f ;btfss STATUS,Z ;goto keyscanRealase ;Z=0有键按下;call delay ;Z=1无键按下CALL Display_led;CALL Display_led;movf PORTB,W ;读取RB口数据到W(d=0)andlw 0x1f ;屏蔽高4位bcf STATUS,Z ;xorlw 0x1f ;btfss STATUS,Z ;goto keyscanRealase ;Z=0有键按下goto keyscan ;Z=1无键按下;---------------------------------------------keyscan_endRETURN;;-------------keyscan_end------------------------------;***********Adjust_TIME END************************;;===============SET_Flag SUB ======================================= SET_FlagBCF STATUS,RP0; select bank0;MOVF FSR,W;SUBLW 0x21;BTFSS STATUS,Z; FSR=21H?GOTO SET_F2 ;;CALL ArrangHour;---------------BSF Flag,1; 1BCF Flag,2; 0BCF Flag,3; 0;------------------------------------SET_F2MOVF FSR,W;SUBLW 0x23;BTFSS STATUS,Z; FSR=23H?GOTO SET_F3;;CALL ArrangMin;---------------BCF Flag,1; 0BSF Flag,2; 1BCF Flag,3; 0;------------------------------------SET_F3MOVF FSR,W;SUBLW 0x25;BTFSS STATUS,Z; FSR=25H?GOTO SET_END ;;CALL ArrangSec;-----BCF Flag,1; 0BCF Flag,2; 0BSF Flag,3; 1SET_ENDRETURN ;;================SET_Flag END=========================;******************************************;===================================================== ; NAME : Time_sub (Key2_SUB);=====================================Time_subBTFSS Flag,1 ; FSR=21h=HourLGOTO $+2;CALL Hour_sub;;-------------------BTFSS Flag,2 ; FSR=23h=HourLGOTO $+2;CALL Min_sub;;--------------------BTFSS Flag,3 ; FSR=25h=HourLGOTO $+2;CALL Sec_sub;RETURN ;;===============Hour_sub=====================Hour_subMOVF HourL,F ; F->FBTFSS STA TUS,Z ; HourL=0?GOTO HourL_NotZero ;No INDF--MOVF HourH,F ;BTFSS STA TUS,Z ;HourH=0?GOTO HourH_NotZero ; Not ZeroMOVLW .2 ;MOVWF HourH ;2->hourHMOVLW .3 ;MOVWF HourL ;3->HourLGOTO Hour_sub_end ;HourH_NotZero ;DECF HourH,F ; HourH--MOVLW .9MOVWF HourL ;9->HourLGOTO Hour_sub_end;HourL_NotZero;DECF HourL,F;Hour_sub_endRETURN;===============Hour_sub END====================== Min_subMOVF MinH,F ;BTFSS STA TUS,Z ; MinH=0?GOTO MinH_NotZero ; NOMOVF MinL,F ; F->FBTFSS STA TUS,Z ; MinL=0?GOTO MinL_NotZero ; NoHour00 ;(1)-00-MOVLW .5 ;MOVWF MinH ; 5->MinHMOVLW .9 ;MOVWF MinL ; 9->MinLGOTO Min_sub_end ;MinH_NotZero;MOVF MinL,F ; F->FBTFSS STA TUS,Z ; MinL=0?GOTO MinL_NotZero ; No;-(2)-x0-DECF MinH,F ; MinH--MOVLW .9MOVWF MinL ; 9->MinLGOTO Min_sub_end ;MinL_NotZero;(3)0x & xxDECF MinL,F;Min_sub_endRETURN ;;===================Min_sub END====================Sec_subMOVF SecH,f ;BTFSS STA TUS,Z ; SecH=0?GOTO SecH_NotZero ; NOMOVF SecL,F ; F->FBTFSS STA TUS,Z ; SecL=0?GOTO SecL_NotZero ; NoSec00;(1)--00MOVLW .5 ;MOVWF SecH ; 5->SecHMOVLW .9 ;MOVWF SecL ; 9->SecLGOTO Sec_sub_end ;SecH_NotZero;MOVF SecL,F ; F->FBTFSS STA TUS,Z ; SecL=0?GOTO SecL_NotZero ; No;(2)--x0DECF SecH,F ; SecH--MOVLW .9 ;MOVWF SecL ; 9->SecLSecL_NotZero;DECF SecL,F;Sec_sub_endRETURN ;;===================Sec_sub END========================= ;*******************************************************;;----------------------------------------------------;NAME : ArrangTime;========================================= ArrangTimeBTFSS Flag,1 ; FSR=21h=HourLGOTO $+2;CALL ArrangHour;;-------------------BTFSS Flag,2 ; FSR=23h=HourLGOTO $+2;CALL ArrangMin;;--------------------BTFSS Flag,3 ; FSR=25h=HourLGOTO $+2;CALL ArrangSec;RETURN ;;========================================== ArrangMin ;;if FSR= SecL goto hear-------------- MOVF MinL,W ;SUBLW .10 ;BTFSS STA TUS,Z ;到10M?GOTO END_Min ;;CALL CLR_MinL_D2a;CLRF MinL;INCF MinH,F;MOVF MinH,W ;SUBLW .6 ;BTFSS STA TUS,Z ;到60M?GOTO END_Min;CALL CLR_MinH_D3a ;CLRF MinH;CLRF MinL;END_MinRETURN;---------------------------------------------ArrangSec ;if FSR= SecL goto hear----MOVF SecL,w ;SUBLW .10 ;BTFSS STA TUS,Z ;到10S?GOTO END_Sec ;没到10s;CALL CLR_SecL_D0a ;CLRF SecL ;INCF SecH,F ; --SecH++MOVF SecH,W ;SUBLW .6 ;BTFSS STA TUS,Z ;到60S?GOTO END_Sec ;没到60S;CALL CLR_SecH_D1a ;CLRF SecH;CLRF SecL ;;INCF MinL,F;END_SecRETURN;-------------------------------;if FSR= HourL goto hear --- OK -------------------;ArrangHourA ;小时做调整有2种情况:1> h=10 ; 2> h=24 ;MOVF HourH,W ;小时不调整有2种情况:3> h<10 ; 4> 20<H<24;SUBLW .2BTFSS STA TUS,Z ;HourH==2GOTO HourLequ10 ; HourH≠2,做常规调整aMOVF HourL,w ;SUBLW .4BTFSS STA TUS,Z ;HourL==4GOTO END_Hour ;(4>: 20<H<24)CALL CLR_HourH_D5a ;(2>: h=24H)goto END_HourHourLequ10AMOVF HourL,W ;SUBLW .10BTFSS STA TUS,Z ;HourL==10GOTO END_Hour ;(3>: h<10H)CALL CLR_HourL_D4a ;(1>: h=10H)END_HourRETURN ;;--------------------------CLR_HourL_D4aCLRF HourL; else if(HourL==10) { hourL=0;Hourh++;}INCF HourH,F;RETURN;CLR_HourH_D5aCLRF HourH ; if (HourH==2&&HourL==4){ hourH=0;HourL=0;}CLRF HourL ;;INCF DayL,F;RETURN;;------------------------------------------------;*************** ArrangTime END *************************************************;*************************************************************;NAME : Sys_ini 变量初始化清零-子程序;-------------------------------------------------------------Sys_ini;-----I/O-----------------BSF STA TUS,RP0 ;设置文件寄存器体1MOVLW 0x07 ;MOVWF ADCON1 ;RA0 ~ 5设为数字I/OCLRF TRISA ;将RA设置为输出--数码管位码CLRF TRISC ;将RC设置为输出--数码管段码BCF OPTION_REG,NOT_RBPU ;RB1~RB4作(按键)输入必须设上拉电阻(RBPU=0)MOVLW 0XFF;MOVWF TRISB ;将RB设置为输入按键输入RB0~RB3BCF STA TUS,RP0 ;恢复到文件寄存器体0CLRF PORTC ;送计器初值00H到RC口显示MOVLW 03fh ;b'xx11 1111'MOVWF PORTA ;关闭数码管(位码)显示;---TMR0---------------------------------BANKSEL OPTION_REGBCF OPTION_REG,T0CS ;TMR0工作于定时器方式BSF OPTION_REG,PSA ;TMR0不用分频BANKSEL INTCONBCF INTCON,T0IF ;清除TMR0的中断标志BCF INTCON,GIE ;总中断禁止BSF INTCON,T0IE ;TMR0中断允许BCF STATUS,RP0 ;恢复到文件寄存器体0------MOVLW 0x07 ;256-6=250usMOVWF TMR0 ;TMR0设初值RETURN ;;*********************************************************;NAME : Clear_RAM 变量初始化清零-子程序;-------------------------------------------------;Clear RAM (20~2f)40h routine---;20(B'0010 0000');Bank select-IRP AND FSR,7---;2F(B'0011 0000');Clear_RAMMOVLW 0x20 ; Starting Address is 0x20MOVWF FSR ; Use indirect addressingNEXTCLRF INDF ; Clear INDF addressINCF FSR,F ; Increase FSR for next addressBTFSS FSR,6 ; Register clear complete?GOTO NEXT ;RETURN ; CALL Sys_ini ;;----------------------------------------------------;************************************************;NAME : RAM_ini 变量初始化设置;----------------------------------------------RAM_ini ;CLRF FlagKey ;CLRF keyvalue ;CLRF Flag ;CLRF N250us;CLRF N50ms ;CLRF Nsec ;RETURN ;;**************************************************;;************************************************************ ;NAME : Display_led 数码管显示子程序;--------------------------------------------------------Display_ledMOVLW 0FDH ; 0FD 位选1MOVWF PORTA ;0FD->W->RAMOVF HourH,W ;HourH->W+PCLCALL CONVERT ; Look-up tableMOVWF PORTC ;W->RCCALL delay1ms;DELAY ;MOVLW 0FEH ; 0FE 位选2MOVWF PORTA ;MOVF HourL,W ;CALL CONVERT ; Look-up tableMOVWF PORTC ;W->RCCALL delay1ms;DELAYMOVLW 0F7H ; 0F7 位选3MOVWF PORTA ;MOVF MinH,W ;CALL CONVERT ; Look-up tableMOVWF PORTC ;W->RCCALL delay1ms;DELAYMOVLW 0FBH ; 0FB 位选4MOVWF PORTA ;MOVF MinL,W ;CALL CONVERT ; Look-up tableMOVWF PORTC ;W->RCCALL delay1ms;DELAYMOVLW 0DFH ; 0DF 位选5MOVWF PORTA ;MOVF SecH,W ;CALL CONVERT ; Look-up tableMOVWF PORTC ;W->RCCALL delay1ms;DELAYMOVLW 0EFH ; 0EF 位选6MOVWF PORTA ;MOVF SecL,W ;CALL CONVERT ; Look-up tableMOVWF PORTC ;W->RCCALL delay1ms;DELAYRETURN ;-------------------------------;;******************************************************** ;NAME : ISR_TMR0 定时中断子程序;----------------------------------------------------------; ORG 0x04 ;interrupt VectorISR_TMR0MOVWF W_STK ;Store W register in w_stkMOVF STATUS,W ;\ W=STATUS RegisterCLRF STATUS ;> Bank0MOVWF STATUS_STK ;/ Store STATUS to STA TUS_STK MOVF PCLATH,W ;\MOVWF PCLATH_STK ;> Store PCLATH to PCLATH_STK CLRF PCLATH ;/;----Interrupt Flag Test----------------------------------;;----Interrupt Service Routine-------------------MOVLW 06h ;MOVWF TMR0 ;BCF INTCON,T0IF ;清除中断标志INCF N250us,1 ;---N250us++MOVF N250us,w ; 250us*200=50msSUBLW .197 ;197 N250us-200=0?BTFSS STATUS,Z ; Z=1? (N250us=200?)GOTO END_ISR ; Z=0,N250us≠200;-------------------ISR---------------------------------BTFSC Flag,0 ;调整时间时,设置相对应的2位LED闪烁goto LED_FLASH ;;----------------------------ISR-----------------------CLRF N250us ;INCF Nsec,1 ;---Nsec++MOVF Nsec,W ; Nsec*20=1000msSUBLW .19 ; Nsec-20=0?BTFSS STATUS,Z ;GOTO END_ISR ; N250us≠20CLRF Nsec ;INCF SecL,1 ;---1s++MOVF SecL,w ;SUBLW .10 ;BTFSS STATUS,Z ;到10S?GOTO END_ISR ;没到10sCALL CLR_SecL_D0 ;MOVF SecH,W ;SUBLW .6 ;BTFSS STATUS,Z ;到60S?GOTO END_ISR ;没到60SCALL CLR_SecH_D1 ;MOVF MinL,W ;SUBLW .10 ;BTFSS STATUS,Z ;到10SM?GOTO END_ISRCALL CLR_MinL_D2 ;MOVF MinH,W ;SUBLW .6 ;BTFSS STATUS,Z ;到60M?GOTO END_ISRCALL CLR_MinH_D3 ;ArrangHour ;小时做调整有2种情况:1> h=10 ; 2> h=24 ;MOVF HourH,W ;小时不调整有2种情况:3> h<10 ; 4> 20<H<24;SUBLW .2BTFSS STA TUS,Z ;HourH==2GOTO HourLequ10 ; HourH≠2,做常规调整aMOVF HourL,w ;SUBLW .4BTFSS STA TUS,Z ;HourL==4GOTO END_ISR ;(4>: 20<H<24)CALL CLR_HourH_D5 ;(2>: h=24H)goto END_ISRHourLequ10MOVF HourL,W ;SUBLW .10BTFSS STA TUS,Z ;HourL==10GOTO END_ISR ;(3>: h<10H)CALL CLR_HourL_D4 ;(1>: h=10H)GOTO END_ISR ;;-ISR---闪烁显示处理,--ISR---------------------------------------;if(fsr=0x21),RA0/RA1 FLASH with 0.25HZ;;if(fsr=0x23),RA2/RA3 FLASH with 0.25hz;;if(fsr=0x25),RA4/RA5 FLASH with 0.25hz.LED_FLASH;-ISR--End of ISR-----------------------------------END_ISRMOVF PCLATH_STK,W ; W=PCLATH_STKMOVWF PCLATH ; PCLATH=PCLATH_STKMOVF STATUS_STK,W ; W=STA TUS_STKMOVWF STATUS ; STA TUS=STATUS_STKMOVF W_STK,W ; W=W_STKRETFIE;--------------------------------------------------------;-----ISR---计数溢出处理子程序----------------------------CLR_SecL_D0CLRF SecL ;INCF SecH,F ; --SecH++RETURN;CLR_SecH_D1CLRF SecH;INCF MinL,F;RETURN;CLR_MinL_D2CLRF MinL;INCF MinH,F;RETURN;CLR_MinH_D3CLRF MinH;INCF HourL,1;RETURN;CLR_HourL_D4CLRF HourL; else if(HourL==10) { hourL=0;Hourh++;}INCF HourH,F;RETURN;CLR_HourH_D5CLRF HourH ; if (HourH==2&&HourL==4){ hourH=0;HourL=0;} CLRF HourL ;;INCF DayL,F;RETURN;;*****************ISR END**********************************;****************************************************;NAME : delay1ms 1.0MS廷时子程序Display_led used;---------------------------------------------------delay1ms ;子程序名,也是子程序入口地址movlw n1 ;将外层循环参数值送到DATA1movwf data1 ;lp0 movlw n2 ;将内层循环参数值送到DATA2movwf data2 ;lp1 decfsz data2,1 ;变量DA TA2内容递减,若为0则跳跃goto lp1 ;跳转到LP1decfsz data1,1 ;变量DA TA1内容递减,若为0则跳跃goto lp0 ;跳转到LP0return ;返回主程序;************ Used for KEY Double ********************************** delay ;子程序名,也是子程序入口地址movlw 0x13 ;将外层循环参数值送到DA TA1movwf data1 ;(3*255+1+1+1+2)*13+1+1=10010uslp0m movlw n2 ;将内层循环参数值送到DATA2movwf data2 ;lp1m decfsz data2,1 ;变量DATA2内容递减,若为0则跳跃goto lp1m ;跳转到LP1decfsz data1,1 ;变量DA TA1内容递减,若为0则跳跃goto lp0m ;跳转到LP0return ;返回主程序;***************************************************;*************************************************************** END。