蓝桥杯单片机—— PCF8591的基本原理及A/D转换应用(14)

一、原理分析

1、基本概念

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

 I²C总线接口 知识参考:

(46条消息) 【蓝桥杯单片机进阶强化-01】IIC总线接口技术基础_小蜜蜂老师的干货铺-CSDN博客_蓝桥杯iichttps://blog.csdn.net/ohy3686/article/details/86716456?spm=1001.2014.3001.5502

2、特点

【1】通过I2C总线串行输入/输出

【2】PCF8591通过3个硬件地址引脚寻址

【3】PCF8591的模拟电压范围从VSS到VDD

【4】8-bit逐次逼近A/D转换器

【5】通过1路模拟输出实现DAC增益

【6】PCF8591内置跟踪保持电路

3、引脚

AIN0~AIN3:模拟信号输入端。A0~A2:引脚地址端。

AIN0:接到右边排针上,可以用杜邦线连外部模拟电压信号
AIN1:接到光敏电阻上
AIN2:放大器的输出端
AIN3:接到滑动变阻器Rb2上

省赛中考得最多的是通道1和通道3:

 光敏传感器接到AIN1,通道1;控制寄存器应写入:0x01。
 电位器Rb2接到AIN3,通道3;控制寄存器应写入:0x03。

VDD、VSS:电源端。(2.5~6V)

SDA、SCL:I2C 总线的数据线、时钟线。

OSC:外部时钟输入端,内部时钟输出端。

EXT:内部、外部时钟选择线,使用内部时钟时 EXT 接地。

AGND:模拟信号地。

AOUT:D/A 转换输出端。

VREF:基准电源端。

4、设备地址 

 在i2c总线系统中的每个PCF8591设备通过发送一个有效的地址来激活。该地址由一个固定部分和一个可编程部分组成。可编程部分必须根据地址引脚A0、A1和A2进行设置。由原理图知A0、A1和A2都接地。在I2c总线协议中,该地址总是必须作为启动条件后的第一个字节发送。地址字节的最后一位是读/写位,它设置了以下数据传输的方向。写地址为:0x90      读地址为:0x91

5、控制字节

发送到PCF8591设备的第二个字节将存储在其控制寄存器中,并需要控制设备的功能。 

二、程序编写 

功能要求:采样可变电阻电压和光敏电阻电压

1.光敏电阻Rd1接到PCF8591的AIN1引脚;可调电阻Rb2接到PCF8591的AIN3引脚;

2.独立按键S4为通道切换选择,系统上电的时候,采样通道1光敏电阻的数据并显示在数据管上。按下S4松开后,切换到通道3采样可调电阻的数据并显示;再次按下S4松开后,又切换回通道1采样光敏电阻数据,如此循环往复。

3.数码管的显示格式:前3 位数码管显示通道号(CH通道号),后3位显示PCF8591相应通道读取的数据。如下图所示:

先将官方提供的iic.c和iic.h两个文件复制到工程路径下

 iic.c

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}

 iic.h

#ifndef _IIC_H
#define _IIC_H

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 

#endif

main.c

#include "reg52.h"
#include "iic.h"
 
sbit S4 = P3^3;
 
unsigned char dat_Rd1;
unsigned char dat_Rb2;
unsigned char flag = 0;
 
unsigned char code SMG_duanma[18]=
		{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
		 0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};
//数码管显示模块 
void DelaySMG(unsigned int t)
{
	while(t--);
}
 
void DisplaySMG_Bit(unsigned char pos, unsigned char value)
{
   P2=0XE0;P0=0XFF;
   P2=0XC0;P0=0X01<< pos;
	P2=0XE0;P0=value;
}
 
void DisplaySMG_ADC(unsigned char channel, unsigned char dat)
{
	DisplaySMG_Bit(0, SMG_duanma[12]);//显示C
	DelaySMG(100);
	DisplaySMG_Bit(1,0x89);//显示H
	DelaySMG(100);
	DisplaySMG_Bit(2, SMG_duanma[channel]);//显示通道号
	DelaySMG(100);
			
	DisplaySMG_Bit(3, 0xFF);
	DisplaySMG_Bit(4, 0xFF);
	
	DisplaySMG_Bit(5, SMG_duanma[dat / 100]);//百位
	DelaySMG(100);
	DisplaySMG_Bit(6, SMG_duanma[(dat /10 ) % 10]);//十位
	DelaySMG(100);
	DisplaySMG_Bit(7, SMG_duanma[dat % 10]);//个位
	DelaySMG(100);

	P2=0XC0;P0=0Xff;//避免最后一位数码管过亮
	P2=0XE0;P0=0xff;

}
//光敏电阻A/D转化函数 
void Read_RD1()
{
	IIC_Start();//IIC总线起始信号										
	IIC_SendByte(0x90);//PCF8591的写设备地址	 				
	IIC_WaitAck();//等待从机应答	  							
	IIC_SendByte(0x01);//发送PCF8591的控制字节;选择选择模拟量输入通道;光敏传感器相应的控制寄存器应写入0x01	 				
	IIC_WaitAck();//等待从机应答	  							
	IIC_Stop();	//IIC总线停止信号 								
	
	DisplaySMG_ADC(1,dat_Rd1);//光敏电阻通道号:1,数值
	
	IIC_Start();//IIC总线起始信号									
	IIC_SendByte(0x91); //PCF8591的读设备地址						
	IIC_WaitAck(); //等待从机应答								
	dat_Rd1 = IIC_RecByte();//读取PCF8591通道1的数据 	 			
	IIC_SendAck(1); //产生非应答信号									
	IIC_Stop(); //IIC总线停止信号										
	DisplaySMG_ADC(1,dat_Rd1);
}
//可调电阻A/D转化函数 
void Read_RB2()
{
	IIC_Start();								
	IIC_SendByte(0x90); 					
	IIC_WaitAck();  							
	IIC_SendByte(0x03); 				
	IIC_WaitAck();  						
	IIC_Stop(); 									
	
	DisplaySMG_ADC(3,dat_Rb2);
	
	IIC_Start();								
	IIC_SendByte(0x91); 				
	IIC_WaitAck(); 							
	dat_Rb2 = IIC_RecByte(); 			
	IIC_SendAck(1); 									
	IIC_Stop(); 									
	DisplaySMG_ADC(3,dat_Rb2);
}
//按键切换模块 
void Scan_Keys()
{
	if(S4 == 0)
	{
		DelaySMG(100);
		if(S4 == 0)
		{
			if(flag == 0)
			{
				flag = 1;
				while(S4 == 0)
				{
					DisplaySMG_ADC(1,dat_Rd1);
				}
			}
			else if(flag == 1)
			{
				flag = 0;
				while(S4 == 0)
				{
					DisplaySMG_ADC(3,dat_Rb2);
				}
			}
		}
	}
}
 
void main()
{
	P2=0X80;P0= 0xff;
	P2=0XA0;P0= 0x00;
	while(1)
	{
		Scan_Keys();
		if(flag == 0)
		{
			Read_RD1();
		}
		else if(flag == 1)
		{
			Read_RB2();
		}
	}
}

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯单片机—— PCF8591的基本原理及A/D转换应用(14)

发表评论