基于PIC16F887单片机的数字钟完整c程序代码

更新时间:2023-12-22 12:09:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

#include

__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 0b11000000

signed char hourt,mint,sect;//闹钟设置位 int f;//闹钟显示清零判断 char flag=0;//按键标志位

char WW,QW,BW,SW,GW,M;

char table[]=\星期 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);

//===DS1307

void 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);//读DS1307 if(A[0]&0x80) DS1307_CSH();//判断是否初始化 while(1) { clock(); set_time();//按键检测 delaynms(50); if(flag==0) { READ_DS1307(0,7);//读DS1307

MENU_DS1307();//显示DS1307 T=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; //周期为1ms CCPR2L=0x32; CCP2CON=0b00000000;//关闭PWM T2CON=0b00000110; //TMR2预分频1:16,开始工 IIC_CSH(); LCD_CSH(); }

//LCD模块初始化 void LCD_CSH(void) { DELAY(20); //延时20ms LCD_WRITE_4(0b0011,COM); //发送控制序列 DELAY_US(10); //延时100us LCD_WRITE_4(0b0011,COM); //发送控制序列 DELAY_US(10); //延时100us LCD_WRITE_4(0b0011,COM); //发送控制序列 DELAY_US(10); //延时100us LCD_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); //延时2ms LCD_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(); //读为1 LCD_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位清0 R2=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位先清0 LCD_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)ms

void DELAY(unsigned int n) { unsigned int j; char k; for (j=0;j0;k--) NOP(); }

//======延时(n)ms

void delaynms(unsigned int n) { unsigned int j; char k; for (j=0;j0;k--) NOP(); }

//======延时(n×10)us void DELAY_US(char n) { char j; for (j=0;j

//=======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 (ACKSTAT==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); //检查停止位结束 }

//===读DS1307

void 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

//=====显示DS1307

void 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,DAT); LCD_WRITE((A[6]&0x0F)+0x30,DAT); LCD_WRITE('-',DAT); LCD_WRITE((A[5]>>4)+'0',DAT); LCD_WRITE((A[5]&0x0F)+'0',DAT); LCD_WRITE('-',DAT); LCD_WRITE((A[4]>>4)+'0',DAT); LCD_WRITE((A[4]&0x0F)+'0',DAT); LCD_WRITE(' ',DAT); i=A[3]&0x07; LCD_WRITE(table[(i-1)*4],DAT); 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',DAT); LCD_WRITE((A[2]&0x0F)+'0',DAT); LCD_WRITE(0x3A,DAT); LCD_WRITE((A[1]>>4)+'0',DAT); LCD_WRITE((A[1]&0x0F)+'0',DAT); LCD_WRITE(0x3A,DAT); LCD_WRITE((A[0]>>4)+'0',DAT); 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; //接收数据存入R1 PEN=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,DAT); //° 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模式 } } }

本文来源:https://www.bwwdw.com/article/4lp5.html

Top