PCF8951在90c51上的使用

     PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。在90c51上PCF8591的4个引脚AIN0, AIN1,AIN2和AIN3可接注入光敏电阻,滑变电阻器之类的原件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。2条双向串行线,一条数据线SDA,一条时钟线SCL。


A/D实现:诸如光敏电阻将模拟量转化为电压连在AIN1口,而PCF将电压转化为数字由数据线SDA输出。


工作原理:

首先说PCF使用的I2C总线协议

I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。 
数据的传输使用数据线SDA,一条时钟线SCL。SDA每次传输一字节。

以下来自一位大佬的http://blog.csdn.net/subkiller/article/details/6854910


 1. I2C开始和结束信号
   开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
   结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

  I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴...


c51代码:

忽略<>里的东西

void I2C_start()
{
	SCL = 1;
	SDA = 1;
	delay5us();
	SDA = 0;
	delay5us();
	SCL = 0;		
}

2. I2C位传输
   数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;
   若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)
   数据改变:SCL为低电平时,SDA线才能改变传输的bit

I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴...

代码

void I2C_write(uchar dat)
{
	uchar i;
	for(i=0; i<8; i++)
	{
		SCL = 0;
		delay5us();
		SDA = dat & 0x80;
		delay5us();
		SCL = 1;
		dat <<= 1;
		delay5us();		
	}	
	SCL = 0;
}

传输数据是一位一位地传,每次SCL为0时,SDA赋值要被传输的数据,SCL拉高,SDA的数据传送。


3. I2C应答信号

   Master每发送完8bit数据后等待Slave的ACK。
   即在第9个clock,若从IC发ACK,SDA会被拉低。
   若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示:
I2C学习笔记 - dp - dp: 生活的脚步,进步的点滴...
代码

uchar I2C_WaitAck()		   
{
	uint i = 0;
	SDA = 1;    		  
	delay5us();
	SCL = 1;
	delay5us();
	while(SDA == 1 && i < 300)
		i++;
	if(SDA)
	{
		SCL = 0;
		I2C_stop();
		return 0;
	}			
	else 
	{
		SCL = 0;
		return 1;
	}
}

while循环或者SDA为1没有回应或者继续延时

返回1有回应


接下来就是读取数据

代码

uchar I2C_read()
{
	uchar i;
	uchar byte;
	SCL = 0;
	delay5us();
	SDA = 1;		
	for(i=0; i<8; i++)
	{
		SCL = 1;   
		byte <<= 1;
		delay5us();			
		if(SDA)
			byte |= 0x01;
		SCL = 0;
		delay5us();
	}
	return byte;
}

每次赋值在byte的第一位,之后byte位移。


关于PCF8591的读写

写入数据时:起始信号->器件地址->应答信号->控制字节->写入的数据->应答信号(从机)->写入的数据->应答信号(从机)。。。。->停止信号

读取数据时:起始信号->器件地址(写)->应答信号(从机)->控制字节->应答信号(从机)->停止信号(这个前提是设置读取的是哪一个通道,采用的哪种模                           式)    接着再是:起始信号->器件地址(读)->读取的字节->非应答信号(主机)->停止信号

下面来自另一位大佬 http://www.cnblogs.com/whik/p/6650955.html

PCF8591的操作和AT24C02非常类似,只不过AT24C02是写入或读出数据,而PCF8591是AIN端口输入模拟电压,然后PCF8591将转换后的数字量通过IIC总线发送给单片机,或是单片机通过IIC总线给一个数字量,然后PCF8591通过AOUT端口将模拟电压输出.

控制字格式

最高位默认为0

第6位是选择是否允许模拟电压输出,在DA转换时设置为1,AD转换时设置为0或1均可

第5/4位是选择模拟电压输出方式,一般选择00单端输入方式,其他的几种方式如下图所示

 

第3位默认为0

第2位是自动增量使能位,如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。

第1/0为是在AD转换时选择哪一个通道输入的电压转换为数字量.

由之前的图可以得知,如果显示光敏电阻的变化,那么通道输入0000 0001即可,就是0x01


下面说器件地址

PCF8591的器件地址

每一个IIC器件都有一个器件地址,来区分不同的IIC设备,下面是PCF8591的地址

 

 

它的地址是由1001和A2A1A0组成的,在原理图中可以看出,A2A1A0均为0,所以器件地址为0x90/0x91,最后一位是读写方向位,0表示下一个字节往总线上写数据,1表示下一个字节从总线上读取数据.


代码

完整的代码,烧录在51上后显示的是前三位为滑变电阻器变化值,后三位显示光敏电阻,数码管通过中断控制,尽管我将周期写得很短很短了,它还是闪烁的我眼都要瞎了,只能说可以看清数字

#include <reg52.h>
#include "intrins.h"

#define uint unsigned int
#define uchar unsigned char

sbit SCL = P2^0;
sbit SDA = P2^1;

void delay5us();
void I2C_start();
void I2C_write(uchar dat);
uchar I2C_read();
uchar I2C_WaitAck();
void I2C_Ack(uchar ackbit);
void I2C_stop();
void PCF8591_init();
uchar ADC_PCF8591();

#define uint unsigned int 
#define uchar unsigned char
uchar code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
uchar dspbuf[]={10,10,10,10,10,10,10,10};
uchar dspcom = 0;
sfr AUXR = 0x8E;

void close_buzz()
{
	P2 = (P2 & 0x1f)|0xa0; 
	P0 &= 0xbf;
	P2 &= 0x1f;	
}

void Timer1Init(void)		
{
	AUXR |= 0x40;		
	TMOD &= 0x0F;		
	TH1=(65535-65000)/256;
	TL1=(65535-65000)%256;
	TF1 = 0;		
	TR1 = 1;		
	ET1 = 1;
	EA = 1;
}

