51微控制器開發系列三_數碼管動態掃描顯示

huang20083200056發表於2014-03-18

51微控制器開發系列三

數碼管動態掃描顯示

象棋小子    1048272975

數碼管由於發光亮度強,指示效果好,非常適合於電梯樓層等數值顯示應用中。對於一位數碼管,可以採用靜態顯示,但實際應用中都是需要顯示多位數值,數碼管模組也只能動態顯示,因此筆者在這裡簡單分析一下數碼管動態掃描驅動的實現。

1. 數碼管原理概述

數碼管由多個發光二極體封裝在一起組成“8”字型的器件,引線已在內部連線完成,只引出它們的各個筆劃,公共電極。數碼管實際上是由七個發光管組成8字形構成的,加上小數點就是8個。這些段分別由字母a,b,c,d,e,f,g,dp來表示。數碼管根據內部接法又可分成共陽極數碼管和共陰極數碼管。共陽數碼管是指將所有發光二極體的陽極接到一起形成公共陽極(COM)的數碼管(如下圖SM*10501),共陰數碼管是指將所有發光二極體的陰極接到一起形成公共陰極(COM)的數碼管如下圖(SM*20501)。以共陽數碼管為例,要想顯示數字2,需把A、B、G、E、D段點亮,即公共端接上正電源,ABGED段陰極拉低,其餘段拉高即可顯示數字2。


2. 硬體設計

筆者此處以四位一體共陽數碼管顯示為例講解其大概的硬體設計。

微控制器的IO口均不能流過過大的電流,LED點亮時有約10ms的電流,因此數碼管的段碼輸出不要直接接微控制器IO口,應先經過一個緩衝器74HC573。微控制器IO口只需很小的電流控制74HC573即可間接的控制數碼管段的顯示,而74HC573輸出也能負載約10ms的電流。設定數碼管段的驅動電流為ID=15ma,這個電流點亮度好,並且有一定的裕度,即使電源輸出電壓偏高也不會燒燬LED,限流電阻值

R = (VCC- VCE – VOL – VLED) / ID

VCC為5v供電,VCE為三極體C、E間飽和電壓,估為0.2v, VOL為74hc573輸出低電平時電壓,不同灌電流,此值不一樣,估為0.2v,具體檢視規格書,VLED為紅光碟機動電壓,估為1.7v,根據上式可算出限流電阻為R = 200R。

數碼管需接收逐個掃描訊號,掃描到相應數碼管時,對應的段碼資料有效,即顯示這個數碼管的數值。筆者採用三線八線譯碼器74HC138來產生對應的掃描線訊號。

當各個段碼均點亮時,電流約15max8=90ma流過數碼管公共端,74HC138無法直接驅動這個電流,需加三極體驅動,由於74HC138輸出低電平有效,此處只有PNP三極體適合作為驅動。三極體基極電流設為2ma即可讓三極體飽和,最大驅動電流遠大於90ma。基極偏置電阻阻值

Rb =(VCC - VEB – VOL) / IB

VCC為5v供電,VEB為三極體E、B間的導通電壓0.7v,VOL為74hc138輸出低電平時電壓,可根據規格書估為0.3v,故Rb = 2k即可。


圖2-1 四位一體數碼管原理圖

3. 驅動實現

數碼管段碼接P0口,位碼接P2口第0~2位。對於LED顯示器都是有一個重新整理頻率的,同樣對於數碼碼動態掃描也需要一個掃描頻率。掃描頻率下限為50HZ,低於一定的掃描頻率,顯示會閃爍。頻率過高,則亮度較差且佔用cpu資源。一般整個數碼管掃描一遍時間為約10ms較合適(即掃描頻率100HZ),我們用的是四位數碼管,每個數碼管點亮時間為2ms,掃描一遍時間為8ms。為保證這個重新整理頻率,通過是通過定時器來週期性進行數碼管重新整理。筆者在此以四位一體數碼管實現秒錶計數顯示為例來作程式碼開發。

數碼管動態顯示功能實現模組檔案DigitalTubeTable.c內容如下:

 

#include "reg52.h"

#include"DigitalTube.h"

 

// 數值相對應的段碼,共陽極

static unsigned char codeDigitalTubeTable[12]= { // 共陽LED段碼錶

0xc0, 0xf9, 0xa4, 0xb0, 0x99,0x92, 0x82, 0xf8, 0x80, 0x90, 0xff, 0xbf

//"0"  "1"   "2"   "3"   "4"   "5"   "6"   "7"   "8"   "9" "不亮"  "-"

};

 

