您的位置:首页 > 其它

PCF8591 AD/DA转换

2017-02-08 09:04 204 查看
/*-----------------------------------------------

名称:IIC协议 PCF8591 AD/DA转换

论坛:www.doflye.net

编写:shifang

修改:无

内容:使用4路AD中的4路检测外部模拟量输入(main.c)

------------------------------------------------*/

#include <reg52.h>

#include "i2c.h"

#include "delay.h"

#include "display.h"

#define AddWr 0x90 //写数据地址

#define AddRd 0x91 //读数据地址

extern bit ack;

bit ReadADFlag;

unsigned char ReadADC(unsigned char Chl);

bit WriteDAC(unsigned char dat);

/*------------------------------------------------

主程序

------------------------------------------------*/

main()

{

unsigned char num=0,i;

Init_Timer0();

DelayMs(20);

while (1) //主循环

{

if(ReadADFlag)

{

ReadADFlag=0;

//连续读5次,输入通道后多读几次,取最后一次值,以便读出稳定值

for(i=0;i<5;i++)

num=ReadADC(0);

// x10表示把实际值扩大10,如4.5 变成 45 方便做下一步处理 x5 表示基准电压5V

num=num*5*10/256;

TempData[0]=dofly_DuanMa[num/10]|0x80;

TempData[1]=dofly_DuanMa[num%10];

for(i=0;i<5;i++)

num=ReadADC(1);

num=num*5*10/256; // x10表示把实际值扩大10,如4.5 变成 45 方便做下一步处理

TempData[2]=dofly_DuanMa[num/10]|0x80;

TempData[3]=dofly_DuanMa[num%10];

for(i=0;i<5;i++)

num=ReadADC(2);

num=num*5*10/256; // x10表示把实际值扩大10,如4.5 变成 45 方便做下一步处理

TempData[4]=dofly_DuanMa[num/10]|0x80;

TempData[5]=dofly_DuanMa[num%10];

for(i=0;i<5;i++)

num=ReadADC(3);

num=num*5*10/256; // x10表示把实际值扩大10,如4.5 变成 45 方便做下一步处理

TempData[6]=dofly_DuanMa[num/10]|0x80;

TempData[7]=dofly_DuanMa[num%10];

//主循环中添加其他需要一直工作的程序

}

}

}

/*------------------------------------------------

读AD转值程序

输入参数 Chl 表示需要转换的通道,范围从0-3

返回值范围0-255

------------------------------------------------*/

unsigned char ReadADC(unsigned char Chl)

{

unsigned char Val;

Start_I2c(); //启动总线

SendByte(AddWr); //发送器件地址

if(ack==0)return(0);

SendByte(Chl); //发送器件子地址

if(ack==0)return(0);

Start_I2c();

SendByte(AddRd);

if(ack==0)return(0);

Val=RcvByte();

NoAck_I2c(); //发送非应位

Stop_I2c(); //结束总线

return(Val);

}

/*------------------------------------------------

写入DA转换数值

输入参数:dat 表示需要转换的DA数值,范围是0-255

------------------------------------------------*/

/*bit WriteDAC(unsigned char dat)

{

Start_I2c(); //启动总线

SendByte(AddWr); //发送器件地址

if(ack==0)return(0);

SendByte(0x40); //发送器件子地址

if(ack==0)return(0);

SendByte(dat); //发送数据

if(ack==0)return(0);

Stop_I2c();

}*/

/*-----------------------------------------------

名称:IIC协议

论坛:www.doflye.net

编写:shifang

修改:无

内容:函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作 一定的修改....(本例是1us机器

周期,即晶振频率要小于12MHZ)

------------------------------------------------*/

#include "i2c.h"

#include "delay.h"

#define _Nop() _nop_() //定义空指令

bit ack; //应答标志位

sbit SDA=P2^1;

sbit SCL=P2^0;

/*------------------------------------------------

启动总线

------------------------------------------------*/

void Start_I2c()

