找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 11466|回復: 15
收起左側

單片機水質監(jiān)測Proteus仿真程序 電阻模擬水質濁度和PH值

  [復制鏈接]
ID:511094 發(fā)表于 2019-11-17 19:19 | 顯示全部樓層 |閱讀模式
測量水溫,通過可調電阻模擬水質濁度和PH值,將采集的水質參數(shù)顯示在LCD1602上,同時通過串口上傳數(shù)據(jù)

T  溫度
Z 濁度
P PH值
上傳信息 :  T26Z60P7.5
信息表示:表示溫度26°   濁度60%   PH值為7.5

proteus仿真軟件沒有濁度采集傳感器和PH測量傳感器,所以通過可調電阻模擬,通過AD采集電壓進行顯示,濁度為0%~100%,表示濁度程度不同,
PH值為0~10,表示PH值不同。
數(shù)據(jù)信息通過串口上傳,通過虛擬串口模擬,另一端使用串口調試助手顯示,波特率為9600

仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
通信效果.png 虛擬串口軟件配置.png 計算機設備管理.png

單片機源程序如下:
  1. #include <reg51.h>        
  2. #include "lcd.h"
  3. #include "UART.h"
  4. #include "Delay.h"
  5. #include <intrins.h>
  6. #define uchar unsigned char
  7. #define uint unsigned int
  8. #define ulong unsigned long
  9. #define NACK        0
  10. #define ACK                1
  11. #define MEASURE_TEMP        0x03        //000 0001  1
  12. #define MEASURE_HUMI        0x05        //000 0010  1
  13. #define STATUS_REG_W        0x06        //000 0011  0
  14. #define STATUS_REG_R        0x07        //000 0011  1
  15. #define RESET                        0x1E        //000 1111  0
  16. ulong volt;//測量的電壓值
  17. sbit Data=P2^3;   //定義數(shù)據(jù)線
  18. sbit CLK=P3^3;//定義時鐘信號口
  19. sbit DIN=P3^4;//定義2543數(shù)據(jù)寫入口
  20. sbit DOUT=P3^5;//定義2543數(shù)據(jù)讀取口
  21. sbit CS=P3^2;//定義2543片選信號口
  22. sbit Data_P    = P2^4;                        // SHT11傳感器的數(shù)據(jù)管腳
  23. sbit Sck_P     = P2^3;                        // SHT11傳感器的時鐘管腳
  24. sbit BEEP =P2^5;
  25. uchar tmpe,h;
  26. uchar rec_dat[9];   //用于顯示的接收數(shù)據(jù)數(shù)組
  27. uchar temp_max = 50;
  28. ulong C2_max = 7500000;
  29. ulong LUX_max = 8500000;
  30. ulong C2_now = 0;
  31. ulong LUX_now = 0;
  32. unsigned char temp;                                                        // 保存溫度
  33. unsigned char humi;                                                  // 保存濕度

  34. enum { TEMP,HUMI };
  35. typedef union                              //定義共用同類型
  36. {
  37.         unsigned int i;
  38.         float f;
  39. }value;


  40. int display = 0;
  41. void delay(uchar ms)
  42. {  // 延時子程序
  43. uchar i;
  44. while(ms--)
  45. {
  46.   for(i = 0;i<250;i++);  
  47. }
  48. }

  49. char ShtWriteByte(unsigned char value)
  50. {
  51.         unsigned char i,error=0;
  52.         for(i=128;i>0;i>>=1)  // 高位為1,循環(huán)右移
  53.         {
  54.                 if (i&value)
  55.                         Data_P=1;               // 和要發(fā)送的數(shù)相與,結果為發(fā)送的位
  56.                 else
  57.                         Data_P=0;
  58.                 Sck_P=1;
  59.                 _nop_();                                                // 延時3us
  60.                 _nop_();
  61.                 _nop_();
  62.                 Sck_P=0;
  63.         }
  64.         Data_P=1;                                            // 釋放數(shù)據(jù)線
  65.         Sck_P=1;
  66.         error=Data_P;                                  // 檢查應答信號,確認通訊正常
  67.         _nop_();
  68.         _nop_();
  69.         _nop_();
  70.         Sck_P=0;
  71.         Data_P=1;
  72.         return error;                                 // error=1 通訊錯誤
  73. }

  74. char ShtReadByte(unsigned char ack)
  75. {
  76.         unsigned char i,val=0;
  77.         Data_P=1;                                                 // 釋放數(shù)據(jù)線
  78.         for(i=0x80;i>0;i>>=1)        // 高位為1,循環(huán)右移
  79.         {
  80.                 Sck_P=1;
  81.                 if(Data_P)
  82.                         val=(val|i);            // 讀一位數(shù)據(jù)線的值
  83.                 Sck_P=0;
  84.         }
  85.         Data_P=!ack;                            // 如果是校驗,讀取完后結束通訊
  86.         Sck_P=1;
  87.         _nop_();                                                        // 延時3us
  88.         _nop_();
  89.         _nop_();
  90.         Sck_P=0;
  91.         _nop_();
  92.         _nop_();
  93.         _nop_();
  94.         Data_P=1;                                                 // 釋放數(shù)據(jù)線
  95.         return val;
  96. }


  97. void ShtTransStart(void)
  98. {
  99.         Data_P=1;
  100.         Sck_P=0;
  101.         _nop_();
  102.         Sck_P=1;
  103.         _nop_();
  104.         Data_P=0;
  105.         _nop_();
  106.         Sck_P=0;
  107.         _nop_();
  108.         _nop_();
  109.         _nop_();
  110.         Sck_P=1;
  111.         _nop_();
  112.         Data_P=1;
  113.         _nop_();
  114.         Sck_P=0;
  115. }

  116. void ShtConnectReset(void)
  117. {
  118.         unsigned char i;
  119.         Data_P=1;                                    //準備
  120.         Sck_P=0;
  121.         for(i=0;i<9;i++)          //DATA保持高,SCK時鐘觸發(fā)9次,發(fā)送啟動傳輸,通迅即復位
  122.         {
  123.                 Sck_P=1;
  124.                 Sck_P=0;
  125.         }
  126.         ShtTransStart();           //啟動傳輸
  127. }

  128. char ShtMeasure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode)
  129. {
  130.         unsigned error=0;
  131.         unsigned int i;
  132.         ShtTransStart();                  // 啟動傳輸
  133.         switch(mode)                       // 選擇發(fā)送命令
  134.         {
  135.                 case 1 :                                           // 測量溫度
  136.                         error+=ShtWriteByte(0x03);
  137.                         break;
  138.                 case 2 :                                           // 測量濕度
  139.                         error+=ShtWriteByte(0x05);
  140.                         break;
  141.                 default:
  142.                         break;
  143.         }
  144.         for(i=0;i<65535;i++)
  145.                 if(Data_P==0)
  146.                         break;                                          // 等待測量結束
  147.                 if(Data_P)
  148.                         error+=1;                           // 如果長時間數(shù)據(jù)線沒有拉低,說明測量錯誤
  149.         *(p_value) =ShtReadByte(1);                  // 讀第一個字節(jié),高字節(jié) (MSB)
  150.         *(p_value+1)=ShtReadByte(1);                 // 讀第二個字節(jié),低字節(jié) (LSB)
  151.         *p_checksum =ShtReadByte(0);          // read CRC校驗碼
  152.         return error;                                                                          // error=1 通訊錯誤
  153. }

  154. void CalcSHT11(float *p_humidity ,float *p_temperature)
  155. {
  156.         const float C1=-4.0;                                 // 12位濕度精度 修正公式
  157.         const float C2=+0.0405;                        // 12位濕度精度 修正公式
  158.         const float C3=-0.0000028;        // 12位濕度精度 修正公式
  159.         const float T1=+0.01;                                 // 14位溫度精度 5V條件 修正公式
  160.         const float T2=+0.00008;                 // 14位溫度精度 5V條件 修正公式
  161.         float rh=*p_humidity;                                 // rh: 12位 濕度
  162.         float t=*p_temperature;                        // t:  14位 溫度
  163.         float rh_lin;                                                                // rh_lin: 濕度 linear值
  164.         float rh_true;                                                        // rh_true: 濕度 ture值
  165.         float t_C;                                                                         // t_C : 溫度 ℃
  166.         t_C=t*0.01 - 40;                                                 //補償溫度
  167.         rh_lin=C3*rh*rh + C2*rh + C1;                                        //相對濕度非線性補償
  168.         rh_true=(t_C-25)*(T1+T2*rh)+rh_lin;                //相對濕度對于溫度依賴性補償
  169.         *p_temperature=t_C;                                         //返回溫度結果
  170.         *p_humidity=rh_true;                                 //返回濕度結果
  171. }

  172. unsigned char TempCorrect(int temp)
  173. {
  174.         if(temp<0)        temp=0;
  175.         if(temp>970)  temp=970;
  176.         if(temp>235)  temp=temp+10;
  177.         if(temp>555)  temp=temp+10;
  178.         if(temp>875)  temp=temp+10;
  179.         temp=(temp%1000)/10;
  180.         return temp;
  181. }

  182. unsigned char HumiCorrect(unsigned int humi)
  183. {
  184.         if(humi>999)  humi=999;
  185.         if((humi>490)&&(humi<951))  humi=humi-10;
  186.         humi=(humi%1000)/10;
  187.         return humi+4;
  188. }

  189. void ReadShtData()
  190. {
  191.         value humi_val,temp_val;          // 定義兩個共同體,一個用于濕度,一個用于溫度
  192.         unsigned char error;                                                          // 用于檢驗是否出現(xiàn)錯誤
  193.         unsigned char checksum;                                                  // CRC
  194.         unsigned int temp1,humi1;                                                // 臨時讀取到的溫濕度數(shù)據(jù)

  195.         error=0;                                                                                 //初始化error=0,即沒有錯誤
  196.         error+=ShtMeasure((unsigned char*)&temp_val.i,&checksum,1);         //溫度測量
  197.         error+=ShtMeasure((unsigned char*)&humi_val.i,&checksum,2);         //濕度測量

  198.         if(error!=0)                                                           //如果發(fā)生錯誤,系統(tǒng)復位
  199.                 ShtConnectReset();
  200.         else
  201.         {
  202.                 humi_val.f=(float)humi_val.i;                                 //轉換為浮點數(shù)
  203.                 temp_val.f=(float)temp_val.i;                                  //轉換為浮點數(shù)
  204.                 CalcSHT11(&humi_val.f,&temp_val.f);          //修正相對濕度及溫度
  205.                 temp1=temp_val.f*10;
  206.                 temp=TempCorrect(temp1);
  207.                 humi1=humi_val.f*10-50;
  208.                 humi=HumiCorrect(humi1);
  209.                 humi1=humi1-1;
  210.         }

  211. }


  212. void read2543(uchar addr)
  213. {
  214.         uint ad=0;
  215.         uchar i;
  216.         CLK=0;
  217.         CS=0;//片選段,啟動2543
  218.         addr<<=4;//對地址位預處理
  219.         for(i=0;i<12;i++) //12個時鐘走完,完成一次讀取測量
  220.         {
  221.                 if(DOUT==1)
  222.                         ad=ad|0x01;//單片機讀取ad數(shù)據(jù)
  223.                 DIN=addr&0x80;//2543讀取測量地址位
  224.                 CLK=1;
  225.                 ;;;//很短的延時
  226.                 CLK=0;//產生下降沿,產生時鐘信號
  227.                 ;;;
  228.                 addr<<=1;
  229.                 ad<<=1;//將數(shù)據(jù)移位準備下一位的讀寫
  230.         }
  231.         CS=1;//關2543
  232.         ad>>=1;
  233.         volt=ad;//取走轉換結果
  234.         volt=volt*1221;//例子的滿量程為5V,轉換分辯率為12位(2的12次方=4096) 。即最大值是255,5/4096=1221mV,即例子中的1V代表實際1221mV        
  235. }

  236. void main(void)
  237. {

  238.         LcdInit();
  239.         ShtConnectReset();
  240.         UART_Init();

  241.         
  242.         while(1)
  243.         {
  244.             ReadShtData();

  245.                 DisplayListChar(4,0,"temp:");
  246.                 DisplayOneChar(10,0,(char)(temp/10+'0'));
  247.                 DisplayOneChar(11,0,(char)(temp%10+'0'));
  248.                 DisplayOneChar(12,0,(char)(' '));
  249.                 DisplayOneChar(13,0,(char)('C'));
  250.                 Uart1Send( 'T' );
  251.                 Uart1Send( (char)(temp/10+'0') );
  252.                 Uart1Send( (char)(temp%10+'0') );
  253.                
  254.                 read2543(0);//調用2543驅動程序測量地址為
  255.                 LUX_now=volt*2;
  256.                 DisplayListChar(0,1,"ZD:");
  257.                 DisplayOneChar(3,1,(char)(volt*2/1000000+'0'));
  258.               DisplayOneChar(4,1,(char)((volt*2/100000)%10+'0'));
  259.                 DisplayOneChar(6,1,(char)('%'));
  260.                 Uart1Send( 'Z' );
  261.                 Uart1Send( (char)(volt*2/1000000+'0') );
  262.                 Uart1Send( (char)((volt*2/100000)%10+'0') );

  263.                 read2543(1);//調用2543驅動程序測量地址為
  264.                 C2_now=volt*2;
  265.                 DisplayListChar(10,1,"PH:");
  266.                 DisplayOneChar(13,1,(char)(volt*2/1000000+'0'));
  267.                 DisplayOneChar(14,1,(char)('.'));
  268.               DisplayOneChar(15,1,(char)((volt*2/100000)%10+'0'));
  269.                 Uart1Send( 'P' );
  270.                 Uart1Send( (char)(volt*2/1000000+'0') );
  271.                 Uart1Send( '.' );
  272.                 Uart1Send( (char)((volt*2/100000)%10+'0') );

  273.                
  274.                 if(LUX_now>LUX_max || C2_now>C2_max  || temp>temp_max)
  275.                 {
  276.                         
  277.                         BEEP=0;
  278.                 }else
  279.                 {
  280.                         BEEP=1;
  281.                 }

  282.         }                                
  283. }
