李鸿鸿 发表于 2012-12-2 16:22:54

求最简单的A/D转换程序

本人刚学单片机不久,自学《十天学会单片机和C语言》,现在学到A/D,D/A转换,这方面想了大半天都看不懂例程序,求最简单的A/D转换程序,要加说明

jcrorxp 发表于 2012-12-2 16:35:56

你还不如 贴上来让我们给你解释解释,

tian_cn 发表于 2012-12-2 16:38:39

如果是用STC带AD的,最简单了,手册里就是有,我用STC12C5A系列,手册里提供了两种方法,中断及查询法。
附手册:
http://www.stcmcu.com/datasheet/stc/STC-AD-PDF/STC12C5A60S2.pdf

李鸿鸿 发表于 2012-12-2 16:47:30

jcrorxp 发表于 2012-12-2 16:35 static/image/common/back.gif
你还不如 贴上来让我们给你解释解释,

#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit adwr=P3^6;          //wr端口
sbit adrd=P3^7;          //rd端口
uint i,j;
uchar s;
uchar k,m,n;
uchar code a[]={0x03,0x9f,0x25,0x0d,0x99,
                0x49,0x41,0x1f,0x01,0x09};
void delay(uint x)
{
   for(i=x;i>0;i--)
      for(j=120;j>0;j--);
}
void xianshi(uchar k);//显示数码管
void main()
{
   P2=0xff;
   while(1)
   {
      
      adwr=1;
          _nop_();
          adwr=0;
          _nop_();
          m=P1;
          adwr=1;
          for(s=0;s<20;s++)
          {
             xianshi(n);
          }
          P1=0xff;
          adrd=1;
          _nop_();
          adrd=0;
          _nop_();
          m=P1;
          adrd=1;
          n=m%10;
   }
}
void xianshi(uchar k)
{
   P2=0x00;
   P0=a;
   delay(1);
   P2=0xff;
   P0=0xff;
}
上面的程序是调节电位器可改变数码管的显示,但这程序不能,这程序是本人写的,仿照例题写的,出了一大堆问题,数码管只显示微弱光线的5字

李鸿鸿 发表于 2012-12-2 16:48:53

李鸿鸿 发表于 2012-12-2 16:47 static/image/common/back.gif
#include
#include
#define uint unsigned int


调节电位器一点作用都没有

李鸿鸿 发表于 2012-12-2 16:51:40

tian_cn 发表于 2012-12-2 16:38 static/image/common/back.gif
如果是用STC带AD的,最简单了,手册里就是有,我用STC12C5A系列,手册里提供了两种方法,中断及查询法。
附 ...

我用的是STC89C52单片机,PCF8591转换芯片的

xyz543 发表于 2012-12-2 16:22:55

楼主您要找的资料应该是这个 http://115.com/file/cl00dl9y#

william_rain 发表于 2012-12-2 20:18:51

LZ

PCF8591 是IIC总线的AD

你的程序用的是ADC0804

Tliang 发表于 2012-12-2 21:31:36

PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I2C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。

Tliang 发表于 2012-12-2 21:33:06

善用google,百度

李鸿鸿 发表于 2012-12-2 21:40:26

william_rain 发表于 2012-12-2 20:18 static/image/common/back.gif
LZ

PCF8591 是IIC总线的AD


高手就是高手!换成PCF8591怎么用呢?

李鸿鸿 发表于 2012-12-2 21:42:29

Tliang 发表于 2012-12-2 21:31 static/image/common/back.gif
PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出 ...

那么这个程序怎么改呢?

Tliang 发表于 2012-12-2 21:45:29

李鸿鸿 发表于 2012-12-2 21:42 static/image/common/back.gif
那么这个程序怎么改呢?

