基于STM32F103的空气净化器完整设计实战
2026/8/31 7:48:37 网站建设 项目流程

简介:本资源是一套完整的基于STM32F103RCT6微控制器的空气净化器嵌入式开发资料,面向嵌入式初学者、电子设计爱好者及物联网实践者,解决室内空气质量监测与智能调控的实际工程问题。资源包共162个文件,含38个头文件(.h)与36个源码文件(.c),覆盖传感器驱动(温湿度、甲醛)、PWM风扇控制、LCD显示及系统初始化等核心模块;另有原理图(.schdoc)、PCB设计文件(.pcbdoc)、Keil工程配置(.uvprojx/.uvoptx)、编译输出(.axf/.hex)及调试脚本(.bat),完整呈现从硬件设计到固件烧录的全流程。压缩包大小为4.05MB,结构清晰、模块解耦,便于理解各外设(ADC、TIM、GPIO、UART)协同逻辑。目前已有1493人学习下载,适合用于课程设计、毕业设计或STM32实战进阶,可直接编译运行并快速验证多传感器融合与闭环控制效果。 先说下这套资料的成色。基于STM32F103的空气净化器设计资料,我拿到手之后完整捋过一遍,程序不是那种东拼西凑的Demo,原理图不是缺线少网的截图,PCB也不是只有孤零零一块板框。它是一套能直接编译、直接打样、能跑起来控制风机和显示PM2.5的完整工程。对于刚学完单片机基础、想拿一个真实产品练手的开发者,或者正在做家居小电器方案选型的工程师,这份资料的价值在于:把STM32F103最常见的几大外设——PWM、ADC、DMA、I2C、定时器中断——全部放在一个真实产品场景里串了一遍。今天我把整个设计逻辑摊开讲一遍,包括硬件选型、代码框架、PCB细节和调试中踩过的坑。

1. 项目概述与整体设计思路

1.1 空气净化器的核心功能拆解

空气净化器这东西,功能上看起来简单:开风机、过滤空气、显示个空气质量。但真正落到产品层面,控制逻辑比想象中要多一点。这套资料实现的功能我列一下:

  • 按键开机/关机,支持三档手动风速(弱、中、强)
  • 自动模式:根据PM2.5浓度自动调节风速档位
  • 睡眠模式:低转速、关闭指示灯、降低噪音
  • 实时显示PM2.5浓度、温湿度、当前风速档位
  • 定时关机功能(0.5h / 1h / 2h / 4h)
  • 紫外灯和负离子发生器的开关控制接口
  • 蜂鸣器按键提示音

这些功能说多不多,但每一块都要吃MCU的资源。风机转速靠PWM调速,PM2.5检测靠ADC采样粉尘传感器的模拟电压,温湿度用I2C读传感器,显示用I2C或SPI驱动OLED,按键和蜂鸣器占普通GPIO。整套系统跑下来,STM32F103C8T6这种48脚的中配芯片,资源刚好够用,不会觉得局促,也不会浪费。

1.2 为什么选STM32F103作为控制核心

选题阶段很多人会纠结:空气净化器用51单片机不行吗?用ESP32不行吗?用Arduino不行吗?

说实话,都能做。但这个项目选STM32F103有几个非常具体的理由。第一,它主频72MHz,Cortex-M3内核,跑空气净化器这种级别的控制算法绰绰有余,而且未来想扩展WiFi通信、传感器融合算法,算力都够。第二,外设齐全,TIM支持多路PWM输出,ADC有12位分辨率且支持DMA,I2C和USART都有,这些外设组合起来非常贴合空气净化器这种“采集-处理-控制-显示”的典型架构。第三,成本低、供货稳定、参考资料多,遇到问题几乎都能找到现成解答。

还有一个细节:STM32F103的引脚大部分是5V容忍的,这意味着按键、蜂鸣器这类5V逻辑的外围器件,可以直接互连,不需要额外加电平转换,硬件设计省事很多。我实际做下来,整板除了电源部分,几乎不需要什么专用芯片,设计难度就被拉低了不少。

