PCF8591是一种具有多功能的4通道A/D和D/A转换器。它具有以下功能特性:
1. 4个独立的模拟输入通道,可以测量电压信号。
2. 一个模拟输出通道,可以输出模拟电压信号。
3. 内置的8位A/D转换器,可以将模拟输入信号转换为数字值。
4. 内置的8位D/A转换器,可以将数字值转换为模拟输出信号。
5. 可以通过IIC总线与微控制器或其他设备进行通信。
PCF8591的设备地址设置如下:
- 如果硬件地址引脚A0、A1、A2均接地,则读操作地址为0x91,写操作地址为0x90。
要读取光敏传感器和电位器的模拟输入信号,需要将相应的控制寄存器写入特定的数据。具体来说,控制寄存器的写入数据应包括以下内容:
- 位7: 固定为0。
- 位6: 0:A/D转换 1:D/A转换
- 位5/位4: 00:四路单端输入
01:三路差分输入
10:两路单端,一路差分
11:两路差分输入
- 位3: 固定为0。
- 位2: 0:禁止自动增量 1:允许自动增量
- 位1/位0: 00:通道0 01:通道1
10:通道2 11:通道3
在蓝桥杯单片机设计与开发赛项使用的CT107D单片机开发平台中,PCF8591的三个硬件引脚地址均接地,两路模拟信号均为单端输入,分别是:
光敏传感器接到AIN1,通道1;控制寄存器应写入:0x01。
电位器Rb2接到AIN3,通道3;控制寄存器应写入:0x03。
PCF8591 A/D转换应用的开发流程包括以下步骤:
1. 初始化IIC总线。
2. 设置PCF8591的设备地址。
3. 写入控制寄存器,以选择要读取的模拟输入通道。
4. 读取A/D转换结果。
5. 将数字值转换为实际的电压或其他物理量。
icc.c
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <STC15F2K60S2.H>
#include "intrins.h"
#define DELAY_TIME 5
sbit sda = P2^1;
sbit scl = P2^0;
//
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
icc.h
#ifndef _IIC_H
#define _IIC_H
static void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
#endif
main.c
#include <STC15F2K60S2.H>
#include "iic.h"
//定义动态显示中单个数码管点亮时长
#define TSMG 500
unsigned char SMG_NoDot[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char SMG_Dot[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
unsigned char adc1_value = 0; //AIN1的采样数据
float adc1_volt = 0; //AIN1的换算电压
unsigned int smg1_volt = 0; //AIN1的显示电压
unsigned char adc3_value = 0; //AIN3的采样数据
float adc3_volt = 0; //AIN3的换算电压
unsigned int smg3_volt = 0; //AIN3的显示电压
void SELECT_HC138(unsigned char n,unsigned char dat)
{
P0=dat;
P2=(P2&0x1f)|0x00;
switch(n)
{
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;
}
P2=(P2&0x1f)|0x00;
}
void DisplaySMG_Bit(unsigned char pos,unsigned char value)
{
SELECT_HC138(7,0xff);
SELECT_HC138(6,0x01<<pos);
SELECT_HC138(7,value);
}
void DisplayAll(unsigned char value)
{
SELECT_HC138(6,0xff);
SELECT_HC138(7,value);
}
//===================电压值显示函数===================
void DisplaySMG_ADC()
{
//数码管右起第0位
DisplaySMG_Bit(7,SMG_NoDot[smg1_volt % 10]);
//数码管右起第1位
DisplaySMG_Bit(6,SMG_NoDot[(smg1_volt / 10) % 10]);
//数码管右起第2位
DisplaySMG_Bit(5,SMG_Dot[smg1_volt / 100]);
//数码管右起第5位
DisplaySMG_Bit(2,SMG_NoDot[smg3_volt % 10]);
//数码管右起第6位
DisplaySMG_Bit(1,SMG_NoDot[(smg3_volt / 10) % 10]);
//数码管右起第7位
DisplaySMG_Bit(0,SMG_Dot[smg3_volt / 100]);
DisplayAll(0xff);
}
//===============PCF8591电压采样处理函数===============
//通过I2C总线读取PCF8591模数转换器采集的数据,包括选择通道和读取数据。
unsigned char Read_PCF8591_ADC(unsigned char ain)
{
unsigned char tmp;
I2CStart(); //启动i2c通信
I2CSendByte(0x90); //PCF8591的写设备地址,告诉pcf8591要进行写操作
I2CWaitAck(); //等待设备的应答信号
if(ain == 1)
{
I2CSendByte(0x01); //通道1,光敏电阻电压
}
else if(ain == 3)
{
I2CSendByte(0x03); //通道3,可调电阻电压
}
I2CWaitAck();
I2CStop();
DisplaySMG_ADC(); //等待电压转换完成
I2CStart();
I2CSendByte(0x91); //PCF8591的读设备地址
I2CWaitAck();
tmp = I2CReceiveByte(); //读出AD采样数据
I2CSendAck(1); //产生非应答信号,告诉pcf8591不需要再发送数据
I2CStop();
return tmp;
}
//=============采样光敏电阻和可调电阻的电压=============
//采样AIN1和AIN3通道的数据,并将采样值转换为电压值,最后转换为要显示在数码管上的数据。
void Read_AIN1_AIN3()
{
adc1_value = Read_PCF8591_ADC(1);//读取通道1的adc值
adc1_volt = adc1_value * (5.0 / 255);//adc转换成电压值
smg1_volt = adc1_volt * 100;//转换成整数显示
adc3_value = Read_PCF8591_ADC(3);//读取通道3的值
adc3_volt = adc3_value * (5.0 / 255);
smg3_volt = adc3_volt * 100;
}
void initSystem()
{
SELECT_HC138(4,0xff);
SELECT_HC138(5,0x00);
SELECT_HC138(7,0xff);
}
void main()
{
initSystem();
while(1)
{
Read_AIN1_AIN3();
DisplaySMG_ADC();
}
}