void delay5us()		
{
	uchar i;
	_nop_();
	i = 11;
	while (--i);
}

void I2C_start()
{
	SCL = 1;
	SDA = 1;
	delay5us();
	SDA = 0;
	delay5us();
	SCL = 0;		
}

void I2C_write(uchar dat)
{
	uchar i;
	for(i=0; i<8; i++)
	{
		SCL = 0;
		delay5us();
		SDA = dat & 0x80;
		delay5us();
		SCL = 1;
		dat <<= 1;
		delay5us();		
	}	
	SCL = 0;
}

uchar I2C_WaitAck()		   
{
	uint i = 0;
	SDA = 1;    		  
	delay5us();
	SCL = 1;
	delay5us();
	while(SDA == 1 && i < 300)
		i++;
	if(SDA)
	{
		SCL = 0;
		I2C_stop();
		return 0;
	}			
	else 
	{
		SCL = 0;
		return 1;
	}
}

void I2C_Ack(uchar ackbit)		
{
	SCL = 0;
	if(ackbit)
		SDA = 0;
	else 				   
		SDA = 1;
	delay5us();
	SCL = 1;
	delay5us();
	SCL = 0;
	SDA = 1;
	delay5us();
}

uchar I2C_read()
{
	uchar i;
	uchar byte;
	SCL = 0;
	delay5us();
	SDA = 1;		
	for(i=0; i<8; i++)
	{
		SCL = 1;  
		byte <<= 1;
		delay5us();			
		if(SDA)
			byte |= 0x01;
		SCL = 0;
		delay5us();
	}
	return byte;
}


void I2C_stop()
{
	SCL = 0;
	SDA = 0;
	delay5us();
	SCL = 1;
	delay5us();
	SDA = 1;	
}



uchar ADC_PCF8591_AIN3()
{
	uchar val;
	I2C_start();
	I2C_write(0x90);
	I2C_WaitAck();
	I2C_write(0x03);
	I2C_WaitAck();
	I2C_start();
	I2C_write(0x91);
	I2C_WaitAck();
	val = I2C_read();
	I2C_Ack(0);
	I2C_stop();
//	val = (val*50)/255;
	return val;
}
uchar ADC_PCF8591_AIN1()
{
	uchar val;
	I2C_start();
	I2C_write(0x90);
	I2C_WaitAck();
	I2C_write(0x01);
	I2C_WaitAck();
	I2C_start();
	I2C_write(0x91);
	I2C_WaitAck();
	val = I2C_read();
	I2C_Ack(0);
	I2C_stop();
//	val = (val*50)/255;
	return val;
}
void display()
{
	P2 = (P2 & 0x1f)|0xE0;
	P0 = ~0xff;
	P2 &= 0x1f;
	P2 = (P2 & 0x1f)|0xC0;
	P0 = ~(1 << dspcom);
	P2 &= 0x1f;
	P2 = (P2 & 0x1f)|0xE0;
	P0 = ~tab[dspbuf[dspcom]];
	P2 &= 0x1f;
	if(++dspcom == 8)
		dspcom = 0;
}

void main()
{
	uchar val_AIN1,val_AIN3;
	close_buzz();
	Timer1Init();
	while(1)
	{
		val_AIN1 = ADC_PCF8591_AIN1();
		val_AIN3 = ADC_PCF8591_AIN3();
		dspbuf[0] = val_AIN1/100;
		dspbuf[1] = val_AIN1/10%10;
		dspbuf[2] = val_AIN1%10;	
		dspbuf[5] = val_AIN3/100;
		dspbuf[6] = val_AIN3/10%10;
		dspbuf[7] = val_AIN3%10;	
		
	}												
}
void Timer1() interrupt 3
{
	display();
}




刚看完什么什么特工2,极限特工2?



  • 7
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用C语言编写的PCF8951模块的C51代码示例: ```c #include <reg52.h> #include <intrins.h> sbit SDA = P2^0; //定义SDA sbit SCL = P2^1; //定义SCL void IIC_Start() { SDA = 1; SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); SDA = 0; _nop_(); _nop_(); _nop_(); _nop_(); SCL = 0; } void IIC_Stop() { SDA = 0; SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); SDA = 1; _nop_(); _nop_(); _nop_(); _nop_(); } unsigned char IIC_SendByte(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { SDA = dat & 0x80; dat <<= 1; SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); SCL = 0; } SDA = 1; SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); if (SDA) { return 1; } SCL = 0; return 0; } unsigned char IIC_ReadByte() { unsigned char i; unsigned char dat = 0; SDA = 1; for (i = 0; i < 8; i++) { dat <<= 1; SCL = 1; _nop_(); _nop_(); _nop_(); _nop_(); dat |= SDA; SCL = 0; } return dat; } void PCF8951_Init() { IIC_Start(); IIC_SendByte(0x90); IIC_SendByte(0x00); IIC_Stop(); } void PCF8951_Write(unsigned char addr, unsigned char dat) { IIC_Start(); IIC_SendByte(0x90); IIC_SendByte(addr); IIC_SendByte(dat); IIC_Stop(); } unsigned char PCF8951_Read(unsigned char addr) { unsigned char dat; IIC_Start(); IIC_SendByte(0x90); IIC_SendByte(addr); IIC_Start(); IIC_SendByte(0x91); dat = IIC_ReadByte(); IIC_Stop(); return dat; } void main() { unsigned char temp; PCF8951_Init(); PCF8951_Write(0x00, 0x55); temp = PCF8951_Read(0x00); while (1); } ``` 注意,以上代码仅作为示例,使用前请根据实际情况进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值