1.3 功能模块与引脚资源分配

动手画原理图之前,我习惯先做一张资源分配表,把每个功能模块占用的引脚、用到的外设、通信方式全部列清楚。这样做的好处是后面画原理图、写代码、调板子,遇到问题容易定位。下面这张表是我在这个项目中实际用的分配方案:

功能模块外设资源引脚说明
风机PWM调速TIM2_CH1PA020kHz输出,经MOS管驱动风机
PM2.5粉尘传感器ADC1_IN1PA1DMA循环采样,读取粉尘浓度电压
温湿度传感器I2C1PB6 / PB7SHT30,地址0x44
OLED显示屏I2C1PB6 / PB7SSD1306,地址0x3C,与SHT30共用I2C总线
按键K1~K4GPIO输入PB0~PB3开关机、模式切换、风速加减、定时
紫外灯控制GPIO输出PB4通过三极管/MOS管驱动
负离子发生器GPIO输出PB5通过三极管/MOS管驱动
蜂鸣器GPIO输出PA8有源蜂鸣器,低电平触发
SWD下载调试SWDIO / SWCLKPA13 / PA14程序下载与在线调试
串口调试预留USART1PA9 / PA10预留,后续可接WiFi模块或蓝牙模块

这里要提醒一句:I2C总线上挂两个设备没问题,但要注意地址不能冲突。SHT30默认地址0x44,SSD1306常见地址是0x3C,两个不冲突,所以能共用一条I2C总线。如果你换别的型号传感器,第一件事就是核对地址是否冲突,否则会出现设备无法应答的诡异问题。

2. 硬件设计:从最小系统到整机电路

2.1 STM32F103最小系统设计要点

空气净化器的控制板,核心就是STM32F103最小系统加上外围电路。最小系统这部分看似简单,但很多人第一次画板子就栽在这里。我列几个关键点。

时钟电路:STM32F103用8MHz无源晶振,两个负载电容取18pF到22pF。晶振的两个引脚分别接电容到地,电容值不需要特别精确,20pF左右就行。注意晶振底下尽量不要走其它信号线,否则容易被干扰导致启动失败或者时钟频率不对。

复位电路:NRST引脚接一个100nF电容到地,加一个10kΩ上拉电阻。这样上电时能保证可靠的复位。很多人画最小系统时把复位电路省了,调试器连接时可能还能正常工作,但实际产品上电瞬间芯片状态不确定,很容易出现偶发性死机。

BOOT引脚:BOOT0必须通过10kΩ电阻下拉到地,让芯片从Flash启动。BOOT1随便接,一般也下拉。有时候下载失败,排查到最后发现是BOOT0悬空,电平不确定导致芯片没有正常进入用户程序,这种问题最坑人。

电源去耦:每个VDD引脚旁边放一个100nF陶瓷电容,尽量靠近引脚放置。VDDA引脚要单独接一个10Ω电阻再连3.3V,同时对地接一个1uF+100nF电容,给ADC提供干净一点的模拟电源。这个问题和后面ADC采样数值跳变有直接关系。

2.2 电源拓扑与风机驱动电路

空气净化器的电源拓扑比普通单片机板要复杂一点,因为系统里同时存在12V、5V、3.3V三种电源轨。我用的方案是:

  • 外部12V DC适配器输入
  • 12V直接给风机和紫外灯供电
  • 12V经DC-DC降压到5V,给传感器和蜂鸣器供电
  • 5V经AMS1117-3.3降到3.3V,给MCU、OLED供电

这里有一个设计取舍要说明一下:为什么不直接用一个5V适配器,然后风机也用5V?因为大多数空气净化器的风机额定电压是12V或24V,5V供电会导致转速上不去、风量不够。所以电源输入端直接按12V设计,这样整机结构上更接近真实产品。如果你手头只有5V风机,也可以简化成只用5V和3.3V两路,电路会简单很多。

