这是时间和温度轮流显示的程序- /*
- 项目名称: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
复制代码 |