找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8114|回复: 10
打印 上一主题 下一主题
收起左侧

单片机+TLC549 AD采样LCD12864显示的仿真与程序源码

[复制链接]
跳转到指定楼层
楼主
本帖最后由 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,希望和大家一起讨论,共同进步,教程就到这里,代码如下

  1. #include <reg51.h>
  2. #include <stdio.h> //sprintf函数包含库
  3. #include <intrins.h>
  4. #include <string.h> //strcpy函数包含库
  5. #define uchar unsigned char
  6. #define uint  unsigned int
  7. #define LCD_data  P0             //数据口
  8. #define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};

  9. //LCD型号:TS12864A-3(带汉字库) 控制器ST7920
  10. sbit LCD_RS = P2^0; //寄存器选择输入
  11. sbit LCD_RW = P2^1; //液晶读/写控制
  12. sbit LCD_EN = P2^2; //液晶使能控制
  13. sbit LCD_PSB= P2^3; //串/并方式控制

  14. //TLC549端口定义
  15. sbit DIO=P3^5; //数据线
  16. sbit CS=P3^6;        //片选
  17. sbit CLK=P3^4; //io口时钟

  18. //proteus的带字库LCD12864不支持数字、英文符号和英文标点
  19. //显示字符:◎①②③④⑤⑥⑦⑧⑨⊙Ⅴ
  20. uchar code dis1[]="电压值:";
  21. uchar code zf[]="◎①②③④⑤⑥⑦⑧⑨⊙Ⅴ";
  22. uchar a[14]; //直接给数组a赋值,会出现V.34V,就是第一个字符被吞并,没实物测试,不知道原因,希望有硬件的帮忙测试下^_^

  23. void bitchange(uchar c[]) //字符转换函数
  24. {
  25.         uchar i,m=0,n=0,b[14];
  26.         for(i=0;c[i]!='\0';i++,n+=2)
  27.         {
  28.                 if(c[i]!='.')
  29.                 {
  30.                         m=c[i]-48;
  31.                         b[n]=zf[m*2];
  32.                         b[n+1]=zf[m*2+1];
  33.                 }
  34.                 else
  35.                 {
  36.                         b[n]=zf[20];
  37.                         b[n+1]=zf[21];
  38.                 }
  39.         }
  40.         b[n]=zf[22];
  41.         b[n+1]=zf[23];
  42.         b[n+2]='\0';
  43.         strcpy(c,b);
  44. }

  45. void delay(int ms) //延时函数
  46. {
  47.     while(ms--)
  48.         {
  49.       uchar i;
  50.           for(i=0;i<250;i++)  
  51.            {
  52.                         _nop_();                           
  53.                         _nop_();
  54.                         _nop_();
  55.                         _nop_();
  56.            }
  57.         }
  58. }               

  59. bit lcd_busy() //检查LCD忙状态,lcd_busy为1时,忙,等待;lcd-busy为0时,闲,可写指令与数据。
  60. {                          
  61.     bit result;
  62.     LCD_RS=0;
  63.     LCD_RW=1;
  64.     LCD_EN=1;
  65.     delayNOP();
  66.     result=(bit)(P0&0x80); //强制取最高位P0.7的状态
  67.     LCD_EN=0;
  68.     return(result);
  69. }

  70. void lcd_wcmd(uchar cmd) //写指令数据到LCD,RS=L,RW=L,E=高脉冲,D0-D7=指令码。
  71. {                          
  72.    while(lcd_busy());
  73.     LCD_RS=0;
  74.     LCD_RW=0;
  75.     LCD_EN=0;
  76.     _nop_();
  77.     _nop_();
  78.     P0=cmd;
  79.     delayNOP();
  80.     LCD_EN=1;
  81.     delayNOP();
  82.     LCD_EN=0;  
  83. }

  84. void lcd_wdat(uchar dat) //写显示数据到LCD,RS=H,RW=L,E=高脉冲,D0-D7=数据。
  85. {                          
  86.    while(lcd_busy());
  87.     LCD_RS=1;
  88.     LCD_RW=0;
  89.     LCD_EN=0;
  90.     P0=dat;
  91.     delayNOP();
  92.     LCD_EN=1;
  93.     delayNOP();
  94.     LCD_EN=0;
  95. }

  96. void lcd_pos(uchar X,uchar Y) //设定显示位置
  97. {                          
  98.    uchar  pos;
  99.    if (X==0)
  100.      {X=0x80;}
  101.    else if (X==1)
  102.      {X=0x90;}
  103.    else if (X==2)
  104.      {X=0x88;}
  105.    else if (X==3)
  106.      {X=0x98;}
  107.    pos=X+Y ;  
  108.    lcd_wcmd(pos); //显示地址
  109. }

  110. void lcd_init() //LCD初始化设定
  111. {

  112.     LCD_PSB=1; //并口方式
  113.     lcd_wcmd(0x30); //基本指令操作
  114.     delay(5);
  115.     lcd_wcmd(0x0C); //显示开,关光标
  116.     delay(5);
  117.     lcd_wcmd(0x01); //清除LCD的显示内容
  118.     delay(5);
  119. }

  120. uint TLC549_AD() //TLC549处理
  121. {
  122.         uchar i;
  123.         uint data_ad=0;
  124.         CS=1; //初始化,启动
  125.         CLK=0;
  126.         DIO=1;
  127.         CS=0;
  128.         _nop_();                    
  129.         for(i=0;i<8;i++) //读取采集数据,读取的是上一次采集数据
  130.         {
  131.                 CLK=1;         
  132.                 if(DIO)data_ad|=0x01;
  133.                 CLK=0;  
  134.                 data_ad<<=1;  
  135.         }         
  136.         CS=1;
  137.         data_ad=data_ad*(500/256)+0.5; //0.5V进行四舍五入补偿
  138.         return(data_ad);
  139. }

  140. void main()
  141. {
  142.     uchar i;
  143.         float AD_convert;
  144.         uchar AD1=35;
  145.     delay(10); //延时
  146.     lcd_init(); //初始化LCD      
  147.         while(1)
  148.         {
  149.             AD_convert=TLC549_AD()/100.0;
  150.         sprintf(a, "%.2f", AD_convert); //将转换结果转换成字符
  151.         i=0;
  152.             lcd_pos(1,0);             //设置显示位置为第一行的第1个字符
  153.             while(dis1[i] != '\0')
  154.              {                         //显示“电压值:”
  155.                lcd_wdat(dis1[i]);
  156.                i++;
  157.              }
  158.                 i=0;
  159.             lcd_pos(2,3);             //设置显示位置为第二行的第3个字符
  160.                 bitchange(a);
  161.             while(a[i] != '\0')
  162.              {                         //显示采集的电压值
  163.                lcd_wdat(a[i]);
  164.                    i++;
  165.              }
  166.          }   
  167. }

