|
本帖最后由 destiny_xl 于 2018-6-2 13:49 編輯
AD采樣顯示(TLC549+LCD12864)
大家好,第一次發帖,本來準備早點發的,但是有個程序bug調了幾天都沒有解決,因為快畢業啦,手頭許多硬件都賣啦。然后無意間在51黑電子論壇看到個帶字庫的LCD12864,有點感興趣,順便用了一款8位的串行接口采用逐次逼近型的A/D轉換器TLC549,合在一起做了一個AD實時采樣電壓并用LCD12864顯示的電路 ,整體圖如下圖所示,因為縮放的太小啦,LCD12864的字符無法顯示,無奈屏幕不夠大 ,講究看下把。
TLC549進行AD轉換用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 程序與仿真
|
評分
-
查看全部評分
|