news 2026/6/25 18:31:55

C语言基础回炉第六天:补漏洞、跑验收、串起 STM32 数据链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言基础回炉第六天:补漏洞、跑验收、串起 STM32 数据链路

前言

前五天我主要在补 C 语言和嵌入式常用数据处理能力:位运算、字符串和内存函数、链表、数组查找、环形缓冲区、UART 帧解析。今天不是继续盲目往后学新知识,而是先做一次集中验收,再把这些训练内容放回自己的真实项目里理解。

这一天的重点有两个:

  1. 把前几天留下的基础漏洞补掉,保证练习脚本真正通过。
  2. 对照smart_env_monitorzhijing_edge_gateway两个项目,理解从 STM32 采集数据到 PC 端解析、Web/API/MQTT 输出的完整链路。

这比单独刷题更接近真实嵌入式开发。因为项目里不会只问一个函数能不能写出来,而是要看数据从哪里来、经过哪些任务、通过什么接口传出去、异常时怎么定位。

一、今天先做集中验收

今天重新运行了前五天的核心练习。第一次验收时,数组、环形缓冲区和 UART 帧解析相关练习已经通过,但 Day1 的重写练习暴露出两个回归问题:

FAIL ...02_string_memory_retype.c:74 expression: MyStrcmp("abc", "abd") < 0 FAIL ...03_singly_linked_list_retype.c:56 expression: head == &nodes[4]

这两个失败说明:

  • MyStrcmp找到第一个不同字符后没有返回差值,而是错误地返回了 0。
  • 单链表反转函数仍然是占位实现,直接返回了原头节点。

这也提醒我,前几天写过的内容不能只靠印象判断“会了”。必须重新运行脚本,让测试结果说话。

修复后再次运行 Day1 脚本,结果为:

Building 01_bit_ops_retype.c Running 01_bit_ops_retype.exe 01_bit_ops_retype passed Building 02_string_memory_retype.c Running 02_string_memory_retype.exe 02_string_memory_retype passed Building 03_singly_linked_list_retype.c Running 03_singly_linked_list_retype.exe 03_singly_linked_list_retype passed All day01 retype exercises passed

Day2 到 Day5 的综合练习也重新运行通过,数组处理、环形缓冲区和 UART 帧解析三部分都没有再失败:

Building 01_array_tools.c Running 01_array_tools.exe 01_array_tools passed Building 02_ring_buffer.c Running 02_ring_buffer.exe 02_ring_buffer passed Building 03_uart_frame_parser.c Running 03_uart_frame_parser.exe 03_uart_frame_parser passed All embedded data structure exercises passed

到这里,Day1 到 Day5 的核心练习才算有了完整的代码证据。

二、MyStrcmp这次错在哪里

strcmp的语义不是“相同返回 0,不同也随便返回一个值”,而是要根据第一个不同字符的大小返回正数或负数。正确逻辑是:

static int MyStrcmp(const char *a, const char *b) { const unsigned char *pa = (const unsigned char *)a; const unsigned char *pb = (const unsigned char *)b; while (*pa != '\0' && *pa == *pb) { pa++; pb++; } return (int)(*pa) - (int)(*pb); }

这里有两个点要注意:

  1. 比较时应该按unsigned char处理,避免字符最高位导致符号扩展问题。
  2. 循环结束后,不管是遇到不同字符,还是其中一个字符串结束,都可以用当前字符差值作为结果。

比如:

"abc" 和 "abd" 比较到 c 和 d,c - d < 0 "abd" 和 "abc" 比较到 d 和 c,d - c > 0 "abc" 和 "abcd" 比较到 \0 和 d,\0 - d < 0

这个函数看起来很小,但它训练的是边界意识:字符串结束符本身也参与比较。

三、链表反转和快慢指针

单链表反转这次失败,是因为函数还没有真正改指针。正确反转需要三个指针:

static Node *ReverseList(Node *head) { Node *prev = NULL; Node *current = head; while (current != NULL) { Node *next = current->next; current->next = prev; prev = current; current = next; } return prev; }

核心顺序不能乱:

  1. 先保存next,否则改掉current->next后会丢失后续链表。
  2. 再让current->next指向prev
  3. 最后整体向前移动。

链表中点和环检测也都用快慢指针:

  • FindMiddle:快指针每次走两步,慢指针每次走一步;偶数长度返回第二个中点。
  • HasCycle:如果链表有环,快慢指针最终会相遇;如果没有环,快指针会先走到空。