风机驱动电路是硬件设计的核心。STM32的GPIO只能输出几毫安电流,肯定不能直接驱动风机,所以要在中间加一级MOS管。我用的是一颗N沟道MOS管,型号可以选AO3400这类低导通电阻的管子。电路结构是:PWM信号串一个100Ω电阻接MOS管栅极,栅极对地接一个10kΩ下拉电阻,防止MCU复位瞬间PWM输出高阻状态导致风机误转。MOS管的源极接地,漏极接风机的负极,风机正极接12V。风机线圈是感性负载,所以MOS管漏极要并联一个续流二极管,二极管负极接12V,正极接漏极。这个二极管必不可少,否则MOS管关断瞬间会产生很高的尖峰电压,轻则造成系统复位,重则击穿MOS管。

另外,紫外灯和负离子发生器这类负载,功率不大,用一颗NPN三极管(比如S8050)驱动就够了。注意继电器的场合不要用三极管,这东西线圈电流太大,必须用MOS管或者专门驱动芯片。

2.3 传感器、显示与交互电路

PM2.5检测我选用的是夏普GP2Y1010AU0F粉尘传感器。这个传感器是空气净化器里的经典方案,淘宝上很容易买到,价格也不高。它的输出是一个模拟电压,浓度越高电压越高。但硬件电路有几个坑:传感器内部有一颗红外LED,需要周期性的脉冲驱动,典型的驱动脉冲是10ms周期、0.32ms脉宽,LED的驱动电流大概几十毫安。这意味着传感器不是简简单单三根线接上去就能用,还得有LED驱动和运放调理电路。好在资料里已经把GP2Y1010AU0F的典型应用电路给出来了,照着画就基本没问题。

温湿度传感器我用的SHT30,I2C接口,精度和稳定性都比DHT11好不少。DHT11不是不能用,只是它的时序靠软件模拟,代码里容易因为中断干扰导致读取出错。而SHT30走硬件I2C,不需要精确延时,写代码省心很多。

显示部分用0.96寸OLED,SSD1306控制器,I2C接口,只需要接VCC、GND、SCL、SDA四根线。OLED的显示内容我建议分成三个区域:第一行显示当前模式和风速档位,第二行显示PM2.5数值,第三行显示温湿度。UI不用做得花哨,黑色底白色字,信息清楚就行。

按键电路一定要做处理。直接用GPIO接按键到地,内部上拉,这是最简单的做法。如果担心EMC干扰导致误触发,可以在按键两端并联一个100nF电容做硬件消抖。注意PCB布局时按键要放在结构上手指能按到的位置,不然画出来好看但装进壳子里按不到,就尴尬了。

2.4 原理图设计里几个容易踩的坑

原理图阶段踩过的坑,我总结几次最耽误时间的。

第一,粉尘传感器的模拟输出线和风机PWM线在原理图里如果靠得太近,打样回来后PM2.5数值会漂得离谱。这是因为PWM信号在PCB上会产生电场干扰,而GP2Y1010AU0F的输出阻抗不低,很容易耦合噪声。解决方法是模拟信号走线尽量短、尽量粗,并且在传感器输出到ADC引脚之间加一个100nF滤波电容。

第二,I2C上拉电阻不能省。STM32内部虽然有上拉,但驱动能力不够,总线频率高了波形就会变形。我在SCL和SDA上各接了一个4.7kΩ上拉电阻到3.3V,这个阻值是常规做法,实测通信稳定。如果你把OLED和传感器都挂在这条总线上,上拉电阻一定要加,不然显示雪花或者传感器读不到数据。

第三,12V和3.3V电源轨的地,在原理图上虽然都是GND,但布局布线时要把电源地和模拟地分开处理。我采用的是单点接地,整个PCB的地平面铺铜后在电源输入端附近汇合。这个做法能有效降低电机PWM开关噪声对ADC采样的干扰。后面PCB章节还会再详细讲。

3. 程序框架与核心代码实现

3.1 程序架构与工程组织

