51单片机和ADC0809配合时出现错误现象,求解

我使用的是HKD-MCS5X开发板,自己焊了一个ADC0809和一个电位计,电位计的中间抽头接到ADC0809的IN0上。单片机晶振12MHz。

P3_0接Start和ALE;P3_1接OE;P3_2接EOC;P3_3接CLK(使用单片机内部定时器产生500KHz的方波);P1口接AD的输出。

我现在试验的一个程序,是要从AD上采样一个数据,将这个数据换算成延时的计数,进而让P0^0控制的Led灯能变化频率的闪烁。灯每闪三下自动重新采样数据。

现在出现的问题是这样:

有时可以正常出现灯闪烁的实验现象,但当将电位计转一下后,再采样时单片机卡死,开发板上数码管保持一个混乱效果(这个我觉得是因为这个开发板上P1口是控制数码管的,程序卡死在了AD输出的环节),反复插拔电源线和重新按板子上的Power才可以恢复正常。
但正常现象的时候,旋动电位计,得到的闪烁频率也并不是预期的线性变化。电位计电压从0到最大的过程中,灯闪的频率从较快到较慢再较快。有时甚至觉得有些混乱。不知原因。

以下是我的源程序,望高手解惑

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char

uchar ADResult;
uchar n;
sbit P00=P0^0;
sbit ST=P3^0;
sbit OE=P3^1;
sbit EOC=P3^2;
sbit ADCLK=P3^3;

unsigned char ADConvert(void)
{
ADCLK=0;
ST=0;
OE=0;
//初始化ADC0809时钟信号中断设置
EA=1;
ET0=1;
TMOD=0x01;
TH0=(65536-1)/256;
TL0=(65536-1)%256;
TR0=1;
//开始转换
ST=1;
ST=0;
while(EOC==1){}
while(EOC==0){}
OE=1;
ADResult=P1;
OE=0;
ST=1;
ST=0;
return(ADResult);
}

void AD_CLK(void) interrupt 1 using 1
{
ADCLK=!ADCLK;
TH0=(65536-1)/256;
TL0=(65536-1)%256;
}

void LedDelay(uint i)//延时程序,i是时间参数
{
uint j=200;
for(;i>0;i--)
{
for(j=125;j>0;j--);
}
}

void main(void)
{
uchar k;
for(;;)
{
n=ADConvert();
n=3*n;
for(k=0;k<3;k++)
{
P00=0; //单片机内部给p00脚加低电平,关闭小灯
LedDelay(n);
P00=1; //单片机内部给p00脚加高电平,点亮小灯
LedDelay(n);
}
}
}
我知道有带AD的开发板……只是那些都比较贵,没有合适的。就买的相对便宜的然后自己焊的AD。1L的程序好像和我的问题没有什么关系吧

2L说的判断是否完成,我是用while(EOC==0)那句来实现的。因为0809开始转换后EOC是从1掉到0的,当转换完成后EOC再回到1.

感谢3L的建议!我的fosc是12MHz,那ALE就得2MHz,不知道接0809行不行。但我搜索了下,发现也有别人这么直接用。我会去试验一下!

你把adc的CLK接单片机的ALE 试试。
定时器 就 不用了。
我之前遇到的问题是这样的(可能和你有点不一样):
用proteus 仿真 是好的(也用的是定时器控制CLK)
但是,实际线路中,开机第一次转换是好的,接下来改变电位器就没反应了。
改变电位器后,再重启就又有一次好的(此时电位器的值)。

