我采用TSW-30浊度传感器,利用51单片机做了一个水质监测系统,AD用的是PCF8591,用LCD1602显示,但是显示过程中总是显示0(最小值),3000(最大值),然后是一些数字在变化,例如,1180,3000,1135,3000,1101,3000,不管是在清水中,还是在浊水中变化都一样,且模拟输入电压在不同的浊度水中变化明显,以下是程序资料,求诸位大神帮帮我
- /********************(C) COPRIGHT 2019 Crownto electronic **************************
- * 文件名 :main.c
- * 描述 :
- * 硬件连接:
- * PCF8591:VCC -> 5V; GND -> GND; SCL -> P1.6;SDA -> P1.7;
- * OUT1~OUT8 -> P3口
- * LCD1602:RS -> P2.5; RW -> P2.6; E -> P2.7;
- * D0~D7 -> P0口
- * 浊度传感器模块: VCC -> 5V; GND -> GND; AO -> AIN0;
- *
- * 功能描述:测量浊度值液晶显示;
- 串口接收测量所得的浊度值(波特率9600);
- * 可连接上位机显示浊度值;
- **********************************************************************************/
- #include <reg52.h>
- #include <include.h>
- typedef unsigned char uchar;
- typedef unsigned char uint;
- /**************外部变量定义************************/
- int num=0;
- /**************变量定义***************************/
- //double PH=0.0;
- //unsigned char disbuff[5]={0};
- double ADC_Voltage=0.0;
- float TU=0.0;
- float TU_value=0.0;
- float TU_calibration=0.0;
- unsigned char disbuff[13]={0};
- float temp_data=25.0;
- float K_Value=3047.19;
- /*
- * 函数名:Get_Voltage_Value
- * 描述 :获取ADC0809的转换电压值
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- * AIN0(0X40):热敏电阻
- * AIN1(0X41):悬空
- * AIN2(0X42):滑动变阻器
- * AIN3(0X43):光敏电阻
- */
- void Get_Voltage_Value()
- {
- ISendByte(PCF8591,0x40);
- num=IRcvByte(PCF8591); //ADC0 模数转换1 PH电极
- // TU =num * 5.0/ 255; //转换为电压值
- }
- /*
- * 函数名:Character_Conversion
- * 描述 :延时函数
- *
- * 输入 :unsigned char n:延时量
- * 输出 :无
- * 说明 :
- */
- void TU_Value_Conversion()
- {
- Get_Voltage_Value();
- TU=(num*5.0)/256;
- TU_calibration=-0.0192*(temp_data-25)+TU;
- TU_value=-865.68*TU_calibration + K_Value;
-
- if(TU_value<=0){TU_value=0;}
- if(TU_value>=3000){TU_value=3000;}
-
- /*显示酸碱度*/
- disbuff[0]=(int)(TU_value)/1000+'0';
- disbuff[1]=(int)(TU_value)%1000/100+'0';
- disbuff[2]=(int)(TU_value)%100/10+'0';
- disbuff[3]=(int)(TU_value)%10+'0';
-
-
- DisplaySingleChar(0x03,0,disbuff[0]);
- DisplaySingleChar(0x04,0,disbuff[1]);
- DisplaySingleChar(0x05,0,disbuff[2]);
- DisplaySingleChar(0x06,0,disbuff[3]);
- }
- void StartUART( void )
- { //波特率9600
- SCON = 0x50;
- TMOD = 0x20;
- TH1 = 0xFD;
- TL1 = 0xFD;
- PCON = 0x00;
- TR1 = 1;
- }
- //**********通过串口将接收到数据发送给PC端**************
- void R_S_Byte(uchar R_Byte)
- {
- SBUF = R_Byte;
- while( TI == 0 ); //查询法
- TI = 0;
- }
- /*
- * 函数名:main
- * 描述 :主函数
- * 输入 :无
- * 输出 :无
- */
- void main(void)
- {
- int i;
- LCDInit();
- StartUART();
-
- DisplayString(0x0,0," Welcome TU ");
- DisplayString(0x0,1,"Detection system");
- delay_1s();
- WriteCmd(LCD_CLS);
-
- DisplayString(0x0,0,"TU=");
- DisplaySingleChar(0x08,0,'p');
- DisplaySingleChar(0x09,0,'p');
- DisplaySingleChar(0x0A,0,'m');
-
-
- while(1)
- {
- TU_Value_Conversion();
- // display_value();
- for(i=0;i<5;i++)
- {
- R_S_Byte(disbuff[i]);
- }
- // R_S_Byte('\r');//发送回车换行符
- // R_S_Byte('\n');
- delay_1s();
- }
- }
- /******************** (C) COPYRIGHT 2015 Silicone shell electronic studio **************************
- * 文件名 :Lcd1602.c
- * 描述 : 1602液晶显示屏库函数
- * 硬件连接: EN:P2.5
- * RW:P2.6
- * RS:P2.7
- * D0~D7:P0口
- *
- * 实验平台:SHELL1.0开发板
- *
- * 作者 :Silicone shell electronic studio
- * 淘宝 :[url=http://shop111698447.taobao.com/shop/view_shop.htm?spm=a1z0e.1.10010.5.GCUiZL]http://shop111698447.taobao.com/ ... 0e.1.10010.5.GCUiZL[/url]
- **********************************************************************************/
- #include "lcd.h"
- #include <intrins.h>
- #include <reg52.h>
- /*********************LCD1602端口定义***************************/
- sbit LCD_E =P2^7; //执行使能端
- sbit LCD_RW =P2^5; //读写控制端
- sbit LCD_RS =P2^6; //数据命令选择端
- /*
- * 函数名:delay_1s
- * 描述 :延时函数1s
- *
- * 输入 :unsigned int time:延时量
- * 输出 :无
- * 说明 :液晶显示用延时函数
- */
- void delay_1s() //延时1s
- {
- unsigned char i, j, k;
- _nop_();
- i = 8;
- j = 1;
- k = 243;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
- /*
- * 函数名:Delay
- * 描述 :延时函数
- *
- * 输入 :unsigned int time:延时量
- * 输出 :无
- * 说明 :
- */
- void Delay(unsigned int time)
- {
- unsigned int timeCounter = 0;
- for (timeCounter = time;timeCounter > 0 ;timeCounter --)
- DelayUs(255);
- }
- /*
- * 函数名:DelayUs
- * 描述 :延时函数(微秒)
- *
- * 输入 :unsigned int time:延时量
- * 输出 :无
- * 说明 :
- */
- void DelayUs(unsigned int time)
- {
- unsigned int timeCounter = 0;
- for (timeCounter = 0;timeCounter < time;timeCounter ++)
- _nop_();
- }
- /****************************************************************************************\
- ** LCD驱动模块 **
- \****************************************************************************************/
- /*
- * 函数名:LCDInit
- * 描述 :液晶初始化函数
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void LCDInit(void)
- {
- //三次显示模式设置
- LCD_Data=0;
- LCD_E=Disable;
- Delay(5);
- WriteCmd(LCD_Init);
- Delay(5);
- WriteCmd(LCD_Init);
- Delay(5);
- WriteCmd(LCD_Init);
- WriteCmd(LCD_Init); //初始化
- WriteCmd(LCD_CloseCtr); //关显示
- WriteCmd(LCD_CLS); //清屏幕
- WriteCmd(LCD_EnterSet); //光标移动设置
- WriteCmd(LCD_DispCtr); //显示开以及光标设置
-
- }
- /*--------------------------------- LCD模式设置函数--------------------------------------*\
-
- SetWriteCmd() 设置LCD为写命令模式
- SetReadCmd() 设置LCD为读命令模式
- SetWriteData() 设置LCD为写数据模式
-
- \*----------------------------------------------------------------------------------------*/
- /*
- * 函数名:SetWriteCmd
- * 描述 :设置LCD为写命令模式
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void SetWriteCmd(void)
- {
- LCD_RW=Write;
- LCD_RS=Cmd;
- }
- /*
- * 函数名:SetReadCmd
- * 描述 :设置LCD为读命令模式
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void SetReadCmd(void)
- {
- LCD_RW=Read;
- LCD_RS=Cmd;
- }
- /*
- * 函数名:SetWriteData
- * 描述 :设置LCD为写数据模式
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void SetWriteData(void)
- {
- LCD_RW=Write;
- LCD_RS=Data;
- }
- /*--------------------------------- LCD功能执行函数--------------------------------------*\
-
- WriteCmd() 写命令
- WriteData() 写数据
- ExecuteCmd() 执行命令
- SetXY() 显示定位
- DisplaySingleChar() 显示单个字符
- DisplayString() 显示一串字符
- IsBusy() 忙标志检测
- \*----------------------------------------------------------------------------------------*/
- /*
- * 函数名:WriteCmd
- * 描述 :写命令
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void WriteCmd(char cmd)
- {
- while(IsBusy());
- LCD_Data=cmd;
- SetWriteCmd();
- ExecuteCmd();
- }
- /*
- * 函数名:WriteData
- * 描述 :写数据
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void WriteData(char ddata)
- {
- while(IsBusy());
- LCD_Data=ddata;
- SetWriteData();
- ExecuteCmd();
- }
- /*
- * 函数名:ExecuteCmd
- * 描述 :执行命令
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void ExecuteCmd(void)
- {
- LCD_E=Enable;
- LCD_E=Disable;
- }
- /*
- * 函数名:SetXY
- * 描述 :显示定位
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void SetXY(char x,char y)
- {
- if (y)
- x|=0x40;
- x|=0x80;
- Delay(5);
- WriteCmd(x);
- }
- /*
- * 函数名:DisplaySingleChar
- * 描述 :显示单个字符
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void DisplaySingleChar(char x,char y,char cchar)
- {
- SetXY(x,y);
- WriteData(cchar);
- }
- /*
- * 函数名:DisplayString
- * 描述 :显示字符串
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- void DisplayString(char x,char y,char *str)
- {
- while(*str)
- {
- Delay(5);
- DisplaySingleChar(x++,y,*str);
- str++;
- }
- }
- /*
- * 函数名:IsBusy
- * 描述 :忙标志检测
- *
- * 输入 :无
- * 输出 :无
- * 说明 :
- */
- bit IsBusy(void)
- {
- LCD_Data=0xFF;
- SetReadCmd();
- ExecuteCmd();
- // return (bit)(P0 & 0x80);
- return (bit)(LCD_Data & 0x80);
- }
- #ifndef __INCLUDE_H
- #define __INCLUDE_H
- //#define uchar unsigned char
- //#define uint unsigned int
- #include <stdio.h>
- #include "math.h"
- #include "I2C.h"
- #include "PCF8591.h"
- #include "lcd.h"
- #endif /* __INCLUDE_H */
- extern bit ack;
- //起动总线函数
- extern void Start_I2c();
- //结束总线函数
- extern void Stop_I2c();
- //应答子函数
- extern void Ack_I2c(bit a);
- //字节数据发送函数
- extern void SendByte(unsigned char c);
- //有子地址发送多字节数据函数
- extern bit ISendStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no) ;
- //无子地址发送多字节数据函数
- extern bit ISendStrExt(unsigned char sla,unsigned char *s,unsigned char no);
- //无子地址读字节数据函数
- extern unsigned char RcvByte();
- #include "PCF8591.h"
- #include "I2C.h"
- /*******************************************************************
- DAC 变换, 转化函数
- *******************************************************************/
- bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val)
- {
- Start_I2c(); //启动总线
- SendByte(sla); //发送器件地址
- if(ack==0)return(0);
- SendByte(c); //发送控制字节
- if(ack==0)return(0);
- SendByte(Val); //发送DAC的数值
- if(ack==0)return(0);
- Stop_I2c(); //结束总线
- return(1);
- }
- /*******************************************************************
- ADC发送字节[命令]数据函数
- *******************************************************************/
- bit ISendByte(unsigned char sla,unsigned char c)
- {
- Start_I2c(); //启动总线
- SendByte(sla); //发送器件地址
- if(ack==0)return(0);
- SendByte(c); //发送数据
- if(ack==0)return(0);
- Stop_I2c(); //结束总线
- return(1);
- }
- /*******************************************************************
- ADC读字节数据函数
- *******************************************************************/
- unsigned char IRcvByte(unsigned char sla)
- { unsigned char c;
- Start_I2c(); //启动总线
- SendByte(sla+1); //发送器件地址
- if(ack==0)return(0);
- c=RcvByte(); //读取数据0
- Ack_I2c(1); //发送非就答位
- Stop_I2c(); //结束总线
- return(c);
- }
- #ifndef _PCF8591_H_
- #define _PCF8591_H_
- #define PCF8591 0x90 //PCF8591 地址
- bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val);
- bit ISendByte(unsigned char sla,unsigned char c);
- unsigned char IRcvByte(unsigned char sla);
- #endif
- /*************************此部分为I2C总线的驱动程序*************************************/
- #include <reg52.h>
- #include <intrins.h>
- #include <I2C.H>
- #define NOP() _nop_() /* 定义空指令 */
- #define _Nop() _nop_() /*定义空指令*/
- sbit SCL=P2^1; //I2C 时钟
- sbit SDA=P2^0; //I2C 数据
- bit ack; /*应答标志位*/
- /*******************************************************************
- 起动总线函数
- 函数原型: void Start_I2c();
- 功能: 启动I2C总线,即发送I2C起始条件.
- ********************************************************************/
- void Start_I2c()
- {
- SDA=1; /*发送起始条件的数据信号*/
- _Nop();
- SCL=1;
- _Nop(); /*起始条件建立时间大于4.7us,延时*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SDA=0; /*发送起始信号*/
- _Nop(); /* 起始条件锁定时间大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SCL=0; /*钳住I2C总线,准备发送或接收数据 */
- _Nop();
- _Nop();
- }
- /*******************************************************************
- 结束总线函数
- 函数原型: void Stop_I2c();
- 功能: 结束I2C总线,即发送I2C结束条件.
- ********************************************************************/
- void Stop_I2c()
- {
- SDA=0; /*发送结束条件的数据信号*/
- _Nop(); /*发送结束条件的时钟信号*/
- SCL=1; /*结束条件建立时间大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- SDA=1; /*发送I2C总线结束信号*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- }
- /*******************************************************************
- 字节数据发送函数
- 函数原型: void SendByte(UCHAR c);
- 功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
- 此状态位进行操作.(不应答或非应答都使ack=0)
- 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
- ********************************************************************/
- void SendByte(unsigned char c)
- {
- unsigned char BitCnt;
- for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/
- {
- if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/
- else SDA=0;
- _Nop();
- SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/
- _Nop();
- _Nop(); /*保证时钟高电平周期大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- SCL=0;
- }
- _Nop();
- _Nop();
- SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop();
- _Nop();
- if(SDA==1)ack=0;
- else ack=1; /*判断是否接收到应答信号*/
- SCL=0;
- _Nop();
- _Nop();
- }
- /*******************************************************************
- 字节数据接收函数
- 函数原型: UCHAR RcvByte();
- 功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
- 发完后请用应答函数应答从机。
- ********************************************************************/
- unsigned char RcvByte()
- {
- unsigned char retc;
- unsigned char BitCnt;
- retc=0;
- SDA=1; /*置数据线为输入方式*/
- for(BitCnt=0;BitCnt<8;BitCnt++)
- {
- _Nop();
- SCL=0; /*置时钟线为低,准备接收数据位*/
- _Nop();
- _Nop(); /*时钟低电平周期大于4.7μs*/
- _Nop();
- _Nop();
- _Nop();
- SCL=1; /*置时钟线为高使数据线上数据有效*/
- _Nop();
- _Nop();
- retc=retc<<1;
- if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */
- _Nop();
- _Nop();
- }
- SCL=0;
- _Nop();
- _Nop();
- return(retc);
- }
- /********************************************************************
- 应答子函数
- 函数原型: void Ack_I2c(bit a);
- 功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
- ********************************************************************/
- void Ack_I2c(bit a)
- {
- if(a==0)SDA=0; /*在此发出应答或非应答信号 */
- else SDA=1;
- _Nop();
- _Nop();
- _Nop();
- SCL=1;
- _Nop();
- _Nop(); /*时钟低电平周期大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/
- _Nop();
- _Nop();
- }
- #ifndef _LCD_H
- #define _LCD_H
- /********************************************************************************\
- ** 宏定义区 **
- \********************************************************************************/
- /*------------------------------- LCD模块 ------------------------------------*/
- #define Busy 0x80 //忙信号
- #define LCD_Data P0 //数据口定义
- #define Write 0x00 //低电平写入
- #define Read 0x01 //高电平读出
- #define Data 0x01 //高电平选择数据
- #define Cmd 0x00 //低电平选择命令
- #define Enable 0x00 //跃变到低电平时执行命令
- #define Disable 0x01
- #define True 0x01
- #define False 0x00
- #define LCD_Init 0x38 //初始化模式
- #define LCD_DispCtr 0x0C //开显示及光标设置
- #define LCD_CloseCtr 0x08 //关显示
- #define LCD_CLS 0x01 //清屏幕
- #define LCD_EnterSet 0x06 //显示光标
- /********************************************************************************\
- ** 函数声明 **
- \********************************************************************************/
- extern void LCDInit(void); //LCD初始化
- void SetWriteCmd(void); //设置写命令模式
- void SetReadCmd(void); //设置读命令模式
- void SetWriteData(void); //设置写数据模式
- extern void WriteCmd(char cmd); //写命令
- void WriteData(char ddata); //写数据
- void ExecuteCmd(void); //执行命令
- void SetXY(char x,char y); //定位显示地址
- extern void DisplaySingleChar(char x,char y,char cchar); //显示单个字符
- extern void DisplayString(char x,char y,char *str); //显示一段字符串
- void Delay(unsigned int time); //延时主程序
- void DelayUs(unsigned int time); //延时子程序
- bit IsBusy(void); //判断忙标志函数
- extern void delay_1s();
- #endif
复制代码
|