基于AT89s52单片机和PCF8591为基础的数模模数转换
我也正在写这个
这个好像用到了I2C总线
正在挣扎中呢
好东东
/*----------------------------------------------
内容:使用4路AD中的1路检测外部模拟量输入
------------------------------------------------*/
#include <reg52.h>
#include "intrins.h"
#define uint unsigned int
#define uchar unsigned char
uchar tempdata[8];
uchar ReadADC(uchar Chl);//读数据函数
bit ack; //应答标志位
sbit SDA=P2^0;//数据线
sbit SCL=P2^1;//时钟线
sbit duan=P2^2;//数码管段锁存
sbit wei=P2^3; //数码管位锁存
uchar code dula[]=
{
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};//0-f,
uchar code wela[]=
{
0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,
}; //0-7
/*void delay2(uint t)
{
while(--t);
}
void delay1(uint t)
{
while(t--)
{
//大致延时1mS
delay2(500);
}
}*/
void delay5us(void) //误差 0us
{
_nop_(); //if Keil,require use intrins.h
}
void delay1(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
/*------------------------------------------------
启动总线
------------------------------------------------*/
void Start_I2c()
{
SDA=1; //发送起始条件的数据信号
SCL=1;
delay5us(); // 时序必要的延时>5us
SDA=0; //发送起始信号,SDA下降沿为起始标志
delay5us(); //时序必要的延时>4us
SCL=0; //钳住I2C总线,准备发送或接收数据(必不可少)
}
/*----------------------------------------------
结束总线
------------------------------------------------*/
void Stop_I2c()
{
SDA=0; //发送结束条件的数据信号
SCL=1; //结束条件建立时间大于4μ
delay5us();//SDA上升沿决定结束信号
SDA=1; //发送I2C总线结束信号
SCL=1;
delay5us();
SDA=0;
}
/*----------------------------------
字节数据传送函数
------------------------------------*/
void send_byte(uchar byte)
{
uchar i;
for(i=0;i<8;i++) //要传送的数据长度为8位
{
if((byte<<i)&0x80)
{SDA=1;}
else
{SDA=0;} //判断发送的8位分别是“0”还是“1”
SCL=1; //置时钟线为高,通知被控器开始接收数据位
delay5us();//数据只有在SCL高电平时有效
SCL=0;//允许数据变化
}
SCL=1;
delay5us();
/* if(SDA==1) //判断地址后的一位0、1
{ack=0;} //决定主机对从机的读写
else
{ack=1;}
SCL=0;//允许数据变化 */
}
/*--------------------------------
字节数据接收函数
----------------------------------*/
uchar rec_byte()
{
uchar rec=0;
uchar i;
for(i=0;i<8;i++)
{
SCL=0; //置时钟线为低,准备接收数据位
delay5us();
SCL=1; //置时钟线为高使数据线上数据有效
rec=rec<<1; //起始rec=0;默认8位全0;只需判断哪一位是1;
if(SDA==1)rec=rec+1; //读数据位,接收的数据位放入rec中
delay5us(); //0000 0000;将从最右侧向左逐位判断
}
SCL=0;//必不可少,允许数据变化
return(rec);
}
/*--------------------------------
应答子函数
----------------------------------*/
void ack_I2c(void)
{
SDA=0;
SCL=1;
delay5us();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
// SDA=0;
}
/*--------------------------------
非应答子函数
----------------------------------*/
void noack_I2c(void)
{
SDA=1;
SCL=1;
delay5us();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
// SDA=0;
}
/******显示函数*******/
void display()
{
static uchar i=0;
P0=0; //清空数据,防止有交替重影
duan=1; //段锁存
duan=0;
P0=wela[i]; //取位码
wei=1; //位锁存
wei=0;
P0=tempdata[i]; //取显示数据,段码
duan=1; //段锁存
duan=0;
i++;
if(i==8)
i=0;
}
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0() interrupt 1
{
TH0=(65536-1000)/256; //重新赋值 2ms
TL0=(65536-1000)%256;
display();
}
/*------------------------------------------------
主程序
------------------------------------------------*/
void main()
{
uchar num;
Init_Timer0();
while (1) //主循环
{
num=ReadADC(0);//范围:0-3;
tempdata[0]=dula[num/100];//
tempdata[1]=dula[(num%100)/10];
tempdata[2]=dula[(num%100)%10];
delay1(100);
}
}
/*------------------------------------------------
读AD转值程序
输入参数 Chl 表示需要转换的通道,范围从0-3
返回值范围0-255
------------------------------------------------*/
uchar ReadADC(uchar Chl)
{
uchar Val;
Start_I2c(); //启动总线
send_byte(0x90); //发送器件地址(写0x90)
ack_I2c();
//if(ack==0)return(0); //主机向从机发送数据
send_byte(0x44|Chl); //发送器件子地址(命令)
ack_I2c();
//if(ack==0)return(0); //模拟量输入
Start_I2c();
send_byte(0x91);//读(0x91)
ack_I2c();
//if(ack==0)return(0);
Val=rec_byte();//将接收到的数据赋给val
noack_I2c(); //发送非应答位
Stop_I2c(); //结束总线
return(Val);
}
楼上的好人啊....