關(guān)鍵字:LCD12864 數(shù)字示波器
本文針對LCD12864 特性,完成了數(shù)字示波器顯示必須的繪圖驅(qū)動程序設(shè)計,,這個教程定位給初學者使用,,我立足從簡單到復雜一步一步介紹設(shè)計過程,,甚至是調(diào)試的過程,還包括一些經(jīng)驗總結(jié),,特別是提供了完整的keil 工程附件,。希望讀者立足示波器項目,學到更多軟硬件設(shè)計經(jīng)驗技巧,。
一,、簡易數(shù)字示波器原理
數(shù)字示波器基本原理可以簡單理解為:數(shù)據(jù)采集+ 圖形顯示,該過程循環(huán)進行,,如圖1 所示,。
圖1 簡易數(shù)字示波器流程圖
LCD 圖形顯示需要根據(jù)LCD 特性設(shè)計,不同LCD驅(qū)動程序不同,,本篇將結(jié)合不帶字庫的LCD12864 設(shè)計顯示程序,。
二、圖形液晶LCD12864繪圖驅(qū)動設(shè)計基礎(chǔ)
關(guān)于LCD 的硬件接口電路,,在其他教程中有詳細介紹,,涉及單片機總線知識和CPLD 內(nèi)部電路,需要認真學習,這里借助現(xiàn)成的驅(qū)動函數(shù),,重點講解LCD繪圖程序設(shè)計,。
LCD12864 的電路接口在頭文件中定義:
#define LCD_LCW XBYTE[0xf4ea]
// 左屏命令寫入
#define LCD_LDW XBYTE[0xf5ea]
// 左屏數(shù)據(jù)寫入
#define LCD_LCR XBYTE[0xf6ea]
// 左屏命令讀出
#define LCD_LDR XBYTE[0xf7ea]
// 左屏數(shù)據(jù)讀出
#define LCD_RCW XBYTE[0xf8ea]
// 右屏命令寫入
#define LCD_RDW XBYTE[0xf9ea]
// 右屏數(shù)據(jù)寫入
#define LCD_RCR XBYTE[0xfaea]
// 右屏命令讀出
#define LCD_RDR XBYTE[0xfbea]
// 右屏數(shù)據(jù)讀出
后面所有對LCD 的編程操作都是基于以上接口定義進行的各種讀寫操作。
首先來看LCD12864 的點陣結(jié)構(gòu)圖,,如圖2 所示,。
圖2 LCD點陣分布結(jié)構(gòu)圖
此LCD 屏由水平128 列,垂直64 行組成,。水平128 列分左右各64 列兩個半屏構(gòu)成,。垂直64 行又分8 頁,每頁8 行(1 列8 點剛好1 字節(jié)),。程序每次對LCD 的繪圖操作就是以最小單位1 字節(jié)進行操作的,。
理解這點至關(guān)重要。也就是每次只能針對8 點進行操作,,而不是1 點進行操作,。左右屏由單獨地址線控制(前面的接口定義就是分左右屏定義的)。實際打點只需往指定“位置”寫入數(shù)據(jù),,“1”亮,,“0”暗。
LCD 驅(qū)動忙檢測函數(shù)void loop_lcd12864_is_busy(unsigned char right),。
void loop_lcd12864_is_busy(unsigned char right)
{
unsigned char tmp,counter=0;
do {
if(right) tmp = LCD_RCR;
else tmp = LCD_LCR;
if(counter++>50) break; // 超時跳出
}
while ((tmp|0x7f)==0xff); //bit7 為1 則表示LCD 內(nèi)部執(zhí)行命令,,處于“忙”狀態(tài)
}
對LCD 進行讀寫操作時,,需要進行“忙”檢測,LCD 內(nèi)部也是由控制器來完成一系列刷屏操作的,,執(zhí)行各種操作都是需要一定的時間,,也就是說不是任何時候外部控制器都可以對LCD 發(fā)操作指令的,只有LCD為空閑狀態(tài)時才可以操作,,忙檢測就是循環(huán)讀取LCD狀態(tài)標志位,,判斷是否空閑,關(guān)于命令的細節(jié)請參考數(shù)據(jù)手冊,。
命令寫入函數(shù)void lcd_cmd_wr(unsigned char cmd,right),。
void lcd_cmd_wr(unsigned char cmd, right)
{
loop_lcd12864_is_busy(right); // 忙檢測
if(right) LCD_RCW = cmd; // 右屏命令寫入
else LCD_LCW = cmd; // 左屏命令寫入
}
數(shù)據(jù)寫入函數(shù)void lcd_dat_wr(unsigned char data,right),。
void lcd_dat_wr(unsigned char data,right)
{
loop_lcd12864_is_busy(right),;
if(right) LCD_RDW = data;
else LCD_LDW = data;
}
lcd_cmd_wr() 和lcd_dat_wr() 兩個函數(shù)分別是給LCD 寫命令和寫數(shù)據(jù)函數(shù),通過寫命令函數(shù)設(shè)定地址,。每個函數(shù)都分左右屏,,“right”參數(shù)選擇,“0”選左屏,“非0”選右屏,。
讀數(shù)據(jù)函數(shù)unsigned char lcd_dat_rd(unsigned char right),。
unsigned char lcd_dat_rd(unsigned char right)
{
loop_lcd12864_is_busy(right);
if(right) return(LCD_RDR),;
else retuen(LCD_LDR),;
}
該函數(shù)可以讀出LCD 當前顯示的數(shù)據(jù),首次操作需要讀2次才有效,。
LCD 清屏函數(shù)void lcd12864_clr(void),。
void lcd12864_clr(void)
{
unsigned char i,j;
for(i=0;i<8;i++) { // 從0 到7 共8 頁
lcd_cmd_wr(ORGX,0); // 分頁設(shè)定左屏0 點地址
lcd_cmd_wr(ORGY+i,0),;
lcd_cmd_wr(ORGX,1),; // 分頁設(shè)定右屏0 點地址
lcd_cmd_wr(ORGY+i,1);
for(j=0;j<64;j++) {
lcd_data_wr(0,0),;
lcd_data_wr(0,1),;
}
}
}
該函數(shù)對LCD 所有點陣寫0,完成一次清屏操作,。這里的ORGY,,PRGX 是設(shè)定光標的命令,光標指向(0,0)字節(jié),,是一個固定值,。實際在執(zhí)行數(shù)據(jù)寫入的時,x 坐標范圍從0 到63,,在連續(xù)寫入過程中能夠?qū)崿F(xiàn)自動加1,,y 軸頁地址范圍從0 到7,需要逐頁設(shè)定,。
LCD 初始化函數(shù)void lcd12864_init(void),。
void lcd12864_init(void)
{
lcd_cmd_wr(DISPON,0); // 顯示開啟
lcd_cmd_wr(DISPFIRST,0),; // 設(shè)定顯示首行地址,,修改首行地址可以實現(xiàn)屏幕滾動顯示效果
lcd_cmd_wr(ORGY,0); // 設(shè)定初始光標
lcd_cmd_wr(ORGX,0),;
lcd_cmd_wr(DISPON,1),; // 初始另外一半
lcd_cmd_wr(DISPFIRST,1);
lcd_cmd_wr(ORGY,1),;
lcd_cmd_wr(ORG,1),;
lcd12864_clr(); // 執(zhí)行清屏,,非必須操作
}
該函數(shù)用來初始化LCD,,設(shè)置顯示模式,光標位置等,在對LCD 繪圖時,,最多的命令就是設(shè)定當前光標位置,,通過光標位置來指定將要操作的LCD 顯示點。
在對LCD 編程操作以前,,一定要執(zhí)行此函數(shù)對LCD 進行初始化操作,。
從驅(qū)動函數(shù)可見,一次對LCD 寫入數(shù)據(jù)是以字節(jié)為單位,,通過寫命令設(shè)定坐標,,y 坐標從0 頁到7 頁,x 坐標從0 列到63 列,,分左右屏,,左上角為坐標(0,0)點,,這和我們習慣的左下角為(0,,0)坐標軸是不一樣的。
因為每次操作LCD 是一個字節(jié)為單位,,對應(yīng)8 點,,如果我們希望以任意點為坐標顯示,還得另外尋找別的辦法編程實現(xiàn)真正“點”顯示,。
如圖3 所示,,在屏幕上指定位置畫點,水平軸就是x,,與LCD 坐標一致,,垂直軸需要將點坐標變成字節(jié)為單位的坐標,我們先按習慣將y 軸64 點從下至上編號0 到63,,其中0 到7 點為字節(jié)0,8 到15 點為字節(jié)1,,依此類推對應(yīng)8 字節(jié),。
圖3 LCD“點”顯示示例
第一點y 軸為30,應(yīng)該對應(yīng)垂直哪個字節(jié)的哪個比特呢,?
實際30 點應(yīng)該在第4 字節(jié)(24 到31)的Bit 6 上,,拿30/8 取整為3,剛好是應(yīng)該跳過的前3 字節(jié)(對應(yīng)0 到23),,那么30%8(30 除8 取余數(shù))呢,,余數(shù)是6,不是剛好是Bit 位嗎,?所以可以這樣將y 值映射到某字節(jié)的某點上,,如果y 軸64 點對應(yīng)8 字節(jié)變量Da[n],n從0 到7,則:
da[y/8] = 1 《 (y%8),;或da[y》3]=0x01《(y&0x07),;后一種算法更優(yōu)。
關(guān)鍵字:LCD12864 數(shù)字示波器
通過總結(jié)規(guī)律,,用以上算法可以將任意0 到63 之間的數(shù)據(jù)作為坐標描點到對應(yīng)的8 個字節(jié)中,,然后將8個字節(jié)全部寫入LCD,則通過剛才算法就會有一點與所給坐標一致,。
第一點:da[30/8] = 1 《 30%8; 即da[3] = 0x40;
第二點:da[10/8] = 1 《10%8; 即da[1] = 0x04;
首先給出列顯示子函數(shù),,在任意列顯示y 值對應(yīng)點。
{
unsigned char j;
if(x<64) { // 根據(jù)列坐標選擇左右半屏
for(j=0;j<8;j++) { // 寫左半屏
lcd_cmd_wr(ORGY+j,0),;
lcd_cmd_wr(ORGX+x,0),;
lcd_data_wr(da[j],0);
}
}
else {
x-=64;// 坐標調(diào)整
for(j=0;j<8;j++) { // 寫右半屏
lcd_cmd_wr(ORGY+j,1),;
lcd_cmd_wr(ORGX+x,1),;
lcd_data_wr(da[j],1);
}
}
}
有了列顯示函數(shù),,LCD 任何坐標位置上描點繪圖函數(shù)為:
void lcd_disp(unsigned char x,y) //x 水平坐標,,y 垂直坐標
{
unsigned char dat[8];
unsigned char j;
y=63-y;// 使xy 坐標符合習慣
for(j=0;j<8;j++) dat[j] = 0x0;
dat[y/8] |= 0x01《(y&0x07);
lcd_row_wr(x,dat),;
}
以上函數(shù)能夠在指定坐標(x,,y)上描點,下面嘗試將ADC 的值采集后送LCD 顯示,。再按時間軸x 軸順序?qū)⒉煌瑫r刻采集到的y 值順序?qū)懭隠CD,,這是我們就可以在LCD 上看到隨時間變化的電壓曲線了。主程序為:
void main()
{
unsigned char i;
lcd12864_init(),;
for(i=0;i<128;i++) {
lcd_disp(i,read_adc(0)/16),;// 從10bit 映射到6bit,要除16
}
while(1),;
}
調(diào)整輸入給ADC 的信號頻率,,可以得到滿意的波形圖了,效果如圖4 所示,。
圖4 LCD實時顯示ADC圖
如果你成功做到了這一步,,可喜可賀,已經(jīng)掌握了繪圖基礎(chǔ)了,,不過程序還要繼續(xù)完善,。
三、圖形液晶LCD12864繪圖驅(qū)動設(shè)計提高
如何在現(xiàn)實波形顯示的基礎(chǔ)上,,同時將定標網(wǎng)格也顯示出來呢,?
首先我們看一種C 語法“A = 0x05; A |= 0x50;”運行以上指令后,,A = 0x55 ;也可以說第二個數(shù)據(jù)0x50 是疊加到第一個數(shù)據(jù)上的,,我們可以用這種算法把需要顯示的亮點(也就是“1”)按一定的算法疊加在一起,,送LCD 顯示,就出現(xiàn)了我們希望的在波形上增加背景網(wǎng)格的效果,。
因為網(wǎng)格與水平x 軸是嚴格關(guān)聯(lián)的,,所以我們可以對x 軸數(shù)據(jù)進行判斷,有規(guī)律的將邊框和背景格點加入,。
改進帶背景格的lcd_disp() 函數(shù),。
void lcd_disp(unsigned char x,unsigned char y)
{
unsigned char da[8];
unsigned char j;
y = 63-y;
for(j=1;j<7;j++) da[j] = 0x0;
da[0]=0x01;
da[7]=0x80;
if(x%5==0) {
da[21/8] |= 0x01《(21%8);
da[42/8] |= 0x01《(42%8),;
}
if((x==0)||(x==127)) {// 加兩端邊框
for(j=0;j<8;j++) da[j] = 0xff;
}
da[y/8] |= 0x01《(y%8),;
lcd_row_wr(x,da);
}
效果如圖5 所示,。
圖5 帶網(wǎng)格的LCD顯示圖
四,、圖形液晶LCD12864移動游標線繪圖驅(qū)動設(shè)計
聲明控制水平線的變量“unsigned charpointY=0;” 范圍0 到63, 聲明控制垂直線的變量“unsigned char pointX=0;”范圍0 到127,。
void lcd_disp(unsigned char x,unsigned char y)
{
unsigned char da[8];
unsigned char j;
y = 63-y;
for(j=1;j<7;j++) da[j] = 0x0;
{// 繪制邊框
da[0]=0x01;
da[7]=0x80;
if((x==0)||(x==127)) {
for(j=0;j<8;j++) da[j] = 0xff;
}
}
if(x%5==0) da[pointY>>3] |= 0x01 《 (pointY&0x07),;
// 繪制由變量pointY 控制的水平游標線
if(x==pointX) // 繪制由變量pointX 控制的垂直游標線
for(j=0;j<64;j++)
if(j%5==0) da[j>>3] |= 0x01 《(j&0x07);
da[y/8] |= 0x01《(y%8),; // 繪制信號波形
lcd_row_wr(x,da),;
}
運行效果如圖6 所示。
圖6 水平垂直移動游標線示例
五,、圖形液晶LCD12864數(shù)字符號顯示
圖形點陣LCD 顯示數(shù)字,,原理是把數(shù)字以點陣的形式取模,再把點陣模寫入特定的LCD 空間即可,,首先來看數(shù)字取模,,如圖7 所示,對數(shù)字“0”按8×5點取模,。
圖7 數(shù)字取模示例圖
縱向看,,8 點一列,從上至下對應(yīng)bit0 到bit7,,我們用1 表示“亮”,0 表示“暗”,,從左至右,,依次確定為0111 1100,即0x7c ,;1000 0010,,即0x82 ,;10000010, 即0x82 ,;1000 0010,, 即0x82 ;0111 1100,,即0x7c ,;如果我們依次將這5 個字節(jié)寫入LCD 某頁連續(xù)5個地址空間,LCD 上就會顯示“0”,。
下面我們把數(shù)字變量在LCD 上動態(tài)顯示,,就是數(shù)值變了,顯示跟著變,。
字符顯示LCD 驅(qū)動函數(shù),,實現(xiàn)8×n 點陣字符寫入函數(shù)。
void lcd_put_xyns(unsigned char x,y,n,unsigned char *s)
{
unsigned char i;
for(i=0;i
if((x+i)>63) {
lcd_cmd_wr(ORGY+y,1),;
lcd_cmd_wr(ORGX+x+i-64,1),;
lcd_dat_wr(s[i],1);
}
else {
lcd_cmd_wr(ORGY+y,0),;
lcd_cmd_wr(ORGX+x+i,0),;
lcd_dat_wr(s[i],0);
}
}
}
參數(shù):“x, y”是坐標,,這里y 是頁坐標,,取值從0 到7,“n”是點陣模字節(jié)數(shù),,“*s”是點陣模起始地址,。
將字模生成字模表:
unsigned char code number[]={
0x7C,0x82,0x82,0x7C,0x84,0xFE,0x80,0x00,0xCC,0xA2,0x
92,0x8C,0x44,0x92,0x92,0x6C,
0x38,0x24,0xFE,0x20,0x9E,0x92,0x92,0x62,0x7C,0x92,0x9
2,0x64,0x06,0xF2,0x0E,0x02,
0x6C,0x92,0x92,0x6C,0x4C,0x92,0x92,0x7C,0x80,
};
lcd_put_xyns(0,0,4,number+0*4); // 直接顯示字符0
lcd_put_xyns(4,0,4,number+1*4),; // 直接顯示字符1
……
tmp=3421; // 以下代碼顯示變量tmp
lcd_put_xyns(80,2,4,number+(tmp/1000)*4),;
lcd_put_xyns(84,2,4,number+(tmp/100%10)*4);
lcd_put_xyns(88,2,4,number+(tmp/10%10)*4),;
lcd_put_xyns(92,2,4,number+(tmp%10)*4),;
關(guān)鍵字:LCD12864 數(shù)字示波器
運行效果如圖8 所示。
圖8 LCD顯示數(shù)字圖
基于以上原理,,我們還可以將其他字符取模顯示,。
最終完成的效果如圖9 所示。
圖9 完整示波器效果圖
六,、數(shù)字示波器幾個參數(shù)
1. 數(shù)據(jù)采樣率與時間軸定標
數(shù)據(jù)采樣率也就是每秒鐘連續(xù)采集到的數(shù)據(jù)個數(shù),,或者說兩個有效數(shù)據(jù)之間的時間間隔。為了在LCD 上還原波形圖,,時間軸與采樣率之間要有嚴格的換算關(guān)系,。
為了還原波形圖,,采樣率與被測量信號頻率之間有一定的關(guān)聯(lián),不同的采樣率,,對應(yīng)不同頻段的信號,,高采樣率適合高頻信號,低采樣率適合變化緩慢的低頻信號,。
從顯示效果來看,,為了在屏幕上再現(xiàn)信號的頻率特征,根據(jù)Nyquist 頻率特征定理,,一般要保證信號的每個周期內(nèi)至少有2 點,,用LCD 再現(xiàn),2 點效果已經(jīng)很差了,。最高采樣率一般由ADC 器件決定,,這里用的TLC1549 最快只能做到88μs 采集一點,按2 點每周期計算的話,,可以做到對5.6K(1000000/88/2) 信號采樣,,實際效果已經(jīng)很差了,1K 以內(nèi)效果最好,。
實際在設(shè)計采樣率檔位時,,最快檔按100μs 每點,屏幕每5 點(500μs)一格,,第一檔就是0.5ms/div,,這一檔位需要連續(xù)采樣,用少量延時控制采樣率為10k,,第二檔就是1ms/div,,第三檔2ms/div,第四檔5ms/div,,第五檔10ms/div,,后面四檔分別用定時器控制完成。
2. 電壓軸分檔定標
由于這版沒做模擬電路,,沒有信號電調(diào)理電路,,所謂電壓檔定標是純軟件算法實現(xiàn),屏幕同樣取5 點一格,,共10 格,,當輸入信號從0 到5V 變化時,LCD 剛好滿屏顯示,,每格0.5V,,另外還設(shè)計了0.1v/div,0.2v/div,,1v/div,,2v/div,5v/div,。共6 檔,。
3. 交流直流切換
功能完善的示波器應(yīng)該從硬件上實現(xiàn)交直流切換,本版先從軟件上實現(xiàn)交流直流顯示,,設(shè)計思想是根據(jù)采樣得到的數(shù)據(jù)的最大值和最小值確定交流信號幅度和中值,,把直流部分減掉,顯示只顯示交流部分,,這就是交流檔,,直流檔就是不做去直流處理。
4. 運行停止切換
該功能實現(xiàn)起來很容易,,所謂停止,,就是停止新的數(shù)據(jù)采集,重復顯示同一幀數(shù)據(jù),,顯示的效果就是波形穩(wěn)定無抖動,,便于對信號電壓和頻率進行測量。
5. 電壓測量
根據(jù)當前電壓檔位(每格表示多少伏),,計算出兩測量線之間的電壓值,,在LCD 上顯示。
6. 頻率測量
根據(jù)當前時間軸檔位(每格表示多長時間),,計算出兩測量線之間的時間,,假定兩測量線之間剛好是一個周期,轉(zhuǎn)換成頻率值在LCD 上顯示,。
7. 波形平移
用變量控制波形在LCD 上顯示的相對位置,,實現(xiàn)波形上下左右平移。
8. 幀同步
我們使用的數(shù)字示波器,,對有規(guī)律的周期信號能夠穩(wěn)定顯示,,要想實現(xiàn)穩(wěn)定顯示,需要在起始點顯示信號的不同周期的同一點,,如何做到這點呢,?
如圖10 所示,我們對比兩幀數(shù)據(jù),,波形起點不在同一點,,我們沒辦法保證每次數(shù)據(jù)采樣剛好在同一點(硬件觸發(fā)的除外),我需要按一定的規(guī)律,,在LCD 上繪圖時,,總是從同一點開始,例如過零點,,這里我們首先用統(tǒng)計的辦法找出信號的最大值和最小值,,計算出信號中交流部分的中點,,也就是過零點,然后逐點比較,,搜尋過零點,。
圖10 不同幀數(shù)據(jù)起點不同
程序設(shè)計思想是逐點比較過濾,我們?nèi)≈兄?,如圖7-1 中第5 點所示,,信號從小于中值到大于中值的上升沿為起點,不同幀信號可能從1,、2,、3、4 任何一點開始,,這就要用程序判斷把設(shè)定的起點5 以前的數(shù)據(jù)丟掉,。
程序是這樣的:
while(da_buffer[i] > dam) if(++i > (DATA_SIZE/2)) break;
while(da_buffer[i] <= dam) if(++i > (DATA_SIZE/2)) break;
while(da_buffer[i] > dam) if(++i > (DATA_SIZE/2)) break;
這里的dam 就是信號交流部分的中值。
程序用幾個while 語句,,看上去很呆板,,實際運行效果很好喔。第一句把比設(shè)定值大的數(shù)據(jù)過濾,,如圖10 中的1,、2、3 點,,如果數(shù)據(jù)是從4 開始的,,第一句會直接跳過;第二句把比設(shè)定值小的數(shù)據(jù)跳過,,找出過零點的上升沿5 點,。
9. 矢量繪圖
前面我們介紹的LCD 描點繪圖不是矢量繪圖,圖形由一系列的“點”組成,,在波形繪圖區(qū),,每列只有1個點,拿方波繪圖來看,,描點繪圖圖形如圖12 所示,,矢量繪圖在點與點之間填充“直線”,方波繪圖效果如圖11 所示,。對比兩種繪圖效果,,最好選擇矢量繪圖,LCD 波形顯示效果較點繪圖好很多,。
圖11 點繪圖
圖12 矢量繪圖
矢量繪圖需要按時間軸連續(xù)兩點同時考慮,,根據(jù)兩點之間的差值補點,這就是繪圖程序disp(x, y, l)中參數(shù)l 的作用。
七,、數(shù)字示波器程序流程圖設(shè)計分析
表達程序設(shè)計思想的關(guān)鍵就是程序流程圖,,下面將重點分析本程序設(shè)計的幾個關(guān)鍵流程圖。
主程序流程圖如圖13 所示,,初始化完成系統(tǒng)初始化設(shè)置,,包括全局變量初始化,紅外按鍵中斷,、定時器中斷初始化,在主循環(huán)程序中,,處理外部按鍵輸入,,由于數(shù)據(jù)采集是在定時中斷中完成的,主循環(huán)中需要等待一幀數(shù)據(jù)采集完成后,,才能對數(shù)據(jù)進行同步處理,,包括直流濾波,數(shù)據(jù)到LCD 映射,,調(diào)用LCD 顯示函數(shù)完成波形繪圖,,一幀數(shù)據(jù)處理完成后,重新開中斷,,等待下一幀數(shù)據(jù)采集,。
圖13 主程序流程圖圖
LCD 波形顯示流程圖如圖14 所示,LCD 波形顯示區(qū)需要根據(jù)新采集到的數(shù)據(jù)不斷刷新,,這里以LCD列為單位,,一次繪圖一個(x, y)坐標點,這里的編程思想是定義7 字節(jié)內(nèi)存變量,,與LCD 的第x 列對應(yīng),,首先對參數(shù)進行檢查,例如y 參數(shù)就不能超過LCD 顯示去最大值,,超過需要修正,,確保點到點映射不出錯,需要顯示的內(nèi)容除了波形信號外,,還有窗口邊框,,背景格,游標線等,,都要同時考慮,。這里的l 參數(shù)是兩點之間的間隔,采用矢量顯示,,兩點之間用直線矢量繪圖代替描點,,顯示效果要好很多。
圖14 LCD波形顯示
數(shù)據(jù)采集流程圖如圖15 所示,數(shù)據(jù)采集需要嚴格等時,,而且根據(jù)不同頻率的信號,,從低頻到高頻需要用不同的采樣率,所以這里用定時器控制采樣時間間隔,。
圖15 數(shù)據(jù)采集流程圖
由于定時器中斷任務(wù)調(diào)用需要額外時間,,對于高速中斷是有一定時間間隔限制的,通過計算,,100μs 周期采樣用定時器實現(xiàn)不了,,所以這里定時數(shù)據(jù)采樣分高速和低速兩檔,高速檔一次一幀,,低速檔一次一點,,一幀數(shù)據(jù)采集完成后,回到主程序?qū)?shù)據(jù)進行處理,。
按鍵任務(wù)流程圖如圖16 所示,,由于示波器控制需要很多按鍵,涉及電壓檔位,,采樣時間檔位,,游標線等,這些檔位都由一個全局變量控制,,在按鍵任務(wù)模塊,,就是根據(jù)有效按鍵,對這些檔位全局變量進行加減調(diào)整,,變量調(diào)整后,,有些效果會在波形顯示刷新中體現(xiàn)出來,還有的需要單獨刷新顯示,。
圖16 按鍵任務(wù)流程圖
八,、經(jīng)驗總結(jié)與心得體會
STC89C52RC 內(nèi)部擴展RAM 只有256 字節(jié),不像數(shù)據(jù)手冊上介紹的512 字節(jié),,外部RAM 超量使用會導致意想不到的后果,,經(jīng)常莫名其妙的死機。
窗口波形顯示有兩種模式,,逐點顯示(采集一個數(shù)據(jù)馬上刷新顯示)和逐幀顯示(采集完成一幀數(shù)據(jù)后刷新顯示),,經(jīng)過測試論證,低頻逐點視覺效果好,,高頻沒區(qū)別,,但是逐點沒辦法同步。
由于版面限制,,這里發(fā)表的只是一個壓縮版,,詳細資料見“大學生電子實驗室論壇” http://www.ceet.hbnu.edu.cn/bbs/,。
初學者在學習他人程序時,不要僅僅對程序代碼下功夫看懂,,其實真正學習的捷徑是看懂程序流程圖,,學習他人的程序設(shè)計思想,在吸收他人程序設(shè)計思想的前提下,,具體編程實現(xiàn)特定的功能,,程序可以有多種“寫法”。
作為終端輸出顯示裝置,,并不需要很高的刷新速度,,因為它是給“人”看的,每秒超過10 次的變化,,對人眼睛產(chǎn)生不了有用的效果,。
我寫這篇教程,特別注重解決問題方法的總結(jié),,我認為掌握一種解決問題的方法比掌握一種具體的知識要重要得多。