2、单片机选型与硬件平台:STM32/GD32选型依据、最小系统电路、电源设计、晶振与复位电路

好,咱们开始第二章。这一章聊的是硬件选型和最小系统设计。说白了,就是决定用哪颗芯片,以及怎么让它跑起来。

很多初学者喜欢一上来就画原理图、焊板子。我个人习惯是,先花半天时间把选型定死。芯片选错了,后面所有工作都得推倒重来。我在项目中遇到过不止一次,因为选型时少看了一个外设资源,导致后期不得不换平台,那叫一个痛苦。

2.1 STM32 vs GD32:怎么选?

先说说这两家的关系。GD32是国产兆易创新的产品,指令集和STM32高度兼容。说白了,你拿STM32的代码,改几个头文件,基本就能在GD32上跑。但两者还是有区别的。

对比项 STM32(意法半导体) GD32(兆易创新)
主频 通常72MHz~240MHz 同定位下略高,可达108MHz~200MHz
Flash速度 零等待执行(ART加速器) 零等待执行,但部分型号需注意预取配置
价格 较高,尤其近两年涨价严重 便宜,性价比突出
供货 交期不稳定 国产芯片,供货相对稳定
生态 极其成熟,资料多如牛毛 兼容STM32生态,但部分库需适配
抗干扰 经过大量工业验证,稳定 中低端应用没问题,极端环境需测试

我的建议是:

  • 做产品量产,尤其是成本敏感的暖通控制器,优先考虑GD32。省下来的钱够买好几个传感器了。
  • 做样机或学习,用STM32。资料多,遇到问题好查。我记得第一次用GD32时,有个定时器配置死活不对,最后发现是库函数里一个宏定义和STM32不一样。
  • 如果项目要求高可靠性,比如医院空调、数据中心精密空调,我建议用STM32。抗干扰和长期稳定性确实更让人放心。

核心原则:选型不是选最好的,而是选最合适的。暖通空调控制对算力要求不高,但对IO数量和PWM通道数有要求。先列需求,再选芯片。

2.2 最小系统电路

芯片选好了,接下来就是让它能工作。最小系统,说白了就是让单片机“活过来”的最低配置。包括:电源、晶振、复位、下载电路。

嗯,这里要注意。很多新手画最小系统,照着网上的图抄一遍就完事了。但实际项目中,每个引脚怎么接都是有讲究的。

2.2.1 电源设计

单片机需要稳定的3.3V供电。暖通空调系统里,通常有24V交流或12V直流输入。所以需要一级降压。

我个人习惯用两级方案:

  • 第一级:用DC-DC降压芯片(比如MP2359、TPS5430),把12V或24V降到5V。效率高,发热小。
  • 第二级:用LDO(比如AMS1117-3.3),把5V降到3.3V。纹波小,给单片机供电更干净。

我曾经在一个项目中,为了省成本,直接用LDO从12V降到3.3V。结果LDO烫得能煎鸡蛋,没几天就烧了。后来老老实实加了DC-DC,问题解决。

警告:单片机电源引脚旁边,一定要加0.1μF和10μF的去耦电容。而且电容要尽量靠近芯片引脚。这不是玄学,是电磁兼容的基本要求。不加的话,单片机容易死机、复位、甚至烧坏。

2.2.2 晶振电路

晶振是单片机的心脏。没有它,单片机就没法按节奏工作。

STM32/GD32通常需要两个晶振:

  • 主晶振(HSE):8MHz。用于产生系统时钟。为什么是8MHz?因为内部PLL可以倍频到72MHz或更高。
  • RTC晶振(LSE):32.768kHz。用于实时时钟,省电。

晶振电路其实很简单,就是晶振两端各接一个20pF左右的电容到地。但这里有个坑:

避坑指南:我曾经遇到过晶振不起振的情况。查了半天,发现是PCB布局时,晶振走线太长,而且旁边有高频信号干扰。后来把晶振紧贴芯片引脚,走线尽量短,地线包一圈,问题解决。记住:晶振走线越短越好,周围不要走其他信号线。

代码里配置时钟也很简单,以STM32为例:

// 配置系统时钟为72MHz
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    // 使能HSE晶振
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;   // 8MHz / 8 = 1MHz
    RCC_OscInitStruct.PLL.PLLN = 72;  // 1MHz * 72 = 72MHz
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // 72MHz / 2 = 36MHz? 不对,这里PLLP是主时钟输出
    // 实际STM32F103的PLLP是分频系数,通常设为RCC_PLLP_DIV2,输出72MHz
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    // 配置系统时钟源为PLL
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;  // APB1最大36MHz
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  // APB2最大72MHz
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
}

这段代码看着长,其实逻辑很简单:先让外部8MHz晶振工作,然后通过PLL倍频到72MHz,最后把系统时钟切换到PLL输出。

2.2.3 复位电路

复位电路的作用,就是让单片机在上电时,从一个确定的状态开始运行。

最简单的复位电路:一个10kΩ上拉电阻接到3.3V,一个0.1μF电容接到GND,中间引出复位引脚。上电瞬间,电容充电,复位引脚保持低电平,等电容充满后,引脚变为高电平,单片机开始运行。

但实际项目中,我建议加一个复位芯片,比如MAX809。为什么?

  • 它能提供精确的复位阈值。当电压低于某个值(比如2.93V)时,强制复位。
  • 它能防止电压抖动导致的误复位。

我曾经在一个项目中,电源纹波比较大,导致单片机频繁复位。用示波器一看,复位引脚在电压波动时出现了毛刺。后来加了一个复位芯片,世界清净了。

总结一下最小系统设计要点

  • 电源:两级降压,DC-DC + LDO,去耦电容不能省
  • 晶振:走线短,远离干扰,匹配电容要选对
  • 复位:RC电路够用,但工业应用建议加复位芯片
  • 下载电路:SWD接口,留出SWDIO、SWCLK、GND、3.3V四个引脚

嗯,这一章的内容就这些。选型和最小系统是硬件设计的基础,基础打牢了,后面写代码、调参数才能顺风顺水。下一章我们聊传感器选型与接口设计,到时候见。