基於proteus的51單片機仿真實例八十、模數轉換器ADC0832應用實例

1、ADC0832是一種8位分辨率,雙通道AD轉換芯片。它能夠對兩路模擬信號進行模數轉換,可以在單端輸入方式和差分輸入方式下工作。ADC0832引腳圖如下圖:

引腳說明如下:
/CS:片選端,低電平時選中芯片
CH0:模擬輸入通道0
CH1:模擬輸入通道1
GND:電源地
DI:數據信號輸入,通道選擇控制端
DO:數據信號輸出,轉換後的數據由此端口輸出
CLK:時鐘輸入端
VCC:電源
 
2、ADC0832的控制原理
ADC0832的工作時序圖如下:

。當ADC0832未工作時,必須將片選端CS置於高電平。此時,芯片禁用。當需要進行A/D轉換時,應將片選端CS置於低電平並保持到轉換結束。芯片開始工作後,還需讓單片機想芯片的CLK端輸入時鐘脈衝,在第一個時鐘脈衝的下降沿之前將DI端的輸出必須是高電平,表示開始轉換。在第2、3個脈衝的下降沿之前。DI端口輸入兩位數據,這兩位數據用於選擇數據採集通道。
當DI端依次輸入1、0時,選擇通道0;
當DI端依次輸入1、1時,選擇通道1;
當DI端依次輸入0、0時,CH0作爲正輸入端,CH1作爲負輸入端;
當DI端依次輸入0、1時,CH0作爲負輸入端,CH1作爲正輸入端;
在第三個脈衝下降沿後,DI端口就失去作用了。此後數據輸出端DO開始輸出轉換後的數據。在第四個脈衝的下降沿輸出轉換後數據的最高位直到第11個脈衝下降沿輸出數據的最低位。至此,一個字節的數據輸出完成。然後從此位開始輸出下一個相反字節的數據,即從第11個脈衝的下降沿輸出數據的最低位,直到第19個脈衝時數據輸出完成,也標誌着一次AD轉換結束。後一相反字節的8個數據位是作爲校驗位使用的,一般只讀出第一個字節的前8個數據位即能滿足要求,對於後8位數據,可以將其丟棄。
正常情況下,ADC0832與單片機的接口應爲4條數據線:CS,CLK,DI,DO。但由於DI和DO兩個端口在通信時並未同時使用,而是先有DI端口輸入兩位數據來選擇通道,再由DO端口輸出數據,因此,實際使用中可以將DI和DO並聯在一根數據線上使用。
 
3、作爲單通道模擬信號輸入時,ADC0832的輸入電壓範圍是0-5V,輸入電壓爲0時,轉換後的值0x00,輸入電壓爲5V時,轉換後的值0xff,即十進制數255.轉換後的輸出值(數字量D):D=255/5*V=51V。其中D爲轉換後的數字量,V爲輸入的模擬電壓。
 
4、本例利用ADC0832設計一個5V直流數字電壓表,將輸入的直流電壓轉換成數字信號後,通過LCD1602液晶顯示出來。
實現方法:
1)ADC0832的啓動:
首先將ADC0832的片選端口CS置爲低電平(接地也可)。然後在第一個CLK脈衝下降沿之前將DI端口置爲高電平,啓動ADC0832開始工作。
2)通道選擇:
本例選擇通道CH0作爲模擬信號的輸入通道,根據通信協議,DI在第2、3個CLK脈衝的下降沿之前應分別輸入1和0.
3)數據讀取
在第4-11個脈衝下降沿讀取8位轉換後的數字量。
 
5、在keil c51中新建工程ex68,編寫如下程序代碼,編譯並生成ex68.hex文件
//基於ADC0832的數字電壓表
#include<reg51.h>    //包含單片機寄存器的頭文件
#include<intrins.h>  //包含_nop_()函數定義的頭文件
//ADC0832端口引腳定義
sbit CS=P3^0;       //將CS位定義爲P3.4引腳
sbit CLK=P3^6;      //將CLK位定義爲P1.0引腳
sbit DIO=P3^7;       //將DIO位定義爲P1.1引腳
//全局變量聲明
unsigned char code digit[10]={"0123456789"};   //定義字符數組顯示數字
unsigned char code Str[]={"Volt="};            //說明顯示的是電壓

