news 2026/10/30 1:06:50

基于STM32F103C8T6的实验室巡检遥控小车设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于STM32F103C8T6的实验室巡检遥控小车设计与实现

实验室巡检这件事,说大不大,说小也不小。我读研那会儿帮导师管过一间电子实验室,每天晚上十点要挨个检查设备断电情况、记录温湿度、看看有没有异常发热的板子。刚开始坚持了两个月,后来实在扛不住,就开始琢磨能不能用一个小车替我把这活儿干了。这个想法最终变成了一个基于STM32F103C8T6的巡检遥控小车项目,前后折腾了大概三周,中间踩了不少坑,也积累了一些在常规教程里看不到的经验。这篇文章就把整个方案从头到尾拆开讲清楚,包括硬件选型逻辑、软件架构设计、调试过程中遇到的真实问题,以及我最后是怎么解决的。适合有51单片机基础、正在往STM32过渡的嵌入式学习者,也适合需要做类似课程设计或毕业设计的同学参考。

1. 为什么选STM32F103C8T6而不是51单片机

1.1 巡检小车的核心需求倒推主控选型

先想清楚这个小车到底要干什么。实验室巡检场景下,它需要完成这几件事:第一,能遥控移动,前后左右加调速;第二,能采集环境数据,至少包括温度和湿度;第三,能把数据实时显示在本地屏幕上;第四,能把数据传到上位机或者手机端;第五,最好能自动避障或者至少不撞东西。

把这些需求翻译成硬件指标:至少需要两路PWM输出驱动电机、一路I2C或SPI驱动OLED、一路单总线或I2C读取温湿度传感器、一路UART连接无线模块、若干GPIO用于按键和传感器输入。算下来至少需要十几个可用引脚,还要有定时器资源、中断资源、足够的Flash和RAM。

51单片机能不能做?能。STC89C52有32个GPIO,定时器也有,理论上可以跑起来。但问题在于:当你同时跑电机PWM、OLED刷新、DHT11时序、串口收发的时候,51的算力就开始捉襟见肘了。DHT11的时序对时间敏感,OLED刷新又需要占用大量CPU周期,串口中断还要及时响应,这几个任务在51上很容易互相打架。我试过用51做类似的项目,OLED刷新的时候DHT11读数就会丢,反过来也一样。

STM32F103C8T6就不一样了。Cortex-M3内核跑72MHz,硬件I2C、硬件SPI、多个定时器、DMA控制器,这些外设可以分担大量CPU负载。比如OLED刷新可以用硬件I2C加DMA,CPU只需要配置一次,剩下的数据搬运DMA自己完成。DHT11虽然还是要软件模拟时序,但72MHz的主频下,微秒级延时精度比51好太多,时序稳定性完全不是一个级别。

1.2 最小系统板的选型与引脚分配策略

市面上STM32F103C8T6最小系统板大概十几块钱,核心板加排针加USB接口,拿来就能用。但选板子的时候要注意几个细节:第一,确认板子上有8MHz晶振和32.768kHz晶振,前者用于主时钟,后者用于RTC(虽然这个项目不一定用RTC,但有备无患);第二,确认BOOT0和BOOT1跳线帽齐全,下载程序时需要切换;第三,确认板子引出了所有GPIO,有些廉价板子会省掉几个引脚。

引脚分配我建议提前画一张表,不然后面改代码的时候会乱。我的分配方案是这样的:

功能模块引脚外设资源备注
电机A方向PA0GPIO普通推挽输出
电机A调速PA1TIM2_CH2PWM输出
电机B方向PA2GPIO普通推挽输出
电机B调速PA3TIM2_CH3PWM输出
OLED SCLPB6I2C1_SCL硬件I2C
OLED SDAPB7I2C1_SDA硬件I2C
DHT11数据PA5GPIO软件模拟时序
ESP8266 TXPA9USART1_TX接模块RX
ESP8266 RXPA10USART1_RX接模块TX
超声波TrigPB0GPIO输出触发
超声波EchoPB1GPIO输入捕获
按键1PB12GPIO上拉输入
按键2PB13GPIO上拉输入

这个分配方案的好处是:电机PWM用了TIM2的两个通道,同一个定时器下频率一致,调速逻辑统一;OLED用了硬件I2C1,不占用软件模拟的CPU时间;ESP8266用了USART1,这是STM32上最常用的串口,资料最多;超声波和按键用了普通GPIO,灵活调整。