程序部分我使用KEIL5开发环境,标准外设库编写。使用HAL库的思路完全一样,只是API名字不同。整个工程我按模块划分文件,每个模块一个.c和一个.h,大致结构如下:

  • main.c:初始化外设,主循环调度
  • pwm.c:风机PWM初始化及占空比设置
  • adc.c:ADC+DMA采样及滤波处理
  • sensor.c:SHT30温湿度读取、PM2.5浓度计算
  • oled.c:OLED显示驱动
  • key.c:按键扫描与事件处理
  • control.c:主状态机、模式控制和风机档位管理
  • timer.c:定时器中断,作为系统时基

这种模块化组织方式的好处是,改动任何一个功能模块,不需要牵扯其它文件。比如我后期想换一个传感器型号,只需要改sensor.c,主循环里的调度逻辑完全不用动。

主程序的框架是一个超级循环加定时器中断。10ms的定时器中断负责按键扫描和LED闪烁这类时间敏感任务,主循环负责较慢的传感器读取、显示刷新和模式控制。这样做避免了在一个大循环里用delay延时,导致按键响应迟钝的问题。

3.2 PWM配置与风机调速

风机调速是空气净化器最核心的控制功能。我用TIM2的通道1产生PWM信号,频率设为20kHz。为什么是20kHz而不是1kHz或者200Hz?因为风机在低于15kHz的PWM频率下会发出人耳可闻的“滋滋”声,20kHz接近人耳听觉上限,噪音基本听不到。同时20kHz对MOS管的开关损耗也不大,是一个比较均衡的选择。

定时器时钟是72MHz,要输出20kHz,只需要做一次分频:72MHz除以3600等于20kHz。所以我设置预分频PSC=0,自动重载值ARR=3599,输出比较寄存器CCR就是占空比。占空比从0到100%对应CCR从0到3599。三档风速我分别取占空比30%、60%、90%,睡眠模式取20%,这样既保证最低转速能维持空气循环,又不会出现电机堵转。

PWM初始化代码大致如下:

void PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); // PA0复用为TIM2_CH1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = 3600 - 1; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 1800; // 初始50%占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_Cmd(TIM2, ENABLE); } void Fan_SetDuty(uint16_t duty) { TIM_SetCompare1(TIM2, duty); }

这里有个常见错误:定时器的时钟来自APB1,APB1预分频如果不设置,默认就是72MHz。如果你改过RCC的时钟树配置,一定要用SystemInit默认的72MHz主频设置,否则PWM频率计算会出错。我调试时遇到过PWM频率变成18kHz的情况,查了半天发现是时钟树配置被改过。

3.3 ADC采样、DMA与PM2.5计算

粉尘传感器的输出电压要经过ADC转换变成数字量。STM32F103的ADC是12位分辨率,采样范围0到3.3V。我使用ADC1的通道1,对应PA1引脚,采样模式配置为连续转换加DMA循环搬运。

DMA的作用是让ADC自动把采样结果搬运到内存数组里,CPU不需要每次转换完都进一次中断。我在内存里放了一个32个元素的数组,DMA循环填充,主循环里定时对这32个数做平均滤波,这样能有效压低传感器输出中的随机噪声。

ADC和DMA的初始化核心配置如下:

#define ADC_BUF_SIZE 32 uint16_t adc_buf[ADC_BUF_SIZE]; void ADC_DMA_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // PA1模拟输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // DMA1通道1搬运ADC1数据 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = ADC_BUF_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE); }

传感器输出电压和PM2.5浓度的换算,这里要特别说明。GP2Y1010AU0F的输出电压和粉尘浓度近似线性,但不同批次、不同环境下传感器的基准电压和灵敏度都有差异。资料代码里我留了一个宏定义做换算,默认按浓度=(输出电压-0.6V)*200计算,单位ug/m3,输出电压低于0.6V按0处理。这只是给调试用的参考值,真正要做到比较准,必须拿标准粉尘源做两点校准。如果你只是做样机演示,这个换算关系完全够用。