//液晶端口定義
sbit RS=P2^0;           //寄存器選擇位,將RS位定義爲P2.0引腳
sbit RW=P2^1;           //讀寫選擇位,將RW位定義爲P2.1引腳
sbit E=P2^2;            //使能信號位,將E位定義爲P2.2引腳
sbit BF=P0^7;           //忙碌標誌位,,將BF位定義爲P0.7引腳
/*****************************************************
函數功能:延時1ms
(3j+2)*i=(3×33+2)×10=1010(微秒),可以認爲是1毫秒
***************************************************/
void delay1ms()
{
   unsigned char i,j; 
  for(i=0;i<10;i++)
   for(j=0;j<33;j++)
    ;   
 }
/*****************************************************
函數功能:延時若干毫秒
入口參數:n
***************************************************/
 void delaynms(unsigned char n)
 {
   unsigned char i;
 for(i=0;i<n;i++)
    delay1ms();
 }
/*****************************************************
函數功能:判斷液晶模塊的忙碌狀態
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
bit BusyTest(void)
  {
    bit result;
 RS=0;       //根據規定,RS爲低電平,RW爲高電平時,可以讀狀態
    RW=1;
    E=1;        //E=1,才允許讀寫
    _nop_();   //空操作
    _nop_();
    _nop_(); 
    _nop_();   //空操作四個機器週期,給硬件反應時間 
    result=BF;  //將忙碌標誌電平賦給result
   E=0;         //將E恢復低電平
   return result;
  }
/*****************************************************
函數功能:將模式設置指令或顯示地址寫入液晶模塊
入口參數:dictate
***************************************************/
void WriteInstruction (unsigned char dictate)
{   
    while(BusyTest()==1);   //如果忙就等待
  RS=0;                  //根據規定,RS和R/W同時爲低電平時,可以寫入指令
  RW=0;   
  E=0;                   //E置低電平(根據表8-6,寫指令時,E爲高脈衝,
                           // 就是讓E從0到1發生正跳變,所以應先置"0"
  _nop_();
  _nop_();               //空操作兩個機器週期,給硬件反應時間
  P0=dictate;            //將數據送入P0口,即寫入指令或地址
  _nop_();
  _nop_();
  _nop_();
  _nop_();               //空操作四個機器週期,給硬件反應時間
  E=1;                   //E置高電平
  _nop_();
  _nop_();
  _nop_();
  _nop_();               //空操作四個機器週期,給硬件反應時間
   E=0;                  //當E由高電平跳變成低電平時,液晶模塊開始執行命令
 }
/*****************************************************
函數功能:指定字符顯示的實際地址
入口參數:x
***************************************************/
 void WriteAddress(unsigned char x)
 {
     WriteInstruction(x|0x80); //顯示位置的確定方法規定爲"80H+地址碼x"
 }
/*****************************************************
函數功能:將數據(字符的標準ASCII碼)寫入液晶模塊
入口參數:y(爲字符常量)
***************************************************/
 void WriteData(unsigned char y)
 {
    while(BusyTest()==1);  
   RS=1;           //RS爲高電平,RW爲低電平時,可以寫入數據
   RW=0;
   E=0;            //E置低電平(根據表8-6,寫指令時,E爲高脈衝,
                     // 就是讓E從0到1發生正跳變,所以應先置"0"
   P0=y;           //將數據送入P0口,即將數據寫入液晶模塊
   _nop_();
   _nop_();
    _nop_();
     _nop_();       //空操作四個機器週期,給硬件反應時間
   E=1;           //E置高電平
   _nop_();
   _nop_();
   _nop_();
  _nop_();        //空操作四個機器週期,給硬件反應時間
  E=0;            //當E由高電平跳變成低電平時,液晶模塊開始執行命令
 }
/*****************************************************
函數功能:對LCD的顯示模式進行初始化設置
***************************************************/
void LcdInitiate(void)
{
    delaynms(15);               //延時15ms,首次寫指令時應給LCD一段較長的反應時間
    WriteInstruction(0x38);     //顯示模式設置:16×2顯示,5×7點陣,8位數據接口
 delaynms(5);                //延時5ms ,給硬件一點反應時間
    WriteInstruction(0x38);
 delaynms(5);               //延時5ms ,給硬件一點反應時間
 WriteInstruction(0x38);     //連續三次,確保初始化成功
 delaynms(5);               //延時5ms ,給硬件一點反應時間
 WriteInstruction(0x0c);     //顯示模式設置:顯示開,無光標,光標不閃爍
 delaynms(5);               //延時5ms ,給硬件一點反應時間
 WriteInstruction(0x06);     //顯示模式設置:光標右移,字符不移
 delaynms(5);                //延時5ms ,給硬件一點反應時間
 WriteInstruction(0x01);     //清屏幕指令,將以前的顯示內容清除
 delaynms(5);             //延時5ms ,給硬件一點反應時間
 }

