我采用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
復制代碼
|