你先看IIC协议,在看芯片数据手册就可以写出来了。//-----------------------函数声明,变量定义--------------------------------------------------------
#include <reg51.h>
#include <intrins.h>
sbit SDA=P2^1;                        // 将p1.0口模拟数据口
sbit SCL=P2^0;                        // 将p1.1口模拟时钟口
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};                  
bit   bdata SystemError;                // 从机错误标志位
//-----------------------PCF8591专用变量定义--------------------------------------------------------
#define PCF8591_WRITE 0x90
#define PCF8591_READ0x91
#defineNUM4                      // 接收和发送缓存区的深度
unsigned char idata receivebuf;    // 数据接收缓冲区
//--------------------------------------------------------------------------------------------------
// 函数名称: iic_start()
// 函数功能: 启动I2C总线子程序
//--------------------------------------------------------------------------------------------------
void iic_start(void)
{EA=0;            //时钟保持高,数据线从高到低一次跳变,I2C通信开始
SDA = 1;         
SCL = 1;
delayNOP();      // 延时5us
SDA = 0;
delayNOP();
SCL = 0;
}
//--------------------------------------------------------------------------------------------------
// 函数名称: iic_stop()
// 函数功能: 停止I2C总线数据传送子程序
//--------------------------------------------------------------------------------------------------
void iic_stop(void)
{
SDA = 0;       //时钟保持高,数据线从低到高一次跳变,I2C通信停止
SCL = 1;
delayNOP();
SDA = 1;
delayNOP();
SCL = 0;
}
//--------------------------------------------------------------------------------------------------
// 函数名称: slave_ACK
// 函数功能: 从机发送应答位子程序
//--------------------------------------------------------------------------------------------------
void slave_ACK(void)
{
SDA = 0;   
SCL = 1;
delayNOP();   
SDA = 1;
SCL = 0;
}
//--------------------------------------------------------------------------------------------------
// 函数名称: slave_NOACK
// 函数功能: 从机发送非应答位子程序,迫使数据传输过程结束
//--------------------------------------------------------------------------------------------------
void slave_NOACK(void)
{
SDA = 1;   
SCL = 1;
delayNOP();
SDA = 0;
SCL = 0;
}
//--------------------------------------------------------------------------------------------------
// 函数名称: check_ACK
// 函数功能: 主机应答位检查子程序,迫使数据传输过程结束
//--------------------------------------------------------------------------------------------------
void check_ACK(void)
{
SDA = 1;      // 将p1.0设置成输入,必须先向端口写1
SCL = 1;
F0 = 0;
if(SDA == 1)    // 若SDA=1表明非应答,置位非应答标志F0
F0 = 1;
SCL = 0;
}

