51单片机和ADC0809配合时出现错误现象,求解
我使用的是HKD-MCS5X开发板,自己焊了一个ADC0809和一个电位计,电位计的中间抽头接到ADC0809的IN0上。单片机晶振12MHz。P3_0接Start和AL...
我使用的是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行不行。但我搜索了下,发现也有别人这么直接用。我会去试验一下! 展开
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行不行。但我搜索了下,发现也有别人这么直接用。我会去试验一下! 展开
4个回答
展开全部
你把adc的CLK接单片机的ALE 试试。
定时器 就 不用了。
我之前遇到的问题是这样的(可能和你有点不一样):
用proteus 仿真 是好的(也用的是定时器控制CLK)
但是,实际线路中,开机第一次转换是好的,接下来改变电位器就没反应了。
改变电位器后,再重启就又有一次好的(此时电位器的值)。
下面是我之前的提问:呵呵,希望对你有帮助!
http://zhidao.baidu.com/question/143979152.html
定时器 就 不用了。
我之前遇到的问题是这样的(可能和你有点不一样):
用proteus 仿真 是好的(也用的是定时器控制CLK)
但是,实际线路中,开机第一次转换是好的,接下来改变电位器就没反应了。
改变电位器后,再重启就又有一次好的(此时电位器的值)。
下面是我之前的提问:呵呵,希望对你有帮助!
http://zhidao.baidu.com/question/143979152.html
展开全部
不用那么麻烦 你落伍了 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);
}
#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);
}
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
你的程序应该判断是否AD完成!
现在的情况是有时候AD没有结束,你就把结果读进去了,所以会出现不规律的情况。增加一个if判断语句即可。
现在的情况是有时候AD没有结束,你就把结果读进去了,所以会出现不规律的情况。增加一个if判断语句即可。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
你用ALE作为时钟
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询