复制代码

来张成功的图片,老脸一红。



图5 显示结果


还有压缩包的内容,有写好的程序和仿真,还有把LCD12864的程序分割出来啦,bug就出现啦



图6 程序与仿真






AD采样显示(TLC549+LCD12864).zip

443.56 KB, 下载次数: 133, 下载积分: 黑币 -5

全部代码和程序

评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:305196 发表于 2018-5-4 09:44 | 只看该作者
哎呀,格式一直用不好,出现各种问题,感觉好无奈。
回复

使用道具 举报

板凳
ID:1 发表于 2018-5-4 16:48 | 只看该作者
destiny_xl 发表于 2018-5-4 09:44
哎呀,格式一直用不好,出现各种问题,感觉好无奈。

格式还可以,资料也不错 谢谢分享,编辑一下,有一个未使用附件 使用即可
回复

使用道具 举报

地板
ID:305196 发表于 2018-5-5 20:12 | 只看该作者
admin 发表于 2018-5-4 16:48
格式还可以,资料也不错 谢谢分享,编辑一下,有一个未使用附件 使用即可

我是准备上传附件的,但是点了上传不了,在试试
回复

使用道具 举报

5#
ID:305196 发表于 2018-10-23 10:36 | 只看该作者
真是巧,最近要用LCD12864,原来12864还有多种规格啊,这个12864-S自带对比度调节,不用焊接电位器了,还有并串口模式,今天检测了下以前写的一个程序,发现是同样的问题, 开始以为是proteus中12864库的问题,最后检查程序发现,是while一直循环有问题,改成放到最后while(1); 就可以啦,仿真和实物都可以通过。


回复

使用道具 举报

6#
ID:76408 发表于 2019-3-13 09:10 | 只看该作者
谢谢楼主,收藏了。
回复

使用道具 举报

7#
ID:408974 发表于 2019-3-17 11:47 | 只看该作者
在仿真软件中没有自带的LCD12864要自己去下载吗?
回复

使用道具 举报

8#
ID:408974 发表于 2019-3-17 11:48 | 只看该作者
成森林 发表于 2019-3-13 09:10
谢谢楼主,收藏了。

ISIS仿真软件中没有自带的LCD12864怎么办,下载这个文件打开说没有LCD12864这个中文字库
回复

使用道具 举报

9#
ID:408974 发表于 2019-3-17 12:15 | 只看该作者
在ISIS仿真软件中没有LCD12864怎么办
回复

使用道具 举报

10#
ID:512403 发表于 2019-4-23 20:46 | 只看该作者
怎么显示不一样
回复

使用道具 举报

11#
ID:964308 发表于 2021-10-17 15:34 来自手机 | 只看该作者
gongzuoshi 发表于 2019-3-17 11:48
ISIS仿真软件中没有自带的LCD12864怎么办,下载这个文件打开说没有LCD12864这个中文字库

百度应该能找到
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表