上午花了一上午时间,用12864液晶写了一个电子时钟加温度传感器程序,先说一下程序的功能,可以实现显示年月日时间和温度,
年月日和时间是可通过按键调节的,调节相应的选项时,该选项会闪烁,并停止走时,当调节完毕后时钟恢复走时。现在将程序和思路写下来,以便日后查看和与大家探讨改进,欢迎高手提出宝贵意见。
我使用的是HJ12864M-1带字库液晶,所以在显示上稍微方便一点。下面先来说一下我的编程思路。时间更新用的是单片机自带的定时器,液晶要显示数字必需将它转换成ASCii码的形式,数字0-9的ASCii码与数字之间有一个定量的关系,当数字加上0x30之后便得到该数字的ASCii码,这样以来液晶更新数据就变得简单了。调节时间时对应选项闪烁,是通过不断的交替写入数据和空格实现的。温度显示用的是DS18B20,,将测得的当前温度不断更新显示在液晶上。调节时间用的是三个独立按键。由于这个程序我使用模块化来写的,就只能将每个模块分别给出来,大家只要组装一下便可以使用。如果需要完整程序的可以给我留言我发给你们。
下面是12864液晶的初始化,读写命令,及读忙操作
#include "lcd12864.h" #include <reg52.h> sbit RS=P2^5; //控制端口位定义 sbit RW=P2^6; sbit EN=P2^7; void init_12864() { delay(40); write_com(0x30);//8位数据格式,基本指令显示 delay(10); //延时时间 write_com(0x30);//8位数据格式,基本指令显示 delay(37); write_com(0x0C);//开显示、关闭光标 delay(10); write_com(0x01);//清屏指令 delay(10); //延时 write_com(0x06);//设置显示点:指针自加1 } void delay(uint t) { uint i,j; for(i=120;i>0;i--); for(j=t;j>0;j--); } /********************************************************** void delay_us(uchar t) //延时计算公式:5+2*t { while(--t); } ***********************************************************/ void read_busy() { EN=0; RW=1; RS=0; EN=1; while(P0&0x80); EN=0; } void write_com(uchar com) //写命令 { read_busy(); EN=1; RS=0; RW=0; P0=com; delay(1); EN=0; } void write_dat(uchar dat) //写数据 { read_busy(); EN=1; RS=1; RW=0; P0=dat; delay(1); EN=0; } 控制闪烁的函数如下: void shan(void) { uchar i; write_com(0x94); //将数据写在0x94地址上 if(f==1) //按键按一下年开份始闪烁 { { tab2[8]=' '; //向要闪烁的位置写空格 tab2[9]=' '; } for (i=8;i<=15;i++) { write_dat(tab2[i]); //写数据 } goto return1; } if(f==2) //按键按两下月份开始闪烁 { { tab2[11]=' '; tab3[12]=' '; } for (i=8;i<=15;i++) { write_dat(tab2[i]); } goto return1; } if(f==3) //按键按三下,日期开始闪烁 { { tab2[14]=' '; tab2[15]=' '; } for (i=8;i<=15;i++) { write_dat(tab2[i]); } goto return1; } write_com(0x8b); if(f==4) //按键按四下,小时开始闪烁 { { tab3[6]=' '; tab3[7]=' '; } for (i=6;i<=13;i++) { write_dat(tab3[i]); } goto return1; } if(f==5) //按键按五下,分钟开始闪烁 { { tab3[9]=' '; tab3[10]=' '; } for (i=6;i<=13;i++) { write_dat(tab3[i]); } goto return1; } if(f==6) //按键按六下,秒开始闪烁 { { tab3[12]=' '; tab3[13]=' '; } for (i=6;i<=13;i++) { write_dat(tab3[i]); } goto return1; } if(f==7) //按键按七下,调时完毕,停止闪烁,开始走时 { { for (i=6;i<=13;i++) { write_dat(tab3[i]); TR0=1; //时间设定完毕,打开定时器 } } } return1:_nop_(); } 显示数组: uchar code tab1[]="时钟 +温度显示 "; uchar tab2[16]="日期:20"; uchar tab3[14]="时间:"; uchar tab4[12]="当前温度:" ; 定时器初始化,ASCii码转换 /********************************************************** 程序功能:12864液晶显示电子时钟(包括年月日时分秒),具有闪烁,移位,调时功能 并显示当前温度 程序编译环境:keil4 程序运行环境:HJ12864M-1 整理人:张家越 QQ:435835181 整理时间:2011-04-17 *********************************************************/ #include <reg52.h> #include"lcd12864.h" #include <intrins.h> #include "flash.h" #include"scan.h" #include "18B20.h" uchar tempreture[2]; #define uchar unsigned char #define uint unsigned int uchar utime; //定时20ms,每20ms,utime++ void shan(); //控制闪烁函数 void tkey(void); //按键处理函数 void init_clock() //定时器初始化函数 { TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; ET0=1 ; EA=1; TR0=1; } void iscii_change() //将需要显示的时间转换成ISCii码 { tab3[6]=clock[3]/10+0x30; tab3[7]=clock[3]%10+0x30; tab3[8]=0x3a; tab3[9]=clock[4]/10+0x30; tab3[10]=clock[4]%10+0x30; tab3[11]=0x3a; tab3[12]=clock[5]/10+0x30; tab3[13]=clock[5]%10+0x30; tab2[8]=clock[0]/10+0x30; tab2[9]=clock[0]%10+0x30; tab2[10]=0x2d; tab2[11]=clock[1]/10+0x30; tab2[12]=clock[1]%10+0x30; tab2[13]=0x2d; tab2[14]=clock[2]/10+0x30; tab2[15]=clock[2]%10+0x30; tab4[10]=temp/10+0x30; tab4[11]=temp%10+0x30; } void display() //显示函数 { uchar i; write_com(0x80); for(i=0;i<16;i++) { write_dat(tab1[i]); } write_com(0x90); for(i=0;i<16;i++) { write_dat(tab2[i]); } write_com(0x88); for(i=0;i<14;i++) { write_dat(tab3[i]); delay(1); } write_com(0x98); for(i=0;i<12;i++) { write_dat(tab4[i]); } } void main() { init_clock(); init_12864(); while(1) { Read_temp(); iscii_change(); display(); tkey(); shan(); } } void clk()interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; utime++; if(utime ==20) //一秒钟时间到,秒加一 { utime=0; clock[5]++; } else if(clock[5]==60) //秒钟加到60分钟加一 { clock[5]=0; clock[4]++; } else if(clock[4]==60) { clock[4]=0; clock[3]++ ; } else if(clock[3]==24) { clock[3]=0; clock[2]++; } else if(clock[2]==31) { clock[2]=0; clock[1]++; } else if(clock[1]==13) { clock[1]=0; clock[0]++; } else if(clock[0]==100) { clock[0]=0; } } 按键扫描函数 uchar clock[6]={11,3,22,12,22,34}; //用来存放年的后两位,月,日,时,分,秒 sbit key1=P3^2; //位定义三个按键(用来调时) sbit key2=P3^3; sbit key3=P3^4; void tkey(void) { /*******移位键*********/ if (key1==0) { //delay(10); f++; TR0=0; //调整时间时关闭定时器 } if (f==8) f=1; /**********加一键*********/ if(key2==0) { // delay(10); clock[f-1]++; } if (f==1) { if (clock[f-1]==100){ clock[f-1]=0;} } else if(f==2) { if(clock[f-1]==13) clock[f-1]=0; } else if(f==3) { if(clock[f-1]==31) clock[f-1]=0; } else if(f==4) { if(clock[f-1]==24) clock[f-1]=0; } else{ if (clock[f-1]==60) clock[f-1]=0; } /******减一键***********/ if(key3==0) { // delay(10); clock[f-1]--; } else if (f==1) { if (clock[f-1]==0xff){ clock[f-1]=99;} } else if (f==2) { if (clock[f-1]==0xff){ clock[f-1]=12;} } else if (f==3) { if (clock[f-1]==0xff){ clock[f-1]=30;} } else if (f==1) { if (clock[f-1]==0xff){ clock[f-1]=23;} } else { if (clock[f-1]==0xff) clock[f-1]=59; } } 18B20温度传感器控制函数: #include<reg52.h> #include<intrins.h> #include "lcd12864.h" #define uchar unsigned char #define uint unsigned int uchar temp=80,temp_L,temp_H; sbit DQ=P2^3; void delay_us(uchar i) //延时函数,计算公式:延时时间T=5+2*i; { while(--i); } bit Reset_DS18B20(void) //DS18B20复位函数 { bit DS18B20_exist; DQ=1; DQ=0; delay_us(250); //将DQ拉低480 ~ 960us,产生复位信号 DQ=1; //将总线释放,进入接收状态 delay_us(30); //等待15-60us,DS18b20发出存在信号,将总线拉低60-240us DS18B20_exist=DQ; delay_us(200); //存在信号持续60 ~ 240us if(DS18B20_exist) return 1; //返回1,DS18B20复位失败,总线上无DS18B20 else return 0; //返回0,DS18B20复位成功,总线上存在DS18b20 } //写数据--线低后高 void write_DS18B20(unsigned char value) { unsigned char i; for(i=0;i<8;i++) { DQ=1; DQ=0; //将总线拉低,数据送入总线 _nop_(); DQ=value&0x01; delay_us(20); //DS18b20在之后的15-60us的时间对总线数据采样 DQ=1; //连续写入将须将总线释放至少1us value=value>>1; } } //读数据--先低后高 unsigned char Read_DS18B20(void) { unsigned char value,i; for(i=0;i<8;i++) { DQ=1; DQ=0; delay_us(1); //主机将总线拉低7us,!!!!时间不能过长 DQ=1; //之后释放总线,告诉DS18B20“读”数据 _nop_(); _nop_(); value=value>>1; if(DQ) value|=0x80; //数据读取 delay_us(20); } return value; } void Read_temp() { Reset_DS18B20(); write_DS18B20(0xCC); write_DS18B20(0x44); Reset_DS18B20(); write_DS18B20(0xcc); write_DS18B20(0xBE); temp_L=Read_DS18B20(); temp_H=Read_DS18B20(); temp=(temp_H*256+temp_L)/16; } ------------------------------------- #include "lcd12864.h" #include <reg52.h> sbit RS=P2^5; //控制端口位定义 sbit RW=P2^6; sbit EN=P2^7; void init_12864() { delay(40); write_com(0x30);//8位数据格式,基本指令显示 delay(10); //延时时间 write_com(0x30);//8位数据格式,基本指令显示 delay(37); write_com(0x0C);//开显示、关闭光标 delay(10); write_com(0x01);//清屏指令 delay(10); //延时 write_com(0x06);//设置显示点:指针自加1 } void delay(uint t) { uint i,j; for(i=120;i>0;i--); for(j=t;j>0;j--); } /********************************************************** void delay_us(uchar t) //延时计算公式:5+2*t { while(--t); } ***********************************************************/ void read_busy() { EN=0; RW=1; RS=0; EN=1; while(P0&0x80); EN=0; } void write_com(uchar com) //写命令 { read_busy(); EN=1; RS=0; RW=0; P0=com; delay(1); EN=0; } void write_dat(uchar dat) //写数据 { read_busy(); EN=1; RS=1; RW=0; P0=dat; delay(1); EN=0; }
完整代码下载:点这里