注意:PA9和PA10同时也是下载口USART1的引脚,如果你用串口下载程序,下载时需要拔掉ESP8266,否则会冲突。我建议用SWD下载(ST-Link),这样USART1可以一直连着ESP8266,不用反复插拔。

1.3 电机驱动与电源方案的取舍

电机驱动我用的是L298N模块,这个模块老归老,但胜在便宜、资料多、驱动能力强。TB6612FNG更高效,但价格贵一些,而且需要额外的逻辑电平转换。对于实验室巡检小车这种低速、轻载的场景,L298N完全够用。

电源方案是很多人容易忽略的地方。STM32需要3.3V,L298N需要5V到12V,ESP8266需要3.3V且峰值电流能到300mA,OLED需要3.3V或5V。如果你只用一节18650电池(3.7V),升压到5V再降压到3.3V,效率损失大不说,ESP8266发射瞬间的电流波动可能导致STM32复位。

我的方案是:两节18650串联(7.4V)给L298N供电,同时通过LM2596降压模块降到5V,再通过AMS1117-3.3降到3.3V给STM32和ESP8266。这样电源余量充足,ESP8266发射时也不会拉低主控电压。实测下来,两节2000mAh的18650可以连续跑大概4个小时,巡检一圈实验室(大概50平米)耗电不到10%。

2. 从零搭建Keil工程与标准库环境

2.1 为什么不用HAL库而选标准库

这个问题在嵌入式圈子里争论了很久。HAL库是ST官方主推的,跨系列移植方便,但代码臃肿、执行效率低、抽象层太厚,出了问题不好排查。标准库虽然ST已经不再更新,但代码精简、寄存器操作直观、资料丰富,特别适合F103C8T6这种资源有限的芯片。

我个人的选择是标准库。原因很简单:这个项目里我用到的外设不多(GPIO、TIM、I2C、USART),标准库的配置代码我闭着眼睛都能写出来,出了问题看寄存器就能定位。HAL库的I2C硬件bug在F103上是有名的,动不动就卡死在while循环里,标准库反而没这个问题。

当然,如果你已经熟悉HAL库,或者项目需要跨系列移植,用HAL也没问题。关键是选一个你熟悉的,不要两个混着用。

2.2 新建工程模板的完整步骤

新建一个基于标准库的STM32F103C8T6工程,步骤不复杂,但细节很多,漏一步就编译不过。我按顺序列一下:

  1. 下载STM32F10x标准外设库(版本3.5.0),解压后找到Libraries文件夹。
  2. 在Keil中新建工程,选择芯片型号STM32F103C8。
  3. 在工程目录下建三个文件夹:Start、Library、User。
  4. 把启动文件startup_stm32f10x_md.s(注意是md,不是hd)复制到Start文件夹。
  5. 把stm32f10x.h、system_stm32f10x.c、system_stm32f10x.h、core_cm3.h、core_cm3.c复制到Start文件夹。
  6. 把标准库中src和inc文件夹下的所有.c和.h文件复制到Library文件夹。
  7. 在User文件夹下新建main.c、stm32f10x_conf.h、stm32f10x_it.c、stm32f10x_it.h。
  8. 在Keil的工程管理窗口中添加对应的组和文件。
  9. 在Options for Target中设置C/C++的Include Paths,添加Start、Library、User三个路径。
  10. 在Define中填入USE_STDPERIPH_DRIVER, STM32F10X_MD。
  11. 在Debug中选择ST-Link Debugger,Settings中确认能识别到芯片。
  12. 编译,应该零错误零警告。

提示:stm32f10x_conf.h这个文件是标准库的配置文件,里面通过#include的方式决定哪些外设驱动参与编译。你用到哪个外设就取消对应行的注释,不用的注释掉,可以减小代码体积。

2.3 时钟配置与延时函数的坑

标准库的SystemInit函数默认把系统时钟配置为72MHz,但前提是你的板子上焊的是8MHz晶振。有些廉价板子用的是12MHz或者其他的,这时候需要改system_stm32f10x.c里的PLL配置。怎么确认?用示波器测PA8引脚(MCO输出),或者在代码里翻转一个GPIO,用逻辑分析仪看频率。

延时函数我建议用SysTick定时器做,不要用for循环空跑。for循环的延时时间受编译器优化等级影响很大,Debug和Release模式下可能差好几倍。SysTick配置成1ms中断,在中断里维护一个全局变量,需要延时的时候直接读这个变量就行。

