找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1189|回复: 0
打印 上一主题 下一主题
收起左侧

电赛 简易智能液体容器制作 附TDS传感器STM32单片机程序

[复制链接]
跳转到指定楼层
楼主
本设计以STM32F1单片机为控制核心,设计并制作了简易多功能液体容器.设计主要包括单片机控制模块、电源模块、超声波测距模块、TDS传感器模块、压力传感器模块、显示模块。该设计利用超声波测量液体液位,压力传感器测量液体重量;TDS传感器可检测水中含有的溶解物,利用TDS值,可以区分不同浓度的盐水、不同的液体种类。再由两个OLED屏幕显示液体液位、重量、浓度、种类等参数。经测试,系统基本完成了要求。

一、系统方案
本系统主要由单片机控制模块、电源模块、超声波测距模块、TDS传感器模块、压力传感器模块、显示模块组成。
1.1单片机控制模块的论证与选择
方案一:采用STC89C51单片机为主控芯片,单片机只有32个IO口、2个定时器和2个外部中断,内部RAM为128字节,速度和性能比较低,功能较少,所需外围电路较多,不考虑此方案。
方案二:采用STM32F103C8T6单片机作为控制芯片。由 ST 厂商推出的 STM32 系列单片机,功能强大,性价比高。STM32F103C8T6最小系统板集成了工作频率为72 MHz的高性能ARM Cortex -M3 32位RISC内核、高速嵌入式存储器(最高128字节的闪存和最高20k字节的SRAM),以及连接到两条APB总线的各种增强型I/o和外设。所有器件都提供两个12位ADC、三个通用16位定时器和一个PWM定时器,以及标准和高级通信接口:最多两个I2C和SPI、三个USARTs、一个USB和一个CAN。在可行性与精确度指标上比较过后,决定采用方案二。
1.2显示模块的论证与选择
方案一:采用LCD1602显示。LCD1602是字符型液晶,显示字母和数字比较方便,控制简单,成本较低。内部含有日文平假名、英文字母、数字和一些常用符号字库,没有中文字库。但可以自定义的显示字符,只有两行显示。
方案二:采用OLED显示。OLED即有机发光二极管,具有自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快等优点,与LCD1602相比,OLED引脚较少,只有4个引脚,使用简单,方便。
在可行性上比较过后,决定采用方案二。
1.3测距模块的论证与选择
方案一:超声波测距。本系统采用超声波传感器进行液位测距,超声波具有易于定向发射、方向性好、强度易控制、与被测量物体不需要直接接触的特点。超声波对液体、固体的穿透本领很大,尤其是在不透明的固体中,超声波碰到杂质或分界面会产生显著反射,形成反射回波使得超声波测距有较高的准确性。
方案二:光电液位传感器测距。光电传感器内部包含一个近红外发光二极管和一个光敏接收器。发光二极管所发出的光被导入传感器顶部的透镜。当液体浸没光电液位开关的透镜时,则光折射到液体中,从而使接收器收不到或只能接收到少量光线。光电液位开关通过感应这一变化,接收器可以驱动内部的电气开关,从而启动外部报警或控制电路。但光电液位传感器需要接触液体,容易受到环境损坏。
在可行性上比较过后,决定采用方案一。
1.4液体浓度和种类检测的论证与选择
方案一:TDS传感器。TDS传感器可准确测量水中含有的溶解物,水中含有的溶解物越多,TDS值越高。可利用TDS值区分盐水浓度、不同液体的种类。TDS传感器配合8 位高性价比单片机,内部已做 AD采集,并通过算法计算出对应的TDS值。
方案二::PH传感器。PH传感器可检测溶液中的PH值,不同的PH值对应不同的输出信号。PH传感器配合8位单片机处理器,通过此单片机的10位ADC对放大后的传感器信号采样,板载电位器调节输出信号的量程,并通过最小二乘法软件算法计算出信号与PH值得线性函数关系式,进而采用线性函数关系式求出信号对应的PH值。但不同浓度的盐水溶液中PH值差别不大,不能满足要求。在可行性上比较过后,决定采用方案一。

制作出来的实物图如下:


