以單片機為核心器件,組成一個簡單數字電壓表。
(1)采用1路模擬量輸入,能夠測量0-10V(20v、30v、40v)之間的直流電壓值。
(2)電壓顯示可采用LCD1602顯示,能夠顯示兩位小數。
簡易數字電壓表的制作,主要涉及數據(電壓)測量、A/D轉換及控制顯示方面的知識。
(1)A/D轉換采用PCF8591實現。
(2)電壓顯示采用LCD1602。
(3)單片機選用AT89C5.
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
仿真圖.png (51.03 KB, 下載次數: 35)
下載附件
2022-11-13 11:45 上傳
單片機源程序如下:
- #include <reg52.h>
- #include <intrins.h> //包含函數_nop_()定義的頭文件
- #define u8 unsigned char
- #define u16 unsigned int
-
- #define AddWr 0x90 //PCF8591寫地址
- #define AddRd 0x91 //PCF8591讀地址
- #define w_com P0
-
- sbit RS=P2^2;
- sbit RW=P2^3;
- sbit E=P2^4;
- sbit Sda=P1^2; //定義IIC總線引腳
- sbit Scl=P1^1;
- u8 datetab[10]; //存入電壓值
- u8 ADtemp; //通道轉換后存入的數值
- float V_1602;
- u16 num=0;
- unsigned long num_pow(u8 m,u8 n) //指數運算
- {
- unsigned long result=1;
- while(n--) result*=m;
- return result;
- }
- void float2str(u8 str[],double floa,u8 len1,u8 len2) //浮點型轉字符型數組
- {
- u8 i=0,j=0;
- u16 zhengshu=floa;
- u16 xiaoshu=(floa-zhengshu)*num_pow(10,len2);
- while(len1--)
- {
- str[len1]=zhengshu%10+0x30;
- zhengshu=zhengshu /10;
- i++;
- }
- str[i]='.';
- while(len2--)
- {
- str[i+len2+1]=xiaoshu%10+0x30;
- xiaoshu=xiaoshu/10;
- j++;
- }
- str[i+j+1]='\0';
- }
- /*------------------------------------------------
- 啟動IIC總線
- ------------------------------------------------*/
- void Start(void)
- {
- Sda=1;
- _nop_();
- Scl=1;
- _nop_();
- Sda=0; //sda負跳變
- _nop_();
- Scl=0;
- }
- /*------------------------------------------------
- 停止IIC總線
- ------------------------------------------------*/
- void Stop(void)
- {
- Sda=0;
- _nop_();
- Scl=1;
- _nop_();
- Sda=1; //sda正跳變
- _nop_();
- Scl=0;
- }
- /*------------------------------------------------
- IIC總線應答
- ------------------------------------------------*/
- void Ack(void)
- {
- Sda=0; //scl高電平期間sda輸出低電平
- _nop_();
- Scl=1;
- _nop_();
- Scl=0;
- _nop_();
- }
- /*------------------------------------------------
- IIC總線非應答
- ------------------------------------------------*/
- void NoAck(void)
- {
- Sda=1; //scl高電平期間sda輸出高電平
- _nop_();
- Scl=1;
- _nop_();
- Scl=0;
- _nop_();
- }
- /*------------------------------------------------
- 向PCF8591發送1字節數據(/地址/控制命令等)
- ------------------------------------------------*/
- void Send(u8 Data)
- {
- u8 BitCounter=8; //定義發送位數為8
- do
- {
- Scl=0;
- _nop_();
- if((Data&0x80)==0x80) //逐位判別1/0后送至SDA
- Sda=1; //scl低電平期間數據送至sda線
- else
- Sda=0;
- Scl=1; //scl變高輸出數據(寫入pcf8591)
- Data=Data<<1;
- BitCounter--;
- }while(BitCounter);
- Scl=0;
- }
- /*------------------------------------------------
- 從PCF8591讀入1字節(例如A/D轉換結果)
- ------------------------------------------------*/
- u8 Read(void)
- {
- u8 temp=0;
- u8 BitCounter=8;
- Sda=1; //拉高數據線
- do
- {
- temp=temp<<1; //逐位移入temp
- Scl=0;
- _nop_();
- Scl=1; //scl變高采樣sda線
- _nop_();
- if(Sda) //判別SDA線上為1/0
- temp=temp|0x01;
- else
- temp=temp&0xfe;
- BitCounter--;
- }while(BitCounter);
- return(temp); //返回值為讀入的字節
- }
- void DACconversion(u8 sla,u8 c, u8 Val) //8591輸出一個數據
- {
- Start();//啟動總線
- Send(sla);//發送器件地址
- Ack();
- Send(c);//發送控制字節
- Ack();
- Send(Val);//發送DAC的數值
- Ack();
- Stop();//結束總線
- }
- /*----------------------------------------------------------
- 啟動PCF8591 Chl 通道A/D轉換并讀取轉換結果
- --------------------------------------------------------------*/
- u8 ReadADC(u8 Chl)
- {
- u8 Data;
- Start(); //開始信號
- Send(AddWr); //發寫地址(0x90)
- Ack(); //等待 PCF8591應答
- Send(0x40|Chl); //寫入控制字并啟動 Chl通道A/D轉換
- Ack(); //等待 PCF8591應答
- Start(); //重發開始信號
- Send(AddRd); //寫入讀地址
- Ack();
- Data=Read(); //讀取A/D轉換結果(注意是上次的)
- NoAck(); //發非應答信號
- Stop(); //停止總線操作
- return Data; //返回A/D轉換結果
- }
- void delay(u16 i)
- {
- while(i--);
- }
- void LCD_busy(void)
- {
- u8 temp;
- do{
- temp =0xff;
- E = 0;
- RS= 0;
- RW = 1;
- E =1;
- temp = w_com;
- }while(temp&0x80); // 如果 BF =1 則持續檢查
- E = 0;
- }
- void write_command(u8 com)
- {
- LCD_busy();
- E= 0;
- RS =0;
- RW =0;
- w_com = com;
- E =1;
- delay(100);
- E = 0;
- }
- void write_data(u8 com)
- {
- LCD_busy();
- E=0;
- RS= 1;
- RW =0;
- w_com = com;
- E=1;
- delay(100);
- E =0;
- }
-
-
-
-
- void lcd_initial(void)
- {
- write_command(0x38); //8位數據接口,雙行顯示
- delay(100);
- write_command(0x0c); //開顯示屏
- delay(100);
- write_command(0x01); //清屏
- delay(100);
- write_command(0x06); //光標移動
- delay(100);
-
- }
-
-
- void string(u8 y,u8 x, u8 *s) //x表示行,y表示列
- {
- if (x==1)
- {
- write_command(0xc0|y); //因為DDRAM尋址指令是 0x80開頭。
- }
- else
- write_command(0x80|y);
-
- while(*s != '\0')
- {
- write_data(*s++);
- }
- }
- void string_word(u8 y,u8 x,u8 num)
- {
- if (x==1)
- {
- write_command(0xc0|y); //因為DDRAM尋址指令是 0x80開頭。
- }
- else
- write_command(0x80|y);
-
- write_data(num);
- }
-
- void main()
- {
- lcd_initial();
- while(1)
- {
- ADtemp=ReadADC(1); //讀取通道1 A/D轉換結果
- V_1602=ADtemp*(10.0/256); //計算電壓值 10.0 20.0 30.0 40.0
- float2str(datetab,V_1602,2,2); //顯示整數位與小數位的個數
- string(5,0,datetab); //顯示的位置和內容
- string_word(10,0,'V'); //顯示單位
- delay(10000);
- }
- }
-
復制代碼
Keil代碼與Proteus8.13版本的仿真下載(注意不能兼容其他版本 只能用8.13打開):
程序+Proteus8.13仿真圖.7z
(74.12 KB, 下載次數: 77)
2022-11-15 18:10 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|