volatile uint32_t g_msTick = 0; void SysTick_Handler(void) { g_msTick++; } void Delay_ms(uint32_t ms) { uint32_t start = g_msTick; while ((g_msTick - start) < ms); }

这个延时函数在72MHz下精度很高,实测误差在1%以内。注意g_msTick要加volatile,否则编译器优化后可能读不到最新值。

3. 外设驱动逐个攻破:OLED、DHT11与ESP8266

3.1 OLED显示模块的I2C驱动与汉字取模

0.96寸OLED我用的是SSD1306驱动芯片,I2C接口,分辨率128x64。这个屏幕便宜、显示效果好、资料多,几乎是嵌入式项目的标配。但I2C通信有个坑:市面上有些模块的I2C地址是0x78,有些是0x7A,买回来先用扫描程序确认一下。

OLED驱动分两层:底层是I2C读写字节,上层是SSD1306的初始化、清屏、画点、显示字符和汉字。底层I2C我用的是硬件I2C1,配置成标准模式(100kHz)或快速模式(400kHz)。实测400kHz下刷新一屏大概20ms,肉眼看不到闪烁。

汉字显示需要取模。常用的取模软件是PCtoLCD2002,设置成阴码、逐列式、顺向、C51格式。取出来的数组直接放到代码里,通过OLED_ShowChinese函数逐列写入。注意OLED的显存是按页组织的,每页8行,共8页,写汉字的时候要计算好起始页和列地址。

void OLED_ShowChinese(uint8_t x, uint8_t y, uint8_t index) { uint8_t i, j; uint8_t page = y / 8; for (i = 0; i < 16; i++) { OLED_SetCursor(x + i, page); OLED_WriteByte(OLED_Data, HZ[index][i * 2]); OLED_WriteByte(OLED_Data, HZ[index][i * 2 + 1]); } }

注意:0.9寸OLED和0.96寸OLED的I2C兼容性有差异。0.9寸有些用的是SSD1306,有些用的是SH1106,初始化命令不一样。如果你买的是0.9寸屏,显示偏移或者花屏,大概率是驱动芯片不对,换SH1106的初始化序列试试。

3.2 DHT11温湿度传感器的时序调试经验

DHT11是单总线传感器,一根数据线完成所有通信。它的时序要求比较严格:主机拉低至少18ms,然后拉高20-40us,然后释放总线,等待传感器响应。传感器会拉低80us,再拉高80us,然后开始传输40位数据。每位数据以50us低电平开始,高电平持续26-28us表示0,持续70us表示1。

在STM32上模拟这个时序,关键是用微秒级延时。我用的是SysTick或者TIM做微秒延时,精度比空循环高很多。读数据的时候要注意:DHT11对时序敏感,中断会干扰时序,所以读数据的时候最好关掉全局中断。

