要做一个项目,被分配到做DS18B20温度传感与YL69土壤湿度传感器在51单片机上用LCD显示屏显示出来。温度传感模块很简单,网上到处都是资料,但是YL69的资料就很少了,特别还是在51单片机上实现。
其实懂了原理也还是简单。将传感器的AO口与单片机的ADDA模块通道3相连,将会实现数字量转换为模拟量,GND接地,VCC接电源(这里我们不接DO口,不会影响)。接下来就是代码部分。
此代码实现的是,YL69获取的数据在液晶显示屏上显示出来
#include<reg52.h>
#include<intrins.h>
#include<math.h>
typedef unsigned char uchar ;
typedef unsigned int uint ;
#define AT24C02_ADDR 0xa0 //AT24C02地址
#define DAC_EN 0x40
#define ADC_AutoINC 0x04
#define PCF8591_ADDR 0x90 //PCF8591地址
#define MAIN_Fosc 11059200L //定义主时钟
sbit SDA = P2^0;
sbit SCL = P2^1;
sbit LCDEN=P3^4;
sbit LCD_RS = P3^5; //LCD写数据或命令控制IO
sbit LCD_RW = P3^6; //LCD读写控制IO
sbit dula = P2^6;
sbit wela = P2^7;
uint strHEX[4];////INT8UtostrHEX函数转换的字符串显示10进制
void delay_ms(uint z)
{
uint x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
void delay_5us()
{
_nop_();
}
/*I2C初始化*/
void I2C_init()
{
SDA = 1;
_nop_();
SCL = 1;
_nop_();
}
/*I2C起始信号*/
void I2C_Start()
{
SCL = 1;
_nop_();
SDA = 1;
delay_5us();
SDA = 0;
delay_5us();
}
/*I2C终止信号*/
void I2C_Stop()
{
SDA = 0;
_nop_();
SCL = 1;
delay_5us();
SDA = 1;
delay_5us();
}
/*主机发送应答*/
void Master_ACK(bit i)
{
SCL = 0; // 拉低时钟总线允许SDA数据总线上的数据变化
_nop_(); // 让总线稳定
if (i) //如果i = 1 那么拉低数据总线 表示主机应答
{
SDA = 0;
}
else
{
SDA = 1; //发送非应答
}
_nop_();//让总线稳定
SCL = 1;//拉高时钟总线 让从机从SDA线上读走 主机的应答信号
delay_5us();
SCL = 0;//拉低时钟总线, 占用总线继续通信
_nop_();
SDA = 1;//释放SDA数据总线。
_nop_();
}
/*检测从机应答*/
bit Test_ACK()
{
SCL = 1;
delay_5us();
if (SDA)
{
SCL = 0;
_nop_();
I2C_Stop();
return(0);
}
else
{
SCL = 0;
_nop_();
return(1);
}
}
/*发送一个字节*/
void I2C_send_byte(uchar byte)
{
uchar i;
for(i = 0 ; i < 8 ; i++)
{
SCL = 0;
_nop_();
if (byte & 0x80)
{
SDA = 1;
_nop_();
}
else
{
SDA = 0;
_nop_();
}
SCL = 1;
_nop_();
byte <<= 1; // 0101 0100B
}
SCL = 0;
_nop_();
SDA = 1;
_nop_();
}
/*I2C 读一字节*/
uchar I2C_read_byte()
{
uchar dat,i;
SCL = 0;
_nop_();
SDA = 1;
_nop_();
for(i = 0 ; i < 8 ; i++)
{
SCL = 1;
_nop_();
if (SDA)
{
dat |= 0x01; //
}
else
{
dat &= 0xfe; //1111 1110
}
_nop_();
SCL = 0 ;
_nop_();
if(i < 7)
{
dat = dat << 1;
}
}
return(dat);
}
uint *INT8UtostrHEX(uint num) //将一个字节的数据转换为字符串
{
uint i = 0;
switch(num/100)
{
case 0: strHEX[i] = '0'; i++; break;
case 1: strHEX[i] = '1'; i++; break;
case 2: strHEX[i] = '2'; i++; break;
case 3: strHEX[i] = '3'; i++; break;
case 4: strHEX[i] = '4'; i++; break;
case 5: strHEX[i] = '5'; i++; break;
case 6: strHEX[i] = '6'; i++; break;
case 7: strHEX[i] = '7'; i++; break;
case 8: strHEX[i] = '8'; i++; break;
case 9: strHEX[i] = '9'; i++; break;
}
switch(num%100/10)
{
case 0: strHEX[i] = '0'; i++; break;
case 1: strHEX[i] = '1'; i++; break;
case 2: strHEX[i] = '2'; i++; break;
case 3: strHEX[i] = '3'; i++; break;
case 4: strHEX[i] = '4'; i++; break;
case 5: strHEX[i] = '5'; i++; break;
case 6: strHEX[i] = '6'; i++; break;
case 7: strHEX[i] = '7'; i++; break;
case 8: strHEX[i] = '8'; i++; break;
case 9: strHEX[i] = '9'; i++; break;
}
switch(num%100%10)
{
case 0: strHEX[i] = '0'; i++; break;
case 1: strHEX[i] = '1'; i++; break;
case 2: strHEX[i] = '2'; i++; break;
case 3: strHEX[i] = '3'; i++; break;
case 4: strHEX[i] = '4'; i++; break;
case 5: strHEX[i] = '5'; i++; break;
case 6: strHEX[i] = '6'; i++; break;
case 7: strHEX[i] = '7'; i++; break;
case 8: strHEX[i] = '8'; i++; break;
case 9: strHEX[i] = '9'; i++; break;
}
strHEX[3] = '\0';
return (strHEX);
}
void writeComm(uint comm)
{
// while(LCD1602_Check_Busy()); //忙则等待
LCD_RS = 0;
P0=comm;
LCDEN = 1;
_nop_();
LCDEN = 0;
delay_ms(1);
}
//写数据
void writeData(uint dat)
{
// while(LCD1602_Check_Busy()); //忙则等待
LCD_RS = 1;
P0 = dat;
LCDEN = 1;
_nop_();
LCDEN = 0;
delay_ms(1);
}
//写字符串
void LCD1602_Write_String(uint x,uint y,uint *s) //LCD1602写字符串
{
if (y == 0)
{
writeComm(0x80 + x); //表示第一行
}
else
{
writeComm(0xC0 + x); //表示第二行
}
while (*s != '\0')
{
writeData(*s++);
}
}
//初始化显示屏
void init()
{
LCD_RW = 0;
dula = wela = 0;
LCDEN=0;
writeComm(0x38);// 16*2显示
writeComm(0x0c); //打开显示
writeComm(0x06);//显示指针加1
writeComm(0x01); //清屏
delay_ms(5);
}
/*ad读数据*/
bit I2C_ADC_ReadData(uchar ADDR, uint *ADC_Value)
{
I2C_Start() ;
I2C_send_byte(PCF8591_ADDR + 0);
if (!Test_ACK())
{
return(0);
}
I2C_send_byte(ADDR);
Master_ACK(0);
I2C_Start();
I2C_send_byte(PCF8591_ADDR + 1);
if (!Test_ACK())
{
return(0);
}
*ADC_Value = I2C_read_byte();
Master_ACK(0);
I2C_Stop();
return(1);
}
void main()
{
uint ADC_Value;
init(); //LCD1602初始化
I2C_init();
// LCD1602_Write_String(0, 0, "CH0:");
while(1)
{
I2C_ADC_ReadData(3, &ADC_Value);
LCD1602_Write_String(0, 0,INT8UtostrHEX(ADC_Value));
delay_ms(400);
}
}