智能電子時鐘(定時、報警、燈光自動調節)
#include<reg52.h> //包含頭文件,一般情況不需要改動,頭文件包含特殊功能寄存器的定義#include<intrins.h>unsigned char sec = 0;unsigned char min = 0;unsigned char hour = 0;unsigned char count = 0;unsigned char flag = 0;unsigned char flag1 = 0;unsigned char p[3] = {0};unsigned char num=255;bit ack; //應答標志位sbit SDA=P2^1;sbit SCL=P2^0;sbit RS = P2^4; //定義端口 sbit RW = P2^5;sbit EN = P2^6;sbit key1 = P1^0;sbit key2 = P1^1;sbit key3 = P1^2;sbit key4 = P1^3;sbit key5 = P1^4;sbit key6 = P1^5;sbit key7 = P1^6;sbit key8 = P1^7;sbit buzz = P2^2;#define AddWr 0x90 //寫數據地址 #define AddRd 0x91 //讀數據地址extern bit ack;bit WriteDAC(unsigned char dat);#define _Nop() _nop_() //定義空指令 #define RS_CLR RS=0 #define RS_SET RS=1#define RW_CLR RW=0 #define RW_SET RW=1 #define EN_CLR EN=0#define EN_SET EN=1#define DataPort P0/*------------------------------------------------ uS延時函數,含有輸入參數 unsigned char t,無返回值 unsigned char 是定義無符號字符變量,其值的范圍是 0~255 這里使用晶振12M,精確延時請使用匯編,大致延時 長度如下 T=tx2+5 uS ------------------------------------------------*/void DelayUs2x(unsigned char t){ while(--t);}/*------------------------------------------------ mS延時函數,含有輸入參數 unsigned char t,無返回值 unsigned char 是定義無符號字符變量,其值的范圍是 0~255 這里使用晶振12M,精確延時請使用匯編------------------------------------------------*/void DelayMs(unsigned char t){ while(t--) { //大致延時1mS DelayUs2x(245); DelayUs2x(245); }}/*------------------------------------------------ 啟動總線------------------------------------------------*/void Start_I2c(){ SDA=1; //發送起始條件的數據信號 _Nop(); SCL=1; _Nop(); //起始條件建立時間大于4.7us,延時 _Nop(); _Nop(); _Nop(); _Nop(); SDA=0; //發送起始信號 _Nop(); //起始條件鎖定時間大于4μ _Nop(); _Nop(); _Nop(); _Nop(); SCL=0; //鉗住I2C總線,準備發送或接收數據 _Nop(); _Nop();}/*------------------------------------------------ 結束總線------------------------------------------------*/void Stop_I2c(){ SDA=0; //發送結束條件的數據信號 _Nop(); //發送結束條件的時鐘信號 SCL=1; //結束條件建立時間大于4μ _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); SDA=1; //發送I2C總線結束信號 _Nop(); _Nop(); _Nop(); _Nop();}/*---------------------------------------------------------------- 字節數據傳送函數 函數原型: void SendByte(unsigned char c);功能: 將數據c發送出去,可以是地址,也可以是數據,發完后等待應答,并對 此狀態位進行操作.(不應答或非應答都使ack=0 假) 發送數據正常,ack=1; ack=0表示被控器無應答或損壞。------------------------------------------------------------------*/void SendByte(unsigned char c){ unsigned char BitCnt; for(BitCnt=0;BitCnt<8;BitCnt++) //要傳送的數據長度為8位 { if((c<<BitCnt)&0x80)SDA=1; //判斷發送位 else SDA=0; _Nop(); SCL=1; //置時鐘線為高,通知被控器開始接收數據位 _Nop(); _Nop(); //保證時鐘高電平周期大于4μ _Nop(); _Nop(); _Nop(); SCL=0; } _Nop(); _Nop(); SDA=1; //8位發送完后釋放數據線,準備接收應答位 _Nop(); _Nop(); SCL=1; _Nop(); _Nop(); _Nop(); if(SDA==1)ack=0; else ack=1; //判斷是否接收到應答信號 SCL=0; _Nop(); _Nop();}/*---------------------------------------------------------------- 字節數據傳送函數 函數原型: unsigned char RcvByte();功能: 用來接收從器件傳來的數據,并判斷總線錯誤(不發應答信號), 發完后請用應答函數。 ------------------------------------------------------------------*/ unsigned char RcvByte(){ unsigned char retc; unsigned char BitCnt; retc=0; SDA=1; //置數據線為輸入方式 for(BitCnt=0;BitCnt<8;BitCnt++) { _Nop(); SCL=0; //置時鐘線為低,準備接收數據位 _Nop(); _Nop(); //時鐘低電平周期大于4.7us _Nop(); _Nop(); _Nop(); SCL=1; //置時鐘線為高使數據線上數據有效 _Nop(); _Nop(); retc=retc<<1; if(SDA==1)retc=retc+1; //讀數據位,接收的數據位放入retc中 _Nop(); _Nop(); } SCL=0; _Nop(); _Nop(); return(retc);}/*---------------------------------------------------------------- 應答子函數原型: void Ack_I2c(void); ----------------------------------------------------------------*/void Ack_I2c(void){ SDA=0; _Nop(); _Nop(); _Nop(); SCL=1; _Nop(); _Nop(); //時鐘低電平周期大于4μ _Nop(); _Nop(); _Nop(); SCL=0; //清時鐘線,鉗住I2C總線以便繼續接收 _Nop(); _Nop(); }/*---------------------------------------------------------------- 非應答子函數原型: void NoAck_I2c(void); ----------------------------------------------------------------*/void NoAck_I2c(void){ SDA=1; _Nop(); _Nop(); _Nop(); SCL=1; _Nop(); _Nop(); //時鐘低電平周期大于4μ _Nop(); _Nop(); _Nop(); SCL=0; //清時鐘線,鉗住I2C總線以便繼續接收 _Nop(); _Nop(); }/*---------------------------------------------------------------- 向無子地址器件發送字節數據函數 函數原型: bit ISendByte(unsigned char sla,ucahr c); 功能: 從啟動總線到發送地址,數據,結束總線的全過程,從器件地址sla. 如果返回1表示操作成功,否則操作有誤。注意: 使用前必須已結束總線。----------------------------------------------------------------*//*bit ISendByte(unsigned char sla,unsigned char c){ Start_I2c(); //啟動總線 SendByte(sla); //發送器件地址 if(ack==0)return(0); SendByte(c); //發送數據 if(ack==0)return(0); Stop_I2c(); //結束總線 return(1);}*//*---------------------------------------------------------------- 向有子地址器件發送多字節數據函數 函數原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no); 功能: 從啟動總線到發送地址,子地址,數據,結束總線的全過程,從器件 地址sla,子地址suba,發送內容是s指向的內容,發送no個字節。 如果返回1表示操作成功,否則操作有誤。注意: 使用前必須已結束總線。----------------------------------------------------------------*/bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no){ unsigned char i; for(i=0;i<no;i++) { Start_I2c(); //啟動總線 SendByte(sla); //發送器件地址 if(ack==0)return(0); SendByte(suba); //發送器件子地址 if(ack==0)return(0); SendByte(*s); //發送數據 if(ack==0)return(0); Stop_I2c(); //結束總線 DelayMs(1); //必須延時等待芯片內部自動處理數據完畢 s++; suba++; } return(1);}/*---------------------------------------------------------------- 向無子地址器件讀字節數據函數 函數原型: bit IRcvByte(unsigned char sla,ucahr *c); 功能: 從啟動總線到發送地址,讀數據,結束總線的全過程,從器件地 址sla,返回值在c. 如果返回1表示操作成功,否則操作有誤。注意: 使用前必須已結束總線。----------------------------------------------------------------*//*bit IRcvByte(unsigned char sla,unsigned char *c){ Start_I2c(); //啟動總線 SendByte(sla+1); //發送器件地址 if(ack==0)return(0); *c=RcvByte(); //讀取數據 NoAck_I2c(); //發送非就答位 Stop_I2c(); //結束總線 return(1);}*//*---------------------------------------------------------------- 向有子地址器件讀取多字節數據函數 函數原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no); 功能: 從啟動總線到發送地址,子地址,讀數據,結束總線的全過程,從器件 地址sla,子地址suba,讀出的內容放入s指向的存儲區,讀no個字節。 如果返回1表示操作成功,否則操作有誤。注意: 使用前必須已結束總線。----------------------------------------------------------------*/bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no){ unsigned char i; Start_I2c(); //啟動總線 SendByte(sla); //發送器件地址 if(ack==0)return(0); SendByte(suba); //發送器件子地址 if(ack==0)return(0); Start_I2c(); SendByte(sla+1); if(ack==0)return(0); for(i=0;i<no-1;i++) { *s=RcvByte(); //發送數據 Ack_I2c(); //發送就答位 s++; } *s=RcvByte(); NoAck_I2c(); //發送非應位 Stop_I2c(); //結束總線 return(1);}/*------------------------------------------------ 判忙函數------------------------------------------------*/ bit LCD_Check_Busy(void) { DataPort= 0xFF; RS_CLR; RW_SET; EN_CLR; _nop_(); EN_SET; return (bit)(DataPort & 0x80); } /*------------------------------------------------ 寫入DA轉換數值輸入參數:dat 表示需要轉換的DA數值,范圍是0-255------------------------------------------------*/bit WriteDAC(unsigned char dat){ Start_I2c(); //啟動總線 SendByte(AddWr); //發送器件地址 if(ack==0)return(0); SendByte(0x40); //發送器件子地址 if(ack==0)return(0); SendByte(dat); //發送數據 if(ack==0)return(0); Stop_I2c(); } /*--------------------------------------------------- 按鍵控制 --------------------------------------------------*/void push_button(){ if(!key5) { DelayMs(10); if(!key5) { while(!key5); EA = 0; } } if(!key1) //1 { DelayMs(10); if(!key1) { while(!key1); sec++; if(sec == 60) { sec = 0; min++; } } } if(!key2) //2 { DelayMs(10); if(!key2) { while(!key2); sec--; if(sec == 255) { sec = 59; min--; } } } if (!key3)//3 { DelayMs(10); if(!key3) { while(!key3); min++; if(min == 60) { min = 0; hour++; } } } if(!key4)//4 { DelayMs(10); if(!key4) { while(!key4); min--; if(min == 255) { min = 59; if((hour-1) == 255) { hour = 23; } } } } if(!key7) //7 { EA = 1; } if(!key6)//6 { sec = 0; min = 0; hour = 0; EA = 1; } if(!key8)//8 { DelayMs(10); if(!key8) { while(!key8); hour++; if(hour == 24) { hour = 0; } } }}/*------------------------------------------------ 寫入命令函數------------------------------------------------*/ void LCD_Write_Com(unsigned char com) { // while(LCD_Check_Busy()); //忙則等待 DelayMs(5); RS_CLR; RW_CLR; EN_SET; DataPort= com; _nop_(); EN_CLR; }/*------------------------------------------------ 寫入數據函數------------------------------------------------*/ void LCD_Write_Data(unsigned char Data) { //while(LCD_Check_Busy()); //忙則等待 DelayMs(5); RS_SET; RW_CLR; EN_SET; DataPort= Data; _nop_(); EN_CLR; }/*------------------------------------------------ 清屏函數------------------------------------------------*/ void LCD_Clear(void) { LCD_Write_Com(0x01); DelayMs(5); }/*------------------------------------------------ 寫入字符串函數------------------------------------------------*/ void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) { if (y == 0) { LCD_Write_Com(0x80 + x); } else { LCD_Write_Com(0xC0 + x); } while (*s) { LCD_Write_Data( *s); s ++; } }/*------------------------------------------------ 寫入字符函數------------------------------------------------*/ void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) { if (y == 0) { LCD_Write_Com(0x80 + x); } else { LCD_Write_Com(0xC0 + x); } LCD_Write_Data( Data); }/*------------------------------------------------ 初始化函數------------------------------------------------*/ void LCD_Init(void) { LCD_Write_Com(0x38); /*顯示模式設置*/ DelayMs(5); LCD_Write_Com(0x38); DelayMs(5); LCD_Write_Com(0x38); DelayMs(5); LCD_Write_Com(0x38); LCD_Write_Com(0x08); /*顯示關閉*/ LCD_Write_Com(0x01); /*顯示清屏*/ LCD_Write_Com(0x06); /*顯示光標移動設置*/ DelayMs(5); LCD_Write_Com(0x0C); /*顯示開及光標設置*/ } /*------------------------------------------------ 主函數------------------------------------------------*/ void main(void) { IRcvStr(0xae,0,p,8); hour = p[2]; min = p[1]; sec = p[0]; LCD_Init(); TMOD = 0x01; TL0 = 0xb0; TH0 = 0x3c; EA = 1; ET0 = 1; TR0 = 1; while(1) { LCD_Write_Char(7,0,0X30 + sec%10);// p[0] = sec%10 + 0x30; LCD_Write_Char(6,0,0X30 + sec/10); p[0] = sec; LCD_Write_Char(5,0,0x3a); LCD_Write_Char(4,0,0X30 + min%10); p[1] = min; LCD_Write_Char(3,0,0X30 + min/10);// p[3] = min/10 + 0x30; LCD_Write_Char(2,0,0x3a); LCD_Write_Char(1,0,0X30 + hour%10); p[2] = hour; LCD_Write_Char(0,0,0X30 + hour/10);// p[5] = hour/10 + 0x30; ISendStr(0xae,0,p,8); p[0] = 0; p[1] = 0; p[2] = 0; push_button(); if(flag1) //等于10秒時,LED慢慢變亮,等于40秒時LED自動關閉 { WriteDAC(num); if(num != 0 ) { num--; } } else { num = 255; WriteDAC(num); } }}void time0_isr(void) interrupt 1{ count++; EA = 0; TH0 = 0x3C; TL0 = 0xb0; if(count == 20) { count = 0; sec++; if(sec == 60)//用于顯示0~9 { sec = 0; min++; flag = 0; } if(min == 60) { min = 0; hour++; flag = 1; } if(hour == 24) { hour = 0; } if(sec == 10) { flag1 = 1; } if(sec == 40) { flag1 = 0; } } EA = 1; if(flag) { buzz = ~buzz; P3 = 0x00; DelayMs(10); P3 = 0xff; DelayMs(10); } }
新聞熱點
疑難解答