ADC采样还有一个硬性要求:传感器LED脉冲和ADC采样时序要配合。GP2Y1010AU0F的LED脉冲宽度0.32ms,必须在LED点亮之后的280us左右去采样,得到的才是有效的浓度对应电压。这部分如果传感器模块已经集成了驱动电路,就不用自己操心时序;但如果买的是裸传感器,就必须在程序里控制LED脉冲和采样间隔。资料里的代码用的是传感器模块,所以主循环直接读AD值就行。

3.4 OLED显示与按键扫描

OLED显示驱动本身不复杂,SSD1306的初始化代码网上到处都是。我讲两个容易忽略的细节。第一,I2C通信时序要稳定,建议把I2C时钟频率控制在400kHz以内,STM32F103的I2C外设跑400kHz没有问题。第二,OLED的刷新频率不用太高,每秒刷新几次就够,而且不要在主循环里刷一整个屏幕,那样占用时间太多。我采用的方式是:数据变化的时候才更新对应的区域,通过设置显示坐标,只更新变化的部分。这样主循环的CPU占用率很低,可以腾出时间做别的事。

按键扫描用10ms定时中断来做。每次进入中断,读取四个按键的GPIO电平,放入一个状态缓冲区,然后通过边沿检测判断是短按还是长按。我实现的逻辑是:

  • 短按:按键按下时间小于1秒,释放时触发一次按键事件
  • 长按:按键持续按下超过1秒,触发一次长按事件

这样功能键、开关机键就可以区分短按和长按的操作。比如开关机键短按是开机/关机,长按是进入睡眠模式。这种交互逻辑在实际产品里很常见,代码实现也不复杂。

3.5 模式控制与状态机

空气净化器的状态,我定义成4种:待机、手动、自动、睡眠。整机运行的核心就是一个状态机,状态切换条件来自按键事件和PM2.5浓度。

手动模式最直接:用户按下风速+或风速-,程序把档位值在1、2、3之间循环,然后调用Fan_SetDuty设置对应的占空比。

自动模式是重点。我设定两个阈值:PM2.5小于35ug/m3判定为优,风机转低档;35到75ug/m3为良,转中档;大于75ug/m3转高档。这个阈值参考了空气质量标准,实际可以根据产品定位调整。自动模式下的档位变化不是瞬时的,我加了一个防抖逻辑——连续3次检测都超过阈值才切换档位,避免浓度在阈值附近时风机频繁变速。

睡眠模式的逻辑稍微特殊一点:风机固定20%占空比,OLED背光调暗或者直接关掉显示,所有按键的LED指示灯也熄灭。这样夜间运行时不会产生光污染。

定时关机我放在主循环里处理,倒计时结束直接进入待机状态,关闭风机和紫外灯,同时OLED显示关机画面。时间基准用的就是定时器10ms中断里累计出来的秒数,不开额外定时器。

代码的模块化程度再强调一下:主循环只负责调度,具体逻辑都在各模块文件里。这五六个模块文件看下来,整个控制逻辑是清晰可见的。后面如果要加空气质量历史曲线、手机APP控制,都是在现有框架上扩展,不需要重写底层。

4. PCB设计:布局、布线到打样

4.1 布局分区思路

PCB布局我采用的是功能分区法,整板分成四个区域:电源区、电机驱动区、主控区、接口区。分区的核心原则是强弱分离——大电流、高频开关的电路,跟小信号模拟电路必须拉开距离。

电源区放在板子一角,包含DC输入端子、防反接二极管、DC-DC芯片、LDO和对应的滤波电容。电机驱动区紧挨着电源区,因为风机电流就是从电源轨直接来的。主控区放在板子中间,STM32F103、晶振、复位电路、去耦电容、SWD接口都在这里。接口区分布在板子边缘,包括OLED接口、传感器接口、按键接口、蜂鸣器接口。

为什么要这样分?因为风机驱动线上的电流是脉冲式的,会产生很强的电磁干扰,如果主控区和驱动区混在一起,ADC采样和I2C通信很容易被干扰。实际测试时我发现,驱动区靠近传感器接口的话,PM2.5数值会周期性跳动,频率和PWM频率吻合,把分区拉开之后问题就消失了。