//--------------------------------------------------------------------------------------------------
// 函数名称: IICSendByte
// 入口参数: ch
// 函数功能: 发送一个字节
//--------------------------------------------------------------------------------------------------
void IICSendByte(unsigned char ch)
{
unsigned char idata n=8;   // 向SDA上发送一位数据字节,共八位
while(n--)
{
if((ch&0x80) == 0x80)    // 若要发送的数据最高位为1则发送位1
{
   SDA = 1;    // 传送位1
   SCL = 1;
   delayNOP();
   SDA = 0;
   SCL = 0;   
}
else
{
   SDA = 0;    // 否则传送位0
   SCL = 1;
   delayNOP();
   SCL = 0;
}
ch = ch<<1;    // 数据左移一位
}
}
//--------------------------------------------------------------------------------------------------
// 函数名称: IICreceiveByte
// 返回接收的数据
// 函数功能: 接收一字节子程序
//--------------------------------------------------------------------------------------------------
unsigned char IICreceiveByte(void)
{
unsigned char idata n=8;    // 从SDA线上读取一上数据字节,共八位
unsigned char tdata;
while(n--)
{
SDA = 1;
SCL = 1;
tdata = tdata<<1;    // 左移一位,或_crol_(temp,1)
if(SDA == 1)
   tdata = tdata|0x01;    // 若接收到的位为1,则数据的最后一位置1
else
   tdata = tdata&0xfe;    // 否则数据的最后一位置0
SCL=0;
}
return(tdata);
}
//--------------------------------------------------------------------------------------------------
// 函数名称: DAC_PCF8591
// 入口参数: slave_add从机地址,n要发送的数据个数
// 函数功能: 发送n位数据子程序
//--------------------------------------------------------------------------------------------------
void DAC_PCF8591(unsigned char controlbyte,unsigned char wdata)
{   
iic_start();                // 启动I2C
IICSendByte(PCF8591_WRITE);   // 发送地址位
check_ACK();                // 检查应答位
    if(F0 == 1)
{
SystemError = 1;
return;    // 若非应答表明器件错误或已坏,置错误标志位SystemError
}
    IICSendByte(controlbyte&0x77); //Control byte
check_ACK();                // 检查应答位
    if(F0 == 1)
{
SystemError = 1;
return;    // 若非应答表明器件错误或已坏,置错误标志位SystemError
}
   IICSendByte(wdata); //data byte
check_ACK();                // 检查应答位
    if(F0 == 1)
{
SystemError = 1;
return;    // 若非应答表明器件错误或已坏,置错误标志位SystemError
}
iic_stop();         // 全部发完则停止
delayNOP();
delayNOP();
delayNOP();
delayNOP();
}
//--------------------------------------------------------------------------------------------------
// 函数名称: ADC_PCF8591
// 入口参数: controlbyte控制字
// 函数功能: 连续读入4路通道的A/D转换结果到receivebuf
//--------------------------------------------------------------------------------------------------
void ADC_PCF8591(unsigned char controlbyte)
{
    unsigned char idata receive_da,i=0;
iic_start();
IICSendByte(PCF8591_WRITE); //控制字
check_ACK();
if(F0 == 1)
{
SystemError = 1;
return;
}
IICSendByte(controlbyte); //控制字
check_ACK();
if(F0 == 1)
{
SystemError = 1;
return;
}
    iic_start();   //重新发送开始命令
    IICSendByte(PCF8591_READ); //控制字
check_ACK();
if(F0 == 1)
{
SystemError = 1;
return;
}
while(i<4)
{
receive_da=IICreceiveByte();
receivebuf=receive_da;
slave_ACK();    // 收到一个字节后发送一个应答位
}
slave_NOACK();    // 收到最后一个字节后发送一个非应答位
iic_stop();
}
//--------------------------------------------------------------------------------------------------
// 函数名称: main
// 函数功能: 主程序
//--------------------------------------------------------------------------------------------------
void main(void)
{
DAC_PCF8591(0x40,0); //控制字为0100 0000,允许模拟量输出
while(1);                     //零值点输出测试
DAC_PCF8591(0x40,0xff); //控制字为0100 0000,允许模拟量输出
                     //满值点输入测试
ADC_PCF8591(0x40);
}











从网上下的。能不能用我不知道。一百度就出来了

wsy2012 发表于 2012-12-2 22:23:31

如果楼主用STC的话可以看看这个:
http://www.doyoung.net/program/ADC/index.html
具体可以上STC的官网看看:
http://www.mcu-memory.com/
(千万不要在吃饭时看,这个官网的样子让人很无语)

xyz543 发表于 2012-12-3 11:05:08

wsy2012 发表于 2012-12-2 22:23 static/image/common/back.gif
如果楼主用STC的话可以看看这个:
http://www.doyoung.net/program/ADC/index.html
具体可以上STC的官网看看 ...

"千万不要在吃饭时看,这个官网的样子让人很无语" ,顶楼上的这句话,哈!~ {:lol:}

mjh630 发表于 2012-12-3 11:30:53

Tliang 发表于 2012-12-2 21:45 static/image/common/back.gif
你先看IIC协议,在看芯片数据手册就可以写出来了。从网上下的。能不能用我不知道。一百度就出来了 ...

你这个代码让楼主刚学单片机的人,啃上一个月了,人家都被 你吓傻了!还IIC,人家说的是AD,DA,你说什么别的

Tliang 发表于 2012-12-3 11:35:44

mjh630 发表于 2012-12-3 11:30 static/image/common/back.gif
你这个代码让楼主刚学单片机的人,啃上一个月了,人家都被 你吓傻了!还IIC,人家说的是AD,DA,你说什么别的
...

拜托,你先看别人用的什么东西再发言OK。。
你牛逼你教会楼主不要IIC来控制这个芯片啊。

jhjh630 发表于 2012-12-3 11:37:26

把你的例句和你的的程序一起发给我,我帮你看下,看能不能帮你的忙!QQ:290412297

李鸿鸿 发表于 2012-12-3 12:26:37

