当前位置: 首页 > news >正文

stm32HAL库onenet平台数据实时获取实例--PH值获取与上传

文章目录

    • 概要
    • 整体架构流程
    • PH值的感知
    • PH值的上传
    • 小结

概要

在电赛之中,常常会涉及到单片机与网络平台的实时交互,而交互又分为上行链路交互与下行链路的交互,其中上行链路的交互最主要的莫过于数据的实时上传,今天我就来分享一下如何使用stm32F407ZGT6的HAL库与onenet平台实现上行链路数据的实时上传。

整体架构流程

一.感知层

使用PH4502C模块,PH测量模块的核心技术点如下

(1)PH测量使用ADC1接口,采用的是DMA回调,这样的设计首先可以节省CPU的算力,一旦启动 DMA,ADC 的转换结果会自动通过硬件通路存入指定的内存缓冲区(adc_dma_buf),完全无需 CPU 介入转换过程,极大提升了系统响应速度。

(2)采用的是DMA回调循环模式,DMA 配置为循环模式后,当PH_SAMPLE_COUNT个样本采集完成后,DMA 指针会自动重置到缓冲区起始位置,实现“只留最新数据”的循环覆盖。

(3)采用高效的均值滤波,由于 DMA 在后台持续运行,主程序调用Sensor_Get_PH函数时,缓冲区中始终存有最新的PH_SAMPLE_COUNT次采样样本,只需进行简单的累加求平均,即可在不阻塞 ADC 转换的前提下获取稳定的 PH 值。

二.通信层

采用的是EC20模块,连接onenet平台,重点是要将获取到的PH值上传到onenet平台,已知数据上传的JSON格式如下:

{ "id": "123", "params": { "ph": %.2f } }

PH值的感知

一,感知层配置

(1)PH-4502C接口配置

(2)DMA配置

在整体流程架构中介绍,本项目采取的是DMA循环回调模式,并采取均值滤波获取稳定的PH值,具体操作流程如下图所示

首先是设置DMA循环模式:

第一步设置哪个接口,上面IN0,IN1,IN2.......代表的是ADC的多个通道,由于我们接的是PA4,代表的是ADC1的4通道,第二步是在下方的Configuration配置之中设置ADC的配置,打开DMA Settings,点击下方的Add,选择DMA模式,在下方的配置之中设置为Circle模式

这时我们烧录到单片机之中,会产生如下的效果

由于我们是将所测得的数据储存到adc_dma_buf之中,这时如果仅仅只是进行第一步和第二步测试,最终只能接收到一个数据,这个数据没有进行实时刷新,并且经过均值滤波之后测出的PH值为14。那么为什么会产生这样的现象呢?首先产生一个数据的原因是没有设置Number Of Conversion,这是只产生一个数据的原因,Number Of Conversion 是定义 ADC 扫描序列物理长度的参数,在代码中,我设置了每16个数据进行采样,采样后取均值,我错误地将Number Of Conversion设为 1,这意味着 ADC 完成 1 次通道转换后就认为“序列结束”了,因此只出现了1个数据。其次一个原因就是未开启连续转换模式(Continuous Conversion Mode),导致最终数据无法如果没有开启Continuous Conversion Mode,ADC 在完成用户设置的Number Of Conversion次数后,会进入休眠状态 (Idle),此时它不再向 DMA 发出任何搬运请求。基于上述分析,可知,嵌入式开发可以总结为驱动-硬件-搬运”三方握手模型,即在驱动(HAL层)开启 ADC 与 DMA 的搬运开关,在硬件 (ADC)产生模拟信号转数字信号的“脉冲”,搬运 (DMA)搬运数据流,扫描序列物理长度在硬件层产生,连续转换模式在搬运层之中展现,这样可以使得DMA进行连续搬运所接收到的数据。

开启上述功能便可以收集到实时更新的数据并且能够使用均值滤波进行实时更新,最终效果如下所示:

(3)PH处理代码实例

代码:Sensor.h #ifndef __SENSOR_H #define __SENSOR_H #include "main.h" #include "ec20.h" #define PH_SAMPLE_COUNT 16 // DMA 循环采样次数(循环采样,实时覆盖) //外部调用变量 extern ADC_HandleTypeDef hadc1; //函数声明 void Sensor_Init(void);//ADC1初始化 float Sensor_Get_PH(void);//ADC1获取PH值 #endif
代码:Sensor.c #include "ec20.h" #include "Sensor.h" #include <stdio.h> #include <string.h> uint16_t adc_dma_buf[PH_SAMPLE_COUNT];//设置DMA缓存区 /*DMA初始化*/ void Sensor_Init(void) { memset(adc_dma_buf,0,sizeof(adc_dma_buf)); HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_dma_buf, PH_SAMPLE_COUNT); } /*获取并解析PH值*/ float Sensor_Get_PH(void) { uint32_t sum=0; float avg_adc=0; float voltage=0; float ph_val=0; for(int i=0;i<PH_SAMPLE_COUNT;i++)//对所采取的数据进行累加,目的是为了求平均值(均值滤波) { sum+=adc_dma_buf[i]; } avg_adc = (float)sum / PH_SAMPLE_COUNT; // avg_adc=(float)adc_dma_buf[0]; voltage = avg_adc * (3.3f / 4095.0f); // 假设参考电压为 3.3V ph_val = 7.0f + ((2.5f - voltage) / 0.05916f);//ph值计算公式 return ph_val; }