下面是我之前的提问:呵呵,希望对你有帮助!
http://zhidao.baidu.com/question/143979152.html
温馨提示:内容为网友见解,仅供参考
第1个回答  2010-04-12
不用那么麻烦 你落伍了 STC12系列就自带AD转换
#include <intrins.H>
#include <STC_NEW_8051.H>
#define uchar unsigned char
#define uint unsigned int
#include <1602.h>
#include <rs232.h>
#include <EEPROM.h>
int ADC_data[10];
sbit key=P3^2;
sbit Rxd=P3^0;
sbit Txd=P3^1;
uint ADC_data_avr;
uint ADC_data_sum;
uchar ADC_data_avr_miao,ADC_data_avr_fen,ADC_data_avr_ge;
void main()
{
uchar i;
lcdinit();
lcddisplaytable(0x80," Last Result",14);
EEPROM_Read();
initiate_RS232();
P1ASF=0xff;
ADC_CONTR=0x80;
while(1)
{
while(key==0)
{
lcddisplaytable(0x80," Result ",14);
ADC_data_sum=0;
for(i=0;i<10;i++)
{
ADC_CONTR=0xe8;
while(!(ADC_CONTR & 0x10));
ADC_CONTR=0xe0;
ADC_RESL=ADC_RESL & 0x03;
ADC_data[i]=(ADC_RES<<2)+ADC_RESL;
ADC_data_sum=ADC_data_sum+ADC_data[i];
}
ADC_data_avr=ADC_data_sum/10;
lcddisplaytable(0x80+0x40,"Average=",8);
ADC_data_avr_ge=ADC_data_avr*5/1024;
lcddisplay(0x88+0x40,ADC_data_avr_ge+48);
lcddisplay(0x89+0x40,'.');
ADC_data_avr_fen=(ADC_data_avr*50/1024)%10 ;
lcddisplay(0x8a+0x40,ADC_data_avr_fen+48);
ADC_data_avr_miao=(ADC_data_avr*50/102)%10;
lcddisplay(0x8b+0x40,ADC_data_avr_miao+48);
lcddisplay(0x8c+0x40,'V');
rs232_send(ADC_data_avr_ge,'.',ADC_data_avr_fen,ADC_data_avr_miao);
EEPROM_write(ADC_data_avr_ge,ADC_data_avr_fen,ADC_data_avr_miao);
key=1;
delay_1ms(1000);
}
}
}

#define Fosc 11071690// 22118400
#define BAUD 115200 //波特率
#define RELOAD_115200 (256 - (Fosc/16*10/BAUD+5)/10 ) //1T模式, 波特率加倍
#define BRTx12_enable() AUXR |= 0x04 //BRT 独立波特率发生器的溢出率快 12 倍
#define BRT_start() AUXR |= 0x10 //启动独立波特率发生器 BRT 计数。
void initiate_RS232 (void) //串口初始化
{
ES = 0; //禁止串口中断
SCON = 0x50; //可变波特率. 8位无奇偶校验
AUXR |= 0x01; //使用独立波特率发生器
PCON |= 0x80; //波特率加倍
BRTx12_enable(); //BRT 独立波特率发生器的溢出率快 12 倍
BRT = RELOAD_115200; //设置独立波特率发生器 BRT 的自动重装数
BRT_start(); //启动独立波特率发生器 BRT 计数。
ES = 1;
}
//---------------------------------------------------------------------
void Send_Byte(uchar one_byte) //发送一个字节
{
TI = 0; //清零串口发送中断标志
SBUF = one_byte;
while (TI == 0);
TI = 0; //清零串口发送中断标志
}
void rs232_send(uchar ge,uchar dian,uchar fen,uchar miao)
{
Send_Byte(ge);
Send_Byte(dian);
Send_Byte(fen);
Send_Byte(miao);
}
第2个回答  2010-04-12
你的程序应该判断是否AD完成!
现在的情况是有时候AD没有结束,你就把结果读进去了,所以会出现不规律的情况。增加一个if判断语句即可。
第3个回答  2010-04-13
你用ALE作为时钟

51单片机和ADC0809配合时出现错误现象,求解
你把adc的CLK接单片机的ALE 试试。定时器 就 不用了。我之前遇到的问题是这样的(可能和你有点不一样):用proteus 仿真 是好的(也用的是定时器控制CLK)但是,实际线路中,开机第一次转换是好的,接下来改变电位器就没反应了。改变电位器后,再重启就又有一次好的(此时电位器的值)。下面是...