jhjh630 发表于 2012-12-3 11:37 static/image/common/back.gif
把你的例句和你的的程序一起发给我,我帮你看下,看能不能帮你的忙!QQ:290412297 ...

教程上用的是ADC0804,我的开发板用的是PCF8591,程序编写方法都一样吧?我想原来的程序不用管了,芯片都不同。
PCF8591的例题是这样的:#ifndef __PCF8591_H__
#define __PCF8591_H__

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

//该ADC和DAC是串口输出,只要接两根线
sbit SCL=P3^6;//时钟脉冲
sbit SDA=P3^7;//双向输入输出数据端

#define SCL_SET SCL=1
#define SCL_CLR SCL=0
#define SDA_SET SDA=1
#define SDA_CLR SDA=0
#define AddWr 0x92   //写数据地址
#define AddRd 0x93   //读数据地址
#define adCon 0x40   //AD控制字节

//延时1US
void PDFDelay(uint cnt)
{
        while(--cnt);
}

void start()
{
        SDA_SET;
        PDFDelay(1);
        SCL_SET;
        PDFDelay(5);
        SDA_CLR;
}

void stop()
{
        SDA_CLR;
        PDFDelay(1);
        SCL_SET;
        PDFDelay(5);
        SDA_SET;
}

void ack()
{
        SDA_CLR;
        SCL_SET;
        PDFDelay(1);
        SCL_CLR;
}

void noAck()
{
        SDA_SET;
        SCL_SET;
        PDFDelay(1);
        SCL_CLR;
}

void send(uchar Data)
{
        uchar i=0;
        uchar temp=0;
        temp=Data;
        for(i=0; i<8; i++)
        {
                SCL_CLR;
                PDFDelay(1);
                if(temp&0x80) SDA_SET;
                else SDA_CLR;
                PDFDelay(1);
                SCL_SET;
                PDFDelay(1);
                temp<<=1;
        }
        SCL_CLR;
}

uchar recive()
{
        uchar i=0;
        uchar temp=0;
        SDA_SET;//必须设置
        for(i=0; i<8; i++)
        {
                SCL_CLR;//拉低允许数据改变
                PDFDelay(1);
                SCL_SET;//拉高保持数据,等待读走
                PDFDelay(2);
                if(SDA) temp|=0x01;
                else temp&=0xfe;
                if(i<7)   temp<<=1;//最低位发送完成不能移位,否则出错
        }
        SCL_CLR;
        return temp;
}

//ADC读函数。输入参数ch为通道数:0至3通道
uchar ADCGet(uchar ch)
{
        uchar temp=0;
        start();
        send(AddWr);//确认芯片
        ack();
        send(adCon|ch);//确认通道
        ack();
        //读出数据,放进temp
        start();
        send(AddRd);
        ack();
        temp=recive();
        noAck();
        stop();
        return temp;
}

//DAC设定参。输入参数value为设定的数字量
void DACSet(uchar value)
{
        start();
        send(AddWr);
        ack();
        send(0x40);//写入控制位,使能DAC输出
        ack();
        send(value);
        ack();
        stop();
}
//#include<reg52.h>
//#include"PCF8591.h"//自己封装的PCF8591芯片控制函数

void main()
{       
        while(1)
        {
                P1=ADCGet(2);//将2通道采样回来的值直接付给流水灯。二通道采样的是电位器的值,直接旋转电位器即可看到效果
        }
}

Tliang 发表于 2012-12-3 12:29:13

本帖最后由 Tliang 于 2012-12-3 13:31 编辑

                                                             楼被占了。。

李鸿鸿 发表于 2012-12-3 12:31:26

Tliang 发表于 2012-12-2 21:45 static/image/common/back.gif
你先看IIC协议,在看芯片数据手册就可以写出来了。从网上下的。能不能用我不知道。一百度就出来了 ...

控制SDA和SCL经过模数转换就能得到不同的地址?,再根据不同的地址让单片机做出不同的反应?

raxb 发表于 2012-12-3 12:42:00

李鸿鸿 发表于 2012-12-3 12:31 static/image/common/back.gif
控制SDA和SCL经过模数转换就能得到不同的地址?,再根据不同的地址让单片机做出不同的反应? ...