单片机源程序如下:
  1. #include "stm32f10x.h"
  2. #include <string.h>
  3. #include "delay.h"
  4. #include "stdio.h"
  5. #include "bsp_SysTick.h"
  6. #include "math.h"
  7. #include "Key.h"
  8. #include "OLED.h"
  9. #include "bsp_adc.h"
  10. #include "ds18b20.h"
  11. #include "timer.h"
  12. #include "bsp_usart1.h"
  13. #include "bsp_usart2.h"

  14.    
  15. volatile uint32_t time = 0; // ms 计时变量
  16. uint32_t a = 0;
  17. uint32_t b = 0;
  18. uint32_t sta= 0;
  19. ////定义变量

  20. GPIO_InitTypeDef  GPIO_InitStructure;
  21. unsigned char AD_CHANNEL=0;


  22. float TDS=0.0,TDS_voltage;
  23. float TDS_value=0.0,voltage_value;
  24. float compensationCoefficient=1.0;//温度校准系数
  25. float compensationVolatge;
  26. float kValue=1.67;
  27. float TEMP_Value=0.0;
  28. float averageVoltage=0;
  29. //char  TEMP_Buff[5];   //温度存放数组
  30. char  TDS_Buff[6];




  31. extern  u8 SET_Flag,SET_Count; //设置标志位
  32. extern u8 CLC_Flag; //清屏标志位
  33. extern u8 Warning_flag;
  34. u8 Warning_count=0;




  35. // ADC1转换的电压值通过MDA方式传到SRAM
  36. extern __IO uint8_t ADC_ConvertedValue[4];

  37. // 用于保存转换计算后的电压值          
  38. float ADC_ConvertedValueLocal[4];




  39. void GPIO_Configuration(void)
  40. {
  41. //        GPIO_InitTypeDef GPIO_InitStructure;
  42.        
  43.         /* Enable the GPIO  Clock */                                                        
  44.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO,ENABLE);
  45.        
  46.         //GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);                //屏蔽所有作为JTAG口的GPIO口
  47.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);                //屏蔽PB口上IO口JTAG功能


  48. }

  49. ///**************温度采集函数***************/
  50. //void TEMP_Value_Conversion()
  51. //{
  52. //       
  53. //          TEMP_Value=DS18B20_Get_Temp();
  54. //       
  55. //          TEMP_Buff[0]=(int)(TEMP_Value)%1000/100+'0';       
  56. //          TEMP_Buff[1]=(int)(TEMP_Value)%100/10+'0';
  57. //          TEMP_Buff[2]='.';
  58. //          TEMP_Buff[3]=(int)(TEMP_Value)%10+'0';
  59. //}


  60. /**************TDS值采集函数***************/
  61. float TDS_Value_Conversion()
  62. {
  63.           u32 ad=0;
  64.           u8 i;

  65.           float compensationCoefficient;
  66.           float compensationVolatge;
  67.           float temperature=25.0;//假设温度是25度,进行温度补偿,如果有18B20,则采集温度后,更新这个温度值
  68.           
  69.                
  70.           ad=0;
  71.           for(i=0;i<50;i++)//读取50次的AD数值取其平均数较为准确       
  72.                 {
  73.                         ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  74.                         while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//转换结束标志位
  75.                         ad=ad+ADC_GetConversionValue(ADC1);//返回最近一次ADCx规则组的转换结果               
  76.                 }
  77.                 ad=ad/50;
  78.         //ADC_ConvertedValueLocal[0]=(float)ad/4096*3.3; //AD转换
  79.          averageVoltage        =(float)ad/4096*3.3; //AD转换
  80.                
  81.         // averageVoltage = getMedianNum(analogBufferTemp, SCOUNT) * (float)VREF / 1024.0; // read the analog value more stable by the median filtering algorithm, and convert to voltage value
  82.          compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0); //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
  83.    compensationVolatge = averageVoltage / compensationCoefficient; //temperature compensation
  84.    TDS_value = (133.42 * compensationVolatge * compensationVolatge * compensationVolatge - 255.86 * compensationVolatge * compensationVolatge + 857.39 * compensationVolatge) * 0.5; //convert voltage value to tds value       
  85.                 
  86.                
  87.                
  88.                
  89.                
  90.        
  91.         /*显示EC*/
  92.         TDS_Buff[0]=(int)(TDS_value)/1000+'0';
  93.         TDS_Buff[1]=(int)(TDS_value)%1000/100+'0';
  94.         TDS_Buff[2]=(int)(TDS_value*100)%100/10+'0';       
  95.         TDS_Buff[3]=(int)(TDS_value*100)%10+'0';

  96.         return TDS_value ;
  97. }
  98. ///*************数据显示函数***************/
  99. //void Display_Data()
  100. //{
  101. //        //OLED_ShowStr(24,2,TEMP_Buff,2);//测试6*8字符
  102. //        //OLED_ShowStr(36,4,TDS_Buff,2);//测试6*8字符
  103. //}
  104.         float TDS_Bugg1[2];
  105.   uint8_t Num = 0;
  106.   uint32_t Num1=0;


  107. void text1()
  108. {       
  109.                                         a=0;
  110.                             delay_ms(100);
  111.                             TDS_Value_Conversion();//TDS
  112.                             delay_ms(100);
  113.                                         TDS_Bugg1[0]=TDS_Value_Conversion();
  114.                                         delay_ms(10);       
  115.           OLED_ShowNum(2,1,TDS_Bugg1[0],3);
  116. }

  117. void text2()
  118. {
  119.                                         a=1;
  120.                 delay_ms(100);
  121.                             TDS_Value_Conversion();//TDS
  122.                             delay_ms(100);
  123.                                         TDS_Bugg1[1]=TDS_Value_Conversion();
  124.                                         delay_ms(10);       
  125.           OLED_ShowNum(3,1,TDS_Bugg1[1],3);
  126.                 if( TDS_Bugg1[0] < TDS_Bugg1[1])
  127.                       {
  128.                               OLED_ShowString(1,5,"thick water");
  129.                                         }
  130.                                                 else       
  131.                                {
  132.                                 OLED_ShowString(2,5,"light water");
  133.                             
  134.               }
  135. }
  136. void text3()
  137. {
  138.                                                                 a=2;
  139.                       delay_ms(10);
  140.                                   TDS_Value_Conversion();//TDS
  141.                                   delay_ms(10);
  142.                                                                          OLED_ShowNum(4,1,TDS_Value_Conversion(),3);
  143.                                                                          if(TDS_Value_Conversion()>=686||TDS_Value_Conversion()<700)
  144.                                                                          {
  145.                                                                                   OLED_ShowString(3,5,"water");
  146.                                                                          }
  147. }



  148. /**
  149.   * @brief  主函数
  150.   * @param  无
  151.   * @retval 无
  152.   */
  153. int main(void)
  154. {         

  155.         GPIO_Configuration(); //IO口配置
  156.     /* 配置USART1 */
  157.     USART1_Config();
  158.        
  159.     /* 配置USART2 */
  160.     USART2_Config();
  161.    
  162.     /* 初始化系统定时器 */
  163.     SysTick_Init();
  164.    
  165.                 Key_Init();
  166.        
  167.           TIM3_Init();                 //初始化配置TIM
  168.        
  169.                 //I2C_Configuration(); //I2C初始化
  170.           OLED_Init();  //OLED初始化
  171.           ADCx_Init();                // ADC 初始化
  172.           adc_init();
  173.                
  174.     OLED_Clear();//清屏
  175.        

  176.     OLED_ShowString(1,1,"TDS:");
  177.        
  178. //TDS 接A1
  179. //接上串口模块 A9-RX   A10-TX
  180. //波特率115200
  181. //接好后,直接打开串口软件看输出TDS值。
  182. //注意,如果启用温度补偿,需要解开”温度数据转换“调用,然后把读到的值更新到TDS温度补偿值中即可。
  183. //其他OLED显示是屏蔽了,要是OLED显示,解开初始和调用函数屏蔽即可。

  184.   while(1)
  185.         {       
  186.                
  187.                         if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0 && a==0 && sta ==0)
  188.                         {       
  189.                                         text1();       
  190.                                 sta = 1;
  191.                         }
  192.                         if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0 && a==0 && sta ==1)
  193.                         {       
  194.                                         text2();       
  195.                                 sta = 2;
  196.                         }
  197.                         if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0 && a==1 && sta ==2)
  198.                         {       
  199.                                         text3();       
  200.                                         sta = 3;
  201.                         }
  202.                        
  203.        
  204.                         if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0 && sta==3 )
  205.                         {       
  206.                                         text3();       
  207.                                 sta = 3;                               
  208.                         }
  209.                
  210.                
  211.         }
  212. }       


  213. /*********************************************END OF FILE**********************/
复制代码


Keil代码下载: TDS使用版 源程序.7z (253.46 KB, 下载次数: 16)
HZ711+hcsor04源程序.7z (198.11 KB, 下载次数: 8)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表