从STM32CubeMX配置到AI应用:嵌入式设备请求春联生成云服务
从STM32CubeMX配置到AI应用嵌入式设备请求春联生成云服务最近在捣鼓一个挺有意思的小项目想用一块小小的单片机给家里的老人送点不一样的春节祝福。想法很简单让一块STM32开发板自己联网去“求”一副春联然后把对联显示在小屏幕上。听起来是不是有点“赛博过年”的味道这背后其实是一个典型的物联网IoT应用把最传统的嵌入式硬件和时下热门的AI云服务给连了起来。整个过程就像搭积木我们用STM32CubeMX这个图形化工具快速配置好单片机的“身体”硬件外设然后给它装上“嘴巴和耳朵”Wi-Fi模块教它怎么上网、怎么跟远方的AI“大脑”云端春联生成模型说话最后再把“大脑”回复的祝福语用“眼睛”OLED屏幕展示出来。下面我就把这个从零搭建“智能硬件送祝福”系统的完整过程一步步拆开讲给你听。1. 项目构思与核心组件这个项目的核心目标是让一个资源有限的嵌入式设备能够主动调用强大的云端AI能力。我们选择的硬件平台是STM32F103C8T6最小系统板它价格亲民、资料丰富是很多单片机爱好者的入门首选。虽然它本身没有网络功能但我们可以通过外接模块来弥补。整个系统的架构可以分为三层硬件层STM32F103C8T6作为主控负责协调所有外设。我们为它搭配了ESP8266 Wi-Fi模块来实现网络连接以及一块I2C接口的OLED屏幕用于显示结果。通信层单片机通过串口UART与ESP8266模块通信使用AT指令集驱动模块连接家里的Wi-Fi并通过HTTP协议与云端服务器对话。服务层在云端我们部署了一个能够根据关键词生成春联的AI模型服务。单片机只需要发送一个简单的HTTP请求就能获得一副定制化的对联。你可能会问为什么不让单片机自己运行AI模型原因很简单像STM32F103C8T6这样的微控制器其计算能力和内存通常只有几十KB的RAM根本无法承载现代AI模型。因此“端侧采集/控制 云侧智能计算”成了最实际可行的方案。我们让单片机做它擅长的事——可靠地控制硬件和传输数据而把复杂的生成任务交给云端。2. 硬件准备与STM32CubeMX工程创建工欲善其事必先利其器。我们先来清点一下需要的硬件材料STM32F103C8T6最小系统板一块。ESP8266-01S Wi-Fi模块一个。选择01S是因为它体积小3.3V供电与STM32电平兼容无需电平转换。**0.96寸OLED显示屏SSD1306驱动**一块I2C接口。杜邦线若干用于连接。一台3.3V/5V的USB转串口工具用于程序下载和调试。硬件连接是关键的第一步接线错误会导致后续所有工作无法进行。连接关系如下表所示STM32F103C8T6引脚连接至备注3.3VESP8266 VCC, OLED VCC供电GNDESP8266 GND, OLED GND共地PA9 (USART1_TX)ESP8266 RX单片机发送数据给Wi-Fi模块PA10 (USART1_RX)ESP8266 TX单片机接收来自Wi-Fi模块的数据PB6 (I2C1_SCL)OLED SCLI2C时钟线PB7 (I2C1_SDA)OLED SDAI2C数据线ESP8266 GPIO0悬空或接3.3V确保模块处于正常工作模式非烧录模式接线完成后就可以打开STM32CubeMX软件开始配置了。新建一个工程选择正确的芯片型号“STM32F103C8T6”。首先配置时钟树在“RCC”配置中将高速外部时钟HSE设置为“Crystal/Ceramic Resonator”。然后进入“Clock Configuration”标签页将系统时钟源选择为HSE并将主频设置为72MHz这是F103系列的最高频率能提升程序运行效率。接着配置外设USART1这是我们与ESP8266通信的通道。在“Pinout Configuration”视图中找到USART1将其模式设置为“Asynchronous”异步通信。参数可以先用默认值波特率1152008位数据无校验1位停止位后续在代码中还可以调整。配置完成后软件会自动将PA9和PA10引脚分配为USART1_TX和USART1_RX。I2C1用于驱动OLED屏幕。找到I2C1将其模式设置为“I2C”。同样软件会自动分配PB6和PB7引脚。SYS为了使用printf函数重定向到串口进行调试我们需要在“SYS”设置中将“Debug”选为“Serial Wire”。同时将“Timebase Source”从默认的SysTick改为其他定时器如TIM1以避免与HAL库的延时函数冲突。最后生成代码在“Project Manager”标签页设置好项目名称、存储路径并将“Toolchain / IDE”选为你使用的IDE如MDK-ARM V5或STM32CubeIDE。在“Code Generator”部分建议勾选“Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral”这样代码结构会更清晰。点击“GENERATE CODE”STM32CubeMX就会为你生成一个包含所有基础硬件初始化代码的完整工程。3. 驱动开发OLED显示与ESP8266通信生成了基础工程后我们需要为两个外设编写驱动代码。首先将OLED屏幕和ESP8266的常用驱动文件通常是一些.c和.h文件添加到项目的Src和Inc文件夹中。3.1 OLED屏幕显示驱动OLED驱动通常提供了一些基础函数比如初始化OLED_Init()、清屏OLED_Clear()、在指定位置显示字符串OLED_ShowString()等。我们的任务是在main.c中调用它们。首先在main.c的/* USER CODE BEGIN Includes */部分包含OLED的头文件。然后在main函数中硬件初始化完成后/* USER CODE BEGIN 2 */区域调用OLED_Init()进行初始化。初始化成功后可以显示一个开机界面比如“AI Couplet Demo”。/* USER CODE BEGIN 2 */ OLED_Init(); OLED_Clear(); OLED_ShowString(0, 0, AI Couplet, 16); OLED_ShowString(0, 2, Initializing..., 16); HAL_Delay(1000); /* USER CODE END 2 */3.2 ESP8266 Wi-Fi模块通信驱动与ESP8266的通信本质是通过串口发送和接收AT指令。我们需要编写一个稳健的驱动来处理指令发送、响应等待和解析。一个核心函数是发送AT指令并等待特定响应。这里以连接Wi-Fi为例/** * brief 向ESP8266发送命令并检查响应 * param cmd: 要发送的AT指令 * param ack: 期望收到的响应关键字 * param timeout: 等待超时时间毫秒 * retval 0:成功, 其他:失败 */ uint8_t ESP8266_SendCmd(char *cmd, char *ack, uint32_t timeout) { char response[256]; memset(response, 0, sizeof(response)); // 清空串口接收缓冲区 __HAL_UART_FLUSH_DRREGISTER(huart1); // 发送指令 HAL_UART_Transmit(huart1, (uint8_t*)cmd, strlen(cmd), 1000); // 等待并接收响应 uint32_t startTick HAL_GetTick(); uint16_t len 0; while((HAL_GetTick() - startTick) timeout) { uint8_t ch; if(HAL_UART_Receive(huart1, ch, 1, 50) HAL_OK) { if(len sizeof(response)-1) { response[len] ch; } // 检查是否包含期望的应答 if(strstr(response, ack) ! NULL) { return 0; // 成功 } } } return 1; // 超时或未找到应答 }在主循环前的初始化阶段/* USER CODE BEGIN 2 */我们需要按顺序执行一系列AT指令来配置ESP8266测试模块AT\r\n期待回复OK。设置模式ATCWMODE1\r\n设置为Station模式即客户端模式期待OK。连接Wi-FiATCWJAP你的Wi-Fi名称,你的Wi-Fi密码\r\n这个过程可能需要几秒期待WIFI CONNECTED和WIFI GOT IP最后是OK。查询IP可选ATCIFSR\r\n可以查看模块获取到的IP地址。每一步都最好用ESP8266_SendCmd函数进行检查如果某一步失败可以在OLED屏幕上显示错误信息方便调试。4. 集成与测试实现HTTP请求与解析当Wi-Fi连接成功后最激动人心的部分就来了——让单片机与云端对话。我们假设云端有一个提供春联生成API的服务其地址是http://api.example.com/couplet它接受一个GET请求参数keyword可以是“春节”、“平安”等主题词返回一个JSON格式的数据例如{上联:xxx, 下联:yyy, 横批:zzz}。4.1 构造并发送HTTP请求在单片机上我们需要手动构造一个完整的HTTP GET请求字符串。由于STM32内存有限我们需要精打细算地使用缓冲区。/** * brief 请求生成春联 * param keyword: 春联主题关键词 * retval 0:成功并解析, 其他:失败 */ uint8_t RequestCouplet(char *keyword) { char http_cmd[512]; char response[1024]; // 预留稍大的缓冲区接收响应 memset(response, 0, sizeof(response)); // 1. 建立TCP连接 (假设API服务器地址是 192.168.1.100端口 80) sprintf(http_cmd, ATCIPSTART\TCP\,\%s\,%d\r\n, 192.168.1.100, 80); if(ESP8266_SendCmd(http_cmd, CONNECT, 5000)) { OLED_ShowString(0, 4, TCP Connect Fail, 16); return 1; } // 2. 构造HTTP GET请求 // 注意实际的主机名、路径和参数需要替换为你的真实API地址 sprintf(http_cmd, GET /couplet?keyword%s HTTP/1.1\r\nHost: api.example.com\r\nConnection: close\r\n\r\n, keyword); // 3. 发送数据长度 sprintf(response, ATCIPSEND%d\r\n, strlen(http_cmd)); if(ESP8266_SendCmd(response, , 2000)) { OLED_ShowString(0, 4, Send Cmd Fail, 16); return 2; } // 4. 发送HTTP请求数据 if(ESP8266_SendCmd(http_cmd, SEND OK, 5000)) { OLED_ShowString(0, 4, Send Data Fail, 16); return 3; } // 5. 接收HTTP响应 (这里需要更复杂的接收逻辑来获取完整数据) // 通常响应会分多次通过串口返回需要循环接收并拼接 // 接收到数据后会以“IPD,len:data”的格式提示 // 我们需要解析这个格式提取出data部分即HTTP响应体 // ... (接收和拼接响应的代码) // 6. 关闭TCP连接 ESP8266_SendCmd(ATCIPCLOSE\r\n, CLOSED, 2000); // 7. 从完整的响应中找到JSON正文并解析 // 首先找到HTTP头结束的标志“\r\n\r\n” char *json_start strstr(response, \r\n\r\n); if(json_start) { json_start 4; // 跳过空行 // 调用JSON解析函数提取上联、下联、横批 if(ParseCoupletJson(json_start)) { return 0; // 成功 } } return 4; // 解析失败 }4.2 解析JSON响应在资源受限的单片机上解析JSON不适合引入复杂的解析库。我们可以编写一个简单的函数利用strstr、strtok等函数来提取关键信息。这里假设返回的JSON格式非常简单规整。/** * brief 简单的JSON解析提取春联内容 * param json_str: 指向JSON字符串起始位置的指针 * retval 0:成功, 其他:失败 */ uint8_t ParseCoupletJson(char *json_str) { // 这是一个非常简易的解析仅适用于格式固定的简单JSON // 例如{上联:天增岁月人增寿, 下联:春满乾坤福满门, 横批:四季平安} char *p; char upper[64], lower[64], horizontal[64]; // 查找并提取上联 p strstr(json_str, \上联\:\); if(p) { p strlen(\上联\:\); sscanf(p, \%[^\]\, upper); // 读取直到下一个双引号的内容 OLED_ShowString(0, 2, upper, 16); // 显示在OLED第二行 } // 类似方法提取下联和横批... // ... return 0; }5. 应用逻辑与效果展示将以上所有模块组合起来就构成了我们应用的主逻辑。我们可以在main函数的超级循环中周期性地执行一次“求春联”的任务。/* USER CODE BEGIN WHILE */ while (1) { OLED_Clear(); OLED_ShowString(0, 0, Requesting..., 16); // 尝试请求一个主题为“春节”的春联 if(RequestCouplet(春节) 0) { // 成功显示结果后保持一段时间 HAL_Delay(10000); // 显示10秒 } else { // 失败显示错误信息 OLED_ShowString(0, 4, Request Failed, 16); HAL_Delay(3000); } // 可以在这里加入按键检测按一下按钮就换一个主题词重新请求 // 例如keyword “平安”、“吉祥”、“发财”等 /* USER CODE END WHILE */当程序成功运行你会看到OLED屏幕首先显示“Requesting...”随后Wi-Fi模块的指示灯会闪烁表示网络活动。几秒钟后一副崭新的、由云端AI生成的春联就会出现在屏幕上上联、下联、横批排列整齐。你可以通过修改代码中的keyword来获取不同主题的祝福比如“健康”、“学业”、“事业”等等。这个项目虽然小但它清晰地展示了一个完整的“端-云”协同的物联网应用原型。STM32F103C8T6作为终端可靠地完成了网络连接、数据发送和结果展示的任务而复杂的AI生成模型则部署在云端提供了终端无法企及的智能。这种架构非常适合智能家居、工业传感、可穿戴设备等众多需要“轻端侧重云侧”能力的场景。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。