|
本帖最后由 destiny_xl 于 2018-6-2 13:49 编辑
AD采样显示(TLC549+LCD12864)
大家好,第一次发帖,本来准备早点发的,但是有个程序bug调了几天都没有解决,因为快毕业啦,手头许多硬件都卖啦。然后无意间在51黑电子论坛看到个带字库的LCD12864,有点感兴趣,顺便用了一款8位的串行接口采用逐次逼近型的A/D转换器TLC549,合在一起做了一个AD实时采样电压并用LCD12864显示的电路,整体图如下图所示,因为缩放的太小啦,LCD12864的字符无法显示,无奈屏幕不够大,讲究看下把。
图1 TLC549进行AD转换用LCD12864显示
下面我简单地来介绍一下,代码部分注释的也比较详细,我只简单地说下原理,具体的还得看datesheet搞懂原理和时序,编写程序才能得心应手。因为时间关系,很多代码也是基于别人基础上改的,我主要解决的问题是让LCD12864能显示数字。大家可能觉得很奇怪,LCD12864本来就可以显示数字啊,但是有时候手头没硬件,又急需测试下自己的LCD12864能否正常工作,proteus没有找到带字库的LCD12864。但是论坛有个人分享了一个LCD12864的库,我按照他的方法真的可以实现在proteus仿真LCD12864,具体操作方法请看帖子:使用proteus中12864液晶再也不用担心没有字库了?,我在这里就不详述了。
大家也像我迫不及待的装好LCD12864的库之后,发现不能显示数字、英文符号和英文标点,同时测试的时候发现,有些复杂的汉字也无法显示。毕竟字符种类太多,也没有办法全部一一封装进去。意外发现有个数字带圈的特殊字符可以显示,然后就到网上收集,发现可以完全支持我的实验需要的字符,分享给大家◎①②③④⑤⑥⑦⑧⑨⊙Ⅴ,值得一题的是,Ⅴ是中文的数字5,不是英文的V,前者是汉字2个字符,后者是英文1个字符。
图2 显示字符
东西都齐啦,就开始编写程序啦,C语言也很久没学啦,对于字符的处理费了很大一部分时间,不过终于写好了,就是程序中的字符转换函数 bitchange,这个函数的功能主要是将英文的字符转换成带圈的中文字符,原理就是把一个字节的字符转换成2个字符,具体的大家分析下程序就可以看 懂,利用了一个strcpy复制函数,包含在string.h的头文件中。
程序的大致流程是首先我们通过AD采样,将采样的数据进行简单的补偿后储存,然后调用LCD12864显示模块进行显示。期间一直有个问题,调了几天还是没有解决,开始都是分开调的,后面发现联调的时候这个bug又消失啦,所以大家还是有硬件的最好测试喜爱,顺便告诉下我。TLC549的处理模块,比较简单,按照时序进行移位储存即可,bug的原因出现在LCD12864中,就是我加上Ⅴ字符后程序显示有问题,去掉这个字符显示一切正常,问题的截图和去掉当我把b[n]=zf[22];和b[n+1]=zf[23];两条语句去掉后的结果如下图所示。
图3 显示异常结果
图4 去掉Ⅴ之后的显示结果
我初步估计可能有两个原因,一是我的字符转换函数bitchange有问题,但是我VC6.0编译通过才拿来用的,可能还是有什么隐藏的bug;二是那个LCD12864的bug,希望和大家一起讨论,共同进步,教程就到这里,代码如下。
- #include <reg51.h>
- #include <stdio.h> //sprintf函数包含库
- #include <intrins.h>
- #include <string.h> //strcpy函数包含库
- #define uchar unsigned char
- #define uint unsigned int
- #define LCD_data P0 //数据口
- #define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
- //LCD型号:TS12864A-3(带汉字库) 控制器ST7920
- sbit LCD_RS = P2^0; //寄存器选择输入
- sbit LCD_RW = P2^1; //液晶读/写控制
- sbit LCD_EN = P2^2; //液晶使能控制
- sbit LCD_PSB= P2^3; //串/并方式控制
- //TLC549端口定义
- sbit DIO=P3^5; //数据线
- sbit CS=P3^6; //片选
- sbit CLK=P3^4; //io口时钟
- //proteus的带字库LCD12864不支持数字、英文符号和英文标点
- //显示字符:◎①②③④⑤⑥⑦⑧⑨⊙Ⅴ
- uchar code dis1[]="电压值:";
- uchar code zf[]="◎①②③④⑤⑥⑦⑧⑨⊙Ⅴ";
- uchar a[14]; //直接给数组a赋值,会出现V.34V,就是第一个字符被吞并,没实物测试,不知道原因,希望有硬件的帮忙测试下^_^
- void bitchange(uchar c[]) //字符转换函数
- {
- uchar i,m=0,n=0,b[14];
- for(i=0;c[i]!='\0';i++,n+=2)
- {
- if(c[i]!='.')
- {
- m=c[i]-48;
- b[n]=zf[m*2];
- b[n+1]=zf[m*2+1];
- }
- else
- {
- b[n]=zf[20];
- b[n+1]=zf[21];
- }
- }
- b[n]=zf[22];
- b[n+1]=zf[23];
- b[n+2]='\0';
- strcpy(c,b);
- }
- void delay(int ms) //延时函数
- {
- while(ms--)
- {
- uchar i;
- for(i=0;i<250;i++)
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
- }
- }
- bit lcd_busy() //检查LCD忙状态,lcd_busy为1时,忙,等待;lcd-busy为0时,闲,可写指令与数据。
- {
- bit result;
- LCD_RS=0;
- LCD_RW=1;
- LCD_EN=1;
- delayNOP();
- result=(bit)(P0&0x80); //强制取最高位P0.7的状态
- LCD_EN=0;
- return(result);
- }
- void lcd_wcmd(uchar cmd) //写指令数据到LCD,RS=L,RW=L,E=高脉冲,D0-D7=指令码。
- {
- while(lcd_busy());
- LCD_RS=0;
- LCD_RW=0;
- LCD_EN=0;
- _nop_();
- _nop_();
- P0=cmd;
- delayNOP();
- LCD_EN=1;
- delayNOP();
- LCD_EN=0;
- }
-
- void lcd_wdat(uchar dat) //写显示数据到LCD,RS=H,RW=L,E=高脉冲,D0-D7=数据。
- {
- while(lcd_busy());
- LCD_RS=1;
- LCD_RW=0;
- LCD_EN=0;
- P0=dat;
- delayNOP();
- LCD_EN=1;
- delayNOP();
- LCD_EN=0;
- }
- void lcd_pos(uchar X,uchar Y) //设定显示位置
- {
- uchar pos;
- if (X==0)
- {X=0x80;}
- else if (X==1)
- {X=0x90;}
- else if (X==2)
- {X=0x88;}
- else if (X==3)
- {X=0x98;}
- pos=X+Y ;
- lcd_wcmd(pos); //显示地址
- }
-
- void lcd_init() //LCD初始化设定
- {
- LCD_PSB=1; //并口方式
- lcd_wcmd(0x30); //基本指令操作
- delay(5);
- lcd_wcmd(0x0C); //显示开,关光标
- delay(5);
- lcd_wcmd(0x01); //清除LCD的显示内容
- delay(5);
- }
- uint TLC549_AD() //TLC549处理
- {
- uchar i;
- uint data_ad=0;
- CS=1; //初始化,启动
- CLK=0;
- DIO=1;
- CS=0;
- _nop_();
- for(i=0;i<8;i++) //读取采集数据,读取的是上一次采集数据
- {
- CLK=1;
- if(DIO)data_ad|=0x01;
- CLK=0;
- data_ad<<=1;
- }
- CS=1;
- data_ad=data_ad*(500/256)+0.5; //0.5V进行四舍五入补偿
- return(data_ad);
- }
- void main()
- {
- uchar i;
- float AD_convert;
- uchar AD1=35;
- delay(10); //延时
- lcd_init(); //初始化LCD
- while(1)
- {
- AD_convert=TLC549_AD()/100.0;
- sprintf(a, "%.2f", AD_convert); //将转换结果转换成字符
- i=0;
- lcd_pos(1,0); //设置显示位置为第一行的第1个字符
- while(dis1[i] != '\0')
- { //显示“电压值:”
- lcd_wdat(dis1[i]);
- i++;
- }
- i=0;
- lcd_pos(2,3); //设置显示位置为第二行的第3个字符
- bitchange(a);
- while(a[i] != '\0')
- { //显示采集的电压值
- lcd_wdat(a[i]);
- i++;
- }
- }
- }
复制代码来张成功的图片,老脸一红。
图5 显示结果
还有压缩包的内容,有写好的程序和仿真,还有把LCD12864的程序分割出来啦,bug就出现啦。
图6 程序与仿真
|
评分
-
查看全部评分
|