{

SDA=1; //发送起始条件的数据信号

_Nop();

SCL=1;

_Nop(); //起始条件建立时间大于4.7us,延时

_Nop();

_Nop();

_Nop();

_Nop();

SDA=0; //发送起始信号

_Nop(); //起始条件锁定时间大于4μ

_Nop();

_Nop();

_Nop();

_Nop();

SCL=0; //钳住I2C总线,准备发送或接收数据

_Nop();

_Nop();

}

/*------------------------------------------------

结束总线

------------------------------------------------*/

void Stop_I2c()

{

SDA=0; //发送结束条件的数据信号

_Nop(); //发送结束条件的时钟信号

SCL=1; //结束条件建立时间大于4μ

_Nop();

_Nop();

_Nop();

_Nop();

_Nop();

SDA=1; //发送I2C总线结束信号

_Nop();

_Nop();

_Nop();

_Nop();

}

/*----------------------------------------------------------------

字节数据传送函数

函数原型: void SendByte(unsigned char c);

功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对

此状态位进行操作.(不应答或非应答都使ack=0 假)

发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

------------------------------------------------------------------*/

void SendByte(unsigned char c)

{

unsigned char BitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位

{

if((c<<BitCnt)&0x80)SDA=1; //判断发送位

else SDA=0;

_Nop();

SCL=1; //置时钟线为高,通知被控器开始接收数据位

_Nop();

_Nop(); //保证时钟高电平周期大于4μ

_Nop();

_Nop();

_Nop();

SCL=0;

}

_Nop();

_Nop();

SDA=1; //8位发送完后释放数据线,准备接收应答位

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop();

_Nop();

if(SDA==1)ack=0;

else ack=1; //判断是否接收到应答信号

SCL=0;

_Nop();

_Nop();

}

/*----------------------------------------------------------------

字节数据传送函数

函数原型: unsigned char RcvByte();

功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),

发完后请用应答函数。

------------------------------------------------------------------*/

unsigned char RcvByte()

{

unsigned char retc;

unsigned char BitCnt;

retc=0;

SDA=1; //置数据线为输入方式

for(BitCnt=0;BitCnt<8;BitCnt++)

{

_Nop();

SCL=0; //置时钟线为低,准备接收数据位

_Nop();

_Nop(); //时钟低电平周期大于4.7us

_Nop();

_Nop();

_Nop();

SCL=1; //置时钟线为高使数据线上数据有效

_Nop();

_Nop();

retc=retc<<1;

if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中

_Nop();

_Nop();

}

SCL=0;

_Nop();

_Nop();

return(retc);

}

/*----------------------------------------------------------------

应答子函数

原型: void Ack_I2c(void);

----------------------------------------------------------------*/

/*void Ack_I2c(void)

{

SDA=0;

_Nop();

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop(); //时钟低电平周期大于4μ

_Nop();

_Nop();

_Nop();

SCL=0; //清时钟线,钳住I2C总线以便继续接收

_Nop();

_Nop();

}*/

/*----------------------------------------------------------------

非应答子函数

原型: void NoAck_I2c(void);

----------------------------------------------------------------*/

void NoAck_I2c(void)

{

SDA=1;

_Nop();

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop(); //时钟低电平周期大于4μ

_Nop();

_Nop();

_Nop();

SCL=0; //清时钟线,钳住I2C总线以便继续接收

_Nop();

_Nop();

}

/*----------------------------------------------------------------

向无子地址器件发送字节数据函数

函数原型: bit ISendByte(unsigned char sla,ucahr c);

功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.

如果返回1表示操作成功,否则操作有误。

注意: 使用前必须已结束总线。

----------------------------------------------------------------*/

/*bit ISendByte(unsigned char sla,unsigned char c)

{

Start_I2c(); //启动总线

SendByte(sla); //发送器件地址

if(ack==0)return(0);

SendByte(c); //发送数据

if(ack==0)return(0);

Stop_I2c(); //结束总线

return(1);

}

*/

