蓝桥杯单片机(十一)PCF8591(A/D转换)

PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行IIC总线接口。
首先蓝桥杯单片机开发板上的原理图部分
在这里插入图片描述
其中A0-A2为地址线,主要功能是当有多个PCF8591时,可将A0-A2按不同的最小项来区分不同PCF8591,比如第一个PCF8691的A0-A2=000,第二个A0-A2=001。
AIN0-AIN3是PCF8591的模拟输入端,参考电压为Vref两端的电压。
VDD和VSS为电源端。
AOUT是模拟输出端,AGND为模拟信号地。
SCL为IIC时钟线,SDA为IIC数据线。

本次主要将AIN1和AIN3接入的光敏电阻和滑动变阻器的A/D转换。在这里插入图片描述
首先看蓝桥杯官方提供的IIC的读写程序,通过PCF8591数据手册的IIC时序也能编写。

#define DELAY_TIME 5

//
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;  					
    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;
}

//
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;  
}

//
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;    
}

值得注意时,使用时#define DELAY_TIME 5要扩大一点,原因之前有讲。
然后就是IIC对硬件读程序,首先要发送起始信号,发送硬件地址加写指令等待,然后发送寄存器地址等待,然后发送停止信号,再发送硬件地址加读指令等待,然后接受数据等待,然后发送停止信号。
IIC对硬件写程序,首先要发送起始信号,发送硬件地址加写指令等待,然后发送寄存器地址等待,发送数据致寄存器等待,然后发送停止信号。
程序如下

void IIC_write(uchar hw_address,uchar reg_address,uchar data)
{
//hw_address为硬件地址,最低为表示读或者写 读1,写0
//reg_address为寄存器地址
//num为写入的数据
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);
	IIC_WaitAck();
	IIC_SendByte(data);
	IIC_WaitAck();	
	IIC_Stop();	
}	

uchar IIC_read(uchar hw_address,uchar reg_address)
{
//hw_address为硬件地址,最低为表示读或者写 读1,写0
//reg_address为寄存器地址
	uchar num;
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);	
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(hw_address|0x01);
	IIC_WaitAck();
	num=IIC_RecByte();
	IIC_WaitAck();
	IIC_Stop();	
	
	return num;
}

然后打开PCF8591查看硬件地址
在这里插入图片描述
由于A0,A1,A2接地,所以0X90为写,0X91为读。
在这里插入图片描述
然后对模式进行选择,第二位表示模拟输出,因为时A/D不需要,所以置0,三四位表示选择AIN0-3对应通道的模式,这里选择00直接对应,六位表示自动增量,置零,七八位表示通道对应的AIN0-3,这与三四位联系起来要。
所以0X01对应AIN1对应光敏电阻。
0X03对应AIN3对应滑动变阻器。

最后写一个数码管显示光敏电阻和滑动变阻器的程序:

#include <STC15F2K60S2.H>
#include "intrins.h"

sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */
#define uchar unsigned char
#define uint unsigned int
#define DELAY_TIME 40 //扩大8倍
#define PCF8591_address 0x90 //PCF 地址
#define Light_address 0x01 //光敏电阻 地址
#define Move_address 0x03 //滑动变阻器 地址

bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_Stop(void);
void IIC_Start(void);
void IIC_Delay(unsigned char i);
unsigned char IIC_RecByte(void);
void IIC_SendByte(unsigned char byt);
uchar IIC_read(uchar hw_address,uchar reg_address);
void IIC_write(uchar hw_address,uchar reg_address,uchar num);

void init(void);
void SMG_output(void);
void Delay1ms(void);

uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
uchar SMG[8]={10,10,10,10,10,10,10,10};
uchar move=0,light=0;
void main(void)
{
	init();
	while(1)
	{//读取滑动变阻器
		move=IIC_read(PCF8591_address,Move_address);
		//读取光敏电阻
		light=IIC_read(PCF8591_address,Light_address);
		
		SMG[0]=move/100;SMG[1]=move%100/10;SMG[2]=move%10;
		SMG[5]=light/100;SMG[6]=light%100/10;SMG[7]=light%10;
		SMG_output();
	}
}

void IIC_write(uchar hw_address,uchar reg_address,uchar num)
{
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);
	IIC_WaitAck();
	IIC_SendByte(num);
	IIC_WaitAck();	
	IIC_Stop();	
}	

uchar IIC_read(uchar hw_address,uchar reg_address)
{
	uchar num;
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);	
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(hw_address|0x01);
	IIC_WaitAck();
	num=IIC_RecByte();
	IIC_WaitAck();
	IIC_Stop();	
	
	return num;
}

//
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;  					
    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;
}

//
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;  
}

//
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;    
}

void init(void)
{
	P2=(P2&0X1F)|0XA0;
	P0=0X00;
	P2=(P2&0X1F)|0X80;
	P0=0XFF;
	P2=(P2&0X1F)|0XC0;
	P0=0XFF;
	P2=(P2&0X1F)|0XE0;
	P0=0XFF;	
}

void SMG_output(void)
{
	uchar i;
	for(i=0;i<8;i++)
	{
	P2=(P2&0X1F)|0XC0;
	P0=(1 << i);
	P2=(P2&0X1F)|0XE0;
	P0=tab[SMG[i]];			
	Delay1ms();
	}
	P2=(P2&0X1F)|0XC0;
	P0=0XFF;
	P2=(P2&0X1F)|0XE0;
	P0=0XFF;		
}

void Delay1ms(void)		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

最后效果如下,前三位显示光敏电阻,后三位显示滑动变阻器。
在这里插入图片描述
不懂可以私信和评论

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月明Mo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值