4.2 布线规则与层叠方案

这个项目用两层板就能搞定,不需要上四层。两层板的关键是地平面的完整性。

布线规则我按电流大小来定宽度。12V电源输入线和风机供电线,至少1.5mm宽,最好能到2mm。5V电源线至少1mm宽。3.3V电源线0.5mm以上。信号线0.25mm到0.3mm都行。不要小看这条规则,很多板子打样回来一开风机就重启,就是电源线太细、压降太大导致的。

晶振布线要特别注意:晶振引脚的两根线走短走直,并且尽量包地处理,即晶振底下铺一圈地铜,周围不要走其它信号线。我见过有人在晶振旁边走了一根PWM信号线,结果系统时钟总是不稳定,时好时坏,最后查出来就是干扰问题。

粉尘传感器的模拟信号线从接口到ADC引脚之间,走的线要短,旁边不要走数字信号线。可以在传感器信号线上串联一个100Ω电阻,引脚处再加100nF电容到地,组成一个低通滤波器,能滤掉一部分高频干扰。

过孔的使用也有讲究。电源引脚必须打两个以上过孔连接到另一层的电源网络,单过孔在大电流下电阻偏大。地过孔越多越好,因为过孔是连接顶层和底层地铜的关键通道,数量少了地平面就不完整。

4.3 出图打样前的检查清单

出Gerber文件之前,我强烈建议过一遍下面这些检查项,都是实战中攒下来的经验:

  • 检查所有的封装焊盘和实际元器件尺寸是否一致。电容电阻的封装比较容易看错,0603和0805差一个数量级,用卡尺量一下最保险。
  • 检查DC输入端的极性。防反接二极管的方向一旦画反,上电瞬间就烧板。
  • 检查晶振两个负载电容是否都接到GND。很多人只画一个电容,导致晶振起振困难。
  • 检查MOS管的D极和S极有没有接反。接反的话PWM怎么调风机都不转,因为体二极管把电流直接旁路了。
  • 检查丝印是否压住焊盘。压在焊盘上的丝印会影响焊接,尤其是表贴器件。
  • 检查定位孔的机械层是否正确。如果用AD画,定位孔建议放在机械层1;如果用立创EDA,直接用板框工具画孔就行。
  • DRC检查必须零错误。间距、线宽、钻孔尺寸、开路短路,一个都不能放过。

打样的时候,我的建议是选嘉立创这类常规工艺,板厚1.6mm,铜厚1盎司,绿油白丝印,下单前看一眼板子尺寸,控制在数量价优惠范围内。打样回来先不要急着焊全套芯片,我习惯先焊电源部分,确认3.3V、5V正常之后再焊MCU和相关电路。这样如果电源出问题,不会把主控芯片烧掉。

5. 调试实录与问题排查

5.1 下载与启动问题

打样回来第一件事就是下载程序。最常见的现象是KEIL提示“No target connected”或者“Cannot access target”。排查顺序我总结成四个步骤:第一,量MCU的VDD是不是3.3V,地是不是真的连通;第二,量NRST复位引脚,正常应该是高电平,如果是低电平说明复位电路有问题或者芯片进入了复位状态;第三,确认BOOT0是低电平,如果悬空或者被拉到高电平,芯片会从系统存储器启动而不是用户Flash,程序自然跑不起来;第四,确认SWD的四根线有没有接对——SWDIO、SWCLK、GND、VCC,少一根都没法下载。

还有一个不太容易想到的地方:SWD占用的是PA13和PA14,如果你在程序里把这俩引脚配置成了普通GPIO输出,那程序第一次下载后,第二次就下载不进去了。解决办法是在工程里把SWD的两个引脚配置为复用功能,或者下载时按住复位键不放,等KEIL连接上之后再松手。

5.2 风机不转或者风速不受控

风机不转先别急着怀疑程序。首先把PWM占空比设成100%,也就是直接把输出拉高,看风机转不转。如果还不转,问题在驱动电路或者风机本体,和程序无关。

