h>
#define uchar unsigned char
#define uintunsigned int
#defineDelay4us(){_nop_();_nop_();_nop_();_nop_();}
sbitLCD_RS=P2^6;
sbitLCD_RW=P2^5;
sbitLCD_EN=P2^7;
sbitSCL=P2^0; //I2C时钟引脚
sbitSDA=P2^1; //I2C数据输入输出引脚
ucharRecv_Buffer[4]; //数据接收缓冲
uintVoltage[]={'0','0','0','0'}; //数据分解为电压x。
xx
bitbdataIIC_ERROR; //I2C错误标志位
ucharLCD_Line_1[]={” 。
V "};
//延时
voiddelay(intms)
{
uchari;
while(ms--)for(i=0;i<250;i++) Delay4us();
}
//LCD忙检测
bit LCD_Busy_Check()
{
bitResult;
LCD_RS=0;LCD_RW=1;
LCD_EN=1;Delay4us();Result=(bit)(P0&0x80);
LCD_EN=0;
return Result;
}
//写指令
voidLCD_Write_Command(ucharcmd)
{
while(LCD_Busy_Check());
LCD_RS=0;LCD_RW=0;LCD_EN=0;_nop_();_nop_();
P0=cmd;Delay4us();
LCD_EN=1;Delay4us();LCD_EN=0;
}
//写数据
voidLCD_Write_Data(uchardat)
{
while(LCD_Busy_Check());
LCD_RS=1;LCD_RW=0;LCD_EN=0;P0=dat;Delay4us();
LCD_EN=1;Delay4us();LCD_EN=0;
}
//初始化
voidLCD_Initialise()
{
LCD_Write_Command(0x38);delay(5);
LCD_Write_Command(0x0c);delay(5);
LCD_Write_Command(0x06);delay(5);
LCD_Write_Command(0x01);delay(5);
}
//设置显示位置
voidLCD_Set_Position(ucharpos)
{
LCD_Write_Command(pos|0x80);
}
//显示一行
voidLCD_Display_A_Line(ucharLine_Addr,uchars[])
{
uchari;
LCD_Set_Position(Line_Addr);
for(i=0;i<16;i++)LCD_Write_Data(s[i]);
}
// 将模数转换后得到的值分解存入缓存
voidConvert_To_Voltage(ucharval)
{
ucharTmp; //最大值为255,对应5V,255/5=51
Voltage[2]=val/51+’0'; //整数部分
Tmp=val%51*10; //第一位小数
Voltage[1]=Tmp/51+'0';
Tmp=Tmp%51*10;
Voltage[0]=Tmp/51+’0’;
}
/**********************************************************
函数名称:
iic_start()
函数功能:
启动I2C总线子程序
时钟保持高,数据线从高到低一次跳变,I2C通信开始
**********************************************************/
voidiic_start(void)
{
SDA= 1;
SCL =1;
Delay4us();//延时5us
SDA=0;
Delay4us();
SCL =0;
}
/**********************************************************
函数名称:
iic_stop()
函数功能:
停止I2C总线数据传送子程序
时钟保持高,数据线从低到高一次跳变,I2C通信停止
**********************************************************/
voidiic_stop(void)
{
SDA=0;
SCL=1;
Delay4us();
SDA=1;
Delay4us();
SCL= 0;
}
/**********************************************************
函数名称:
iicInit_()
函数功能:
初始化I2C总线子程序
**********************************************************/
voidiicInit(void)
{
SCL=0;
iic_stop();
}
/**********************************************************
函数名称:
slave_ACK
函数功能:
从机发送应答位子程序
**********************************************************/
voidslave_ACK(void)
{
SDA=0;
SCL= 1;
Delay4us();
SCL= 0;
SDA= 1;
}
/**********************************************************
函数名称:
slave_NOACK
函数功能:
从机发送非应答位子程序,迫使数据传输过程结束
**********************************************************/
voidslave_NOACK(void)
{
SDA= 1;
SCL= 1;
Delay4us();
SDA=0;
SCL=0;
SDA =0;
}
/**********************************************************
函数名称:
check_ACK
函数功能:
主机应答位检查子程序,迫使数据传输过程结束
**********************************************************/
voidcheck_ACK(void)
{
SDA=1;//置成输入
SCL=1;
F0=0;
Delay4us();
if(SDA==1)
//若SDA=1表明非应答
F0=1;
//置位非应答标志F0
SCL= 0;
}
/**********************************************************
函数名称:
IICSendByte
入口参数:
indata
函数功能:
发送一个字节
**********************************************************/
voidIICSendByte(unsignedcharindata)
{
unsignedcharn=8;//发送一字节数据,共八bit
while (n--)
{
SDA=(bit)(indata&0x80);
SCL=1;
Delay4us();
SCL=0;
indata=indata<〈 1;//数据左移一位
}
}
/**********************************************************
函数名称:
IICreceiveByte
返回接收的数据tdata
函数功能:
接收一字节子程序
**********************************************************/
unsigned charIICreceiveByte(void)
{
unsignedcharn =8;//读取一字节数据,共八bit
unsignedchartdata=0;
while(n-—)
{
SDA=1;
SCL =1;
tdata= tdata 〈<1;//左移一位
if(SDA==1)
tdata =tdata| 0x01;
//若接收到的位为1,则数据的最后一位置1
else
tdata= tdata &0xfe;
//否则数据的最后一位置0
SCL=0;
}
return (tdata);
}
/**********************************************************
函数名称:
ADC_PCF8591
函数功能:
A/D转换,结果存入receivebuf
**********************************************************/
void ADC_PCF8591(unsignedcharcontrolbyte)
{
unsignedchari=0;
iic_start();
IICSendByte(0x90);//控制字0x90
check_ACK();
IICSendByte(controlbyte);//通道控制字
check_ACK();
iic_start(); //重新发送开始命令
IICSendByte(0x91);//控制字0x91
check_ACK();
IICreceiveByte();//空读一次
slave_ACK();//收到一个字节后发送一个应答位
while (i〈 3)
//采集0,1,2通道
{
Recv_Buffer[i++]=IICreceiveByte();
slave_ACK();
}
Recv_Buffer[3] =IICreceiveByte();//采集第3通道
slave_NOACK();//收到最后一个字节后发送一个非应答位
iic_stop();
}
//主程序
voidmain()
{
LCD_Initialise();
while
(1)
{
ADC_PCF8591(0x04);
Convert_To_Voltage(Recv_Buffer[0]);
LCD_Line_1[2]=Voltage[2];
LCD_Line_1[4]=Voltage[1];
LCD_Line_1[5]=Voltage[0];
LCD_Display_A_Line(0x00, LCD_Line_1);
}
}
8、结语
在这次单片机课设中,通过自己动手查阅资料,不仅知道了芯片PCF8591和LCD1602工作原理、各引脚的功能等,还巩固了C语言程序的编写,对51单片机也有了更深的理解,能熟练的运用Keil等软件。
期间遇到过LCD显示数据会抖动的问题,检查了相关的IIC总线程序,延长了延时程序,修改了LCD查忙时程序与AD转换程序中的控制字写入检查模块,在主程序中增加了一个模块:
若控制字写入有问题则重新启动IIC总线重新开始转换电压与数据传送.问题解决!
9、参考文献
单片机原理及应用(c语言版)周国运