PT_THREAD 的嵌套协程示例
一、前言
在单片机开发中,资源相对比较紧张的情况下,通过嵌套协程,可以将复杂任务分解为多个独立的、可管理的子任务,同时保持代码的结构化和可读性,特别适合嵌入式系统的开发需求。
二、主要特点
-
协程嵌套结构:
- 主协程(如
main_control_thread
)管理整体流程 - 子协程(如
temp_sensor_thread
)负责特定子任务 - 主协程通过
PT_WAIT_UNTIL
等待子协程完成
- 主协程(如
-
状态管理:
- 每个协程维护自己的状态变量(如
last_time
、offset
) - 避免全局变量,提高代码可复用性和安全性
- 每个协程维护自己的状态变量(如
-
非阻塞执行:
- 所有
PT_WAIT_UNTIL
不会阻塞整个系统 - 等待期间可执行其他协程或主循环代码
- 所有
-
错误处理:
- 可在子协程中返回错误码,主协程根据结果处理
- 示例:若下载失败,主协程可选择重试或通知用
三、一下举一个例子进行详细讲解其实现方法:
#include "pt.h"// 模拟网络读取
bool network_read(uint8_t *buffer, uint32_t len) {// 实际应用中会从网络接收数据static uint32_t bytes_received = 0;if (bytes_received >= 10240) { // 模拟10KB文件return false; // 下载完成}// 填充随机数据for (uint32_t i = 0; i < len; i++) {buffer[i] = rand() % 256;}bytes_received += len;return true; // 继续下载
}// 计算CRC校验
uint16_t calculate_crc(const uint8_t *data, uint32_t len) {// 实际CRC计算实现uint16_t crc = 0xFFFF;for (uint32_t i = 0; i < len; i++) {crc ^= data[i];for (int j = 0; j < 8; j++) {if (crc & 0x0001) {crc = (crc >> 1) ^ 0xA001;} else {crc >>= 1;}}}return crc;
}/*** 文件下载协程* 负责从网络下载文件到缓冲区*/
static PT_THREAD(file_download_thread(struct pt *pt, uint8_t *buffer, uint32_t *size)) {static uint32_t offset = 0;const uint32_t CHUNK_SIZE = 512;bool download_complete = false;PT_BEGIN(pt);while (!download_complete) {// 下载一个数据块PT_WAIT_UNTIL(pt, network_read(buffer + offset, CHUNK_SIZE));offset += CHUNK_SIZE;printf("已下载: %u bytes\n", offset);// 检查是否下载完成if (!network_read(NULL, 0)) { // 调用network_read(..., 0)检查是否还有数据download_complete = true;*size = offset;}// 让出控制权,允许其他任务执行PT_YIELD(pt);}printf("文件下载完成,总大小: %u bytes\n", *size);PT_END(pt);
}/*** 文件校验协程* 负责计算下载文件的CRC校验值并验证*/
static PT_THREAD(file_verify_thread(struct pt *pt, uint8_t *buffer, uint32_t size, uint16_t expected_crc)) {static uint32_t chunk_offset = 0;static uint16_t calculated_crc = 0;const uint32_t CHUNK_SIZE = 1024;PT_BEGIN(pt);// 分块计算CRC校验while (chunk_offset < size) {uint32_t chunk_size = (size - chunk_offset > CHUNK_SIZE) ? CHUNK_SIZE : size - chunk_offset;// 计算当前块的CRC并累加calculated_crc = calculate_crc(buffer + chunk_offset, chunk_size);chunk_offset += chunk_size;printf("CRC计算进度: %u/%u bytes\n", chunk_offset, size);// 让出控制权PT_YIELD(pt);}// 验证CRCif (calculated_crc == expected_crc) {printf("CRC校验成功! 计算值: 0x%04X, 期望值: 0x%04X\n", calculated_crc, expected_crc);} else {printf("CRC校验失败! 计算值: 0x%04X, 期望值: 0x%04X\n", calculated_crc, expected_crc);}PT_END(pt);
}/*** 主下载控制协程* 嵌套调用下载和校验协程,管理整个流程*/
static PT_THREAD(download_manager_thread(struct pt *pt)) {struct pt download_pt, verify_pt;static uint8_t file_buffer[10240]; // 10KB缓冲区static uint32_t file_size;const uint16_t EXPECTED_CRC = 0x1234; // 预期CRC值PT_BEGIN(pt);// 1. 下载文件printf("开始文件下载...\n");PT_INIT(&download_pt);PT_WAIT_UNTIL(pt, file_download_thread(&download_pt, file_buffer, &file_size) == PT_ENDED);// 2. 校验文件printf("开始文件校验...\n");PT_INIT(&verify_pt);PT_WAIT_UNTIL(pt, file_verify_thread(&verify_pt, file_buffer, file_size, EXPECTED_CRC) == PT_ENDED);// 3. 完成printf("文件下载和校验流程全部完成!\n");PT_END(pt);
}