51匯流排方式獲取adc0809數值

weixin_33749242發表於2018-11-27

最近微控制器有一個實驗挺有意思的,使用51微控制器以匯流排的方式讀取adc0809的資料

先補充點關於微控制器匯流排的預備知識,我一開始不瞭解匯流排的時候做這個實驗也是很懵逼的。

微控制器的三匯流排結構

51微控制器有三條匯流排:資料匯流排、地址匯流排、控制匯流排

從圖中可以看出,8位資料匯流排由P0組成,16位地址匯流排由P0和P2組成,控制匯流排由P3和相關引腳組成

採用匯流排的方式可以簡化程式設計,節省I/O口,便於外設擴充套件

但是資料口和地址口在P0是怎麼複用的呢,這就需要看到時序了

從圖中可以看出,P0口是資料/地址分時複用的,這是P0口內部的複用結構完成的

實操練習

51微控制器與adc0809接線原理圖如下

解釋電路

P2.7口用作adc0809的選擇線

P0.0~P0.2所接的A B C是adc0809的IN0通道選擇線

接下來就是計算adc0809的地址了

P2 P0

0xxx xxxx xxxx x000

因此地址為0x7ff8

遇到的問題

本來應該顯示5v的位置只顯示1.144v,而且在電阻增大的過程中,顯示的值先減小後增大又減小,具體情況如圖

實在沒有辦法的情況下,借別的同學的程式碼來看,沒發現自己的程式在時序、地址上的錯誤。

琢磨了微控制器的數值變換的現象後,突然覺得是不是儲存ad轉換數值的變數溢位了,然後就發現我的變數型別是int,而別人的變數型別是long int

在將儲存ad轉換的變數型別修改過後,程式就執行正常了

程式程式碼

#include <reg51.h>
#include <absacc.h>

typedef unsigned char uchar;
typedef unsigned int uint8;
typedef unsigned long int uint16;

uchar led_mod[] = {    0x3f,0x06,0x5b,0x4f,    //!< 數碼管編碼
                    0x66,0x6d,0x7d,0x07,    
                    0x7f,0x6f,0x77,0x7c,
                    0x39,0x5e,0x79,0x71};

#define AD_IN0 XBYTE [0x7ff8]

sbit EOC = P3^5;
sbit CLK = P3^3;

sbit seg1 = P2^0;
sbit seg2 = P2^1;
sbit seg3 = P2^2;
sbit seg4 = P2^3;

uint16 adc_data = 0;    //> 儲存ad轉換結果

/**
 * @brief 延遲函式
 * 
 */

void delay_ms(uint8 time)
{
    uint8 j;
    for (; time>0; time--)
    {
        for(j=114; j>0; j--);
    }
}

/**
 * @brief 定時器初始化
 * 
 */

void timer_init(void)
{
    TMOD |= 0x02;                                                   
    TH0 = 200;          //> 產生方波週期2us           
    TL0 = 200;                              

    ET0 = 1;                                      
    TR0 = 1;                                      
}

/**
 * @brief 數碼管動態顯示函式
 * 
 */

void display(void)
{
    adc_data = adc_data*1000/51;                //> 解析度為5/256約為1/51
    P1 = 0x00;
    P1 = led_mod[adc_data/1000]|0x80;
    seg1 = 0;
    delay_ms(2);
    seg1 = 1;
    P1 = 0x00;
    P1 = led_mod[(adc_data%1000)/100];
    seg2 = 0;
    delay_ms(2);
    seg2 = 1;
    P1 = 0x00;
    P1 = led_mod[(adc_data%100)/10];
    seg3 = 0;
    delay_ms(2);
    seg3 = 1;
    P1 = 0x00;
    P1 = led_mod[adc_data%10];
    seg4 = 0;
    delay_ms(2);
    seg4 = 1;
}

void main()
{
    timer_init();
    EA = 1;
    while(1)
    {
        AD_IN0 = 0;
        while(EOC == 0);
        adc_data = AD_IN0;
        display();
    }
}

/**
 * @brief 產生時鐘週期
 * 
 */

void timer0() interrupt 1                   
{
    CLK = ~CLK;
}




相關文章