// 每個數碼管需一個位元組的記憶體儲存對應數碼管資料            

static unsigned charFrameBuffer[DigitalTubeNumber];

 

unsigned char*DigitalTube_GetBuffer()

{

       return FrameBuffer;

}

 

void DigitalTube_Scan()

{

       static unsigned char Select = 0; // 記錄掃描的選擇線

       unsigned char Code;

       // 從對應選擇線中找到視訊記憶體資料,並得到相應的段碼

       Code = DigitalTubeTable[FrameBuffer[Select]];

       // 段碼實際輸出到數碼管介面

       DigitalTube_Data(Code);

       // 位選實際輸出到數碼管介面

       DigitalTube_Select(Select);

       Select++; // 進入到下一位選掃描

       if (Select >= DigitalTubeNumber) {

             Select = 0;    // 所有數碼管已掃描,從第一個數碼管再次開始掃描

       }

}

 

我們在數碼管模組標頭檔案DigitalTube.h中實現模組的介面訪問巨集實現,使之方便移植及修改介面配置。模組標頭檔案同時也引出模組的介面函式,void DigitalTube_Scan(void)為數碼管重新整理函式,需週期性呼叫重新整理數碼管顯示。unsigned char *DigitalTube_GetBuffer(void)用來獲得數碼管視訊記憶體,從而更新數碼管視訊記憶體資料。其內容如下:

 

#ifndef __DigitalTube_H__

#define __DigitalTube_H__

 

#ifdef __cplusplus

extern "C" {

#endif

 

// 數碼管模組中的個數,最大為8

#define DigitalTubeNumber      4

 

// 輸出數碼管位選

#defineDigitalTube_Select(Select) {P2 = (P2&0xf8) + (Select);}

// 輸出數碼管段碼

#define DigitalTube_Data(Dat)     {P0 =(Dat);}

 

// 數碼管重新整理函式,必須保證以一定週期呼叫重新整理

void DigitalTube_Scan(void);

// 獲得數碼管視訊記憶體,以作顯示的資料更新

unsigned char*DigitalTube_GetBuffer(void);

 

#ifdef __cplusplus

}

#endif

 

#endif /*__DigitalTube_H__*/

 

外部模組通過引入數碼管的模組標頭檔案DigitalTube.h來實現呼叫數碼管驅動函式,簡單測試呼叫(秒錶數碼管顯示計數)實現如下:

 

#include"reg52.h"

#include"DigitalTube.h"

 

// 以定時器時間為計時標準,記錄時間間隔

static volatile unsignedint SystemTick = 0;

 

// 定時器2ms中斷處理進行數碼管重新整理

void T0_Interrupt()interrupt 1

{

       TH0 = (65536-2000) / 256;

       TL0 = (65536-2000) % 256;

       SystemTick++; // 記錄時間間隔

       DigitalTube_Scan();     //重新整理數碼管

}

 

void T0_Init()

{

       TMOD = 0x01; // 定時器0工作方式1

       // 2ms計時中斷(12M)

       TH0 = (65536-2000) / 256;

       TL0 = (65536-2000) % 256;

       ET0 = 1; // 定時器T0中斷允許

       EA = 1; // 總中斷允許

}

 

void main()

{

       unsigned char *pBuffer;

       unsigned char i;

       // 定時器初始化

       T0_Init();

       // 獲得數碼管視訊記憶體,以作更新資料顯示

       pBuffer = DigitalTube_GetBuffer();

       // 資料管視訊記憶體初始化顯示0

       for (i=0; i<DigitalTubeNumber; i++) {

              pBuffer[i] = 0;

       }

       // 開啟定時器進行計時以及數碼管重新整理

       TR0 = 1;

 

       while(1) {

              // SystemTick讀數到500時為1s間隔到

              if (SystemTick > 500) {

                     SystemTick =0; // 重新計秒

                     // 更新數碼管秒錶計數視訊記憶體     

                     for (i=0; i<DigitalTubeNumber; i++) {

                            pBuffer[DigitalTubeNumber-1-i]++;

                            if (pBuffer[DigitalTubeNumber-1-i] <10) {

                                   break; // 未到10,不用進位更新高位視訊記憶體,退出

                            } else {

                                   // 到10,這一位清0,並繼續迴圈更新高位視訊記憶體

                                   pBuffer[DigitalTubeNumber-1-i] =0;

                            }

                     }                         

              }                         

       }

}

附錄:

此章節的Keil工程,包含原始碼,Preteus模擬,包含模擬電路,可直接檢視效果,DigitalTube.rar。

http://pan.baidu.com/s/19wRr4

 

相關文章