復制代碼

所有資料51hei提供下載:
水質監(jiān)測.rar (14.47 MB, 下載次數(shù): 412)

評分

參與人數(shù) 2黑幣 +55 收起 理由
檸軒0 + 5
admin + 50 共享資料的黑幣獎勵!

查看全部評分

回復

使用道具 舉報

ID:614056 發(fā)表于 2020-4-14 09:45 | 顯示全部樓層
這種方案有幾個小問題,1.AD速率比較慢,往往測試時間比較久還得不到穩(wěn)定的PH值
2.測試精度不高,重復性不好
之前我也是想了很多辦法都沒有解決好這個問題,后續(xù)加了個輔助電路方解決,目前量產中
回復

使用道具 舉報

ID:666145 發(fā)表于 2019-12-17 12:38 | 顯示全部樓層
在嗎?非常感謝。我下載了。想請教一下。
回復

使用道具 舉報

ID:605716 發(fā)表于 2020-4-9 15:41 | 顯示全部樓層
哇,壓縮包貌似只能用winrar才可以解壓成功
回復

使用道具 舉報

ID:728691 發(fā)表于 2020-4-14 08:12 來自觸屏版 | 顯示全部樓層
好資料,51黑有你更精彩!!!
回復

使用道具 舉報

ID:733754 發(fā)表于 2020-4-21 19:12 | 顯示全部樓層
你好,我的課題也是跟你幾乎一樣,也是監(jiān)測水質然后遠程通訊,我想想你請教點問題,大神,哈哈哈
回復