用51单片机和ADC0809做电压表如图连接能仿真,为什么焊接出来有错,数码...
1、有可能是你的程序写的有误,仿真是一回事,真正运行是另一回事。2、如果你是完全按照图上焊接的,你这个板子其实是不稳定的,为什么呢,因为单片机直接驱动数码管是不够力的,虽然你用的是P0口,但是驱动数码管也很费力,如果你需要帮忙,可以百度Hi联系我 ...

adc0809转换的一些问题(与51单片机配合)
1 、地址是人为定义的,在51单片机中P0口是低位地址8位与数据口8位分时复用,所有连接在地址总线上的器件,都必须有一个地址区间(地址块),例如,RAM 62256需要32Kbyte,0000H--7FFFH,就是一个片选信号。ad转换器需要一个,经过地址译码器,译码后的“区间”,即储存器的片选信号,译码器可以分成...

我这个51单片机AD转换电路错在哪里呢,怎么老是运行不起
仿真图中,用单片机的ALE输出信号,又用D触发器分频后送到ADC0809上,要是实物这种做法还可以。但是,用proteus 仿真就不行了,单片机的ALE是没有信号输出的,所以ADC电路无时钟信号。其实,仿真时,可以直接用时钟信号的,在proteus 左边工具栏中选信号源,就是S字母那个,从中选DCLOCK,就是时钟脉冲信...

基于51单片机和ADC0809做的数字电压表,为什么测一节干电池的电压比1.5...
原因可能有两点:AD转换器的参考电压有偏差, 实际值比理论值要低, 也许就是参考电压低于5V 是电池电压比较高, 电池的特点是电量满时或无负载时电压比较高, 输出电压会随着放电时间而降低, 就像手机锂电池, 充满电时是4.2V, 放完电差不多在3.3V左右.你可以用电压表测试量一下AD转换器的参考电压...

ADC0809与单片机接线,为什么ADC0809的地址是7FF8H?
对于一种A\/D转换其来说,转换时间作为一项技术指标是已知的和固定的。例如ADC0809转换时间为128μs,相当于6MHz的MCS-51单片机共64个机器周期。可据此设计一个延时子程序,A\/D转换启动后即调用此子程序,延迟时间一到,转换肯定已经完成了,接着就可进行数据传送。(2)查询方式 A\/D转换芯片由表明转换...

8051单片机和ADC0809 连接的C语言编程
也可以将ADC0809的完成引脚接到单片机的外部中断引脚上,这样就可以在中断中读取.代码自己找下吧,网上很多的.这个给你参考:define voldata P2 sbit adra=P0^0;sbit adrb=P0^1;sbit adrc=P0^2;sbit ale=P0^3;sbit st=P0^4;sbit eoc=P0^5;sbit oe=P0^6;unsigned char getvol(unsigned char ...

两片adc0809怎样与mcs51单片机连接组成16位数据采集器
adc0809本身是8位的A\/D转换器,两片不论怎么接也不可能组成16位的数据采集器的,只能再增加8个通道,共16个通道。但与16位是两个概念。举个例子吧,两个1.6米的人,你怎么才能把他们两个人变成3.2米的人呢?这是不可能的,这是一个道理。

江湖告急:急求ADC0809数模转换器与51单片机的接法! 最主要的是给出辅 ...
你自己看清楚,三角形的电源都是5V.每个管脚外面都有数字,找对应的好了。这个电路完全可以工作,你可以参考彭伟老师的《单片机C语言程序设计实训——基于8051+proteus仿真》一书,程序代码、电路那里都有。

ADC0809与8051单片机接口有哪些控制信号?作用分别是什么?
先看ADC0809的资料:ADC0809芯片有28条引脚,采用双列直插式封装,下面说明各引脚功能。 IN0~IN7:8路模拟量输入端。2-1~2-8:8位数字量输出端。ADDA、ADDB、ADDC:3位地址输入线,用于选通8路模拟输入中的一路 ALE:地址锁存允许信号,输入,高电平有效。START: A/D转换启动脉冲输入端...

相似回答