尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32F103C6T6引脚配置与CubeMX实战避坑指南

STM32F103C6T6引脚配置与CubeMX实战避坑指南 前些天帮朋友查一块C6T6板子LED怎么都不亮。代码是照着网上教程抄的PA5输出翻转可那块最小系统板上的LED偏偏焊在PC13PA5上面连的是个空焊盘。改完引脚地址灯亮了但没过两分钟又踩了另一个坑他想把板子上预留的串口3接口用起来结果C6T6根本没有USART3这个外设。这类问题十有八九都出在“只背了引脚号没真正吃透引脚功能”上。STM32F103C6T6是一颗LQFP48封装、32KB Flash、10KB SRAM的入门级Cortex-M3芯片市面上大量小体积控制板、传感器驱动板、毕业设计核心板都在用。它和更常见的C8T6引脚完全兼容看着好像很熟悉但C8T6的代码拿过来不一定能跑更不是所有F103教程都能照搬。这篇文章就围绕这颗芯片从引脚排列、功能分组、外设复用到CubeMX里的真实配置再到几个典型的翻车现场完整梳理一遍。适合正在画板子、调板子或者想搞懂这颗芯片为什么“和教程对不上”的人。1. 一块48脚芯片为什么还要单独聊引脚1.1 C6T6在F103家族里的真实定位STM32F103系列里C6T6属于低密度产品。注意这个“低密度”不是引脚密度而是Flash和SRAM的容量档位。C6T6那块Flash只有32KBSRAM只有10KB最大主频72MHz内置ARM Cortex-M3内核没有浮点单元外设数量也被砍了一刀。很多教程默认用C8T6做例子C8T6是64KB Flash、20KB SRAM开发板也便宜资料也最多。C6T6和C8T6都是LQFP48封装引脚完全兼容所以很多人画完板子直接焊C6T6觉得“容量小点而已代码一样写”。这个思路在纯GPIO点灯、跑跑定时器时没问题但一旦用到完整外设列表差异就出来了。我在选型时一般先看一张对比表确认这颗芯片到底“少”在哪项目STM32F103C6T6STM32F103C8T6Flash32KB64KBSRAM10KB20KB封装LQFP48LQFP48GPIO数量37个37个USART2个USART1、USART23个USART1、USART2、USART3SPI2个2个I2C2个2个ADC1个10个外部通道1个10个外部通道定时器TIM1/TIM2/TIM3/TIM4/TIM6/TIM7全部都有USB有有CAN有有FSMC无无C6T6虽然叫“小容量”但USB和CAN居然都在。真正砍掉的是USART3以及部分高密度才有的外设。这个我后面会专门讲因为很多人在这上面栽过跟头。1.2 引脚兼容不等于外设兼容LQFP48封装的STM32F103无论C4、C6、C8还是CB物理引脚定义完全一致Pin 1到Pin 48哪个脚接VDD、哪个脚是PA0全部相同。这意味着你画一块板子可以根据供货和成本自由选择焊C6T6还是C8T6硬件不用改。但外设数量是芯片内部决定的和引脚是否兼容没关系。C6T6没有USART3而C8T6有所以当你从C8T6工程迁到C6T6时如果原工程里用了USART3默认引脚PB10/PB11CubeMX在选C6T6时根本不会出现USART3这个选项。底层寄存器也许能写但外设根本没被实例化硬件上不会有任何反应。这类问题最迷惑人的地方在于编译不会报错芯片也能跑只是那几个引脚没信号。我做项目时养成了一个习惯硬件定下来之后第一件事不是抄代码而是把数据手册里的外设列表和引脚映射表打印出来逐个核对项目里要用的外设是否存在于这颗芯片上。这一步能省掉后面好几天的排查时间。2. LQFP48引脚逐组拆解先认识每个“坑位”2.1 引脚编号规则和全景分组LQFP48封装四周各12个引脚共48脚。芯片上有圆圈标记的是Pin 1沿逆时针方向递增。拿到全新芯片或原理图封装时先找Pin 1位置再按逆时针编号这个方向错了整个图纸全乱。C6T6的48个引脚大致分为五类电源类、时钟类、复位/启动类、调试类、GPIO类。下面这张表是我平时画图纸时常用的分组参考引脚编号引脚名称归类1VBAT后备电池/电源2PC13-TAMPER-RTCGPIO/特殊功能3PC14-OSC32_IN低速晶振/GPIO4PC15-OSC32_OUT低速晶振/GPIO5PD0-OSC_IN高速晶振/GPIO6PD1-OSC_OUT高速晶振/GPIO7NRST复位8VSSA模拟地9VDDA模拟电源10-19PA0-PA7、PB0-PB1GPIO/ADC输入20PB2-BOOT1启动/GPIO21-22PB10、PB11GPIO/I2C2/TIM223-24VSS_1、VDD_1数字电源25-28PB12-PB15GPIO/SPI229-33PA8-PA12GPIO/USB/定时器34PA13-JTMS-SWDIO调试/GPIO35-36VSS_2、VDD_2数字电源37PA14-JTCK-SWCLK调试/GPIO38PA15-JTDI调试/GPIO39PB3-JTDO调试/GPIO40PB4-JNTRST调试/GPIO41PB5GPIO42-43PB6、PB7GPIO/I2C144BOOT0启动45-46PB8、PB9GPIO/CAN47-48VSS_3、VDD_3数字电源这里有个容易混淆的地方PD0和PD1在有些资料里直接标注为OSC_IN和OSC_OUT有些标注为PD0和PD1。作为普通IO使用时它们是可以当输入输出的但如果你接了8MHz高速外部晶振这两个脚就被占用了。PC14/PC15同理接了32.768kHz低速晶振后就不能当普通IO。2.2 电源引脚3路VDD、3路VSS、VDDA、VSSA、VBATC6T6上有3组数字电源引脚VDD_1、VDD_2、VDD_3对应3个地引脚VSS_1、VSS_2、VSS_3。很多人画最小系统板时只接一组VDD和VSS结果芯片工作不稳定、GPIO输出异常、程序偶尔跑飞。这3组电源引脚必须在电路上全部连接不能只接其中一组。此外还有VDDA和VSSA是模拟电源和模拟地给ADC、内部复位电路、PLL等模拟部分供电。即使你不用ADCVDDA也必须接不能悬空。我见过一块ADC读数严重跳变的板子最后发现是VDDA只接了一个细长走线且没有放去耦电容。正确做法是VDDA和VSSA之间放一个1uF和100nF电容并联布局上尽量靠近芯片引脚。VBAT是后备电池电源引脚为内部RTC和备份寄存器供电。如果用不到电池备份功能最简单的做法是把VBAT直接接到VDD不要悬空。悬空可能导致内部备份域状态不确定某些异常复位情况下RTC配置丢失。去耦电容是画板时最容易忽视的细节。我的习惯是每个VDD引脚就近放一个100nF电容VDDA放1uF和100nF电容地端直接打孔到主地平面。电源走线从5V转3.3V的LDO出来后先经过磁珠或小电阻再到VDDA效果更好。2.3 时钟、复位和启动引脚时钟引脚分两组。高速外部时钟HSE用OSC_IN和OSC_OUT接8MHz晶振配合两个大约20pF的负载电容。低速外部时钟LSE用OSC32_IN和OSC32_OUT接32.768kHz晶振主要用于RTC。如果你只用内部HSI时钟8MHz晶振可以不接PD0/PD1就能释放出来当普通IO用但这样主频精度全靠内部RC振荡器对串口波特率精度要求高的场合会有风险。NRST是外部复位引脚低电平有效内部有上拉电阻。电路上建议加一个100nF电容到地增强抗干扰能力。有些模块会把NRST引出来接一个按键方便手动复位。要注意NRST不能直接接强下拉否则芯片会一直处于复位状态。启动引脚是BOOT0和PB2/BOOT1。F103的启动模式由这两个引脚在上电或复位时的电平决定BOOT0BOOT1PB2启动区域说明0任意主Flash正常执行用户程序10系统存储器进入串口ISP Bootloader11SRAM从SRAM启动一般调试用设计上BOOT0最好用一个10k电阻下拉到地确保正常上电时从主Flash启动。PB2这个引脚在启动时被采样为BOOT1启动后就可以当普通IO使用。但如果电路上把PB2接到了强驱动的器件且上电时电平为高BOOT0又是高芯片就会进入SRAM启动程序不会从Flash跑表现为“下载正常但不执行”。这类问题排查起来特别隐蔽。3. 37个GPIO和外设复用图纸上必须提前圈出来的线3.1 从IO到ADC采样通道不是随便选的C6T6有37个GPIO其中可用作ADC1输入的有10个外部通道分布如下ADC通道引脚说明ADC1_IN0PA0支持WKUP唤醒ADC1_IN1PA1ADC1_IN2PA2默认还复用USART2_TXADC1_IN3PA3默认还复用USART2_RXADC1_IN4PA4默认还复用SPI1_NSSADC1_IN5PA5默认还复用SPI1_SCKADC1_IN6PA6默认还复用SPI1_MISOADC1_IN7PA7默认还复用SPI1_MOSIADC1_IN8PB0ADC1_IN9PB1所以设计ADC输入电路时如果同时又要用SPI1或USART2就得认真协调因为PA2、PA3、PA4、PA5这些引脚是复用的。遇到这种情况我一般优先把ADC输入放到PA0、PA1、PB0、PB1上这几个引脚在默认功能里没有太多通信外设占用冲突最小。3.2 常用通信外设的默认引脚位置C6T6没有USART3但USART1和USART2都有。常用外设和引脚的默认对应关系如下外设引脚A引脚B备注USART1PA9TXPA10RX默认64脚以上封装可重映射到PB6/PB7USART2PA2TXPA3RX重映射到PD5/PD6但C6T6无PD5/PD6SPI1PA5SCKPA6MISO、PA7MOSI、PA4NSS重映射到PB3/PB4/PB5方式受调试脚限制I2C1PB6SCLPB7SDA重映射到PB8/PB9会与CAN冲突I2C2PB10SCLPB11SDAC6T6上可用USBPA11DMPA12DP需要外接1.5k上拉电阻CANPB8RXPB9TX需要CAN收发器我用红色标注一下USB和CAN共享512字节的包缓冲区硬件上可以同时存在但实际使用中两者不能同时工作。这一点在数据手册里写得很清楚很多人都没注意到。如果项目里既要USB虚拟串口又要CAN总线选型时不能选这颗芯片。3.3 重映射在小封装上的“灰色地带”重映射AFIO remap是F103系列一个很实用的功能可以让同一个外设的引脚换到另一组位置。但C6T6因为是48脚小封装许多重映射目标引脚根本没有引出来。比如USART2重映射到PD5/PD6PD5和PD6在LQFP48封装里是不存在的。TIM3完全重映射到PC6/PC7/PC8/PC9PC6到PC9在这个封装里也没有。所以用CubeMX配置时你会看到某些重映射选项变灰或者不可选这很合理。重映射可用性要严格对照引脚封装来看不能拿着ZET6或VET6的映射表直接套。使用重映射时还有一个容易忽略的坑AFIO时钟必须手动使能。CubeMX生成代码时如果检测到重映射会自动处理但如果你在寄存器级别写代码遗漏了__HAL_RCC_AFIO_CLK_ENABLE()重映射就是不生效的GPIO电平明明没问题外设功能就是不出来。4. 从原理图到CubeMX一次完整的引脚配置实战4.1 先把最小系统板的接线看明白我在调试或接到一块新板子时第一步不是打开CubeMX而是拿原理图逐脚对照。假设现在有一块C6T6最小系统板外设规划如下LED接在PA5低电平点亮一个按键接PA0按下为低电平USART1通过CH340接到电脑PA9为TX、PA10为RX一个电位器输出接到PB0用ADC1_IN8采集电压SWD下载口接PA13/PA14另外预留串口ISP下载能力这个规划里PA5用于普通输出PA0可做普通输入同时也兼顾WKUP唤醒功能PA9/PA10用于串口PB0用于ADC采样。全部都是默认映射不涉及重映射是最稳的组合。拿到原理图后我习惯在纸上画一个引脚占用表把每个引脚旁边写上“用途”和“是否复用”。这一步看起来繁琐但能让后续的问题排查快很多。4.2 CubeMX配置过程与外设分配打开STM32CubeMX在芯片选择界面输入“STM32F103C6T6”选择LQFP48封装。进入Pinout视图后按图纸逐一点击引脚分配功能。首先把调试接口设为Serial Wire。这一步极其重要因为C6T6的PA13和PA14是SWD调试引脚如果不启用调试功能生成的代码可能会把这些引脚配置成普通IO下次连接ST-Link直接失败。接着分配PA5设为GPIO_Output在GPIO设置里把初始电平设为High因为LED低电平点亮初始化时让它灭PA0设为GPIO_Input内部上拉打开按键另一端接地平时读到高按下为低PA9和PA10设为USART1波特率1152008位数据1停止位无校验PB0设为ADC1_IN8配置为连续转换关闭软件触发时钟树配置里HSE选择Crystal/Ceramic ResonatorPLL源选HSEPLL倍频调成x9得到72MHz主频。此时Flash等待周期自动计算为2ADC时钟分频选6分频得到12MHz符合ADC最大14MHz的限制。如果是外部晶振没焊只有内部HSI那也可以走HSI倍频到64MHz这属于降级方案串口波特率精度略差。生成工程前记得在Project Manager里选择Toolchain为MDK-ARM或STM32CubeIDE并勾选“Generate peripheral initialization as a pair of .c/.h files per peripheral”这样每个外设单独一套文件好维护。4.3 生成代码后最值得看的几个初始化点CubeMX生成的代码里最值得逐行看的是 RCC 初始化和每个外设的 Init 结构体。时钟部分长这样RCC_OscInitTypeDef RCC_OscInitStruct {0}; RCC_OscInitStruct.OscillatorType RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSEPredivValue RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL RCC_PLL_MUL9; if (HAL_RCC_OscConfig(RCC_OscInitStruct) ! HAL_OK) { Error_Handler(); }GPIO初始化的重点在于确定输出类型、上下拉和速度GPIO_InitStruct.Pin GPIO_PIN_5; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, GPIO_InitStruct);PA5驱动LED推挽输出、无上下拉、低速就够。有些人不管什么引脚都选High速度反而可能引入不必要的EMI问题。按键输入PA0则要选上拉输入GPIO_InitStruct.Pin GPIO_PIN_0; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; HAL_GPIO_Init(GPIOA, GPIO_InitStruct);串口初始化则是典型的波特率、字长、停止位配置huart1.Instance USART1; huart1.Init.BaudRate 115200; huart1.Init.WordLength UART_WORDLENGTH_8B; huart1.Init.StopBits UART_STOPBITS_1; huart1.Init.Parity UART_PARITY_NONE; huart1.Init.Mode UART_MODE_TX_RX; huart1.Init.HwFlowCtl UART_HWCONTROL_NONE; huart1.Init.OverSampling UART_OVERSAMPLING_16; HAL_UART_Init(huart1);到这一步原理图上规划的引脚已经变成了代码里真实的寄存器配置。这也是我从“图纸”到“实战”之间最关键的一道转换。5. 点灯、回环、采样三个测试串起引脚配置5.1 推挽、开漏、上下拉到底是用来做什么的生成代码后先别急着写业务逻辑用三个小测试验证引脚功能比一口气写完整个项目再调试要省事得多。第一个测试是LED也就是GPIO输出。在main循环里翻转PA5HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); HAL_Delay(500);灯能闪起来说明引脚输出模式、时钟树、电源都正常。这时可以顺便测试一下输出模式的区别把PA5改成开漏输出不加外部上拉灯会明显变暗甚至不亮。推挽输出和开漏输出的区别在于推挽输出能主动输出高低电平开漏输出只能主动拉低高电平要靠外部上拉电阻提供。LED这种直接负载推挽就够I2C这类总线协议开漏才是正确姿势。按键输入测试也很直观。读取PA0的电平按下时读到0松开时读到1说明内部上拉生效。如果按下和松开完全没有变化多半是引脚配置成了推挽输出或者内部上拉没打开。5.2 串口引脚收发与“反接”的尴尬第二个测试是串口回环。先把PA9和PA10用一根杜邦线短接然后运行uint8_t buf[] hello c6t6\r\n; HAL_UART_Transmit(huart1, buf, sizeof(buf)-1, 1000); HAL_UART_Receive(huart1, buf, 5, 1000);把发送的内容再接收回来用调试器或者串口工具查看。如果串口工具收到乱码先检查波特率是否匹配再检查电脑端串口助手的数据位和停止位设置。如果完全没收到最常见的原因就是TX和RX接反了。还有个容易被忽略的地方USART1的PA9/PA10是FT引脚也就是5V容忍引脚可以直接和5V电平的USB转串口芯片通信。但FT只表示“输入可以容忍5V”不表示输出能拉到5V输出依然是3.3V。绝大多数USB转串口模块能识别3.3V高电平但个别老式模块不行这时候需要加电平转换。5.3 ADC引脚与参考电压VDDA不能悬空第三个测试是ADC采样。用HAL库的阻塞轮询模式读取PB0HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 100); uint16_t value HAL_ADC_GetValue(hadc1);电位器从3.3V分压到PB0转动时value应在0到4095之间变化。如果value一直是0或者4095不变化先量PB0引脚电压是否真的在变化。如果电压在变但ADC读数固定重点检查VDDA和VSSA是否接好以及ADC时钟是否超过了14MHz。ADC参考电压就是VDDA不是VDD。C6T6没有独立的外部VREF引脚ADC满量程电压直接等于VDDA。所以如果VDDA纹波大采样值就会跟着抖动。想采样稳定除了电源滤波之外还可以在代码里开ADC的平均滤波或过采样。我在做电池电压检测时一般连续采集16次去掉最大最小再取平均效果比直接采一次稳很多。6. 翻车现场这些引脚问题我曾一个个填过坑6.1 把SWD脚当普通IO后连不上调试器C6T6的PA13/PA14默认是SWD调试引脚PA15/PB3/PB4默认是JTAG调试引脚。芯片复位后这些引脚默认被调试外设占用不能当普通GPIO使用。如果强行在CubeMX里把它们配置成普通IO且没有使能Serial Wire调试模式程序烧进去后调试器就再也连不上了。这个问题我踩过救砖办法是把BOOT0拉高复位芯片让芯片进入系统存储器Bootloader模式用串口ISP把Flash擦掉再把BOOT0拉低复位。这个过程中不用仿真器只要芯片的USART1引脚接一个USB转串口配合ST官方的Flash Loader工具就能擦除。C6T6没有独立串口下载引脚用的就是PA9/PA10注意BOOT0要接高且PB2BOOT1保持低。更推荐的预防办法是CubeMX里第一件事就选SYS - Debug - Serial Wire。这个选项会让PA13/PA14保持调试功能不参与普通GPIO配置。那些引脚确实少用两个IO但保证调试器随时能连比省两个引脚划算太多。6.2 C8T6代码抄到C6T6USART3并不存在这是C6T6最典型的认知误区。C8T6有USART3默认引脚是PB10和PB11。很多现成教程和例程里USART3用的是这两个引脚直接搬到C6T6上代码能编译下载但串口永远等不到数据。因为C6T6这个型号的USART外设只到USART2USART3根本没有被实现在芯片里。CubeMX选型的时候外设列表里只有USART1和USART2你就该意识到代码得改。我自己的处理方式是需要用两个以上串口的项目尽量不要选C6T6老老实实选C8T6或者更大容量型号 。如果只是临时借用C6T6做主控而且只需要一个串口用USART1的PA9/PA10最省事能绕开很多外设冲突。这里还有个隐藏问题C6T6的SRAM只有10KB如果用了USB协议栈或者比较大的RTOS很容易超内存。编译时看map文件如果RAM占用超过8KB就要非常警惕了因为堆和栈还要占用空间。很多“程序跑着跑着死机”的问题就是RAM溢出。6.3 USB与CAN的共享缓冲区死角C6T6在硬件上同时集成了USB和CAN控制器这在低密度F103里算一个亮点。但USB和CAN共用512字节的包缓冲区这是芯片内部硬件设计决定的。实际使用中USB和CAN不能同时工作。数据手册里的原话翻译过来就是USB和CAN共享同一块专用的分组缓冲区USB功能正在使用时不建议同时使用CAN。这个“不能同时工作”不是软件上的冲突而是物理层面的共享限制。如果项目界面规划里同时出现USB虚拟串口和CAN总线明显不能指望用C6T6一颗芯片搞定。我见过一个项目工程师设计时用了CAN但发现USB枚举不成功折腾了很久最后才找到这条数据手册里的小字说明。遇到这类问题不要怀疑是自己的代码或电路问题先查数据手册的外设共享说明。6.4 PC14/PC15和PB2的“标签骗局”PC14和PC15在引脚表里的标签是OSC32_IN和OSC32_OUT但它们同时也是普通IO。问题是这两个引脚在作为GPIO使用时驱动能力和PA/PB口不一样比普通IO弱不少。特别是推挽输出高电平时带负载能力很有限想用它直接驱动LED或继电器亮度或驱动力都不够。更关键的是这两个引脚没有5V容忍能力。如果原理图里把PC14或PC15直接接到5V逻辑器件上轻则读不到正确电平重则损坏引脚。我的习惯是只要不是必须使用LSE低频晶振或RTCPC14和PC15不用来做关键功能最多接个状态输入。PB2BOOT1也有类似的坑。上电瞬间这个引脚的电平决定启动模式启动完成后才释放为普通IO。如果在PB2上挂了强上拉的EEPROM的WP引脚或其他外设上电时序一旦不符合预期芯片启动模式就可能不对。所以PB2上我通常不接需要强上拉或强驱动的器件如果一定要接至少确保它在上电期间保持低电平。6.5 5V容忍引脚的限制条件F103系列的引脚表里有些标注了“FT”表示5V容忍可以直接接5V逻辑电平的输入信号。比如PA0、PA1、PA2、PA3、PA4、PA5、PA6、PA7等很多常用GPIO都是FT脚。但注意这不是说所有引脚都可以随便接5V。PC14、PC15、PA11、PA12、PA13、PA14等一些引脚并不具备5V容忍能力接了5V就可能损伤芯片。判断某个引脚到底能不能接受5V输入唯一正确的依据是官方数据手册里引脚定义表的“Pin Name”和“Type”列那里会明确标注FT字样。不要依赖网上的“经验贴”背下来因为不同芯片不同封装之间也会有差异。FT引脚的另一个限制是它只能容忍输入5V不代表输出5V。它输出高电平时仍然是3.3V这一点在做电平匹配时要分清。如果接的是需要5V高电平驱动的器件还是要加电平转换电路或MOS管不能指望FT引脚直接输出5V。写在最后STM32F103C6T6是一颗麻雀虽小但五脏俱全的芯片48脚的小身板里塞进了USB、CAN、多个定时器和常用通信接口作为低成本控制核心完全没有问题。但恰恰因为引脚少、外设被裁剪它比C8T6更要求你在动手前就把引脚规划和外设映射想清楚。我习惯在画原理图之前先把所有要用的功能列成一张表逐个对应到C6T6的引脚上确认外设存在、引脚不冲突、电气特性满足要求再开始布线。这个习惯帮我避免过很多次画完板子才发现功能凑不齐的尴尬。如果你正在用这颗芯片建议先把数据手册的引脚定义表和CubeMX的外设列表摆在一起对照着做引脚分配。尤其是USART3缺失、USB与CAN共用缓冲区、SWD引脚复用这些点提前搞清楚能省下大多数无谓的排查时间。
返回列表