通过单片机发地址信号给AD芯片,然后单片机发读命令,就可以把AD芯片里面的数据读出来!!!

zjk 发表于 2012-12-3 12:53:59

{:loveliness:}LZ是妹纸吧。。。

Tliang 发表于 2012-12-3 12:55:42

本帖最后由 Tliang 于 2012-12-3 13:32 编辑

地址开始的时候已经固定,由a0~a2确定,sda是iic总线的数据线,scl是iic总线的时钟线。通过IIC总线发送数据控制芯片转换,和读取转换的数据

kcfoo1 发表于 2012-12-3 13:28:58

先看显示程序都有问题,其他的不用考虑,你就让n=250,看它能显示不?

error_dan 发表于 2012-12-3 13:34:39

目测普中的开发板...

李鸿鸿 发表于 2012-12-3 13:39:08

Tliang 发表于 2012-12-3 12:55 static/image/common/back.gif
地址开始的时候已经固定,由a0~a2确定,sda是iic总线的数据线,scl是iic总线的时钟线。通过IIC总线发送数据 ...

a0~a3是什么?

Tliang 发表于 2012-12-3 13:43:19

楼主我建议你现在跳过这里,然后不看例程,使用PROTEUS软件自己画个流水灯。写程序,自己写完全不看书(因为看书理解了和自己写出来是两回事,抄书没用)。完成后。
再静态数码管显示。
然后动态数码管显示,然后点阵显示。然后在整LCD(简单的时序),595(SPI控制,主要学习时序),24CXX(IIC协议的EEPROM,例程特多)。这样过渡下来。再来整这个芯片。就会觉得小菜一碟了。

李鸿鸿 发表于 2012-12-3 13:44:55

kcfoo1 发表于 2012-12-3 13:28 static/image/common/back.gif
先看显示程序都有问题,其他的不用考虑,你就让n=250,看它能显示不?

n=250?数组根本没有这么大?只是0到9

Tliang 发表于 2012-12-3 13:46:51

李鸿鸿 发表于 2012-12-3 13:39 static/image/common/back.gif
a0~a3是什么?

芯片的引脚。
下载个资料看看吧。。

李鸿鸿 发表于 2012-12-3 13:52:56

Tliang 发表于 2012-12-3 13:43 static/image/common/back.gif
楼主我建议你现在跳过这里,然后不看例程,使用PROTEUS软件自己画个流水灯。写程序,自己写完全不看书(因 ...

这样啊?我想解决了AD转换我就可以做电压表了

Tliang 发表于 2012-12-3 13:56:28

                                                      

Tliang 发表于 2012-12-3 14:14:07

李鸿鸿 发表于 2012-12-3 13:52 static/image/common/back.gif
这样啊?我想解决了AD转换我就可以做电压表了

这个芯片确实不适合新手学习。
做电压表?难道你没有万用表吗?用这个做也是鸡肋。0~5V可以测,超过了就得加工

李鸿鸿 发表于 2012-12-3 14:16:22

Tliang 发表于 2012-12-3 14:14 static/image/common/back.gif
这个芯片确实不适合新手学习。
做电压表?难道你没有万用表吗?用这个做也是鸡肋。0~5V可以测,超过了就 ...

这样啊!我先绕过这,先学会其它的先

Tliang 发表于 2012-12-3 14:23:06

李鸿鸿 发表于 2012-12-3 14:16 static/image/common/back.gif
这样啊!我先绕过这,先学会其它的先

正确的选择,我看你数码管显示都还没掌握呀。。

李鸿鸿 发表于 2012-12-9 21:54:04

我又回来了,经过几天的学习!我终于看懂了

柳舞东城a 发表于 2012-12-10 19:45:56

郭老师的《十天学会单片机》里有讲I2C滴

wantao0916 发表于 2012-12-11 11:52:48

IIC确实够看一阵子

L_Hongzhen 发表于 2012-12-11 19:47:47

百度一下就ok了

李鸿鸿 发表于 2012-12-23 15:29:11

xyz543 发表于 2012-12-2 17:30 static/image/common/back.gif
楼主您要找的资料应该是这个 http://115.com/file/cl00dl9y#

{:smile:}
页: [1]
查看完整版本: 求最简单的A/D转换程序