这三个函数都不是为了背模板,而是为了训练指针移动顺序。嵌入式里很多队列、链表、内存块管理,本质上也离不开这种指针状态维护。

四、前五天内容如何接到真实项目

今天看的真实项目主要有两个:

D:\develop\programfirst\smart_env_monitor D:\develop\programfirst\zhijing_edge_gateway

第一个是 STM32F1 + FreeRTOS 的环境监测项目,第二个是 Windows PC 端的边缘网关程序。

整体数据链路可以概括为:

ADC 采样 -> SensorTask 滤波和换算 -> 全局传感器值 g_temp_value / g_light_value -> WifiTask / DTU_SendTelemetry 组 JSON -> UART / DTU 输出 -> PC 网关读取串口行 -> 解析 [SENSOR] JSON -> Web API / MQTT 发布

这条链路正好把前五天内容串了起来:

  • 位运算和内存操作:底层寄存器、缓冲区、协议字段都会用到。
  • 数组和有效长度:传感器历史、payload、接收缓存都不能只看数组容量。
  • 环形缓冲区:适合 UART 连续接收,解决生产者和消费者速度不一致的问题。
  • UART 帧解析:解决字节流里如何识别完整业务消息的问题。
  • 复杂度和固定内存:STM32F103C8T6 只有 20KB SRAM,不能随意动态分配和无界缓存。

五、STM32 项目里的任务划分

smart_env_monitor里,FreeRTOS 任务大致可以这样理解:

SensorTask :读取 ADC,做滑动均值滤波,更新温度和光照值 DisplayTask :刷新 OLED 显示 ControlTask :根据模式、阈值、传感器值控制蜂鸣器、LED、舵机 WifiTask :处理 DTU 连接、定时上报和下行命令 KeyTask :处理按键、模式切换、阈值调整

这就是项目表达里很重要的一点:任务不是随便拆的,而是按职责拆。采集、显示、控制、通信、按键输入各自有清晰边界。

其中SensorTask里用到了滑动均值滤波:

新 ADC 值 -> 替换环形位置里的旧值 -> 更新 sum -> 求平均值

这和 Day4 的环形缓冲区思想很接近,只不过这里不是存 UART 字节,而是存最近若干次 ADC 采样值。

六、UART/DTU 接收和 Day4、Day5 的关系

项目里HAL_UART_RxCpltCallback每次接收 1 个字节,并在遇到\r\n时认为一行命令结束。它做的事情比较轻:收字节、拼缓冲、设置命令就绪标志,然后重新开启下一次中断接收。

这和 Day4 里总结的原则一致:ISR 里不要做复杂业务逻辑。

更合理的分层应该是:

UART 中断层:快速收字节,放入缓存或设置标志 协议解析层:判断一行或一帧是否完整 业务处理层:执行 SERVO、sget、阈值调整等命令

Day5 的 UART 帧解析训练虽然用的是二进制帧:

0xAA 0x55 LEN CMD PAYLOAD CHECKSUM

而当前项目里 PC 网关解析的是文本行:

[SENSOR] {"light":74,"temp":27,"mode":0,"servo":1500}

但它们的本质是一样的:底层拿到的是连续字节流,应用层必须定义消息边界。二进制协议用帧头和长度,文本协议用换行符和标记字符串[SENSOR]

七、PC 网关项目的验证

今天也运行了zhijing_edge_gateway的本地自测:

.\build\Release\zhijing_edge_gateway.exe --self-test

输出为:

self-test passed.

它覆盖了几个关键点:

  • [SENSOR]JSON 解析。
  • 最新数据 JSON 输出。
  • MQTT Remaining Length 编码。
  • MQTT CONNECT 报文编码。
  • MQTT PUBLISH 报文编码。

再运行 demo:

.\build\Release\zhijing_edge_gateway.exe --demo

输出为:

Demo input: [SENSOR] {"light":74,"temp":27,"mode":0,"servo":1500} [16:01:46] temp=27 C, light=74 %, mode=0, servo=1500 us

这说明 PC 端程序能从一行串口文本里提取业务字段,并转换成可展示、可上报的数据结构。

八、今天必须能口述的项目表达

今天整理后,我需要能把项目讲成下面这段话:

我的项目是一个 STM32F103 + FreeRTOS 的环境监测系统。STM32 端分成传感器采集、显示、控制、通信和按键任务。传感器任务周期读取 ADC,并用滑动均值降低抖动;控制任务根据温度、光照和模式控制 LED、蜂鸣器、舵机;通信任务把实时数据组成 JSON,通过 UART/DTU 上报。PC 端边缘网关从串口读取[SENSOR]数据行,解析出温度、光照、模式和舵机值,再提供 Web API 或通过 MQTT 发布。这个项目里我重点关注了任务职责划分、UART 数据边界、缓冲区有效长度、以及异常数据不应该阻塞主流程。

这段话比单纯说“我做过 STM32 项目”更具体,因为它包含了任务划分、数据流和通信链路。

九、今天的收获

今天最重要的不是多学了一个新知识点,而是把前五天的内容合并成一条工程链路:

  1. 基础函数必须能重新写出来,不能只靠看懂。
  2. 练习是否完成,要以脚本输出为准。
  3. 字符串、链表、数组、缓冲区、帧解析都可以在真实项目里找到对应场景。
  4. STM32 + FreeRTOS 项目表达要讲清楚任务职责,而不是只列外设名字。
  5. 串口通信的关键不是“能发能收”,而是能稳定定义消息边界、处理异常数据、避免 ISR 里做复杂逻辑。

总结

Day6 完成了一次集中验收:Day1 的 C 基础重写练习,以及 Day2 到 Day5 的数组、环形缓冲区、UART 帧解析练习都已经重新通过。今天还把这些训练内容接到了自己的 STM32 环境监测项目和 PC 端边缘网关项目里。

接下来不再围绕训练目录名展开,而是固定两条主线:一条是继续补 C 语言硬功,重点放在指针、内存、结构体、回调函数和模块化接口;另一条是继续吃透自己的项目,把 STM32 端采集控制、UART/DTU 通信、PC 网关解析、Web/MQTT 输出这些链路讲清楚、改明白、跑出证据。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/25 18:29:46

TD-Learning与ϵ-greedy:从经验中学习的强化学习实战核心

1. 项目概述&#xff1a;从“纸上谈兵”到“真刀真枪”的强化学习跃迁你有没有试过学开车&#xff1f;教练在副驾上给你讲了一堆离合、油门、转向的原理&#xff0c;你听得头头是道&#xff0c;可一坐上驾驶座&#xff0c;手忙脚乱&#xff0c;方向盘打反&#xff0c;油门当刹车…

作者头像 李华
网站建设 2026/6/25 18:28:03

用真实气象数据来学习python可视化分析

目录 一、我们为什么要去学习python可视化&#xff1f; 二、为什么用气象数据&#xff1f; 真实项目里怎么更新数据&#xff1f; 三、如何选图&#xff1a;先读表&#xff0c;再想问题 四、matplotlib 基础 四步画图模板 五、八种常用图表详解 5.1 折线图&#xff08;Lin…

作者头像 李华
网站建设 2026/6/25 18:26:30

AI技术落地的七道生死关:从产线到医疗的系统性实践指南

1. 项目概述&#xff1a;这不是一场关于“未来”的演讲&#xff0c;而是一份AI技术落地的实操手记“Artificial Intelligence and Technological Development.”——这个标题乍看像大学通识课的PPT封面&#xff0c;或是某场行业峰会的背景板标语。但在我过去十年跑遍制造业产线…

作者头像 李华
网站建设 2026/6/25 18:24:56

如何高效使用Ryujinx:免费开源的Nintendo Switch模拟器完整指南

如何高效使用Ryujinx&#xff1a;免费开源的Nintendo Switch模拟器完整指南 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx Ryujinx是一款用C#编写的实验性Nintendo Switch模拟器&…

作者头像 李华
网站建设 2026/6/25 18:22:17

邮编驱动的医疗可及性数据管道构建指南

1. 项目概述&#xff1a;当邮编成为健康公平的隐形标尺“你的邮编正在决定你获得的医疗服务”——这句话听起来像一句社会评论&#xff0c;但在我实际跑通这个项目之前&#xff0c;它只是个模糊的共识。直到我拿到英国NHS&#xff08;国家医疗服务体系&#xff09;公开的基层诊…

作者头像 李华
网站建设 2026/6/25 18:21:31

Windows热键冲突终极解决方案:Hotkey Detective 完整使用指南

Windows热键冲突终极解决方案&#xff1a;Hotkey Detective 完整使用指南 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 你…

作者头像 李华