给大家分享一个写得很好的lcd12864液晶屏的源程序,有菜单功能,图文显示,是一个单片机信号发生器项目
实物图:
Altium Designer画的原理图如下:(51hei附件中可下载工程文件)
单片机源程序如下:
- #include <stc12c5a60s2.h>
- #include <intrins.h>
- #include <stdio.h>
- #include "delay.h"
- #include "i2c.h"
- #include "1302.h"
- #include "18b20.h"
- #include "AD9850.h"
- #include "12864.h"
- #include "ZK.h"
- #include <math.h>
- //sbit rs=P2^4;
- //sbit rw=P2^5;
- //sbit en=P2^6;
- //sbit psb=P2^1;
- //sbit res=P2^3;
- //#define dataport P0
- sbit keyadd=P3^5;//按键上移
- sbit keydec=P3^4;//按键下移
- sbit keyenter=P3^3;//按键确认
- sbit keybac=P3^2;//按键后退
- //sbit sda=P3^6;
- //sbit scl=P3^7;
- //sbit SCK=P1^4;
- //sbit SDA=P1^5;
- //sbit RST=P1^6;
- //sbit DQ=P1^3
- bit ReadTimeFlag;//读取时间标志
- bit ReadVolFlag;//读取电压标志
- bit ReadTempFlag;//读取温度标志
- bit keyflag;//按键调整扫描标志
- bit FrequencyKeyFlag;//按键调整频率标志
- bit FrequencyFlag;//进入频率函数标志
- unsigned char curr,currold,level,menu,menuold,select,s1num,time, FrequencyBit;
- float idata FreDisplay;
- unsigned long idata Frequency;
- unsigned char idata VolTemp[3][5];
- unsigned char idata FreTemp[16];
- unsigned char code Signalhead[]={" 信号发生"};
- unsigned char code *SignalMenu[]=
- {
- {" 正\xFD弦信号"},
- {" 三\xFD角信号"},
- {" 方波信号"},
- };
- /*------------------------------------------------
- 液晶主界面显示
- ------------------------------------------------*/
- void lcd12864_write_Main()
- {
- DisplayPicture(0,0,1-curr,menudata[0],32,64);
- DisplayPicture(4,0,2-curr,menudata[1],32,64);
- DisplayPicture(0,31,3-curr,menudata[2],32,64);
- DisplayPicture(4,31,4-curr,menudata[3],32,64);
- }
- /*------------------------------------------------
- 函数发生功能模块显示
- ------------------------------------------------*/
- void lcd12864_write_SignalMenuData()
- {
- unsigned char i;
- lcd12864_clr();
- lcd12864_write_string(0,0,Signalhead);
- for(i=0;i<3;i++)
- {
- lcd12864_write_string(0,i+2,SignalMenu[i]);
- }
- DisplayCGRAM8(0,menu+1);
- }
- void init_time0()
- {
- TMOD=0x11;
- TH0=(65535-2000)/256;
- TL0=(65535-2000)%256;
- TH1=(65535-5123)/256;
- TL1=(65535-5123)%256;
- EA=1;
- ET0=1;
- ET1=1;
- TR0=1;
- TR1=1;
-
-
- }
- /*------------------------------------------------
- 按键调整时间
- ------------------------------------------------*/
- void keycheck()
- {
- if(keydec==0)
- {
- delays(10);
- if(keydec==0)
- {
- while(!keydec);
- s1num++;
- time=1;
- if(s1num>9)
- s1num=1;
-
- }
- }
- if(keyadd==0)
- {
- delays(10);
- if(keyadd==0)
- {
- while(!keyadd);
- time++;
- }
- }
- if(keyenter==0)
- {
- delays(10);
- if(keyenter==0)
- {
- while(!keyenter);
- time--;
- }
-
- }
- if(!keybac)
- {
- delays(10);
- if(!keybac)
- {
- while(!keybac);
- level=0;
- curr=1;
- select=0;
- s1num=0;
- menu=0;
-
- }
- }
-
-
- }
- /*----------------------------------------------------------------------------------------------
- 菜单按键:level用于定义菜单层级,curr用于定义当前选中选项,menu相当于二级中curr
- -------------------------------------------------------------------------------------------------*/
- void keypro()
- {
- if(!keyadd)
- {
- delays(10);
- if(!keyadd)
- {
- while(!keyadd);
- if(level<1)
- {
- if(curr<5)
- curr++;
- if(curr==5)
- curr=1;
- }
- if((level==1)&&(curr==3))
- {
- if(menu<4)
- menu++;
- if(menu==4)
- menu=1;
- }
- }
- }
- if(!keydec)
- {
- delays(10);
- if(!keydec)
- {
- while(!keydec);
- if(level<1)
- {
- if(curr>=0)
- {
- curr--;
- if(curr==0)
- curr=4;
-
- }
- }
- if((level==1)&&(curr==3))
- {
- menu--;
- if(menu==0)
- menu=3;
- }
- }
- }
- if(!keyenter)
- {
- delays(10);
- if(!keyenter)
- {
- while(!keyenter);
- level++;
- if((level==1)&&(curr==3))
- menu=1;
- if((level>=1)&&(curr!=3))
- level=1;
-
- }
- }
- if(!keybac)//按后退键的时候参数初始化下
- {
- delays(10);
- if(!keybac)
- {
- while(!keybac);
- level=0;
- curr=1;
- select=0;
- s1num=0;
- menu=0;
-
- }
- }
- }
- /*------------------------------------------------
- 调整频率时所用的按键程序
- ------------------------------------------------*/
- void FrequencyKey()
- {
-
- if(!keyadd)
- {
- delays(10);
- if(!keyadd)
- {
- while(!keyadd);
- FrequencyFlag=1;
- if(FrequencyBit<=6)
- FrequencyBit++;
- else
- FrequencyBit=0;
- }
- }
- if(!keydec)//dec键用于步进值的选择,增加频率
- {
- delays(10);
- if(!keydec)
- {
- while(!keydec);
- FrequencyFlag=1;
- switch (FrequencyBit)
- {
- case 0:if((Frequency++)<10000000)Frequency+=1;break;
- case 1:if((Frequency+10)<10000000)Frequency+=10;break;
- case 2:if((Frequency+100)<10000000)Frequency+=100;break;
- case 3:if((Frequency+1000)<10000000)Frequency+=1000;break;
- case 4:if((Frequency+10000)<10000000)Frequency+=10000;break;
- case 5:if((Frequency+100000)<10000000)Frequency+=100000;break;
- case 6:if((Frequency+1000000)<10000000)Frequency+=1000000;break;
- default:break;
-
- }
- }
- }
- if(!keyenter)//enter键用于步进值的选择,减小频率
- {
- delays(10);
- if(!keyenter)
- {
- while(!keyenter);
- FrequencyFlag=1;
- switch (FrequencyBit)
- {
- case 0:if((Frequency--)>0)Frequency-=1;break;
- case 1:if((Frequency-10)>0)Frequency-=10;break;
- case 2:if((Frequency-100)>0)Frequency-=100;break;
- case 3:if((Frequency-1000)>0)Frequency-=1000;break;
- case 4:if((Frequency-10000)>0)Frequency-=10000;break;
- case 5:if((Frequency-100000)>0)Frequency-=100000;break;
- case 6:if((Frequency-1000000)>0)Frequency-=1000000;break;
- default:break;
- }
- }
- }
- if(!keybac)//退出时重启下ad9850模块
- {
- delays(10);
- if(!keybac)
- {
- while(!keybac);
- if(level>0)
- level=1;
- ad9850_reset_serial();
-
-
- }
- }
- }
- void main()
- {
- bit oe,Dot;
- xdata char Voldata[85];//存储一个周期内电压值的坐标
- xdata float Volvalue[85];//存储一个周期内的电压值
- int NewTemp,Temp,sum,sumold;
- unsigned char i,num,k,w,x,wold,Tempge,Tempshi,sec,secold,color,VolDigit/*电压整数位*/,VolDecimal/*电压小数位*/,count;
- unsigned char count1[3];
- idata float Vol,Temprature,Voltemp,VolMax,VolMin,LM317Vol,LM317Volold;
- oe=1;
- x=0;
- count=0;
- sum=sumold=0;
- w=wold=0;
- sec=secold=0;
- curr=1;
- Temp=240;
- color=0xff;
- Frequency=FreDisplay=0;
- menu=menuold=0;
- AUXR &= 0xfd;
- init_time0();
- init_12864();
- init_i2c();
- Init_DS18B20();
- Ds1302_Init();
- Ds1302_Read_Time();
- ad9850_reset_serial();
- Clear_GDRAM();
- lcd12864_write_com(0x36);
-
- DrawPicture(user128x64);//开机图片
-
- for(i=0;i<5;i++)
- delays(200);
- CGRAM();
- CGRAM8();
-
- while(1)
- {
- sum=menu*100+curr*10+level;//sum用于记录菜单的状态,sum值必须满足一有按键按下值就要变化,这样才能正确的判断进入哪个选项
- if(sum!=sumold)//只有按键按下也就是sum发生变化时才更新菜单
- {
- sumold=sum;
- switch(sum)
- {
- case 10:lcd12864_clr();lcd12864_write_Main();keyflag=0;FrequencyKeyFlag=0;ReadVolFlag=0;break;
- case 20:lcd12864_write_Main();keyflag=0;FrequencyKeyFlag=0;break;//只按上移下移时还是停留在主菜单
- case 30:lcd12864_write_Main();keyflag=0;FrequencyKeyFlag=0;break;//且不启用调整时间和调整频率时的按键扫描
- case 40:lcd12864_write_Main();keyflag=0;FrequencyKeyFlag=0;break;
- case 11:Clear_GDRAM();lcd12864_write_com(0x36);DrawPicture(VolXY);keyflag=0;FrequencyKeyFlag=0;select=1;ReadVolFlag=1;break;//进入第一项(电压测量)时进行的初始化操作,一般都要清屏在画出相应的菜单,通过赋予select不同值以为后面函数判断进入不同的处理
- case 21:Clear_GDRAM();lcd12864_write_com(0x36);DrawPicture(LM317VolXY);keyflag=0;FrequencyKeyFlag=0;select=6;ReadVolFlag=1;break;//进入第二项(可调输出电压)时的初始化操作
- case 131:lcd12864_write_SignalMenuData();keyflag=0;FrequencyKeyFlag=0;/*select=2;FrequencyFlag=1;FrequencyKeyFlag=1*/;break;//进入第三项(函数输出)时的初始操作,此项下面还有个次级菜单
- case 231:lcd12864_write_SignalMenuData();keyflag=0;FrequencyKeyFlag=0;/*select=2;FrequencyFlag=1;FrequencyKeyFlag=1*/;break;//进入第三项时开启用menu记录选择状态
- case 331:lcd12864_write_SignalMenuData();keyflag=0;FrequencyKeyFlag=0;/*select=2;FrequencyFlag=1;FrequencyKeyFlag=1*/;break;
- case 132:select=2;FrequencyFlag=1;FrequencyKeyFlag=1;keyflag=0;lcd12864_clr();Clear_GDRAM();lcd12864_write_com(0x36);DrawPicture(Coordinate);break;//进入第三项次级菜单,这时要开启频率按键调节按键扫描
- case 232:select=3;FrequencyFlag=1;FrequencyKeyFlag=1;keyflag=0;break;
- case 332:select=4;FrequencyFlag=1;FrequencyKeyFlag=1;keyflag=0;break;
- case 41:/*lcd12864_write_TimeMenuData()*/;select=5;keyflag=1;FrequencyKeyFlag=0;lcd12864_clr();Clear_GDRAM();time=0;break;//进入第四项(时间温度),要开启调节时间按键扫描
-
- default:break;
- }
-
- }
- switch(select)
- {
- case 1: //电压测量
- if(ReadVolFlag==1)
- {
- for(i=0;i<5;i++)//读取5次,以最后一次值为准
- {
- num=read_add(0x41);
-
- }
- Vol=(float) num*5/256*2;//电压转换
- Volvalue[x]=Vol;
- VolDigit=(unsigned char)Vol;//电压整数位
- VolDecimal=(unsigned char)((Vol-VolDigit)*10);//电压小数位
- Voldata[x]=3+(12-VolDigit)*5-(VolDecimal/2);//转换为电压Y坐标存储在数组里
- x++;
- }
-
-
- if(x==85)//坐标内只能显示85个电压值,当显示完85个之后(一个周期完了之后)就需要大小排序,置清除标志位Dot为1
- {
- x=0;
- Dot=1;
- count++;
- if(count==99)
- count=0;
- for(i=0;i<85-1;i++)//冒泡法排序
- {
- for(k=0;k<85-i-1;k++)
- {
- if(Volvalue[k]>Volvalue[k+1])
- {
- Voltemp=Volvalue[k];
- Volvalue[k]=Volvalue[k+1];
- Volvalue[k+1]=Voltemp;
-
- }
- }
- }
- VolMax=Volvalue[84];
- VolMin=Volvalue[0];
- }
- if(Dot)
- DrawDots(11+x+1,Voldata[x],0);//只要第一周期一过就要开始清除上一周期的电压坐标点,12864清GDRAM非常慢,用这种方法清坐标点速度快且得到的坐标线都是连续的很直观
- DrawDots(11+x,Voldata[x-1],1);//,比如说在x=1的位置写入当前电压值坐标就要在x=2的位置清除上一周期的电压值坐标,Voldata[x-1]存储的是当前电压Y坐标,Voldata[x]上一周期x处的电压Y坐标
- sprintf(count1,"T=%02d",(int)count);
- lcd12864_write_string(6,4,count1);//显示周期
- sprintf(VolTemp[0],"%3.2f",Vol);
- lcd12864_write_string(6,1,VolTemp[0]);//显示当前电压
-
- if(Dot)
- {
- sprintf(VolTemp[1],"%3.2f",VolMax);
- lcd12864_write_string(6,2,VolTemp[1]);//显示最大值
-
- sprintf(VolTemp[2],"%3.2f",VolMin);
- lcd12864_write_string(6,3,VolTemp[2]);//显示最小值
- }
-
- break;
- case 6://可调电压
- if(ReadVolFlag==1)
- {
- for(i=0;i<5;i++)//和上面读取电压一样读五次以最后的为准
- {
- num=read_add(0x40);
-
- }
- Vol=(float) num*5/256*2;
- VolDigit=(unsigned char)Vol;
- VolDecimal=(unsigned char)((Vol-VolDigit)*10);
- LM317Vol=VolDigit*10+VolDecimal;//输出的电压值X坐标
- for(i=0;i<15;i++)
- {
- DrawDots(12+LM317Volold,60-i,0);//上次测得的电压坐标清零,
- DrawDots(12+LM317Vol,60-i,1);//显示这次测得的电压
- }
- LM317Volold=LM317Vol;
- sprintf(VolTemp[1],"%3.2fV",Vol);
- lcd12864_write_string(0,1,"输出电压V=");
- lcd12864_write_string(5,1,VolTemp[1]);
- }
- break;
-
- case 2://函数输出
- if(FrequencyFlag==1)
- {
- FrequencyFlag=0;
- ad9850_reset_serial();
- ad9850_wr_serial(0x00,Frequency);
- if((Frequency>=0)&&(Frequency<100))//判断步进值,根据不同步进值来负责w用以后面函数的处理
- w=6;
- if((Frequency>=100)&&(Frequency<1000))
- w=5;
- if((Frequency>=1000)&&(Frequency,10000))
- w=4;
- if((Frequency>=10000)&&(Frequency<100000))
- w=3;
- if((Frequency>=100000)&&(Frequency<1000000))
- w=2;
- if((Frequency>=1000000)&&(Frequency<10000000))
- w=1;
- if(w!=wold)//只有w改变时才画sin函数,根据w的不同更改sin的周期,w改变时还是要清除以前的sin函数
- {
- for(i=6;i-6<128;i++)
- {
- k=6*sin((i-6)*(3.14/(wold*10)))+110;
- DrawDots(i,k,0);
-
- }
- wold=w;
-
- for(i=6;i-6<128;i++)
- {
- k=6*sin((i-6)*(3.14/(w*10)))+110;
- DrawDots(i,k,1);
-
- }
-
-
- }
- switch(FrequencyBit)//显示步进值
- {
-
- case 0:lcd12864_write_string(0,2," ");
- lcd12864_write_string(0,2,"Fre+/-1Hz");break;
- case 1:lcd12864_write_string(0,2," ");
- lcd12864_write_string(0,2,"Fre+/-10Hz");break;
- case 2:lcd12864_write_string(0,2," ");
- lcd12864_write_string(0,2,"Fre+/-100Hz");break;
- case 3:lcd12864_write_string(0,2," ");
- lcd12864_write_string(0,2,"Fre+/-1KHz");break;
- case 4:lcd12864_write_string(0,2," ");
- lcd12864_write_string(0,2,"Fre+/-10KHz");break;
- case 5:lcd12864_write_string(0,2," ");
- lcd12864_write_string(0,2,"Fre+/-100KHz");break;
- case 6:lcd12864_write_string(0,2," ");
- lcd12864_write_string(0,2,"Fre+/-1MHz");break;
- default:break;
- }
-
- if(Frequency<=1000)//显示当前频率Frequency>1000 Frequency<=1000000时显示为KHz
- {
-
- FreDisplay=Frequency;
- sprintf(FreTemp,"Fre=%3.1f Hz",FreDisplay);
- lcd12864_write_string(0,0," ");
- lcd12864_write_string(0,1,FreTemp);
-
-
-
- }
- if((Frequency>1000)&&(Frequency<=1000000))
- {
- FreDisplay=Frequency*0.001;
- sprintf(FreTemp,"Fre=%3.3f KHz",FreDisplay);
- lcd12864_write_string(0,0," ");
- lcd12864_write_string(0,1,FreTemp);
-
-
- }
- if((Frequency>1000000)&&(Frequency<10000000))
- {
- FreDisplay=Frequency*0.000001;
- sprintf(FreTemp,"Fre=%3.3f MHz",FreDisplay);
- lcd12864_write_string(0,0," ");
- lcd12864_write_string(0,1,FreTemp);
-
- }
- }
-
- break;
-
- case 5: //时间温度
-
-
-
- if(s1num!=0)
- {
- color=0x01<<s1num;//根据所按调节时间按键的次数来判断该调那个位置(该调年还是调月等等),color用来将需要调节的位置反白显示
- switch(s1num)//调节时间函数
- {
- case 1:
- time_buf1[1]=14;
- Ds1302_Write_Time();
- break;
- case 2:
- if(time>=12)
- time=0;
- if(time<=0)
- time=12;
- time_buf1[2]=time;
- Ds1302_Write_Time();
- break;
- case 3:
- if(time>=31)
- time=0;
- if(time<=0)
- time=31;
- time_buf1[3]=time;
- Ds1302_Write_Time();
- break;
- case 4:if(time>=8)
- time=0;
- if(time<=0)
- time=7;
- time_buf1[7]=time;
- Ds1302_Write_Time();
- break;
- case 5:if(time>=24)
- time=0;
- if(time<=0)
- time=24;
- time_buf1[4]=time;
- Ds1302_Write_Time();
- break;
- case 6:if(time>=60)
- time=0;
- if(time<=0)
- time=60;
- time_buf1[5]=time;
- Ds1302_Write_Time();
- break;
-
- case 7:
- s1num=0;
- break;
- default:break;
-
- }
- }
-
-
- if(ReadTimeFlag==1)//若读取时间到了就更新时间
- {
- Ds1302_Read_Time();
- ReadTimeFlag=0;
- sec=time_buf1[6];
- DisplayPicture(1,30,(color>>5)-1,num110[time_buf1[4]/10],32,16);//
- DisplayPicture(2,30,(color>>5)-1,num110[time_buf1[4]%10],32,16);
- DisplayPicture(3,30,1,num110[10],32,16);
- DisplayPicture(4,30,(color>>6)-1,num110[time_buf1[5]/10],32,16);
- DisplayPicture(5,30,(color>>6)-1,num110[time_buf1[5]%10],32,16);
-
-
-
- DisplayPicture(1,2,(color>>1)-1,num123[time_buf1[1]],16,16);
- DisplayPicture(2,2,1,year[0],16,16);
- DisplayPicture(3,2,(color>>2)-1,num123[time_buf1[2]],16,16);
- DisplayPicture(4,2,1,year[1],16,16);
- DisplayPicture(5,2,(color>>3)-1,num123[time_buf1[3]],16,16);
- DisplayPicture(6,2,1,year[2],16,16);
- DisplayPicture(1,18,(color>>4)-1,week[time_buf[7]-1],12,48);
- if(sec!=secold)//模拟秒走动函数,只有过来1s才执行
- {
- secold=sec;
- if(sec<=20)//20s之前都在12864第1,2行(也就是y=1,y=2)0-127列(x=0-127)处根据秒的数值画点
- {
- if(sec<=10)//小于10秒时以7格的步进长度画点,若走完一周,就需要开始清除画的点了,根据oe的值判断
- {
- for(i=(sec-1)*7;i<=sec*7;i++)
- {
- DrawDots(i,0,oe);
- DrawDots(i,1,oe);
- }
- }
- if((sec>10)&&(sec<=19))//后9s用6格画点
- {
- for(i=(sec-1)*6+9;i<=sec*6+9;i++)
- {
- DrawDots(i,0,oe);
- DrawDots(i,1,oe);
- }
- }
- if(sec==20)//最后一秒画4格刚好画满
- {
- for(i=124;i<128;i++)
- {
- DrawDots(i,0,oe);
- DrawDots(i,1,oe);
- }
- }
- }
- if((sec>20)&&(sec<=30))//20-30s时在x=126,127,y=0-63的范围内根据秒的值画点,根据oe的值来决定是画点还是清点,
- //oe每一周60s反转一次,就达到了第一个60s沿着12864外圈画点,下一个60s沿着原轨迹清点的效果
- {
- if((sec>20)&&(sec<=25))
- {
- for(i=(sec-1-20)*7;i<=(sec-20)*7;i++)
- {
- DrawDots(126,i,oe);
- DrawDots(127,i,oe);
- }
- }
- if((sec>25)&&(sec<=29))
- {
- for(i=(sec-1-20)*6+6;i<=(sec-20)*6+6;i++)
- {
- DrawDots(126,i,oe);
- DrawDots(127,i,oe);
- }
- }
- if(sec==30)
- {
- for(i=60;i<64;i++)
- {
- DrawDots(126,i,oe);
- DrawDots(127,i,oe);
- }
- }
- }
- if((sec>30)&&(sec<=50))
- {
- if((sec>30)&&(sec<=40))
- {
- for(i=(sec-30-1)*7;i<=(sec-30)*7;i++)
- {
- DrawDots(127-i,62,oe);
- DrawDots(127-i,63,oe);
- }
- }
- if((sec>40)&&(sec<=49))
- {
- DrawDots(60,62,oe);
- for(i=(sec-30-1)*6+9;i<=(sec-30)*6+9;i++)
- {
-
- DrawDots(127-i,62,oe);
- DrawDots(127-i,63,oe);
- }
- }
- if(sec==50)
- {
- for(i=0;i<4;i++)
- {
- DrawDots(i,62,oe);
- DrawDots(i,63,oe);
- }
- }
-
- }
- if((sec>50)&&(sec<=59))
- {
- for(i=(sec-50-1)*7;i<(sec-50)*7;i++)
- {
- DrawDots(0,63-i,oe);
- DrawDots(1,63-i,oe);
- }
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
12864综合程序.rar
(2.26 MB, 下载次数: 572)
|