用万用表量MOS管的D极和S极电压:如果D极一直是12V,说明MOS管没有导通,检查栅极电压有没有被拉到高电平,如果栅极电压正常但MOS管不导通,大概率是封装接反了。如果D极一直是0V,说明电源没到风机,检查供电线路和续流二极管有没有焊反。续流二极管焊反的典型现象是上电就发热,甚至直接烧MOS管。

风速不受控的问题,多出现在PWM配置上。用示波器看PA0输出波形,如果没有波形,检查GPIO是否配置成了复用推挽输出,TIM2的时钟是否已经使能。有波形但占空比不变,那可能是软件里改的寄存器和实际输出不是同一个通道,比如初始化的是TIM2_CH1,设置比较值的时候却用了TIM_SetCompare2。

5.3 PM2.5数值跳变

ADC采样数值跳变是空气净化器调试里最烦人的问题,因为它可能由好几个因素叠加导致。我第一次调的时候,PM2.5显示值在0到500之间疯狂跳动,电机一开数值就乱飞。

排查步骤:先关掉风机,看读数是否稳定。如果关掉风机就稳定,那说明是电机PWM干扰串到了传感器的模拟信号上,这时候要在传感器输出加滤波电容,同时检查传感器和电机驱动的走线间距。如果关掉风机读数还是跳,那问题在ADC配置或者传感器供电上,用万用表量传感器VCC是不是稳定的5V,再看ADC的采样时间是不是太短。GP2Y1010AU0F输出阻抗较高,ADC采样时间至少要配置到239.5个周期,不能默认用最短采样时间。

还有一点是软件上的:滑动平均滤波的窗口大小会影响数据平滑程度和响应速度。窗口太小噪声压不住,窗口太大浓度变化半天才反映出来。我实测下来32个点的窗口比较合适,更新频率1Hz,折中效果最理想。

5.4 常见问题速查表

我把调试过程中遇到比较典型的问题整理成一个速查表,方便你对照排查:

现象可能原因排查思路
无法下载程序BOOT0电平异常、SWD接线错误、芯片供电问题量VDD、NRST、BOOT0电平,检查SWD接线,可降低调试器速度
PWM输出无波形TIM时钟未使能、引脚复用配置错误示波器查PA0,检查AFIO时钟和GPIO_Mode_AF_PP配置
风机不转MOS管未导通、续流二极管反接、电机损坏100%占空比测MOS管D-S电压,确认驱动逻辑
风机噪声大PWM频率过低确认PWM频率在18kHz以上,建议20kHz
PM2.5数值乱跳电机干扰、传感器滤波不足、ADC采样时间太短关电机对比测试,传感器输出加100nF电容,ADC采样时间调大
OLED白屏I2C地址错误、SCL/SDA接反、上拉电阻缺失测SCL/SDA波形,确认地址0x3C,检查上拉电阻
传感器读取数据为0I2C总线锁死、传感器地址冲突断电等几秒恢复I2C总线,逐个挂载设备确认地址
一开风机MCU就复位电源线太细、续流二极管缺失、DC-DC带载不足加大电源线宽,检查续流二极管,测12V在风机启动时的跌落波形

个人体会

整套资料啃完、板子跑起来之后,我最大的感触是:空气净化器这个项目麻雀虽小五脏俱全,它把一个嵌入式产品开发最核心的几件事——需求拆解、资源分配、外设编程、PCB设计、整机调试——全部过了一遍。你做完这个项目之后,再做其它小家电或者物联网设备,基本上就是套用这套框架换传感器、换执行器的事。我建议拿到资料后不要急着改代码,先把原理图从电源到MCU从头到尾看一遍,再对照代码里每个外设的初始化逻辑,最后看PCB每个元件的摆放位置。三样东西串起来之后,你对这套系统的理解才算是完整的。后面如果想把产品做智能化,给MCU加一个WiFi模块或者蓝牙模块,通过串口协议和手机小程序通信,STM32F103这边只需要预留一个USART接口,控制框架完全不用大改。这就是我常说的,先把底子打扎实,后面怎么扩展都顺手。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询