【51单片机快速入门指南】2.1:数码管显示数字、小数 (科学计数法)
目錄
- 硬知識
- 數碼管簡介
- 多位數碼管簡介
- 數碼管動態顯示原理
- 74HC245 芯片簡介
- 74HC138 芯片簡介
- 上機實戰
- 源碼
- Tube.c
- Tube.h
- main.c
- 效果
- 顯示整數
- 正數
- 負數
- 顯示小數(保留三位有效數字)
- 正數
- 負數
普中51-單核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
硬知識
選自《普中51單片機開發攻略_V1.2》
數碼管簡介
???????數碼管是一種半導體發光器件,也稱 LED 數碼管,其基本單元是發光二極管。
???????數碼管按段數可分為七段數碼管和八段數碼管,八段數碼管比七段數碼管多一個發光二極管單元,也就是多一個小數點(DP),這個小數點可以更精確的表示數碼管想要顯示的內容;
???????按能顯示多少個【8】可分為 1 位、 2 位、 3 位、 4 位、 5 位、 6 位、7 位等數碼管。
???????按發光二極管單元連接方式可分為共陽極數碼管和共陰極數碼管。
???????共陽數碼管是指將所有發光二極管的陽極接到一起形成公共陽極(COM)的數碼管,共陽數碼管在應用時應將公共極 COM 接到+5V,當某一字段發光二極管的陰極為低電平時,相應字段就點亮,當某一字段的陰極為高電平時,相應字段就不亮。
???????共陰數碼管是指將所有發光二極管的陰極接到一起形成公共陰極(COM)的數碼管,共陰數碼管在應用時應將公共極 COM 接到地線 GND 上,當某一字段發光二極管的陽極為高電平時,相應字段就點亮,當某一字段的陽極為低電平時,相應字段就不亮。
???????不同位數的數碼管實物圖如下所示:
???????由圖可知,一位數碼管的引腳是 10 個,顯示一個 8 字需要 7 個小段, 另外還有一個小數點,所以其內部一共有 8 個小的發光二極管,最后還有一個 公共端,多數生產商為了封裝統一,單位數碼管都封裝 10 個引腳,其中第 3 和 第 8 引腳是連接在一起的。
???????公共端可分為共陽極和共陰極,圖中間為共陽極內部原理圖,右圖為共陰極內部原理圖。
???????對共陰極數碼管來說,其 8 個發光二極管的陰極在數碼管內部全部連接在一起,所以稱“共陰”,而它們的陽極是獨立的,通常在設計電路時一般把陰極接地。 當我們給數碼管的任意一個陽極加一個高電平時,對應的這個發光二極管就點亮 了。如果想要顯示出一個 8 字,并且把右下角的小數點也點亮的話,可以給 8 個陽極全部送高電平,如果想讓它顯示出一個 0 字,那么我們可以除了給第“g, dp” 這兩位送低電平外,其余引腳全部都送高電平,這樣它就顯示出 0 字了。
???????如果使用共陰數碼管,需要注意增加單片機 IO 口驅動電流,因為共陰數碼管是要靠單片機 IO 口輸出電流來點亮的,但單片機 I/O 口難以輸出穩定的、如此大的電流,所以數碼管與單片機連接時需要加驅動電路,可以用上拉電阻的方法或使用專門的數碼管驅動芯片,比如 74HC573、74HC245 等,其輸出電流較大, 電路接口簡單。
???????共陽極數碼管其內部 8 個發光二極管的所有陽極全部連接在一起,電路連接時,公共端接高電平,因此我們要點亮哪個發光管二極管就需要給陰極送低電平, 此時顯示數字的編碼與共陰極編碼是相反的關系,數碼管內部發光二極管點亮時,也需要 5mA 以上的電流,而且電流不可過大,否則會燒壞發光二極管。因此不僅要防止數碼管電流過大,同時要防止流經數碼管的電流集中到單片機時電流不能過大,否則會損壞主芯片。
???????一般共陽極數碼管更為常用,這是因為數碼管的非公共端往往接在 IC 芯片的 I/O 上,而 IC 芯片的驅動能力往往是比較小的,如果采用共陰極數碼管,它的驅動端在非公共端, 就有可能受限于 IC 芯片輸出電流不夠而顯示昏暗,要外加上拉電阻或者是增加三極管加大驅動能力。但是 IC 芯片的灌電流, 即輸入電流范圍比較大。所以使用共陽極數碼管的好處是:將驅動數碼管的工作交到公共端(一般接驅動電源),加大驅動電源的功率自然要比加大 IC 芯片 I/O 口的驅動電流簡單許多。另一方面,這樣也能減輕主芯片的負擔。
多位數碼管簡介
???????多位數碼管,即兩個或兩個以上單個數碼管并列集中在一起形成一體的數碼管。當多位一體時,它們內部的公共端是獨立的,而負責顯示什么數字的段線 (a-dp)全部是連接在一起的,獨立的公共端可以控制多位一體中的哪一位數碼管點亮,而連接在一起的段線可以控制這個能點亮數碼管亮什么數字,通常把公共端叫做“位選線”,連接在一起的段線叫做“段選線”,有了這兩個線后, 通過單片機及外部驅動電路就可以控制任意的數碼管顯示任意的數字了。
數碼管動態顯示原理
???????當多位數碼管應用于某一系統時,它們的“位選”是可獨立控制的,而“段選”是連接在一起的,我們可以通過位選信號控制哪幾個數碼管亮,而在同一時刻,位選選通的所有數碼管上顯示的數字始終都是一樣的,因為它們的段選是連接在一起的,送入所有數碼管的段選信號都是相同的,所以它們顯示的數字必定一樣,數碼管的這種顯示方法叫做靜態顯示。
???????而動態顯示,就是利用減少段選線,分開位選線,利用位選線不同時選擇通斷,改變段選數據來實現的。比如在第一次選中第一位數碼管時,給段選數據 0, 下一次位選中第二位數碼管時顯示 1。為了在顯示 1 的時候,0 不會消失(當然實際上是消失了),必須在人肉眼觀察不到的時間里再次點亮第一次點亮的 0。 而這時就需要記住,人的肉眼正常情況下只能分辨變化超過 24ms 間隔的運動。 也就是說,在下一次點亮 0 這個數字的時間差不得大于 24ms。這時就會發現, 數碼管點亮是在向右或者向左一位一位點亮,形成了動態效果。如果把間隔時間改長就能直接展現這一現象。
74HC245 芯片簡介
???????74HC245 是一種三態輸出、八路信號收發器,主要應用于大屏顯示,以及其它的消費類電子產品中增加驅動能力。
???????給 OE 使能管腳低電平,DIR 管腳為高電平傳輸方向是 A->B 輸出,DIR 為低電平傳輸方向是 B->A,至于輸出高電平還是輸出低電平取決于輸入端的狀態,如果輸入為低電平,輸出即為低;輸入為高電平,輸出即為高。如果 OE 使能管腳為高電平, 不論 DIR 管腳是高還是低,輸出是高阻態。
???????開發板上OE管腳已接GND,DIR管腳已接VCC,傳輸方向是 A->B。
74HC138 芯片簡介
???????74HC138D 是一種三通道輸入、八通道輸出譯碼器,主要應用于消費類電子產品。
???????給 E1、E2 使能管腳低電平,E3 管腳為高電平,至于哪個管腳輸出有效電平(低電平),要看 A0,A1,A2 輸入管腳的電平狀態。如果 A0,A1,A2 都為低電平,則 Y0 輸出有效電平(低電平),其他管腳均輸出高電平。如果 A0 為高電平,A1, A2 都為低電平,則 Y1 輸出有效電平(低電平),其他管腳均輸出高電平。
???????A0、A1、A2 輸入就相當于 3 位 2 進制數,A0 是低位,A1 是次高位,A2 是高位。而 Y0~Y7 具體哪一個輸出有效電平,就看輸入二進制對應的十進制數值。比如輸入是 101(A2,A1,A0),其對應的十進制數是 5,所以 Y5 輸出有效電平(低電平)。
上機實戰
stdint.h見【51單片機快速入門指南】1:基礎知識和工程創建
源碼
Tube.c
#include <REGX52.H> #include "intrins.h" #include "stdint.h" #include "Tube.h"#define Tube_Port P0sbit P74138_A0 = P2^2; sbit P74138_A1 = P2^3; sbit P74138_A2 = P2^4;//顯示的延時 400us @11.0592MHz void LED_Tube_Delay() {unsigned char i;_nop_();i = 181;while (--i); }//位選 void F74138(uint8_t num) {num &= 7;P74138_A0 = (num & 1);P74138_A1 = (num & 2) >> 1;P74138_A2 = (num & 4) >> 2; }code uint8_t Tube_Codes_0ToF[] = {Tube_Code_0,Tube_Code_1,Tube_Code_2,Tube_Code_3,Tube_Code_4,Tube_Code_5,Tube_Code_6,Tube_Code_7,Tube_Code_8,Tube_Code_9,Tube_Code_A,Tube_Code_b,Tube_Code_C,Tube_Code_d,Tube_Code_E,Tube_Code_F };//以科學計數法顯示小數 void Display_Double(double Num) {uint8_t i = 0;int8_t pow = 0;uint8_t DisplayNum = 0;double Num_clone;char Tube_Double_Buffer[8] = {0};if (Num < 0){Tube_Double_Buffer[7] = Tube_Code_Negative_Sign; Num = -Num;}if (Num < 1e-8) //視為0{for(i = 0; i < 7; ++i)Tube_Double_Buffer[i + 1] = Tube_Code_NULL;Tube_Double_Buffer[0] = Tube_Codes_0ToF[0];}else if (Num > 1e8) //視為溢出,Error{Tube_Double_Buffer[6] = Tube_Code_NULL;Tube_Double_Buffer[5] = Tube_Code_E; Tube_Double_Buffer[4] = Tube_Code_r; Tube_Double_Buffer[3] = Tube_Code_r; Tube_Double_Buffer[2] = Tube_Code_o; Tube_Double_Buffer[1] = Tube_Code_r; Tube_Double_Buffer[0] = Tube_Code_NULL;}else {Num_clone = Num;if(Num_clone < 1000){while(Num_clone < 1000){Num_clone *= 10;++pow;}pow = 3-pow; //求指數}else{pow = 3;while(Num_clone > 9999){Num_clone /= 10;++pow; //求指數}}Num_clone /= 10;for(i = 0; i < 3; ++i) //三位有效數字{DisplayNum = (int)(Num_clone + (i == 0) * 0.5) % 10; //末位四舍五入Tube_Double_Buffer[i + 4] = Tube_Codes_0ToF[DisplayNum];Num_clone /= 10;}Tube_Double_Buffer[6] |= Tube_Code_Dot; //補小數點Tube_Double_Buffer[3] = Tube_Code_E; if(pow < 0){Tube_Double_Buffer[2] = Tube_Code_Negative_Sign; //指數符號為負pow = -pow;}for(i = 0; i < 2; ++i){DisplayNum = pow % 10;Tube_Double_Buffer[i] = Tube_Codes_0ToF[DisplayNum]; //指數pow /= 10;}}for(i = 0; i < 8; ++i){Tube_Port = Tube_Code_NULL; //關閉位選F74138(i); Tube_Port = Tube_Double_Buffer[i]; //顯示LED_Tube_Delay();}return; }//顯示整數 void Display_Int(int32_t Num) {uint8_t i = 0;uint8_t DisplayNum = 0;char Tube_Double_Buffer[8] = {0};if(Num >= 10000000 || Num <= -10000000) {Display_Double((double)Num); //以指數形式輸出return;}else{if(Num < 0){Tube_Double_Buffer[7] = Tube_Code_Negative_Sign; //負號Num = -Num;}for(i = 0; i < 7; ++i){DisplayNum = Num % 10;if(Num == 0 && i != 0)Tube_Double_Buffer[i] = Tube_Code_NULL;elseTube_Double_Buffer[i] = Tube_Codes_0ToF[DisplayNum];Num /= 10;}for(i = 0; i < 8; ++i){Tube_Port = Tube_Code_NULL; //關閉位選F74138(i);Tube_Port = Tube_Double_Buffer[i]; //顯示LED_Tube_Delay();}return;} }//顯示數字 void Display_Num(double Num) {if(Num == (int32_t)Num)Display_Int((int32_t)Num);elseDisplay_Double(Num);return; }Tube.h
#ifndef TUBE_H_ #define TUBE_H_#define Tube_Code_NULL 0x00#define Tube_Code_0 0x3f #define Tube_Code_1 0x06 #define Tube_Code_2 0x5b #define Tube_Code_3 0x4f #define Tube_Code_4 0x66 #define Tube_Code_5 0x6d #define Tube_Code_6 0x7d #define Tube_Code_7 0x07 #define Tube_Code_8 0x7f #define Tube_Code_9 0x6f#define Tube_Code_A 0x77 #define Tube_Code_b 0x7c #define Tube_Code_C 0x39 #define Tube_Code_c 0x58 #define Tube_Code_d 0x5e #define Tube_Code_E 0x79 #define Tube_Code_F 0x71 #define Tube_Code_G 0x3d #define Tube_Code_H 0x76 #define Tube_Code_I 0x30 #define Tube_Code_i 0x10 #define Tube_Code_J 0x0e #define Tube_Code_K 0x7a #define Tube_Code_L 0x38 #define Tube_Code_M 0x55 #define Tube_Code_n 0x54 #define Tube_Code_o 0x5c #define Tube_Code_P 0x73 #define Tube_Code_q 0x67 #define Tube_Code_r 0x50 #define Tube_Code_S 0x64 #define Tube_Code_t 0x78 #define Tube_Code_U 0x3e #define Tube_Code_u 0x1c #define Tube_Code_v 0x62 #define Tube_Code_W 0x6a #define Tube_Code_X 0x36 #define Tube_Code_y 0x6e #define Tube_Code_Z 0x49#define Tube_Code_Dot 0x80 #define Tube_Code_Negative_Sign 0x40void Display_Int(int32_t Num); void Display_Double(double Num); void Display_Num(double Num);#endifmain.c
#include <REGX52.H> #include "intrins.h" #include "stdint.h" #include "Tube.h"void main(void) { while(1){Display_Num(114514);} }效果
顯示整數
正數
較大的數
負數
顯示小數(保留三位有效數字)
正數
負數
總結
以上是生活随笔為你收集整理的【51单片机快速入门指南】2.1:数码管显示数字、小数 (科学计数法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分布式系统必读中文版-分布式系统模式-分
- 下一篇: 2019eclipse 中文汉化包 安装