AD0808调试笔记

1.adc0808在采样期间 A2 A1 A0 是否保持不变

在ADC0808的采样期间,地址线A2、A1、A0是必须保持不变的。这是一个关键点,理解它需要先弄清ADC0808的工作原理。

ADC0808在采样和转换期间,只负责将已经选中的某一路模拟信号转换为数字值,不具备自动切换通道的功能。所以在转换期间改变地址线状态,很可能导致结果出错。

核心原因:地址锁存机制

ADC0808的设计,决定了地址线只在特定时刻被读取,之后不再响应其变化:

  • 地址锁存信号 (ALE) :有一个专门的ALE(地址锁存允许)引脚,地址线(ADD A, B, C)的状态就是在**ALE引脚上升沿**这一瞬间,被锁存(记住)的。

  • 锁存后不再响应:一旦地址被锁存,内部的多路复用开关就固定连接到了对应的模拟输入通道。此后,无论地址线怎么变化,都不会影响正在进行的转换过程。这种设计也叫"写时选通"

2.一次完整的工作流程

你可以参考这个标准流程来编写代码,确保采样正确:

  1. 设置地址 :代码先把想采样的通道地址(A2, A1, A0)送到地址线上。

  2. 锁存地址(ALE高电平) :紧接着给ALE引脚一个正脉冲(高电平)。在脉冲的上升沿,地址被锁存到芯片内部,选定输入通道。

  3. 启动转换(启动正脉冲) :紧接着给START引脚一个至少100ns宽的正脉冲。其下降沿启动A/D转换。

  4. 等待转换完成 :转换期间,EOC(转换结束)引脚为低电平

  5. 读取结果 :等待EOC变高后,给OE(输出允许)引脚一个高电平,此时就能从D0-D7引脚读到转换好的数字量了。

  6. 切换下一通道:重复以上步骤,进行下一路采样。

示例代码:

cpp 复制代码
/*----------------------------------------------------------
 程序名称:ADC0808 电压采集与数码管显示(C语言版)
 硬件平台:8088 单板机 + ADC0808 + 8255
 功能描述:采集 IN0 通道电压,转换为数字量后计算电压值,
           通过 4 位数码管动态显示(单位:0.01V)
----------------------------------------------------------*/

#include <dos.h>
#include <conio.h>

/* 端口地址定义(根据实际硬件连接修改) */
#define ADC_BASE    0x80    /* ADC0808 片选端口(WR启动,RD读取) */
#define ADC_EOC     0x82    /* EOC 状态查询端口(bit0=1 表示转换完成) */
#define DISP_SEG    0x88    /* 数码管段码输出端口(8255 PA口) */
#define DISP_BIT    0x8A    /* 数码管位选输出端口(8255 PB口) */
#define CTRL_8255   0x8C    /* 8255 控制端口 */

/* 共阴数码管段码表(0-9) */
unsigned char code SegCode[10] = {
    0x3F, 0x06, 0x5B, 0x4F, 0x66,
    0x6D, 0x7D, 0x07, 0x7F, 0x6F
};

unsigned char AdcValue;     /* ADC 原始值 0~255 */
unsigned int  Voltage;       /* 电压值(单位:0.01V),例如 500 = 5.00V */

/* 函数声明 */
void Init8255(void);
unsigned char ReadADC(unsigned char channel);
void DisplayVoltage(unsigned int voltage);
void Delay(unsigned int count);
void DelayShort(void);

/*----------------------------------------------------------
 主函数
----------------------------------------------------------*/
void main(void)
{
    Init8255();                     /* 初始化 8255 */
    
    while (!kbhit())                /* 按任意键退出循环 */
    {
        AdcValue = ReadADC(0);      /* 读取通道 IN0 */
        
        /* 电压换算公式:
           Voltage(0.01V) = (AdcValue * 500) / 256
           500 = 5.00V × 100 (转换为 0.01V 单位)
        */
        Voltage = (unsigned int)((unsigned long)AdcValue * 500 / 256);
        
        DisplayVoltage(Voltage);    /* 数码管显示电压值 */
        
        Delay(0xFFFF);              /* 采样间隔控制 */
    }
}

/*----------------------------------------------------------
 8255 初始化:方式0,PA/PB 输出,PC 输入
----------------------------------------------------------*/
void Init8255(void)
{
    outp(CTRL_8255, 0x82);    /* 10000010B */
}

