项目13—PCF8951与LCD1602实现电压表的设计(含PCF8951详细解释)

用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总线的最大速率决定。

项目13—PCF8951与LCD1602实现电压表的设计(含PCF8951详细解释)_第1张图片

项目13—PCF8951与LCD1602实现电压表的设计(含PCF8951详细解释)_第2张图片

项目13—PCF8951与LCD1602实现电压表的设计(含PCF8951详细解释)_第3张图片

LCD1602在前文有所描述,这里不再一一解释。

仿真图如下:

项目13—PCF8951与LCD1602实现电压表的设计(含PCF8951详细解释)_第4张图片

程序如下: 

项目13—PCF8951与LCD1602实现电压表的设计(含PCF8951详细解释)_第5张图片

main.c

#include
#include
#include
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();	
//}

运行结果如下:

项目13—PCF8951与LCD1602实现电压表的设计(含PCF8951详细解释)_第6张图片

你可能感兴趣的:(单片机,嵌入式硬件)