使用道具 舉報

ID:742174 發(fā)表于 2020-5-1 15:40 來自觸屏版 | 顯示全部樓層
goalpeak 發(fā)表于 2020-4-14 09:45
這種方案有幾個小問題,1.AD速率比較慢,往往測試時間比較久還得不到穩(wěn)定的PH值
2.測試精度不高,重復性不 ...

你好,請問能分享一下嗎?
回復

使用道具 舉報

ID:747608 發(fā)表于 2020-5-9 15:16 | 顯示全部樓層
dantemaycry 發(fā)表于 2020-5-8 12:33
單片機水情監(jiān)測系統(tǒng)設計   交流交流?

我課題和你一樣 交流交流?
回復

使用道具 舉報

ID:903852 發(fā)表于 2021-4-11 18:18 | 顯示全部樓層
為什么我打不開這個仿真,本人用proteus8
回復

使用道具 舉報

ID:328014 發(fā)表于 2021-4-11 18:21 | 顯示全部樓層
哈哈哈可以 發(fā)表于 2021-4-11 18:18
為什么我打不開這個仿真,本人用proteus8

你去百度Proteus8.8白菜直裝版,這個版本才能打開,如圖
51hei.png
回復

使用道具 舉報

ID:907892 發(fā)表于 2021-4-18 17:35 | 顯示全部樓層
為什么我沒有仿真,里面打不開
回復

使用道具 舉報

ID:328014 發(fā)表于 2021-4-18 18:36 | 顯示全部樓層
槿榆yyds 發(fā)表于 2021-4-18 17:35
為什么我沒有仿真,里面打不開

8.8版本的仿真,看10樓的回復
回復

使用道具 舉報

ID:575287 發(fā)表于 2021-5-7 16:40 | 顯示全部樓層
想問下如何添加溶解氧電路和程序?
回復

使用道具 舉報

ID:922247 發(fā)表于 2021-5-17 11:24 | 顯示全部樓層
goalpeak 發(fā)表于 2020-4-14 09:45
這種方案有幾個小問題,1.AD速率比較慢,往往測試時間比較久還得不到穩(wěn)定的PH值
2.測試精度不高,重復性不 ...

能分享一下嗎
回復

使用道具 舉報

ID:968818 發(fā)表于 2021-9-28 12:56 | 顯示全部樓層
測PH的要用那個原件呢哥
回復

使用道具 舉報

ID:1007991 發(fā)表于 2022-4-30 17:41 | 顯示全部樓層
大佬能加按鍵上下限電路嗎
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表