/*----------------------------------------------------------
 读取指定 ADC 通道的转换结果(查询方式)
 参数:channel = 0~7(选择 IN0~IN7)
 返回:8 位 ADC 值(0~255)
----------------------------------------------------------*/
unsigned char ReadADC(unsigned char channel)
{
    unsigned char result;
    
    /* 1. 启动 ADC0808 转换 */
    /* 注意:通道选择需通过 A、B、C 地址线实现,
       这里简化处理,假设通道由硬件连线固定为 IN0 */
    outp(ADC_BASE, 0x00);           /* 写任意数据产生 START 脉冲 */
    
    /* 2. 等待 EOC 变高(转换完成) */
    while ((inp(ADC_EOC) & 0x01) == 0)
        ;                           /* 循环查询 */
    
    /* 3. 读取转换结果 */
    result = inp(ADC_BASE);
    
    return result;
}

/*----------------------------------------------------------
 数码管动态显示电压值(4 位显示,范围 0.00V ~ 5.00V)
 输入:voltage(单位 0.01V,例如 500 表示 5.00V)
----------------------------------------------------------*/
void DisplayVoltage(unsigned int voltage)
{
    unsigned char digit[4];         /* 存储 4 位显示数字 */
    unsigned char i;
    unsigned int temp;
    
    /* 拆分 voltage 为 4 位数字
       例如 voltage = 500
       digit[0] = 5   (整数部分)
       digit[1] = 0   (小数第一位)
       digit[2] = 0   (小数第二位)
       digit[3] = 0   (未使用,显示 0 或不显示)
    */
    digit[0] = voltage / 100;       /* 百位(整数部分 0~5) */
    temp = voltage % 100;
    digit[1] = temp / 10;           /* 十位(小数第一位) */
    digit[2] = temp % 10;           /* 个位(小数第二位) */
    digit[3] = 0;                   /* 第四位可显示单位 'U' 或熄灭 */
    
    /* 动态扫描显示(每位显示约 2ms) */
    for (i = 0; i < 4; i++)
    {
        /* 输出段码 */
        outp(DISP_SEG, SegCode[digit[i]]);
        
        /* 输出位选(假设共阴数码管,高电平选通) */
        outp(DISP_BIT, (unsigned char)(1 << i));
        
        DelayShort();               /* 短暂延时保持显示 */
        
        /* 消隐(可选,防止重影) */
        outp(DISP_SEG, 0x00);
    }
}

/*----------------------------------------------------------
 长延时函数(用于控制采样频率)
----------------------------------------------------------*/
void Delay(unsigned int count)
{
    unsigned int i;
    for (i = 0; i < count; i++)
        ;                           /* 空循环延时 */
}

/*----------------------------------------------------------
 短延时函数(用于数码管扫描)
----------------------------------------------------------*/
void DelayShort(void)
{
    unsigned int i;
    for (i = 0; i < 100; i++)
        ;
}

3.特殊情况:无内置采样保持的局限

ADC0808芯片内部没有集成采样保持电路 ,如果输入信号变化很快,会导致转换结果不准确。应用中通常需要外接采样保持电路 ,或确保输入信号在整个转换期间(约100μs)都保持稳定

4.信号输入端不能悬空,否则乱码

相关推荐
木子单片机3 小时前
基于51单片机的步进电机调速系统设计
单片机·嵌入式硬件·51单片机·keil
三易串口屏4 小时前
实验10 物理按键实验
单片机·51单片机·串口屏·串口协议·uart 通信·嵌入式 ui
深圳光特通信豆子4 小时前
10Mb/s TTL单模双纤光收发模块技术规格手册
单片机·嵌入式硬件
潜创微科技4 小时前
IT6635+USB 芯片:4 进 1 出 4K@60Hz 高性能 KVM 切换器一站式方案
嵌入式硬件·音视频
sakiko_4 小时前
Swift学习笔记31-网络请求
网络·笔记·学习·swift
一路往蓝-Anbo4 小时前
第六章:RTOS 任务 —— 任务逻辑与并发的 TDD 路径
网络·stm32·单片机·嵌入式硬件·tdd
夜雪闻竹4 小时前
nomic-embed-text vs text-embedding-3-small 横评
笔记·embedding
星夜夏空994 小时前
STM32单片机学习(20) —— 利用中断实现串口通信(填前面的坑)
stm32·单片机·学习
wengqidaifeng4 小时前
2026年电赛校赛备战MSPM0G3507+keil讲解(上)-----2025年电赛E题小车篇
单片机·嵌入式硬件·电赛