美文网首页
51总线方式获取adc0809数值

51总线方式获取adc0809数值

作者: greedyhao | 来源:发表于2018-11-27 22:29 被阅读0次

    最近单片机有一个实验挺有意思的,使用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;
    }

    相关文章

      网友评论

          本文标题:51总线方式获取adc0809数值

          本文链接:https://www.haomeiwen.com/subject/cjqoqqtx.html