/*----------------------------------------------------------------

向有子地址器件发送多字节数据函数

函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);

功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件

地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。

如果返回1表示操作成功,否则操作有误。

注意: 使用前必须已结束总线。

----------------------------------------------------------------*/

/*bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)

{

unsigned char i;

for(i=0;i<no;i++)

{

Start_I2c(); //启动总线

SendByte(sla); //发送器件地址

if(ack==0)return(0);

SendByte(suba); //发送器件子地址

if(ack==0)return(0);

SendByte(*s); //发送数据

if(ack==0)return(0);

Stop_I2c(); //结束总线

DelayMs(1); //必须延时等待芯片内部自动处理数据完毕

s++;

suba++;

}

return(1);

}

*/

/*----------------------------------------------------------------

向无子地址器件读字节数据函数

函数原型: bit IRcvByte(unsigned char sla,ucahr *c);

功能: 从启动总线到发送地址,读数据,结束总线的全过程,从器件地

址sla,返回值在c.

如果返回1表示操作成功,否则操作有误。

注意: 使用前必须已结束总线。

----------------------------------------------------------------*/

/*bit IRcvByte(unsigned char sla,unsigned char *c)

{

Start_I2c(); //启动总线

SendByte(sla+1); //发送器件地址

if(ack==0)return(0);

*c=RcvByte(); //读取数据

NoAck_I2c(); //发送非就答位

Stop_I2c(); //结束总线

return(1);

}

*/

/*----------------------------------------------------------------

向有子地址器件读取多字节数据函数

函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);

功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件

地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。

如果返回1表示操作成功,否则操作有误。

注意: 使用前必须已结束总线。

----------------------------------------------------------------*/

/*bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)

{

unsigned char i;

Start_I2c(); //启动总线

SendByte(sla); //发送器件地址

if(ack==0)return(0);

SendByte(suba); //发送器件子地址

if(ack==0)return(0);

Start_I2c();

SendByte(sla+1);

if(ack==0)return(0);

for(i=0;i<no-1;i++)

{

*s=RcvByte(); //发送数据

Ack_I2c(); //发送就答位

s++;

}

*s=RcvByte();

NoAck_I2c(); //发送非应位

Stop_I2c(); //结束总线

return(1);

}

*/

#include"display.h"

#include"delay.h"

#define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换

//sbit LATCH1=P2^0;//定义锁存使能端口 段锁存

//sbit LATCH2=P2^3;// 位锁存

extern bit ReadADFlag;

unsigned char code dofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9

unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码

unsigned char TempData[8]; //存储显示值的全局变量

/*------------------------------------------------

显示函数,用于动态扫描数码管

输入参数 FirstBit 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示

如输入0表示从第一个显示。

Num表示需要显示的位数,如需要显示99两位数值则该值输入2

------------------------------------------------*/

void Display(unsigned char FirstBit,unsigned char Num)

{

static unsigned char i=0;

DataPort=0; //清空数据,防止有交替重影

LATCH1=1; //段锁存

LATCH1=0;

DataPort=dofly_WeiMa[i+FirstBit]; //取位码

LATCH2=1; //位锁存

LATCH2=0;

DataPort=TempData[i]; //取显示数据,段码

LATCH1=1; //段锁存

LATCH1=0;

i++;

if(i==Num)

i=0;

}

/*------------------------------------------------

定时器初始化子程序

------------------------------------------------*/

void Init_Timer0(void)

{

TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响

//TH0=0x00; //给定初值

//TL0=0x00;

EA=1; //总中断打开

ET0=1; //定时器中断打开

TR0=1; //定时器开关打开

}

/*------------------------------------------------

定时器中断子程序

------------------------------------------------*/

void Timer0_isr(void) interrupt 1

{

static unsigned int num;

TH0=(65536-2000)/256; //重新赋值 2ms

TL0=(65536-2000)%256;

Display(0,8); // 调用数码管扫描

num++;

if(num==50) //大致100ms

{

num=0;

ReadADFlag=1; //读标志位置1

}

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: