1. GD32C103开发板开箱初体验
第一次拿到GD32C103评估板时,我注意到这块蓝色的小板子比想象中更精致。板载的Type-C接口和CAN收发器接口特别显眼,这让我立刻意识到它在外设支持上的优势。作为兆易创新推出的Cortex-M4内核MCU,GD32C103主频高达108MHz,内置256KB Flash和32KB SRAM,性能完全能满足大多数嵌入式场景需求。
开发板背面丝印清晰地标注了关键引脚定义,比如PA9(BOOT0)、PA11(USB_FS_DM)等。建议新手拿到板子后先做三件事:用手机拍下正反面照片备用;准备好Type-C数据线;下载最新版用户手册。我刚开始时就因为没注意BOOT0引脚状态,导致第一次下载程序就遇到了麻烦——这个引脚必须通过跳线帽接地才能正常启动用户程序。
2. 开发环境搭建实战
2.1 Keil MDK安装避坑指南
在Windows10系统安装Keil MDK时,我强烈建议选择默认路径。曾经为了整洁把软件装在D盘,结果后续安装芯片支持包时各种路径错误。安装完成后需要特别注意:
- 以管理员身份运行Keil
- 在Pack Installer中搜索GD32C10x系列支持包
- 安装完成后检查Device列表是否出现GD32C103型号
注册环节有个小技巧:当License Management界面显示Computer ID后,记得把Target选项改为"ARM"而不是默认的"C51"。我就因为这个细节浪费了半天时间,总提示注册失败。
2.2 GCC环境配置技巧
对于习惯Linux开发的用户,可以选用GCC+OpenOCD方案。具体步骤:
sudo apt install gcc-arm-none-eabi git clone https://gitee.com/longan-labs/GD32C103_GCC.git cd GD32C103_GCC mv Core/FreeRTOS Core/freeRTOS # 注意大小写敏感 mkdir build && cd build cmake .. && make编译成功后会在out目录生成bin文件。这里有个易错点:如果遇到"undefined reference to `_sbrk'"错误,需要检查链接脚本中的堆栈设置。
3. 核心外设配置详解
3.1 CAN总线通信实战
GD32C103自带两个CAN控制器,我用PB8(CAN0_RX)和PB9(CAN0_TX)连接SIT1050T收发器时,发现通信异常。后来查手册才知道需要先开启引脚复用功能:
// 使能GPIO和CAN时钟 rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_CAN0); // 配置PB8/PB9为复用推挽输出 gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8); gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // CAN初始化结构体配置 can_parameter_struct can_init_para; can_struct_para_init(CAN_INIT_STRUCT, &can_init_para); can_init_para.time_triggered = DISABLE; can_init_para.auto_bus_off_recovery = ENABLE; can_init(CAN0, &can_init_para);实际测试时发现CAN FD模式下的数据长度并非1-64任意可选,而是有特定取值:1,2,3,4,5,6,7,8,12,16,20,24,32,48,64。这个细节在手册8.4.9节有特别说明。
3.2 USB虚拟串口开发
实现USB CDC设备需要特别注意描述符配置。字符串描述符采用UCS2编码,每个字符占2字节。例如"GD32"的编码应该是:
uint16_t string_desc[] = { 0x0047, 0x0044, 0x0033, 0x0032 // 'G','D','3','2' };时钟配置是关键,USB FS需要精确的48MHz时钟。我的配置方案是:
- 使用8MHz外部晶振
- 通过PLL倍频到108MHz系统时钟
- 选择PLLCLK作为USB时钟源
- 配置分频器得到48MHz
// 时钟树配置示例 rcu_osci_on(RCU_HXTAL); while(!rcu_osci_stab_wait(RCU_HXTAL)); rcu_ck_sys_config(RCU_CKSYSSRC_PLL); rcu_pll_config(RCU_PLLSRC_HXTAL, 108000000); rcu_osci_on(RCU_PLL_CK); while(!rcu_osci_stab_wait(RCU_PLL_CK)); rcu_usb_clock_config(RCU_USBSRC_PLL_DIV2_5);4. 典型问题排查手册
4.1 程序下载失败排查
遇到下载失败时建议按以下顺序检查:
- BOOT0引脚电平状态(用户模式需接地)
- 复位电路是否正常(实测NRST引脚应有3.3V)
- 下载器连接是否可靠(SWD接口建议用短导线)
- Keil工程配置中的Flash算法选择是否正确
有个隐蔽的坑点:GD32C103的Flash页大小是1KB,但Keil默认可能选择2KB。这会导致擦除操作失败,需要在Options for Target→Target页面手动修改。
4.2 CAN通信异常处理
当CAN总线出现通信故障时,我的排查三板斧:
- 用示波器检查CANH/CANL差分信号
- 确认终端电阻匹配(通常需要120Ω)
- 检查波特率配置(APB1时钟需为60MHz)
曾经遇到个典型案例:两个节点能发送不能接收。最终发现是过滤器配置问题,解决方案是在初始化后添加:
can_filter_parameter_struct filter; can_struct_para_init(CAN_FILTER_STRUCT, &filter); filter.filter_number = 0; filter.filter_mode = CAN_FILTERMODE_MASK; filter.filter_fifo = CAN_FIFO0; can_filter_init(CAN0, &filter);5. 项目实战:环境监测节点
结合前文知识,我们实现一个通过CAN总线传输数据、USB虚拟串口调试的环境监测节点。硬件连接方案:
| 传感器 | 接口类型 | MCU引脚 |
|---|---|---|
| SHT30温湿度 | I2C | PB6/PB7 |
| MQ-135空气质量 | ADC | PA0 |
| CAN收发器 | CAN | PB8/PB9 |
软件架构采用FreeRTOS创建三个任务:
- 传感器数据采集(优先级2)
- CAN总线通信(优先级3)
- USB调试输出(优先级1)
关键代码片段:
// CAN发送任务示例 void can_send_task(void *pvParameters) { can_trasnmit_message_struct tx_msg; tx_msg.tx_sfid = 0x123; // 标准帧ID tx_msg.tx_ft = CAN_FT_DATA; tx_msg.tx_dlen = 8; while(1) { if(xQueueReceive(can_queue, &tx_msg.tx_data, portMAX_DELAY)) { can_message_transmit(CAN0, &tx_msg); vTaskDelay(pdMS_TO_TICKS(100)); } } }调试时发现一个有趣现象:当USB大量输出调试信息时,CAN通信会出现丢帧。通过逻辑分析仪抓包发现是优先级配置不当导致,调整任务优先级后问题解决。这也提醒我们在RTOS系统中,通信任务的优先级通常应该高于数据采集任务。