代码:main.c int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); MX_ADC1_Init(); //初始化步骤 Sensor_Init(); //以下属于通信模块部分// while (1) { //每5s取出我的PH值 if(HAL_GetTick()-last_ph_tick>=10000) { HAL_Delay(500); g_sys_data.ph=Sensor_Get_PH(); last_ph_tick=HAL_GetTick(); } ////////后续通信上报流程/////////// } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } } } /* USER CODE END 4 */

其中在main函数之中,是不需要使用回调函数的,因为数据被 DMA 硬件直接搬运到预设的adc_dma_buf数组中。由于 DMA 是由硬件自动循环触发的,数组里的数据时刻保持更新。对比USART接口,数据是“突发性”到达的,你无法预测它何时到来,因此必须依赖中断/回调函数来“通知”CPU:“有新数据了,快来取!”

PH值的上传

ec20.c /*数据上报函数*/ void EC20_Publish_Property(char *json_params) { char pub_cmd[128];//用于发送JSON的前缀 char full_payload[512];//用于发送JSON的格式 sprintf(full_payload,"{\"id\":\"123\",\"params\":%s}",json_params);//full_payload是原有格式和后面两个东西拼接而成的 sprintf(pub_cmd, "AT+QMTPUBEX=0,0,0,0,\"$sys/z263G74j50/Ship_01/thing/property/post\",%d\r\n", (int)strlen(full_payload));//动态指令用sprint,部分变化,最后拼接 HAL_UART_Transmit(&huart1,(uint8_t*)pub_cmd,strlen(pub_cmd),100);//发送AT指令行 HAL_Delay(200); HAL_UART_Transmit(&huart1,(uint8_t*)full_payload,strlen(full_payload),500);//发送JSON的完整格式 }

最后一行是拼接的核心代码,具体的交互如下述main.c代码

main.c上报代码 if(HAL_GetTick()-last_report_tick>=10000)//每10s上报一次 { char param_buf[256]; // 打包PH数据(符合OneNet物模型格式) sprintf(param_buf, "{\"ph_val\":{\"value\":%.2f}}", current_ph);//合并JSON EC20_Publish_Property(param_buf);//上传JSON last_report_tick = HAL_GetTick(); }

最后在onenet平台产生的数据如下图所示:

小结

本项目实现了PH值的测量,采用了DMA的循环模式,使得上传的PH数据更具实时性,同时采用均值滤波,使得PH值数据更具准确性,在数据上传方面,使用JSON格式并最终实现了实时上传。

http://www.jsqmd.com/news/492988/

相关文章:

  • Qwen3-0.6B-FP8游戏开发辅助:NPC对话生成+任务脚本设计+世界观构建
  • AI头像生成器惊艳效果:生成‘三星堆青铜面具×霓虹光影’文化科技风头像文案
  • gte-base-zh部署优化:使用--model-format pytorch提升加载速度35%
  • 千问3.5-27B企业落地:物流公司运单图识别→提取收发件信息+预测派送时效+异常标记
  • StructBERT情感模型效果展示:多场景文本(评论/对话/描述)分类对比
  • 【XR开发系列】UI 入门 - 创建一个简单的分数显示
  • IndexTTS-2-LLM安装报错?常见问题排查实战手册
  • SecGPT-14B镜像免配置价值:规避pip install超时、依赖冲突等常见问题
  • CLIP-GmP-ViT-L-14基础教程:ViT-L-14架构特点与CLIP-GmP改进点深度解析
  • Gemma-3-12b-it学术研究效果:论文插图→方法论总结+创新点提炼
  • 大模型连“数数“都会数错
  • Qwen3-TTS-12Hz-1.7B-Base实际作品:葡萄牙语航海日志+意大利语葡萄酒品鉴
  • k8s面试题
  • Jimeng LoRA基础教程:safetensors文件夹自动识别与版本刷新机制解析
  • 环境关联数据是指与特定时空场景下自然环境和社会活动密切相关、可影响系统行为或决策的一类动态数据
  • Phi-3-Mini-128K快速部署:无需conda环境,仅需Docker与NVIDIA驱动即可启动
  • python搭建后台框架
  • [特殊字符] Nano-Banana效果展示:同一Prompt下不同种子值的可控变体生成
  • 大数据加工基础组件平台生态,主要基于 Apache Hadoop 生态系统(Hadoop Ecosystem)并扩展了企业级治理、安全与运维能力
  • HBase 是一个分布式的、面向列的开源数据库,构建在 Hadoop 文件系统(HDFS)之上,是 Google Bigtable 的开源实现
  • GLM-4.7-Flash效果实测:4096 tokens长文本摘要完整性分析
  • 每天了解几个MCP SERVER:数据科学神器!AI + Spark 大数据分析,Databricks 让机器学习更简单
  • 知识点1--计算机网络基础
  • 手机短信误删!4 个实用恢复方法,一文看懂轻松
  • 2026年盐城殡葬服务优质机构推荐:一条龙殡仪、一站式殡葬服务、高端殡仪、盐城建湖福寿殡葬礼仪、践行民生服务初心 - 海棠依旧大
  • 每天了解几个MCP SERVER:AI 翻译神器!全球29种语言,DeepL 让翻译更地道
  • 百度飞桨ocr调用
  • 2026年3月优质的盐城殡葬礼仪服务公司选择指南:殡葬一条龙、殡仪服务、一站式殡葬服务公司 - 海棠依旧大
  • Apache Hadoop 生态系统(或与其深度集成)的企业级大数据平台核心服务,常见于 Hortonworks Data Platform(HDP)、Cloudera Data Platform
  • 每天了解几个MCP SERVER:OLAP 分析神器!AI 直接查询大数据,Apache Doris 让数据分析更简单