蓝桥杯学习笔记 单片机CT107D PCF8591使用

一.PCF8591的使用

1.PCF8591介绍

PCF8591是单片、单电源低功耗的8位CMOS数据采集器件,具有IIC总线接口的8位A/D以及D/A转换器,有4路A/D转换输入,1路D/A模拟输出。使用iic通信

2.CT107D中PCF8591引脚介绍

d472bc9f71d34e5390ebb258ba4daecd.png

其中AIN为思路输入通道连接,AIN1连接光敏电阻,AIN3连接RB2电位器P20对应SCL,P21对应sda需要在iic.c中补充。

93400d223b9c4c8e9fcb93be86d9c656.png

3.控制字节

参考数据手册:

c5b9e29607ca4f198960a2b89bd21fc9.png

第7位:置1是允许DA按照写入的值输出 ,置0时会固定输出大约1v的电压

5-6位:

00:四路单端输入(常用)

01:三路差分输入

10:单端和差分输入

11:两路差分输入

(翻译的不一定准确)

第3位:自动增量选择位(一般置0)

1-2位:通道选择

二.数据帧介绍及示例代码

数据类型定义:

unsigned char adc1_value;
float adc1_volt;
unsigned int adc1_smg;
unsigned char adc2_value;
float adc2_volt;
unsigned int adc2_smg;

1.AD

846cd75a1a17466283a20d21276d90b5.png

流程:

  1. 发送Start信号
  2. 写入地址并接受应答
  3. 写入控制字并接受应答
  4. 接受数据并发送应答信号“1”
  5. 发送结束信号

虽然数据手册只给了一点,但在实际使用中,需要先选择AD转换的通道

  1. 发送Start信号
  2. 写入地址并接受应答
  3. 写入控制字并接受应答
  4. 发送结束信号

示例代码:


unsigned char Read_ADC(unsigned char Ain)//Ain:通道选择
{
	unsigned char temp;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	if(Ain==1)
	{
		I2CSendByte(0x01);//选择channel2
	}
	if(Ain==3)
	{
		I2CSendByte(0x03);//选择channel2
	}
	I2CWaitAck();
	I2CStop();
	Display_Dynamic();
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	temp=I2CReceiveByte();//获取8位数据
	I2CSendAck(1);
	I2CStop();
	return temp;
}
void Read_Ain()//数据转化
{
	adc1_value=Read_ADC(1);
	adc1_volt=adc1_value/255.0*5;
	adc1_smg=adc1_volt*100;
	adc2_value=Read_ADC(3);
	adc2_volt=adc2_value/255.0*5;
	adc2_smg=adc2_volt*100;
}

2.DA

1a82e9144a30459c8d72d37bb07bb7b6.png

流程:

  1. 发送Start信号
  2. 写入地址并接受应答
  3. 写入控制字并接受应答
  4. 写入数据并接受应答
  5. 发送结束信号

示例代码

void Write_DAC(unsigned char dat)
{
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x40);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

 碎碎念:如果要使用DA功能需要时刻保持控制字节第七位为1,即使是在AD控制中 (此时才会有符合需要的值输出),

三.练习

在数码管的1,2,3位显示光敏电阻上的分压,在6,7,8位显示电位器Rb2的分压,并将电位器Rb2上的电压通过DAC输出

示例代码:

#include <REGX52.H>
#include "iic.h"
code unsigned char SMG_NoDot[] =
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
code unsigned char SMG_Dot[] =
{0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x88,0x83,0xc6,0xa1,0x86,0x8e};
unsigned char adc1_value;
float adc1_volt;
unsigned int adc1_smg;
unsigned char adc2_value;
float adc2_volt;
unsigned int adc2_smg;
void DelaySMG(unsigned int t)
{
	while(t--);
}
void SelectHC573(unsigned char channel,unsigned char dat)
{
	switch(channel)
	{
		case 4:
			P2=(P2&0x1f)|0x80;
		break;
		case 5:
			P2=(P2&0x1f)|0xa0;
		break;
		case 6:
			P2=(P2&0x1f)|0xc0;
		break;
		case 7:
			P2=(P2&0x1f)|0xe0;
		break;
		case 0:
			P2=(P2&0x1f)|0x00;
		break;
	}
	P0=dat;
	P2=(P2&0x1f)|0x00;
}
void SMG_Display(unsigned char pos,unsigned char dat)
{
	SelectHC573(6,0x01<<(pos-1));
	SelectHC573(7,dat);
	DelaySMG(500);
	SelectHC573(6,0x01<<(pos-1));
	SelectHC573(7,0xff);
}
void Display_Dynamic()
{
	SMG_Display(6,SMG_Dot[adc1_smg/100]);
	SMG_Display(7,SMG_NoDot[adc1_smg%100/10]);
	SMG_Display(8,SMG_NoDot[adc1_smg%10]);
	
	SMG_Display(1,SMG_Dot[adc2_smg/100]);
	SMG_Display(2,SMG_NoDot[adc2_smg%100/10]);
	SMG_Display(3,SMG_NoDot[adc2_smg%10]);
}
unsigned char Read_ADC(unsigned char Ain)
{
	unsigned char temp;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	if(Ain==1)
	{
		I2CSendByte(0x41);//由于要使用DAC所以第七位置1
	}
	if(Ain==3)
	{
		I2CSendByte(0x43);
	}
	I2CWaitAck();
	I2CStop();
	Display_Dynamic();
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return temp;
}
void Write_DAC(unsigned char dat)
{
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x40);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}
void Read_Ain()
{
	adc1_value=Read_ADC(1);
	adc1_volt=adc1_value/255.0*5;
	adc1_smg=adc1_volt*100;
	adc2_value=Read_ADC(3);
	adc2_volt=adc2_value/255.0*5;
	adc2_smg=adc2_volt*100;
}
void Sys_Init()
{
	SelectHC573(4,0xff);
	SelectHC573(5,0x00);
}
void main()
{
	Sys_Init();
	while(1)
	{
		Display_Dynamic();
		Read_Ain();
		Write_DAC(adc1_value);
	}
}

 后续补充:上述代码发现显示的两个数据反了(数码管前三位应该显示的是电位器分压,实际是光敏电阻分压).查询资料发现原因:发送读取指令后读取的是上一次采集的值,所以解决方法也很简单,连续读取两次,舍弃第一次读取的值.修改的代码有点粗略,也希望有大佬指点更简介的代码

unsigned char Read_ADC(unsigned char Ain)
{
	unsigned char temp;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	if(Ain==1)
	{
		I2CSendByte(0x41);
	}
	if(Ain==3)
	{
		I2CSendByte(0x43);
	}
	I2CWaitAck();
	I2CStop();
	Display_Dynamic();
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CSendAck(0);//发送应答位,继续接收数据
	temp=I2CReceiveByte();
	I2CSendAck(1);//发送非应答位,停止接受数据 
	I2CStop();
	return temp;
}

附:

闲来无事看到板子上有个A/D排针,通过原理图发现与AIN0相连,突发奇想做一个小电压表.

unsigned char Read_ADC(unsigned char Ain)
{
	unsigned char temp;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x00);
	I2CWaitAck();
	I2CStop();
	Display_Dynamic();
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return temp;
}
void Read_Ain()
{
	adc1_value=Read_ADC(1);
	adc1_volt=adc1_value/255.0*5;
	adc1_smg=adc1_volt*100;

}

把上述代码替换一下,再选择好数码管就可以了,精度一般般

b62a4ddbbd4a4842b842b95bf46dcb7b.jpeg

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值