/*****************************************************
函數功能:顯示電壓符號
***************************************************/   
void display_volt(void)
 {
    unsigned char i;
  WriteAddress(0x03);    //寫顯示地址,將在第2行第1列開始顯示
  i = 0;                //從第一個字符開始顯示
  while(Str[i] != '\0')  //只要沒有寫到結束標誌,就繼續寫
   {      
   WriteData(Str[i]);   //將字符常量寫入LCD
   i++;                 //指向下一個字符    
  } 
}
/*****************************************************
函數功能:顯示電壓的小數點
***************************************************/   
void  display_dot(void)
{         
  WriteAddress(0x09);   //寫顯示地址,將在第1行第10列開始顯示     
  WriteData('.');       //將小數點的字符常量寫入LCD  
}
/*****************************************************
函數功能:顯示電壓的單位(V)
***************************************************/   
void  display_V(void)
{
    WriteAddress(0x0c); //寫顯示地址,將在第2行第13列開始顯示 
  WriteData('V');     //將字符常量寫入LCD   
   
}
/*****************************************************
函數功能:顯示電壓的整數部分
入口參數:x
***************************************************/ 
void display1(unsigned char x)
{
 WriteAddress(0x08);    //寫顯示地址,將在第2行第7列開始顯示
 WriteData(digit[x]);    //將百位數字的字符常量寫入LCD
 }
/*****************************************************
函數功能:顯示電壓的小數數部分
入口參數:x
***************************************************/ 
 void display2(unsigned char x)
{
  unsigned char i,j;
 i=x/10;            //取十位(小數點後第一位)
 j=x%10;            //取個位(小數點後第二位)
   WriteAddress(0x0a);      //寫顯示地址,將在第1行第11列開始顯示
 WriteData(digit[i]);     //將小數部分的第一位數字字符常量寫入LCD
 WriteData(digit[j]);     //將小數部分的第一位數字字符常量寫入LCD
}
/*****************************************************
函數功能:將模擬信號轉換成數字信號
***************************************************/ 
unsigned char  A_D()
{
  unsigned char i,dat;
   CS=1;   //一個轉換週期開始
   CLK=0;  //爲第一個脈衝作準備
   CS=0;  //CS置0,片選有效
   DIO=1;    //DIO置1,規定的起始信號  
   CLK=1;   //第一個脈衝
   CLK=0;   //第一個脈衝的下降沿,此前DIO必須是高電平
   DIO=1;   //DIO置1, 通道選擇信號  
   CLK=1;   //第二個脈衝,第2、3個脈衝下沉之前,DI必須跟別輸入兩位數據用於選擇通道,這裏選通道CH0 
   CLK=0;   //第二個脈衝下降沿
    
   DIO=0;   //DI置0,選擇通道0
   CLK=1;    //第三個脈衝
   CLK=0;    //第三個脈衝下降沿
   DIO=1;    //第三個脈衝下沉之後,輸入端DIO失去作用,應置1
   CLK=1;    //第四個脈衝
   for(i=0;i<8;i++)  //高位在前
    {
      CLK=1;         //第四個脈衝
      CLK=0; 
      dat<<=1;       //將下面儲存的低位數據向右移
   dat|=(unsigned char)DIO;   //將輸出數據DIO通過或運算儲存在dat最低位 
    }             
    CS=1;          //片選無效 
  return dat;  //將讀書的數據返回     
  }
/*****************************************************
函數功能:主函數
***************************************************/ 
main(void)
{
  unsigned int AD_val;    //儲存A/D轉換後的值
  unsigned char Int,Dec;   //分別儲存轉換後的整數部分與小數部分
   LcdInitiate();         //將液晶初始化
   delaynms(5);           //延時5ms給硬件一點反應時間 
 display_volt();        //顯示溫度說明
   display_dot();         //顯示溫度的小數點
   display_V();           //顯示溫度的單位
   while(1)
      {
    AD_val= A_D();    //進行A/D轉換
    Int=(AD_val)/51;  //計算整數部分
    Dec=(AD_val%51)*100/51;    //計算小數部分
        display1(Int);     //顯示整數部分
    display2(Dec);     //顯示小數部分
    delaynms(250);     //延時250ms
  }
      
}
6、在proteus中新建仿真文件ex68.dsn,電路原理圖如下所示


7、將ex68.hex文件載入at89c51中,啓動仿真,觀察運行結果。下圖是某一時刻程序運行結果


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章