uint8_t DHT11_ReadByte(void) { uint8_t i, byte = 0; for (i = 0; i < 8; i++) { while (!DHT11_DATA_IN); // 等待50us低电平结束 Delay_us(40); byte <<= 1; if (DHT11_DATA_IN) { byte |= 1; while (DHT11_DATA_IN); // 等待高电平结束 } } return byte; }

实测下来,DHT11的读数刷新率大概1Hz,不能太快。如果你连续读,第二次会返回上一次的缓存值。另外DHT11的湿度精度是±5%,温度精度是±2℃,对于实验室巡检来说够用了。如果要更高精度,可以换SHT30或者AHT20,I2C接口,精度高很多,但价格也贵一些。

3.3 ESP8266的AT指令配网与数据上传

ESP8266我用的是ESP-01S模块,AT固件版本。接线很简单:VCC接3.3V,GND接GND,TX接STM32的RX,RX接STM32的TX,EN接3.3V。注意ESP8266的IO口是3.3V电平,不能直接接5V,否则会烧。

AT指令配网流程:

  1. 发送AT,确认模块响应OK。
  2. 发送AT+CWMODE=1,设置为Station模式。
  3. 发送AT+CWJAP="SSID","password",连接WiFi。这一步可能需要几秒钟,要等待OK响应。
  4. 发送AT+CIPSTART="TCP","服务器IP",端口,建立TCP连接。
  5. 发送AT+CIPSEND=长度,然后发送数据。
  6. 发送AT+CIPCLOSE,关闭连接。

这里有个坑:ESP8266恢复出厂设置(AT+RESTORE)的时候,如果循环体中检测不到"OK",很容易进入死循环。我的做法是加超时机制,每次发送AT指令后等待响应,超过5秒没收到就重试,重试3次还不行就复位模块。

uint8_t ESP8266_SendAT(char *cmd, char *expect, uint16_t timeout) { uint8_t retry = 3; while (retry--) { USART1_SendString(cmd); if (USART1_WaitResponse(expect, timeout)) { return 1; } } return 0; }

数据上传我用的是TCP直连,没有走MQTT或者OneNet。原因很简单:TCP直连代码最少,调试最方便。如果你需要接OneNet或者阿里云,需要按照平台的协议封装数据包,工作量会大不少。对于实验室巡检这种小规模场景,TCP直连加一个简单的上位机服务器就够了。

4. 电机控制、避障逻辑与整机联调

4.1 L298N驱动下的PWM调速与死区处理

L298N每个电机需要三个控制信号:使能(PWM)、方向1、方向2。使能引脚接STM32的PWM输出,方向引脚接普通GPIO。调速就是改PWM的占空比,方向就是改两个GPIO的高低电平组合。

PWM频率我设的是10kHz,这个频率下电机噪音小,L298N发热也正常。占空比范围0到100,对应速度0到最大。但实际使用中,占空比低于20%的时候电机可能转不起来,因为静摩擦力太大。所以有效调速范围大概是20%到100%。

void Motor_SetSpeed(uint8_t motor, int16_t speed) { if (speed > 0) { // 正转 if (motor == MOTOR_A) { GPIO_SetBits(GPIOA, GPIO_Pin_0); GPIO_ResetBits(GPIOA, GPIO_Pin_2); TIM_SetCompare2(TIM2, speed); } } else if (speed < 0) { // 反转 // ... } else { // 停止 TIM_SetCompare2(TIM2, 0); } }

死区处理是电机控制里容易被忽略的细节。当电机从正转切换到反转时,如果直接改方向引脚,L298N内部的两个H桥可能瞬间同时导通,导致短路。正确的做法是先把PWM降到0,延时几十毫秒,再改方向,再慢慢加速。这个延时我设的是50ms,实测下来L298N没有出现过热或者异常。

4.2 超声波避障的触发与滤波

超声波模块我用的是HC-SR04,Trig触发,Echo回响。测距原理很简单:Trig给一个10us的高电平,模块发射超声波,Echo变高,收到回波后Echo变低,Echo高电平的持续时间就是超声波往返的时间。距离等于时间乘以声速除以2。

在STM32上实现,可以用输入捕获或者外部中断加定时器。我用的是外部中断加TIM4计数,Echo上升沿开始计数,下降沿停止计数,然后算时间。注意声速受温度影响,20℃时是343m/s,0℃时是331m/s。如果精度要求高,可以用DHT11的温度值做补偿。

float Ultrasonic_GetDistance(void) { uint32_t time; GPIO_SetBits(GPIOB, GPIO_Pin_0); // Trig高 Delay_us(10); GPIO_ResetBits(GPIOB, GPIO_Pin_0); // Trig低 // 等待Echo上升沿,启动定时器 // 等待Echo下降沿,停止定时器 time = TIM_GetCounter(TIM4); return (time * 0.017); // 单位cm,声速343m/s }

滤波是必须的。超声波模块受环境干扰大,单次读数可能跳变。我的做法是连续读5次,去掉最大最小值,取中间3次的平均值。这样处理之后,读数稳定很多,避障逻辑也不会因为一个异常值就误判。

4.3 整机联调中的电源干扰与复位问题

整机联调的时候我遇到了一个很典型的问题:小车跑起来之后,OLED偶尔会花屏,ESP8266偶尔会掉线,STM32偶尔会复位。单独测试每个模块都没问题,一装到车上就出问题。

排查过程是这样的:先用示波器看3.3V电源轨,发现电机启动瞬间有大概200mV的跌落。再测5V轨,跌落更明显,有500mV左右。原因很清楚:电机启动电流大,L298N从5V轨取电,导致5V轨电压跌落,进而影响3.3V稳压器,最终导致STM32复位。

解决方案有三个:第一,在电机电源输入端并联一个大电容(我用了1000uF电解电容加100nF陶瓷电容),吸收启动瞬间的电流冲击;第二,把电机电源和逻辑电源分开走线,从电池端分别引线,不要共用一段导线;第三,在STM32的3.3V输入端加一个100uF电容,提高本地储能。

改完之后,电机启动时3.3V轨的跌落降到50mV以内,OLED和ESP8266都稳定了。这个经验告诉我:嵌入式系统里,电源设计比代码重要得多。代码写得再好,电源不稳,系统照样跑不起来。

5. 调试过程中踩过的坑与排查思路

5.1 程序下载失败的各种原因与对策

STM32下载失败是新手最常遇到的问题,没有之一。我遇到过的情况大概有这几种:

第一种,BOOT0跳线不对。STM32的启动模式由BOOT0和BOOT1决定,下载程序时BOOT0要接高电平(或者通过串口下载时接高),运行时要接低电平。有些板子的跳线帽松了,接触不良,也会导致下载失败。

第二种,ST-Link驱动没装好。设备管理器里如果看到ST-Link旁边有黄色感叹号,说明驱动有问题。重新装一遍ST-Link Utility或者STM32CubeProgrammer,驱动会自动安装。

第三种,SWD引脚被占用。PA13和PA14是SWDIO和SWCLK,如果代码里把这两个引脚配置成了普通GPIO,下载器就连不上了。解决办法是按住复位键,点击下载,在复位释放的瞬间下载器抢到总线。或者把BOOT0接高,从系统存储器启动,这样代码不运行,SWD引脚不会被占用。

第四种,芯片被读保护了。有些芯片出厂时或者被误操作设置了读保护,下载器读不到芯片ID。用STM32CubeProgrammer可以解除读保护,但会擦除整个Flash。

提示:如果你用的是最小系统板,建议常备一个USB转TTL模块。当SWD下载不了的时候,可以用串口下载(BOOT0接高,BOOT1接低,用Flash Loader Demonstrator),这是最后的救命稻草。

5.2 ESP8266 AT指令无响应的排查链路

ESP8266不响应AT指令,排查要按顺序来:

先看电源。ESP8266的峰值电流能到300mA,如果你的3.3V稳压器输出能力不够(比如AMS1117只有800mA但发热严重),模块可能启动不了。用万用表测模块VCC和GND之间的电压,正常应该在3.2V到3.6V之间。

再看串口接线。ESP8266的TX要接STM32的RX,RX要接STM32的TX,这是交叉连接。很多人会接成直连,然后纳闷为什么没反应。另外,ESP8266的EN引脚要接3.3V,有些模块上电默认不使能,需要手动拉高。

然后看波特率。ESP8266默认波特率是115200,但有些固件版本是9600或者74880。如果不确定,先用115200试,不行再换其他波特率。STM32的USART1配置要和模块一致,包括数据位、停止位、校验位。

最后看AT指令格式。AT指令要以回车换行结尾(\r\n),只发"AT"不发回车,模块是不响应的。在代码里发送字符串的时候,记得加上"\r\n"。

如果以上都排查了还是没反应,试试AT+RESTORE恢复出厂设置。注意这个指令执行后模块会重启,需要等待几秒钟。如果恢复出厂设置也失败,可能是固件损坏,需要用烧录工具重新烧录AT固件。

5.3 OLED显示异常的几种典型表现

OLED显示异常我遇到过三种:

第一种,完全不亮。先检查电源,VCC和GND是否接对,3.3V还是5V要看模块规格。然后检查I2C地址,用扫描程序确认地址是0x78还是0x7A。最后检查初始化序列,SSD1306和SH1106的初始化命令不同。

第二种,花屏或者显示错位。这种情况通常是I2C通信速率太高,或者接线太长导致信号完整性差。把I2C速率从400kHz降到100kHz试试,或者缩短接线长度。另外,OLED的显存是按页写的,如果页地址计算错误,显示内容会错位。

第三种,部分像素不亮或者亮度不均。这是OLED屏幕本身的品质问题,便宜模块的次品率不低。如果确认驱动没问题,换一块屏幕试试。

我在调试OLED的时候还遇到过一个奇葩问题:屏幕在电机启动的瞬间会闪一下。后来发现是I2C线走线太长,和电机线捆在一起,电机启动时的电磁干扰耦合到了I2C线上。把I2C线单独走,远离电机线,问题就解决了。

6. 上位机数据接收与巡检记录方案

6.1 用Python快速搭建TCP服务端

上位机我没用复杂的框架,直接用Python的socket库写了一个TCP服务端,接收小车发来的温湿度数据,存到CSV文件里。代码不到50行,跑起来很稳。

import socket import csv from datetime import datetime server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('0.0.0.0', 8080)) server.listen(1) while True: conn, addr = server.accept() with open('inspection_log.csv', 'a', newline='') as f: writer = csv.writer(f) while True: data = conn.recv(1024) if not data: break line = data.decode('utf-8').strip() timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') writer.writerow([timestamp, line]) f.flush() print(f'[{timestamp}] {line}') conn.close()

这个服务端监听8080端口,收到数据后加上时间戳写入CSV。小车端每隔5秒发一次数据,格式是"T:25.3,H:60.2",简单直接。CSV文件可以用Excel打开,也可以后续用pandas做分析。

6.2 数据格式设计与异常值处理

数据格式我设计得很简单:温度用T开头,湿度用H开头,中间用逗号分隔。这样解析起来方便,也不容易出错。如果后续要加其他传感器,比如烟雾或者光照,直接加字段就行。

异常值处理在上位机做。DHT11偶尔会返回0或者255这种明显异常的值,我在Python端加了一个简单的过滤:温度不在-10到50之间、湿度不在0到100之间的数据直接丢弃,不写入CSV。这样记录下来的数据都是有效的。

如果你需要更严谨的数据记录,可以在小车端就做滤波,连续读5次取中值,再上传。这样上位机收到的数据质量更高,但小车端的代码会复杂一些。我选择在上位机做过滤,因为Python处理起来更方便,改起来也快。

6.3 巡检路线的规划与自动模式扩展

目前这个小车是遥控模式,人拿着遥控器操作。但如果要真正实现"自动巡检",需要加自动模式。自动模式的实现思路有两种:

第一种是循迹模式,在地面贴黑色胶带,小车用红外对管或者灰度传感器沿着胶带走。这种方案简单可靠,但需要提前布置场地。

第二种是SLAM模式,用激光雷达或者深度相机建图,然后自主导航。这种方案灵活但成本高,STM32F103的算力也不够跑SLAM,需要加一个树莓派或者Jetson Nano做上位机。

对于实验室巡检这个场景,我建议先用循迹模式。实验室的布局相对固定,贴一圈胶带就能覆盖主要巡检点。在每个巡检点贴一个RFID标签,小车读到标签就停下来采集数据,采集完继续走。这样既实现了自动化,又不需要复杂的导航算法。

我目前只做到了遥控模式,自动模式还在规划中。下一步打算加一个红外循迹模块,先实现最简单的循迹功能,然后再考虑加RFID或者超声波避障。嵌入式项目就是这样,一步一步来,不要想着一次做完所有功能。

7. 写在最后的几点实操体会

这个项目从立项到跑通,前后大概三周时间。中间有几天卡在ESP8266的AT指令上,有两天卡在电源干扰上,还有一天因为SWD引脚被占用导致下载不了程序,折腾了很久。现在回头看,这些问题其实都有成熟的解决方案,只是当时不知道。

如果你也在做类似的项目,我有几个建议:第一,电源一定要舍得下本钱,好的稳压模块和大电容能省掉一半的调试时间;第二,每个模块单独测试通过之后再联调,不要一上来就把所有模块接在一起;第三,串口打印是最好的调试工具,关键位置加printf,比用调试器单步跟踪效率高得多;第四,代码要分模块写,电机、OLED、DHT11、ESP8266各一个.c和.h文件,main函数只负责调度,这样出了问题好定位。

这个项目还有很多可以扩展的地方,比如加摄像头做图像识别、加麦克风做异常声音检测、加烟雾传感器做火灾预警。STM32F103的资源和算力有限,如果要加这些功能,可能需要换F4或者F7系列,或者加一个Linux上位机做协处理。但作为入门嵌入式的练手项目,F103C8T6已经足够带你走完从GPIO到PWM、从I2C到UART、从传感器到无线的完整链路。把这一套跑通,你对嵌入式系统的理解会上一个台阶。

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

全人类AI发展路径:技术民主化与公平性建模

1. 项目背景与问题定义2026年美赛F题直指人工智能发展中最具争议性的命题——是否应该以及如何发展"全人类人工智能"(Humanity-wide AI)。这个看似简单的问题背后&#xff0c;涉及技术伦理、社会公平、经济影响和全球治理等多维度复杂因素。作为数学建模竞赛题目&…

作者头像 李华
网站建设 2026/10/30 1:04:44

TIA Portal中LAD/FBD/STL/SCL注释技巧与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:03:11

被忽略的工业软件:自动控制的核心与工程实践反思

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:03:05

工业机器人开源项目全解析:控制软件、GUI与STL文件复现指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:02:40

不装环境也能玩ESP32:纯浏览器在线开发与云编译指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/30 1:02:35

基于STM32的高精度嵌入式称重系统设计与工业落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华