基于Labview和单片机的液位控制装置 一,功能说明 (1)基于STM32实现主控; (2)OLED实现具体液位控制过程的展示; (3)双继电器控制抽水和进水; (4)液位传感器实现水位数据的测量; (6)t独立按键实现液位的阈值; (6)LABVIEW作为上位机,通过波形图展示实时的水位变化过程 (7)和下位机具备双向通信,可以在上位机上直接改变阈值信息。 二,关键词 Labview; 32单片机;双向通信 三,包含的东西 1、配套文档一份 2、代码+原理图+下位机程序+上位机程序(Labview)

撸起袖子干一个基于Labview和单片机的液位控制系统,绝对是硬件狗和Labview玩家的双重快乐。咱们这次用STM32F103C8T6当主控,搭配双继电器玩抽水与进水,OLED实时显示水位曲线,再通过Labview整点工业上位机的仪式感——这组合拳打下来,高低得让毕设老师眼前一亮。

先说硬件部分的重头戏,液位传感器选了个模拟输出的型号,直接怼到STM32的ADC1通道上。核心代码就这几行:

void ADC1_Init(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
    ADC_Cmd(ADC1, ENABLE);
}

uint16_t Get_WaterLevel(void) {
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    return ADC_GetConversionValue(ADC1);
}

这ADC配置看着简单,实际调试时发现采样周期得调到239.5个周期才能抗住实验室电源的波纹干扰。转换后的数值用滑动平均滤波处理,实测波动能控制在±2cm以内。

OLED显示用硬件I2C驱动,重点在界面布局。把水位柱状图和阈值线做成了动态效果:

void Draw_WaterLevel(uint8_t level) {
    OLED_DrawLine(0, 63-level, 127, 63-level); // 水位线
    OLED_DrawRectangle(105, 20, 127, 30);      // 阈值显示框
    OLED_ShowNum(107, 22, current_threshold, 3, 8); 
}

当水位超过阈值时,整个柱状图会变成闪烁的红色——这招是通过反复擦写局部区域实现的,比全局刷新省资源得多。

按键配置最怕抖动,这里直接上定时器消抖方案:

void EXTI0_IRQHandler(void) {
    if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
        TIM_Cmd(TIM2, ENABLE); // 启动消抖定时器
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

配合50ms的定时器中断检测引脚电平,实测在实验室各种暴力拍打下也没出现误触发。

基于Labview和单片机的液位控制装置 一,功能说明 (1)基于STM32实现主控; (2)OLED实现具体液位控制过程的展示; (3)双继电器控制抽水和进水; (4)液位传感器实现水位数据的测量; (6)t独立按键实现液位的阈值; (6)LABVIEW作为上位机,通过波形图展示实时的水位变化过程 (7)和下位机具备双向通信,可以在上位机上直接改变阈值信息。 二,关键词 Labview; 32单片机;双向通信 三,包含的东西 1、配套文档一份 2、代码+原理图+下位机程序+上位机程序(Labview)

Labview上位机用VISA串口通信,前面板放了两个关键控件:波形图表和数值输入框。数据解析部分用了移位寄存器做缓存,防止数据包被截断:

VISA读取 -> 字符串至字节数组 -> 拼接循环缓冲区 -> 提取完整帧(0xAA开头0x55结尾)

特别要注意的是STM32发送的浮点数用联合体处理:

typedef union {
    float f_val;
    uint8_t bytes[4];
} float_union;

Labview端用"拆解字符串"函数按大端模式重组,再用类型转换变成单精度浮点数。实测115200波特率下,500ms的刷新周期刚好能稳定传输。

双向通信的骚操作在阈值修改功能。当Labview发送新阈值时,STM32会先回复ACK信号:

if(rx_buf[1] == 0x01) { // 阈值修改指令
    new_threshold = (rx_buf[3]<<8) | rx_buf[2];
    Send_ACK();
}

同时OLED立即刷新显示,避免出现设置值与实际值不同步的尴尬。调试时曾遇到Modbus协议和自定义协议混用导致的冲突,最后改用纯自定义协议才解决。

项目最坑的居然是继电器控制逻辑——抽水和进水必须互锁,还要加状态反馈:

void Pump_Ctrl(uint8_t mode) {
    if(mode == PUMP_IN) {
        GPIO_ResetBits(GPIOA, IN_PIN);
        GPIO_SetBits(GPIOA, OUT_PIN);
    } else {
        GPIO_SetBits(GPIOA, IN_PIN);
        GPIO_ResetBits(GPIOA, OUT_PIN);
    }
}

看似简单的GPIO操作,实际接线时忘了加续流二极管,结果现场演示时继电器火花带闪电,差点把院长吓出表情包。

整套系统跑起来后,看着Labview上跳动的曲线和实体设备联动的效果,突然理解了什么叫做"软硬兼施"的快乐。代码仓库里扔着stm32部分的HAL库版本和标准库版本,还有Labview2018和2023的工程文件——毕竟,兼容性才是工程项目的终极boss战。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