成果展示视频:【【Let's do第四期】DIY液体流量检测仪-项目展示】 https://www.bilibili.com/video/BV1vXwpeXEwy/?share_source=copy_web&vd_source=281b35e9473c706c635ce0c93be77625
EETV成果视频链接:https://v.eepw.com.cn/video/play/id/16226
经过一段时间的学习,成功的完成了指定任务,本期给大家分享一下我制作成果的过程。话不多说,开始整活!
第一阶段要分析题目:
搭建keil环境,实现开发板测试,利用定时器实现LED亮灭1秒。
OLED 显示文字信息。
继电器控制抽水泵通断。
实现流量计测量功能
实现定量 100ML,200ML 水量控制
以上是实现的目的,接下来我们使用收到的实物开始了解器件
NUCLEO-F103RB开发板自带STLink调试器,内置电源供电单元,还有很多引出的引脚。
OLED 显示屏使用的IIC协议,因此此器件需要使用硬件的IIC引脚,若引脚不方便,也可以使用软件模拟的II协议,这样任意引脚都支持。
抽水泵是防水的可以直接放入水中,但需要一个5V的开关驱动。
继电器模块能够实现信号的开关,我们使用继电器模块来实现开关水泵。
电源模块可以很方便的输出5V和3.3V,我们本次使用12V DC供电,输出的5V电压用于驱动继电器和水泵。
液体流量传感器,输出是一个方波信号,可以根据脉冲数来计算出水量。
软件框架我采用熟悉并简单的KEIL+STM32Cubemx来实现功能。
以上两款软件不多说,完STM32都回使用的两款软件,也是最好入门的。
根据我们所需要多功能和实物,先做个硬件原理图。
接下来结合硬件接线的特性,分配功能引脚。
以下是我分配引脚功能的说明:
引脚PC13:使用开发板上自带的KEY按键作为我们选择出水量和开关水泵功能。功能的定义为,单按为选择出水量,有100ML和200ML,双击开启继电器,长按则为关闭继电器(在校准流量和调试时使用)。
引脚PA2,PA3:是串口2引脚,可以用于串口输出,用于调试,我们此次使用串口2进行调试程序。
引脚PA5:是板载的LED灯,用于运行的指示灯。0.5S亮灭表示系统正在运行。使用定时器实现。
引脚PA8:用于驱动继电器的,高电平打开继电器,低电平则关闭继电器
引脚PA11:用于捕获水流量脉冲数的引脚。设置为下降沿触发,打开上拉电阻提高获取稳定性。
引脚PA13 PA14:用于程序下载或者Debug调试。很常用
引脚PB8 PB9:模拟IIC协议,用于驱动OLED屏幕,显示设置参数和水流量等信息。
引脚分配好之后,我们生成Keil软件框架,实现我们的功能。
软件方面我使用了一下资源
SSD1306的库,可以使用这个库很方便的驱动OLED屏幕,只需要修改驱动引脚即可。
我是用了取模软件实现了汉字的显示。因此效果如下:
2.使用网络上开源的按键库multi_button,来实现按键的单击,双击,长按等检测。
void Button_Callback(void *button) { PressEvent btn_event_val; btn_event_val = get_button_event((struct Button *)button); if((struct Button *)button == &Button1) { if(btn_event_val == SINGLE_CLICK) { // usartPrintf(huart1,"---> key1 单击按下事件 <---\r\n"); key1.Single_flag=1; } else if(btn_event_val == DOUBLE_CLICK) { key1.Double_flag=1; // usartPrintf(huart1,"---> key1 双击按下事件 <---\r\n"); } else if(btn_event_val == LONG_PRESS_START) { key1.Long_flag=1; // usartPrintf(huart1,"---> key1 达到长按事件阈值触发一次 <---\r\n"); } else if(btn_event_val == LONG_PRESS_HOLD) { // key1.Single_flag=1; // usartPrintf(huart1,"---> key1 长按保持 <---\r\n"); } } }
那么对于操控的逻辑而言,我写了以下代码实现按键切换阈值和开关水泵。
if (key1.Single_flag) { // 处理按键按下的情况 if (water_flag == 1) { water_amount = 100; // 设置显示100 water_flag = 2; // 改变状态标志 } else if (water_flag == 2) { water_amount = 200; // 设置显示200 water_flag = 1; // 改变状态标志 } My_Key_clear(); // 清除按键标志 } //手动启动水泵 if (key1.Double_flag) { Relay1_ON(); golbal_flow.acculat = 0.0;//清空累计流量 My_Key_clear(); // 清除按键标志 } //手动关闭水泵 if (key1.Long_flag) { Relay1_OFF(); My_Key_clear(); // 清除按键标志 }
3.我用定时器实现脉冲计数和LED运行灯的功能,此代码写在定时器中断函数即可,非常的方便,其中还有个定时器用于检测按键。
//硬件定时器 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { //1S if (htim == (&htim2)) { golbal_flow.receive_flag = 1; } //1s if (htim == (&htim3)) { HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); usartPrintf(huart2,"瞬间流量:%.2f L/min 累计流量:%.2f mL \r\n",golbal_flow.instant,golbal_flow.acculat); Page_Main(); } //0.05S if (htim == (&htim4)) { button_ticks(); //按键检测 } }
4.采集的流量脉冲数我写在了,PA11的中断里面,然后配合脉冲转流量的函数实现水流量的检测,具体的软件框架见开源链接的附件中。
在采集流量准确度上,我阅读了相关资料,水流量的采集与水管,传感器的位置(最好是水平),供电电压有关系,排除以上,我还另外做了100ml和500ml的真实脉冲数,根据多次测试和记录,取平均值,这样出水流量就准确了。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == YFS401_Pin) { __HAL_GPIO_EXTI_CLEAR_IT(YFS401_Pin); golbal_flow.pluse_1s++; //下降沿采集脉冲数 usartPrintf(huart2,"触发次数:%.d \r\n",golbal_flow.pluse_1s); } } void Flow_Read(void) { // 根据 Flow_Model 选择不同的流量参数 float flowKValue = flowK[flowModel]; float pulseCntValue = pulseCntPerLiter[flowModel]; if(golbal_flow.pluse_1s > 0) { golbal_flow.acculat += (golbal_flow.pluse_1s * 1000 / pulseCntValue); //将累计的流量转换成mL pluse1L+=golbal_flow.pluse_1s; //总脉冲数 golbal_flow.instant = golbal_flow.pluse_1s / flowKValue; //单位(L/min) if(golbal_flow.acculat >= 1000000) //最大累计流量1000L { golbal_flow.acculat = 0; } } else { golbal_flow.instant = 0; } // usartPrintf(huart2,"瞬间流量:%.2f(L/min) 累计流量:%.2f mL 累计脉冲数:%d \r\n",golbal_flow.instant,golbal_flow.acculat,pluse1L); golbal_flow.receive_flag = 0; //接收完成标志位清零 golbal_flow.pluse_1s = 0; //脉冲数清零 }
5.得到了水流量,那么只需要一个简单的判断函数就可以达到我们想要的 水流量了。我这里使用了标志位作为我判断的一句,因此函数非常的 简单。
//如果当前的水量等于我设定的水量,则停止继电器 if(water_amount <= golbal_flow.acculat) { Relay1_OFF(); }
6.在OLED屏幕上,我的软件框架也非常的简单。
void Page_Main(void) { char arry_dis[3]={0}; //设定流量:ml OLED_ShowChinese(5,0,7,16,1); OLED_ShowChinese(21,0,8,16,1); OLED_ShowChinese(37,0,2,16,1); OLED_ShowChinese(53,0,3,16,1); OLED_ShowString(69,0,(uint8_t *)":",16,1); sprintf(arry_dis,"%d", water_amount); OLED_ShowString(80,0,(uint8_t *)arry_dis,16,0); OLED_ShowString(110,0,(uint8_t *)"mL",16,1); //瞬间流量 OLED_ShowChinese(5,20,11,16,1); OLED_ShowChinese(21,20,12,16,1); OLED_ShowChinese(37,20,2,16,1); OLED_ShowChinese(53,20,3,16,1); OLED_ShowString(69,20,(uint8_t *)":",16,1); sprintf(arry_dis,"%.2f", golbal_flow.instant); OLED_ShowString(80,20,(uint8_t *)arry_dis,16,1); // OLED_ShowString(115,20,(uint8_t *)"L/min",12,1); //累计流量 OLED_ShowChinese(5,40,13,16,1); OLED_ShowChinese(21,40,14,16,1); OLED_ShowChinese(37,40,2,16,1); OLED_ShowChinese(53,40,3,16,1); OLED_ShowString(69,40,(uint8_t *)":",16,1); sprintf(arry_dis,"%.1f", golbal_flow.acculat); OLED_ShowString(80, 40, (uint8_t *)arry_dis, 16, 1); OLED_ShowString(115,40,(uint8_t *)"mL",16,1); OLED_Refresh(); }
以上就是主要代码和实现功能的方式,很高兴您能看到这里。结合我拍摄的功能演示视频以开源的资料。希望可以帮助你。
代码链接: https://pan.baidu.com/s/1Wg280VO-Ehv6YTXEwpzQZg?pwd=mbp5 提取码: mbp5
在这个液体流量控制项目中,我通过STM32开发板成功实现了小抽水泵与继电器的流量控制功能,并结合霍尔效应传感器,准确测量了液体的传播时间,实现了瞬时流量和累计流量的监测。项目的基础任务包括使用Keil环境完成开发板测试、实现LED灯的定时亮灭、OLED显示文字信息以及继电器控制抽水泵的开关。进阶任务则成功实现了流量计测量功能,并能够精准控制100ML和200ML水量的定量控制。
感谢DigiKey联合EEPW举办的此次活动,不仅有老师在线讲解还有众多群友的帮助完成任务。期待下一次的活动。DigiDigiKey联合EEPWKey联DigiKey联合EEPW合EEPWDigiKey联合EEPW