這是時間和溫度輪流顯示的程序- /*
- 項目名稱:0.8寸4位共陽數碼管時鐘
- 1.5個PNP三極管接在共陽極驅動數碼管,這個數碼管小數點都有,冒號是單獨兩個LED
- 2.設置方法:按k1鍵設置狀態(小時位數碼管閃爍),按K2鍵++,按K3鍵--,長按連加連減;
- 按K1鍵第二次,分鐘位數碼管閃爍,按K2鍵++,按K3鍵--,長按連加連減;
- 按K1鍵第三次,退出設置狀態,回到正常走時界面。
- 3. P2.0-P2.4位驅動口,P1口為段驅動口;
- 4. 單片機=STC8H1K16(LQFP32封裝) @11.0592MHz 時鐘芯片=DS3231MZ(SOP-8封裝)
- 測試通過
- 第一次發的程序按鍵長按有bug,也改好了。
- */
- #include <STC8H.H>
- #include <intrins.h>
- #include "ds18b20.h"
- //#include "delay.h"
- #define uchar unsigned char
- #define uint unsigned int
- //typedef unsigned char u8;
- //typedef unsigned int u16;
- //typedef unsigned long u32;
- sbit k1=P0^0;// 按鍵1 設置 +
- sbit k2=P2^7;// 按鍵2 -
- sbit k3=P3^7;//
- sbit k4=P2^5;
- sbit out = P3^2; //輸出端口
- sbit w1 = P2^0; //設置位驅動口
- sbit w2 = P2^1;
- sbit w3 = P2^2;
- sbit w4 = P2^3;
- sbit w5 = P2^4; //冒號控制
- sbit BZ = P0^3;//蜂鳴器控制口
- uint count,cont1,cont2,cont3;
- uint fen,fen_temp;
- uchar fen_L,fen_M,miao,num,num2;
- uchar Ledcount;
- uchar num;
- uchar k1_lock,k2_lock,k3_lock;//按鍵鎖
- uchar knum;
- uint shan,shan1;//秒點閃爍 計時變量
- uint k1_time_count; //K1消抖計數
- uint k2_time_count; //K2消抖計數
- uint k3_time_count; //K3消抖計數
- bit flag; //計時啟動標志
- bit flag1; //按鍵消抖計數標志
- bit flag2; //按鍵消抖計數標志
- bit save_flag;//數據保存標志
- bit save_flag1;//數據保存標志
- bit set_flag=0; //設置標志
- bit fm_flag;//蜂鳴器
- bit flag3;
- bit qh_flag,qh_flag1;
- uchar hour,minute,second,year,month,day,date,week;
- uint TH3231;
- bit ack; //應答標志位
- uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xC6,0xbf,0x8e};//共陽段碼 (0--9、黑屏,C,-,F)0X46 C帶點,0xc6C不帶點
- uchar LedBuff[]={0xff,0xff,0xff,0xff};
- // ------------------------------------------------------------
- // IO口模擬I2C通信
- // ------------------------------------------------------------
- sbit SCL=P3^5; //串行時鐘
- sbit SDA=P3^4; //串行數據
- /********************************************************************************************************
- ** DS3231常數定義
- ********************************************************************************************************/
- #define DS3231_WriteAddress 0xD0 //器件寫地址
- #define DS3231_ReadAddress 0xD1 //器件讀地址
- #define DS3231_SECOND 0x00 //秒
- #define DS3231_MINUTE 0x01 //分
- #define DS3231_HOUR 0x02 //時
- #define DS3231_WEEK 0x03 //星期
- #define DS3231_DAY 0x04 //日
- #define DS3231_MONTH 0x05 //月
- #define DS3231_YEAR 0x06 //年
- #define DS3231_TEMPERATUREH 0x11 //溫度寄存器高字節(8位) 整數部分
- #define DS3231_TEMPERATUREL 0x12 //溫度寄存器低字節(低2位) 小數部分
- #define NACK 1
- #define ACK 0
- /////////////////
- //void Delay5US() //@12.000MHz 延時5us
- //{
- // _nop_(); _nop_(); _nop_();_nop_(); _nop_();_nop_();//STC Y6指令 1T單片機用6個nop,12T用1個nop
- //}
- void Delay5US() //@11.0592MHz STC Y6指令
- {
- unsigned char i;
- _nop_();
- i = 16;
- while (--i);
- }
- void delay(uint x)
- {
- uint y,z;
- for(y=0; y<x; y--)
- for(z=0; z<1200; z--);
- }
- /**********************************************
- //IIC Start
- **********************************************/
- void IIC_Start()
- {
- SCL = 1;
- SDA = 1;
- SDA = 0;
- SCL = 0;
- }
- /**********************************************
- //IIC Stop
- **********************************************/
- void IIC_Stop()
- {
- SCL = 0;
- SDA = 0;
- SCL = 1;
- SDA = 1;
- }
- /********************************************************************************************************
- ** 3231
- ********************************************************************************************************/
- uchar BCD2HEX(uchar val)//轉10進制
- {
- return ((val>>4)*10)+(val&0x0f);
- }
- uchar HEX2BCD(uchar val) //轉16進制
- {
- return (((val%100)/10)<<4)|(val%10);
- }
- void SendByte(uchar c)
- {
- uchar BitCnt;
-
- for(BitCnt=0;BitCnt<8;BitCnt++) //要傳送的數據長度為8位
- {
- if((c<<BitCnt)&0x80)
- SDA=1; //判斷發送位
- else
- SDA=0;
- SCL=1; //置時鐘線為高,通知被控器開始接收數據位
- Delay5US(); //保證時鐘高電平周期大于4μs
- SCL=0;
- }
- SDA=1; //8位發送完后釋放數據線,準備接收應答位
- SCL=1;
- Delay5US();
- if(SDA==1)
- ack=0;
- else
- ack=1; //判斷是否接收到應答信號
- SCL=0;
- Delay5US();
- }
- uchar RcvByte()
- {
- uchar retc;
- uchar BitCnt;
-
- retc=0;
- SDA=1; //置數據線為輸入方式
- for(BitCnt=0;BitCnt<8;BitCnt++)
- {
- SCL=0; //置時鐘線為低,準備接收數據位
- Delay5US(); //時鐘低電平周期大于4.7μs
- SCL=1; //置時鐘線為高使數據線上數據有效
- Delay5US();
- retc=retc<<1;
- if(SDA==1)
- retc=retc+1; //讀數據位,接收的數據位放入retc中
- Delay5US();
- }
- SCL=0;
- return(retc);
- }
-
- void Ack_I2C(bit a)
- {
- SDA = a;
- SCL=1;
- Delay5US(); //時鐘低電平周期大于4us
- SCL=0; //清時鐘線,鉗住I2C總線以便繼續接收
- Delay5US();
- }
- uchar write_byte(uchar addr, uchar write_data)
- {
- IIC_Start();
- SendByte(DS3231_WriteAddress);
- if (ack == 0)
- return 0;
-
- SendByte(addr);
- if (ack == 0)
- return 0;
-
- SendByte(write_data);
- if (ack == 0)
- return 0;
-
- IIC_Stop();
- Delay5US();
- Delay5US();
- return 1;
- }
- uchar read_current()
- {
- uchar read_data;
- IIC_Start();
- SendByte(DS3231_ReadAddress);
- if(ack==0)
- return(0);
- read_data = RcvByte();
- Ack_I2C(1);
- IIC_Stop();
- return read_data;
- }
- uchar read_random(uchar random_addr)
- {
- uchar Tmp;
- IIC_Start();
- SendByte(DS3231_WriteAddress);
- if(ack==0)
- return(0);
- SendByte(random_addr);
- if(ack==0)
- return(0);
- Tmp=read_current();
- if(random_addr==DS3231_HOUR)
- Tmp&=0x3f;
-
- return(BCD2HEX(Tmp));//都轉10進制輸出
- }
- /***********************/
- uchar read_random1(uchar random_addr) //這個是讀溫度函數
- {
- uchar Tmp;
- // write_byte(0x0e,0x20);//0x0e寄存器的CONV位置1開啟溫度轉換,要這句,溫度實時刷新,這句不要,溫度要64s才刷新1次
- //數碼管顯示不能要這句,否則溫度值小數部分亂跳
- IIC_Start();
- SendByte(DS3231_WriteAddress);
- if(ack==0)
- return(0);
- SendByte(random_addr);
- if(ack==0)
- return(0);
- Tmp=read_current();
- return Tmp;
- }
- void ModifyTime(uchar address,uchar num)
- {
- uchar temp=0;
- if(address>6 && address <0) return;
- temp=HEX2BCD(num);
- write_byte(address,temp);
- }
- ////////////////
- /*
- void IapIdle()
- {
- IAP_CONTR = 0; //關閉IAP功能
- IAP_CMD = 0; //清除命令寄存器
- IAP_TRIG = 0; //清除觸發寄存器
- IAP_ADDRH = 0x80; //將地址設置到非IAP區域
- IAP_ADDRL = 0;
- }
- char IapRead(int addr)
- {
- char dat;
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設置等待參數12MHz
- IAP_CMD = 1; //設置IAP讀命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_();
- dat = IAP_DATA; //讀IAP數據
- IapIdle(); //關閉IAP功能
- return dat;
- }
- void IapProgram(int addr, char dat)
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設置等待參數12MHz
- IAP_CMD = 2; //設置IAP寫命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_DATA = dat; //寫IAP數據
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_();
- IapIdle(); //關閉IAP功能
- }
- void IapErase(int addr)
- {
- IAP_CONTR = 0x80; //使能IAP
- IAP_TPS = 12; //設置等待參數12MHz
- IAP_CMD = 3; //設置IAP擦除命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_(); //
- IapIdle(); //關閉IAP功能
- }
- */
- ////////////////////
- void Timer0Init(void) //2毫秒@11.0592MHz
- {
- AUXR |= 0x80; //定時器時鐘1T模式
- TMOD &= 0xF0; //設置定時器模式 16位自動重載
- TL0 = 0x9A; //設置定時初始值
- TH0 = 0xA9; //設置定時初始值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- EA = 1; //開總中斷
- ET0 = 1; //開T0中斷
- }
- //void Timer0Init(void) //5毫秒@11.0592MHz
- //{
- // AUXR |= 0x80; //定時器時鐘1T模式
- // TMOD &= 0xF0; //設置定時器模式
- // TL0 = 0x00; //設置定時初始值
- // TH0 = 0x28; //設置定時初始值
- // TF0 = 0; //清除TF0標志
- // TR0 = 1; //定時器0開始計時
- // EA = 1; //開總中斷
- // ET0 = 1; //開T0中斷
- //}
- /////////////////////////////
- void keyscan()
- {
- uchar temp;
- hour = read_random(DS3231_HOUR);
- minute = read_random(DS3231_MINUTE) ;
- second = read_random(DS3231_SECOND);
-
- if(k1) //
- { //
- k1_time_count=0;
- k1_lock=0;
- flag1 = 0;
- }
- else if((k1_lock==0))
- {
- flag1 = 1; //按鍵按下 消抖計時標志置1 開始消抖計時
- if((k1_time_count==10)) //20毫秒
- {
- k1_time_count=0;
- k1_lock=1;
- knum++;
- if(knum==3)
- {
- knum=0;
- second=0;
- write_byte(DS3231_SECOND, second); //秒寫0
- }
- }
- }
- /////////////////////////////
- if(knum==1) //設置小時
- {
- if(k2 ==1) //++
- {
- k2_time_count=0;
- k2_lock=0;
- flag2 = 0;
- }
- else if(k2_lock==0)
- {
- // flag = 0;
- flag2 = 1;
- // save_flag = 1;
- if(k2_time_count==10) //短按
- {
- k2_time_count=0;
- k2_lock=1;
- hour++;
- if(hour>23)
- hour=0;
- temp=HEX2BCD(hour);
- write_byte(DS3231_HOUR, temp);
- }
- }
- else if(k2_time_count>500) //長按
- {
- // cont1=0; num=0;
- k2_time_count=400;
- hour++;
- if(hour>23)
- hour=0;
- temp=HEX2BCD(hour); //10進制轉16進制
- write_byte(DS3231_HOUR, temp);
- }
- //////////////////////////
- if(k3 == 1) //--
- {
- k3_time_count=0;
- k3_lock=0;
- flag3 = 0;
- }
- else if(k3_lock==0)
- {
-
- flag3 = 1;
- // save_flag1 = 1;
- if(k3_time_count==10) //短按
- {
- // cont1=0; num=0;
- k3_time_count=0;
- k3_lock=1;
- hour--;
- if(hour==255)
- hour=23;
- temp=HEX2BCD(hour);
- write_byte(DS3231_HOUR, temp);
- }
-
- }
- else if(k3_time_count>500) //長按
- {
- // cont1=0; num=0;
- k3_time_count=400; //長按200ms連減
- hour--;
- if(hour==255)
- hour=23;
- temp=HEX2BCD(hour);
- write_byte(DS3231_HOUR, temp);
- }
- }
- ////////////////////////////////
- if(knum==2) //設置分鐘
- {
- if(k2 ==1) //++
- {
- k2_time_count=0;
- k2_lock=0;
- flag2 = 0;
- }
- else if(k2_lock==0)
- {
- // flag = 0;
- flag2 = 1;
- // save_flag = 1;
- if(k2_time_count==10) //短按
- {
- k2_time_count=0;
- k2_lock=1;
- minute++;
- if(minute>59)
- minute=0;
- temp=HEX2BCD(minute);
- write_byte(DS3231_MINUTE, temp);
- }
- }
- else if(k2_time_count>500) //長按
- {
- // cont1=0; num=0;
- k2_time_count=400;
- minute++;
- if(minute>59)
- minute=0;
- temp=HEX2BCD(minute);
- write_byte(DS3231_MINUTE, temp);
- }
- //////////////////////////
- if(k3 == 1) //--
- {
- k3_time_count=0;
- k3_lock=0;
- flag3 = 0;
- }
- else if(k3_lock==0)
- {
-
- flag3 = 1;
- // save_flag1 = 1;
- if(k3_time_count==10) //短按
- {
- // cont1=0; num=0;
- k3_time_count=0;
- k3_lock=1;
- minute--;
- if(minute==255)
- minute=59;
- temp=HEX2BCD(minute);
- write_byte(DS3231_MINUTE, temp);
- }
-
- }
- else if(k3_time_count>500) //長按
- {
- // cont1=0; num=0;
- k3_time_count=400;
- minute--;
- if(minute==255)
- minute=59;
- temp=HEX2BCD(minute);
- write_byte(DS3231_MINUTE, temp);
- }
- }
- }
- ///////////////////////////////
- void display_sf() //顯示 時分
- {
- // year = read_random(DS3231_YEAR);
- // month = read_random(DS3231_MONTH);
- // day = read_random(DS3231_DAY);
- // week = read_random(DS3231_WEEK);
- hour = read_random(DS3231_HOUR);
- minute = read_random(DS3231_MINUTE) ;
- second = read_random(DS3231_SECOND);
- if(knum==0)
- {
- LedBuff[0]= table[hour/10];
- LedBuff[1]= table[hour%10];
- LedBuff[2]= table[minute/10];
- LedBuff[3]= table[minute%10];
- if(shan>250)
- {w5=1; }
- else {w5=0;}
- }
- if(knum==1)
- {
- if(shan1>125)
- {
- LedBuff[0]= table[hour/10];
- LedBuff[1]= table[hour%10];
- }
- else
- {
- LedBuff[0]= table[10];
- LedBuff[1]= table[10];
-
- }
- LedBuff[2]= table[minute/10];
- LedBuff[3]= table[minute%10];
- }
- if(knum==2)
- {
-
- LedBuff[0]= table[hour/10];
- LedBuff[1]= table[hour%10];
-
- if(shan1>125)
- {
- LedBuff[2]= table[minute/10];
- LedBuff[3]= table[minute%10];
- }
- else
- {
- LedBuff[2]= table[10];
- LedBuff[3]= table[10];
- }
- }
- }
- ///////////////////////
- void ds18b20disp(uint Value)
- {
- if(s==0) //顯示正溫度
- {
- if((Value/1000)>0)//大于100度顯示最高位
- LedBuff[0]= table[Value/1000];
- else
- LedBuff[0]=table[10];//小于100度不顯示最高位
- }else {LedBuff[0]=s;}//顯示負號
- LedBuff[1]=table[Value%1000/100]; //十位
- LedBuff[2]=table[Value%100/10];//
- LedBuff[3]=table[11];
- }
- /////////////////////
- /////////////////////
- void main()
- {
- Timer0Init();
- P0M0 = 0x00; //
- P0M1 = 0x00; //
- P1M0 = 0x00; //
- P1M1 = 0x00;
- P2M0 = 0x1f; //p2.0-p2.4 設為推挽輸出
- P2M1 = 0x00;
- P3M0 = 0x04; //P3.2設為推挽輸出才能驅動繼電器
- P3M1 = 0x00;
- P4M0 = 0x00;
- P4M1 = 0x00;
- P5M0 = 0x10;
- P5M1 = 0x00;
- // P2PU=0x10;
- // P2DR=0X00;
- // w5=1;
- while(1)
- {
-
- keyscan();
- if(qh_flag==0)
- {
- display_sf();
- }
- else
- {
- if(knum==0)
- {
- read_temp(); //DS18B20溫度
- ds18b20disp(tvalue);
- w5=1;
- }
- }
- if(knum!=0)
- {
- qh_flag=0;
- }
- // if(shan>250)
- // {BZ=1;}
- // else {BZ=0;}
-
- // BZ=0;
- // Delay_us(10);//實測11us(延時函數里面4個_nop_();@11.0592MHz)
- // BZ=1;
- // Delay_us(10);
-
- }
- }
- void timer0() interrupt 1
- {
- static uint i,j;
- /*
- if(fm_flag)
- {
- BZ = 0; //蜂鳴器開
- cont3++;
- if(cont3==100)//0.2秒
- {
- cont3=0;
- BZ = 1; //蜂鳴器關
- fm_flag=0;
- }
- } */
-
- shan++;
- if(shan==500)
- {
- shan=0;
- }
- if(knum != 0)
- {
- shan1++;
- if(shan1==250)
- shan1=0;
- }
- Ledcount++;
- P1=0xff; //消影
- if(Ledcount==4)
- {
- Ledcount=0;
- }
- switch(Ledcount)
- {
- case 0: w2 = 1; w3 = 1; w4 = 1;w1 = 0; P1 = LedBuff[0]; break;
- case 1: w1 = 1; w3 = 1; w4 = 1;w2 = 0; P1 = LedBuff[1]; break;
- case 2: w1 = 1; w2 = 1; w4 = 1;w3 = 0; P1 = LedBuff[2]; break;
- case 3: w1 = 1; w2 = 1; w3 = 1;w4 = 0; P1 = LedBuff[3]; break;
- default: break;
- }
-
- if(flag1) //按鍵消抖計時
- {k1_time_count++;}
- if(flag2) //按鍵消抖計時
- {k2_time_count++;}
- if(flag3) //按鍵消抖計時
- {k3_time_count++;}
- if(qh_flag1==0 && knum==0)
- {
- i++;
- if(i==500)
- {
- i=0;
- j++;
- if(j==7)
- {
- j=0;
- qh_flag=1;
- qh_flag1=1;
- }
- }
- }
- else
- {
- if(knum==0)
- {
- i++;
- if(i==500)
- {
- i=0;
- j++;
- if(j==3)
- {
- j=0;
- qh_flag=0;
- qh_flag1=0;
- }
- }
- }
- }
- }
- [code]#ifndef __DS18B20_H__
- #define __DS18B20_H__
- //#include "delay.h"
- #define uchar unsigned char
- #define uint unsigned int
-
- /*定義DS18B20數據線*/
- sbit DQ = P0^1;
- //sbit DQ = P5^4;
- /*DS18B20驅動程序------------------------------------------------------------*/
- uchar data disdata[5];
- uint tvalue;//溫度值
- uint s;
- void Delay_us(uchar i) //us延時 STC Y6指令 使用STC8系列
- { //@11.0592MHz
- while(i--)
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- ////////////
- _nop_(); //_nop_();// _nop_(); _nop_();
- }
- }
- /*單總線初始化時序*/
- bit ds_init()
- {
- bit i;
- DQ = 1;
- _nop_();_nop_();_nop_();_nop_();_nop_();
- DQ = 0;
- Delay_us(250); Delay_us(250);//拉低總線499.45us 掛接在總線上的18B20將會全部被復位
- DQ = 1; //釋放總線
- Delay_us(38); //延時37.95us 等待18B20發回存在信號
- i = DQ;
- Delay_us(145); //141.95us
- DQ = 1;
- _nop_();
- return (i);
- }
- /*寫一個字節*/
- void write_byte_ds18b20(uchar dat)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- DQ = 0;
- _nop_();//產生些時序
- DQ = dat & 0x01;
- Delay_us(78);//76.95us
- DQ = 1; //釋放總線準備下一次數據寫入
- _nop_();
- dat >>= 1;
- }
- }
- uchar read_byte()
- {
- uchar i, j, dat;
- for(i=0;i<8;i++)
- {
- DQ = 0;
- _nop_();//產生讀時序
- DQ = 1;
- _nop_();//釋放總線
- j = DQ;
- Delay_us(78);//76.95us
- DQ = 1;
- _nop_();
- dat = (j<<7)|(dat>>1);
- }
- return (dat);
- }
- read_temp()
- {
- // float tt;
- uchar L,M;
- ds_init();
- write_byte_ds18b20(0xcc);//*跳過讀序列號*/
- write_byte_ds18b20(0x44);//*啟動溫度轉換*/
- Delay_us(100);
- ds_init();
- write_byte_ds18b20(0xcc);//*跳過讀序列號*/
- write_byte_ds18b20(0xbe);//*讀取溫度*/
- Delay_us(100);
- L=read_byte();
- M=read_byte();
- tvalue=M;
- tvalue<<=8;
- tvalue=tvalue|L;
- // if(M >= 0x08) //判斷是否為負數
- // {
- // tvalue = ~tvalue + 1;//負數是以補碼的形式存放的需要取反加1
- // s = "-"; //顯示負數符號
- // }
- // else s = 0; //為正數則不顯示負數符號
- tvalue=tvalue*(0.625);//溫度值擴大10倍,精確到1位小數
- return(tvalue);
- }
- /*溫度值顯示-----------------------------------------------------------------*/
- /*
- void ds1820disp()
- {
- disdata[0]=tvalue%1000/100+0x30; //十位數
- disdata[1]=tvalue%100/10+0x30; //個位數
- disdata[2]=tvalue%10+0x30; //小數位
- if(disdata[0]==0x30) { disdata[0]=0x20; }//如果十位為0,不顯示
- set1616pic(5,4,0,1); //顯示"溫度計圖標"
- write_com(0x30); write_com(0x06);
- write_com(0x9d); //在液晶上顯示溫度起始位置:"28.8°C
- write_data(disdata[0]); //顯示十位
- write_data(disdata[1]); //顯示個位
- write_data(0x2e); //顯示小數點
- write_data(disdata[2]); //顯示小數位
- set1616pic(8,4,0,0); //在第8列第4行不反白的°C圖標
- } */
- /*---------------------------------------------------------------------------*/
- #endif
復制代碼 |