用PCF8951,AT89C51,滑动电阻POT—HG,显示器LCD1602,和排阻RESPACK—8。
PCF89C51:
PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。
PCF8591的功能包括多路模拟输入、内置跟踪保持、8-bit模数转换和8-bit数模转换。PCF8591的最大转化速率由I2C总线的最大速率决定。
LCD1602在前文有所描述,这里不再一一解释。
仿真图如下:
程序如下:
main.c
#include<reg51.h>
#include<lcd1602.c>
#include<pcf8591.c>
unsigned char cp,cp1,flash,ad0,ad1;
unsigned int year = 2020;
unsigned int v0,v1,v2,v3;
void timer_isr(void) interrupt 1
{
TH0 = (65535 - 2000) / 256;
TL0 = (65535 - 2000) % 256;
cp++;cp1++;
if(cp1 >= 250)
{
goto_xy(1,0);
display_string("v0:");
display_num(v0 / 100);
display_string(".");
display_num(v0 / 10 % 10);
display_num(v0 % 10);
goto_xy(1,8);
display_string("v1:");
display_num(v1 / 100);
display_string(".");
display_num(v1 / 10 % 10);
display_num(v1 % 10);
}
}
void timer_init(void)
{
TMOD = 0x01;
TH0 = (65535 - 2000) / 256;
TL0 = (65535 - 2000) % 256;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void main(void)
{
timer_init();
lcd1602_init();
lcd1602_clear();
while(1)
{
if(cp >= 250)
{
cp = 0;
ad0 = get_pcf8591_ADC(0);delay(30);
ad0 = get_pcf8591_ADC(0);delay(30);
v0 = ad0 * 1.96;
ad1 = get_pcf8591_ADC(1);delay(30);
ad1 = get_pcf8591_ADC(1);delay(30);
v1 = ad1 * 1.96;
}
}
}
LCD1602.c
#define uchar unsigned char
#define uint unsigned int
sbit RS = P2^4;//数据/命令
sbit RW = P2^5;//读/写
sbit E = P2^6;//使能
uchar i;
void delay(unsigned int x)
{
while(x--);
}
void write_command(uchar command)
{
RW = 0;
RS = 0;
P0 = command;
E = 1;
delay(100);
E = 0;
RW = 1;
}
void write_data(uchar date)
{
RW = 0;
RS = 1;
E = 1;
P0 = date;
delay(100);
E = 0;
RW = 1;
}
void lcd1602_init(void)
{
write_command(0x38);
write_command(0x0f);
write_command(0x0c);
write_command(0x06);
}
void lcd1602_clear(void)
{
write_command(0x01);
write_command(0x02);
}
void display_string(uchar *p)
{
while(*p)
{
write_data(*p);
p++;
}
}
void display_num(uchar x)
{
双数字
// write_data((x / 10) + 0x30);
// write_data((x % 10) + 0x30);
//单数字
write_data(x + 0x30);
}
void goto_xy(uchar x,uchar y)
{
if(x == 1)
write_command(0x80 + y);
if(x == 2)
write_command(0x80 + 0x40 + y);
}
PCF8951.c
#include "intrins.h"
#define somenop Delay5us()
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA_s = P3^7; /* 数据线 */
sbit SCL_s = P3^6; /* 时钟线 */
void Delay5us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 12;
while (--i);
}
//总线启动条件
void IIC_Start(void)
{
SDA_s = 1;
SCL_s = 1;
somenop;
SDA_s = 0;
somenop;
SCL_s = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA_s = 0;
SCL_s = 1;
somenop;
SDA_s = 1;
}
//应答位控制
void IIC_Ack(bit ackbit)
{
if(ackbit)
{
SDA_s = 0;
}
else
{
SDA_s = 1;
}
somenop;
SCL_s = 1;
somenop;
SCL_s = 0;
SDA_s = 1;
somenop;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA_s = 1;
somenop;
SCL_s = 1;
somenop;
if(SDA_s)
{
SCL_s = 0;
IIC_Stop();
return 0;
}
else
{
SCL_s = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA_s = 1;
}
else
{
SDA_s = 0;
}
somenop;
SCL_s = 1;
byt <<= 1;
somenop;
SCL_s = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL_s = 1;
somenop;
da <<= 1;
if(SDA_s)
da |= 0x01;
SCL_s = 0;
somenop;
}
return da;
}
int get_pcf8591_ADC(unsigned char x)
{
unsigned char adc;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(x);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
adc = IIC_RecByte();
IIC_WaitAck();
IIC_Ack(0);
IIC_Stop();
return(adc);
}
//void pcf8591_out(unsigned char x)
//{
// IIC_Start();
// IIC_SendByte(0x90);
// IIC_WaitAck();
// IIC_SendByte(0x40);
// IIC_WaitAck();
// IIC_SendByte(x);
// IIC_WaitAck();
//}
运行结果如下: