1.adc0808在采样期间 A2 A1 A0 是否保持不变
在ADC0808的采样期间,地址线A2、A1、A0是必须保持不变的。这是一个关键点,理解它需要先弄清ADC0808的工作原理。
ADC0808在采样和转换期间,只负责将已经选中的某一路模拟信号转换为数字值,不具备自动切换通道的功能。所以在转换期间改变地址线状态,很可能导致结果出错。
核心原因:地址锁存机制
ADC0808的设计,决定了地址线只在特定时刻被读取,之后不再响应其变化:
-
地址锁存信号 (ALE) :有一个专门的
ALE(地址锁存允许)引脚,地址线(ADD A, B, C)的状态就是在**ALE引脚上升沿**这一瞬间,被锁存(记住)的。 -
锁存后不再响应:一旦地址被锁存,内部的多路复用开关就固定连接到了对应的模拟输入通道。此后,无论地址线怎么变化,都不会影响正在进行的转换过程。这种设计也叫"写时选通"
2.一次完整的工作流程
你可以参考这个标准流程来编写代码,确保采样正确:
-
设置地址 :代码先把想采样的通道地址(
A2, A1, A0)送到地址线上。 -
锁存地址(ALE高电平) :紧接着给
ALE引脚一个正脉冲(高电平)。在脉冲的上升沿,地址被锁存到芯片内部,选定输入通道。 -
启动转换(启动正脉冲) :紧接着给
START引脚一个至少100ns宽的正脉冲。其下降沿启动A/D转换。 -
等待转换完成 :转换期间,
EOC(转换结束)引脚为低电平。 -
读取结果 :等待
EOC变高后,给OE(输出允许)引脚一个高电平,此时就能从D0-D7引脚读到转换好的数字量了。 -
切换下一通道:重复以上步骤,进行下一路采样。
示例代码:
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)都保持稳定。
