尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

WCH CH32V103 RISC-V开发板选型、环境搭建与调试实战

WCH CH32V103 RISC-V开发板选型、环境搭建与调试实战 1. 项目概述初探WCH的RISC-V入门利器最近在捣鼓RISC-V架构的MCU发现沁恒微电子WCH的CH32V103系列是个不错的入门选择。这个系列主打性价比基于青稞RISC-V内核主频最高能跑到80MHz内置了64KB Flash和20KB SRAM外设资源也相当丰富像USB、ADC、定时器这些常用模块都配齐了。对于想从ARM Cortex-M阵营过来尝尝鲜或者单纯想低成本学习RISC-V嵌入式开发的工程师和学生来说CH32V103是个很友好的起点。而“EVT”指的是WCH官方提供的“评估测试板”Evaluation Test Board也就是我们常说的开发板。WCH为CH32V103提供了不止一款EVT板它们就像是官方为你准备好的“实验田”硬件设计已经验证过配套的软件包、例程、调试工具链也一应俱全。拿到手插上USB线基本上就能开始点灯、调串口了极大地降低了从零画板子的时间和风险。我这次弄来了几块不同的CH32V103 EVT板准备好好盘一盘看看它们各自有什么特点硬件设计上有哪些门道以及从开箱到跑起第一个程序的全流程里有哪些需要注意的坑和能提升效率的技巧。2. 核心硬件板卡解析与选型建议WCH为CH32V103提供的EVT板不止一种它们虽然核心芯片相同但在板载资源、接口布局和设计侧重点上各有不同。搞清楚这些差异你才能选到最适合自己当前项目或学习阶段的那一块。2.1 主流EVT板卡型号对比目前市面上比较常见的主要是以下两款我们可以通过一个表格快速抓住核心区别特性CH32V103 EVT (基础版)CH32V103C8T6 EVT (精简版)核心MCUCH32V103F8P6 (LQFP48封装)CH32V103C8T6 (LQFP48封装)核心资源64KB Flash, 20KB SRAM64KB Flash, 20KB SRAM板载调试器WCH-LinkE (内置)通常无需外接WCH-LinkUSB接口1个Type-C用于供电、调试、USB通信1个Micro-USB仅供电外设引出通过2.54mm排针将大部分IO引出通过2.54mm排针将大部分IO引出特色外设板载RGB LED、用户按键、复位按键板载用户LED、用户按键、复位按键电源管理支持USB 5V供电或外部3.3V/5V供电支持USB 5V供电或外部3.3V/5V供电适用场景学习、评估、快速原型开发低成本批量验证、核心功能测试基础版CH32V103 EVT是我最推荐新手入手的。它最大的优势是集成了WCH-LinkE调试器。这意味着你只需要一根USB-C线连接电脑和板子就同时解决了供电、程序下载和调试三大问题无需额外购买或连接任何调试工具开箱即用体验极佳。板载的RGB LED和按键也为学习GPIO控制、中断提供了便利。精简版CH32V103C8T6 EVT则更侧重于对芯片本身进行功能验证或者在你已经拥有独立WCH-Link调试工具的情况下使用。它的成本更低结构更简单适合在项目前期进行芯片选型测试或者用于需要大量连接自定义外设的场合因为板载元件少干扰也相对小一些。注意购买时一定要看清商品描述。有些商家会将“CH32V103 EVT板”特指为集成WCH-LinkE的版本而“CH32V103C8T6最小系统板”可能是不带调试器的精简版。对于初学者强烈建议选择集成调试器的版本能避免很多在调试器配置上遇到的麻烦。2.2 硬件设计亮点与细节剖析拿到板子先别急着上电花几分钟看看硬件设计能帮你后续避坑。首先是电源部分。这两款板子都支持宽电压输入USB的5V或者外部输入的3.3V/5V并通过一颗LDO低压差线性稳压器转换为芯片工作的3.3V。这里有个细节在基础版上因为集成了WCH-LinkE这个Link模块和主MCU通常是共用这个3.3V电源的。这意味着当你通过USB给板子供电时Link和MCU都上电了但如果你只想通过外部3.3V给MCU供电进行调试就需要仔细阅读原理图看看是否有跳线帽需要断开否则可能会造成电源冲突。我遇到过因为没注意这个外部电源一接上USB端口就冒烟的情况幸亏电流小没烧坏。实操心得使用外部供电调试前务必用万用表确认一下电源路径或者干脆在不确定时只用一种电源供电。其次是IO引出的设计。板子将MCU的IO口通过两组标准的2.54mm间距排针引出这很方便连接杜邦线。但要注意有些IO是复用的比如用于USB的DP/DM用于串口的TX/RX。在基础版上这些用于板载调试器通信的引脚通常是PA13/SWDIO, PA14/SWCLK可能也被引出了。关键点当你想要使用这些已被板载功能占用的引脚去做其他事情时比如把SWDIO脚当成普通GPIO用程序可能会下载不进去或者调试器连不上。所以规划引脚功能时第一件事就是查原理图避开这些“特殊引脚”。最后是调试接口。基础版集成的WCH-LinkE实际上是一个复合设备它既是一个基于RISC-V的调试探头也虚拟了一个串口用于打印调试信息。在设备管理器中你会看到两个设备一个“USB串行设备”COM口和一个“WCH-Link RV Debug”设备。这个设计非常贴心省去了你额外连接USB转TTL模块的麻烦。3. 软件开发环境搭建与配置详解硬件准备好了接下来就是搭建软件环境。WCH为RISC-V内核的MCU提供了相对完整的工具链支持但和ARM的Keil、IAR那种高度集成的环境略有不同需要一些手动配置。3.1 工具链获取与安装开发CH32V103主要需要以下三样东西集成开发环境IDE推荐使用MounRiver Studio (MRS)。这是WCH基于Eclipse深度定制的一款IDE专门适配其RISC-V MCU。它内部集成了编译工具链、调试器和项目管理功能对新手最友好。你也可以选择VS Code PlatformIO但MRS在芯片支持、调试配置上更“傻瓜化”。编译工具链也就是RISC-V GCC。幸运的是MRS在安装时已经自动集成了合适的版本如riscv-none-embed-gcc一般无需单独处理。设备支持包与样例代码这就是“EVT”包的核心软件部分。你需要从WCH官网下载“CH32V103 EVT”软件包。这个包里包含了芯片的启动文件、底层驱动库类似于标准外设库、链接脚本以及海量的外设使用例程。安装步骤实录第一步安装MounRiver Studio。从官网下载安装包一路“下一步”即可。建议安装路径不要有中文和空格。第二步获取EVT软件包。访问WCH官网找到CH32V103产品页面在“资料下载”或“工具与软件”栏目下找到“CH32V103 EVT”并下载。解压后你会看到一个结构清晰的目录通常包含EVT文件夹内含EXAM例程和PUB公用文件和CH32V103DS0数据手册等文档。第三步在MRS中关联EVT包。打开MRSWindow-Preferences-MounRiver-SDK Manager。在这里你可以“Import”刚才解压的EVT包路径。关联成功后新建项目时就可以直接选择基于这个EVT包模板了。避坑技巧官网的EVT包和MRS的版本可能存在兼容性问题。如果遇到编译错误比如头文件找不到、链接错误可以尝试将EVT包EVT/EXAM下的具体例程如GPIO文件夹直接拷贝到你的工作空间然后用MRS的“导入现有项目”功能打开这比从零新建项目更稳妥。3.2 第一个工程从点灯到调试我们以最经典的“点灯”为例走通整个流程。3.2.1 创建或导入工程在MRS中File-New-MounRiver Project。输入项目名在“Board”或“MCU”中选择CH32V103系列在“Template”中可以选择一个空的模板或者直接选择GPIO相关的例程模板如果EVT包已正确关联。更简单的方法是直接打开EVT包中的EXAM/GPIO/GPIO_Toggle例程文件夹将其作为你的项目起点。3.2.2 代码浅析与修改打开主文件main.c你会看到基于WCH自有外设库的代码。以翻转LED为例关键步骤通常包括#include debug.h // 调试相关包含printf重定向 #include ch32v10x.h // 芯片头文件包含所有外设寄存器定义 #include ch32v10x_gpio.h #include ch32v10x_rcc.h int main(void) { // 1. 初始化系统时钟非常重要默认可能是内部HSI例程里通常会配置为外部HSE SystemInit(); // 这个函数在EVT包的system_ch32v10x.c中定义需根据板载晶振频率修改 // 2. 使能GPIO端口时钟RISC-V和ARM一样外设时钟默认是关闭的需要手动开启 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 3. 配置GPIO引脚为推挽输出模式 GPIO_InitTypeDef GPIO_InitStructure {0}; GPIO_InitStructure.GPIO_Pin GPIO_Pin_13; // 假设LED连接在PC13 GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; // 输出速度 GPIO_Init(GPIOC, GPIO_InitStructure); while(1) { GPIO_WriteBit(GPIOC, GPIO_Pin_13, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13))); // 翻转PC13 Delay_Ms(500); // 使用EVT包提供的简单延时函数 } }关键点解析SystemInit()这个函数配置系统时钟源和频率。务必检查EVT/PUB文件夹下的system_ch32v10x.c文件确保#define HSE_VALUE的值与你板载晶振的频率一致通常是8MHz。如果这里错了串口波特率、延时函数都会不准。时钟使能RCC_APB2PeriphClockCmd是开启GPIO端口时钟的函数。CH32V103的GPIOA、B、C、D挂在APB2总线上。延时函数例程中的Delay_Ms是基于SysTick定时器实现的。对于简单的演示没问题但在实际项目中如果使用了操作系统或更复杂的定时需求建议使用硬件定时器。3.2.3 编译与下载配置点击MRS工具栏上的“锤子”图标进行编译。编译无误后准备下载。对于集成WCH-LinkE的基础版用USB-C线连接板子和电脑。在MRS中Run-Debug Configurations。在左侧选择你的项目在“Main”选项卡确认工程无误在“Debugger”选项卡确保“Debugger”选择的是WCH-Link并且“Interface”是RV表示RISC-V。端口通常会自动识别。点击“Debug”即可开始下载并进入调试模式。对于使用外接WCH-Link的精简版需要连接WCH-Link的SWD接口SWDIO、SWCLK、GND到板子对应的调试口同时连接WCH-Link的USB到电脑。在MRS的“Debugger”配置中同样选择WCH-Link。3.2.4 调试与串口打印下载成功后程序会自动运行。你可以点击“暂停”按钮暂停程序查看变量、单步执行等。一个非常重要的技巧利用板载WCH-LinkE虚拟的串口进行printf打印。在EVT包的debug.c文件中已经实现了fputc函数重定向到串口1USART1。你只需要在主函数初始化后调用USART1_Init(115200)确保波特率匹配然后在代码中直接使用printf(“Hello CH32V103!\r\n”)即可。在电脑上使用串口助手如MRS自带的、Putty、SecureCRT等选择对应的COM口设备管理器里看到的那个USB串行设备设置相同的波特率就能看到打印信息。这是最有效的调试手段之一。4. 外设驱动深度使用与优化掌握了基本流程后就可以深入探索芯片的外设了。EVT包里提供了几乎所有外设的例程但直接照搬可能不够需要理解其底层机制。4.1 GPIO与中断从基础到高效GPIO看似简单但用好能提升整个系统的响应效率和可靠性。4.1.1 上下拉配置与省电CH32V103的GPIO支持软件配置上拉或下拉电阻。在初始化时除了模式GPIO_Mode_IPU上拉输入、GPIO_Mode_IPD下拉输入这个配置对于按键检测等应用至关重要可以避免引脚悬空时的电平漂移。对于未使用的GPIO引脚最佳实践是将其设置为模拟输入模式如果支持或者设置为输出低电平。这可以降低功耗并提高抗干扰能力。4.1.2 外部中断EXTI的灵活配置CH32V103的每个GPIO都可以配置为外部中断源但中断线是有限的比如EXTI0~EXTI15同一时刻同一中断线只能由一个GPIO端口映射。例如PA0、PB0、PC0都可以映射到EXTI0线上但需要通过GPIO_EXTILineConfig函数来选择具体是哪个端口。// 配置PA0为下降沿触发的外部中断 GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; // 上拉输入常态高电平按下接地产生下降沿 GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); // 将PA0映射到EXTI0线 EXTI_InitTypeDef EXTI_InitStructure {0}; EXTI_InitStructure.EXTI_Line EXTI_Line0; EXTI_InitStructure.EXTI_Mode EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger EXTI_Trigger_Falling; // 下降沿触发 EXTI_InitStructure.EXTI_LineCmd ENABLE; EXTI_Init(EXTI_InitStructure); // 别忘了在NVIC嵌套向量中断控制器中使能EXTI0中断 NVIC_Init(...); // 配置优先级并使能实操心得中断服务函数ISR要尽可能短小只做标志位设置、数据读取等最必要的操作耗时的处理放到主循环中基于标志位进行。避免在ISR中调用printf等可能阻塞或耗时的函数。4.2 定时器精准定时与PWM输出CH32V103拥有多个通用定时器TIM1~TIM4和高级定时器TIM1。定时器是嵌入式系统的“心跳”。4.2.1 微秒级精准延时系统提供的Delay_Ms函数精度不高且会阻塞。对于需要微秒级延时的场景如驱动WS2812B灯珠可以使用定时器实现。以TIM2为例void TIM2_Delay_us_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure {0}; TIM_TimeBaseInitStructure.TIM_Period 72 - 1; // 计数器重装载值 TIM_TimeBaseInitStructure.TIM_Prescaler 1 - 1; // 预分频器72MHz / 1 72MHz TIM_TimeBaseInitStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, TIM_TimeBaseInitStructure); // 计算定时器时钟 72MHz / (1) 72MHz 计数一次时间 1/72MHz ≈ 13.89ns // 要实现1us延时需要计数次数 1us / 13.89ns ≈ 72次 // 所以将Period设为72-1计数器从0计数到71溢出正好1us。 } void delay_us(uint16_t us) { TIM_SetCounter(TIM2, 0); // 计数器清零 TIM_Cmd(TIM2, ENABLE); // 启动定时器 while(TIM_GetCounter(TIM2) us); // 等待计数达到目标值 TIM_Cmd(TIM2, DISABLE); // 关闭定时器 }注意这个delay_us函数在延时期间仍然占用CPU属于忙等待。对于需要长时间、高精度且不阻塞其他任务的定时应该使用定时器中断或更高级的调度器。4.2.2 PWM输出控制舵机/电机利用定时器的PWM模式可以轻松输出占空比可调的方波。以TIM1的通道1PA8输出PWM为例void TIM1_PWM_Init(void) { // 1. 初始化GPIO PA8为复用推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // 2. 初始化定时器时基单元 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure {0}; TIM_TimeBaseInitStructure.TIM_Period 1000 - 1; // 自动重装载值ARR决定PWM频率 TIM_TimeBaseInitStructure.TIM_Prescaler 72 - 1; // 预分频器PSC // PWM频率 72MHz / ((72) * (1000)) 1kHz TIM_TimeBaseInitStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, TIM_TimeBaseInitStructure); // 3. 初始化PWM输出通道 TIM_OCInitTypeDef TIM_OCInitStructure {0}; TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; // PWM模式1 TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; // 输出使能 TIM_OCInitStructure.TIM_Pulse 500; // 比较值CCR决定占空比。此处为500/100050% TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; // 输出极性高电平有效 TIM_OC1Init(TIM1, TIM_OCInitStructure); // 初始化通道1 // 4. 使能TIM1的主输出高级定时器需要 TIM_CtrlPWMOutputs(TIM1, ENABLE); // 5. 启动定时器 TIM_Cmd(TIM1, ENABLE); }之后你只需要通过TIM_SetCompare1(TIM1, pulseValue)函数修改pulseValue即CCR1寄存器的值就能动态改变占空比从而控制舵机角度或电机速度。5. 调试技巧与常见问题排查实录在实际开发中遇到问题才是常态。下面是我在折腾CH32V103 EVT板过程中遇到的一些典型问题及解决方法。5.1 下载与调试连接失败这是新手遇到最多的问题。现象MRS提示“No device found”、“Cannot enter debug mode”或一直显示“Connecting...”。排查步骤检查硬件连接USB线是否插好如果是外接WCH-LinkSWDSWDIO、SWCLK、GND三根线是否连接正确且牢固特别注意WCH-Link的3.3V输出引脚不要接到目标板的VCC除非目标板完全无电。否则可能因电源冲突损坏。只接三根线SWDIO, SWCLK, GND即可目标板由自身电源供电。检查驱动打开设备管理器查看插入WCH-Link后是否出现“WCH-Link RV Debug”设备和一个USB串行设备COM口。如果出现黄色叹号需要手动安装驱动。驱动通常在MRS安装目录下的\MounRiver\Toolchain\wch-linkdriver文件夹里或者从WCH官网下载。检查MRS配置在Debug Configuration里确认“Debugger”选择了WCH-Link“Interface”选择了RV。如果是老版本的WCH-Link非LinkE可能需要选择SWD接口。检查芯片供电与复位用万用表测量板子3.3V电压是否正常。尝试按下板子的复位键然后在复位释放的瞬间点击MRS的下载按钮。有时芯片处于低功耗模式或异常状态需要硬件复位唤醒。检查BOOT模式CH32V103的BOOT0引脚默认通过下拉电阻接地必须为低电平才能从用户Flash启动和调试。如果被意外拉高芯片会进入系统存储器启动模式导致调试器无法连接。检查BOOT0引脚电路。5.2 程序运行异常如死机、跑飞现象程序下载后不运行或运行一段时间后死机。排查思路时钟配置这是头号嫌疑犯。再次确认system_ch32v10x.c中的HSE_VALUE定义是否与板上晶振通常8MHz一致。如果不一致所有基于时钟的定时延时、串口波特率、PWM频率都会出错。堆栈溢出RISC-V架构也需要关注堆栈Stack大小。在启动文件.s文件或链接脚本.ld文件中定义了堆栈大小。如果函数局部变量过大或递归调用过深可能导致栈溢出覆盖其他数据造成不可预知的错误。可以在MRS的工程属性中调整堆栈大小。中断冲突或未清除标志如果使能了中断但在中断服务函数中没有清除相应的中断标志位会导致中断持续触发CPU不断跳入中断看起来就像死机。确保在ISR中读取了状态寄存器或清除了挂起标志。内存访问越界数组越界、指针错误等操作可能篡改了关键数据或代码。使用调试器设置数据断点或者逐步缩小问题代码范围来定位。5.3 串口打印乱码或无输出现象使用了printf但串口助手收到的全是乱码或者什么都没有。解决方法检查波特率确保代码中USART_Init函数设置的波特率如115200与串口助手设置的波特率完全一致。哪怕有微小误差长时间接收也会错乱。检查时钟串口波特率的时钟源来自APB总线。如果系统时钟配置错误APB时钟就不对算出来的波特率自然不准。回归到第一步检查系统时钟配置。检查硬件连接如果使用外接USB转TTL模块确保RX/TX交叉连接模块的TX接板子的RX模块的RX接板子的TX且共地。检查debug.c重定向确认工程中包含了debug.c文件并且其中的USART1初始化参数波特率、停止位等与你调用的一致。有些例程重定向到了USART2你需要根据实际使用的串口修改fputc函数里的发送寄存器。5.4 功耗高于预期现象电池供电项目中发现芯片功耗比数据手册标注的待机功耗大很多。优化方向未用引脚处理将所有未使用的GPIO设置为模拟输入模式这是功耗最低的状态。外设时钟管理在初始化外设后如果长时间不用可以通过RCC_APBxPeriphClockCmd(DISABLE)关闭其时钟。在进入低功耗模式前务必关闭所有不需要的外设时钟。使用低功耗模式CH32V103支持睡眠、停机和待机模式。通过PWR_EnterSleepMode()、PWR_EnterSTOPMode()等函数进入。关键点进入低功耗模式后需要通过特定的唤醒事件如外部中断、RTC闹钟等来唤醒。在进入前要配置好唤醒源。降低系统频率在不需要高性能时通过修改时钟树配置降低系统主频SYSCLK可以显著降低动态功耗。折腾这几块EVT板下来感觉WCH在RISC-V生态的易用性上确实下了功夫。硬件上集成调试器的设计对初学者太友好了软件上MRS和丰富的EVT包基本做到了开箱即用。虽然比起STM32那种庞大的社区和资源还有差距但作为入门RISC-V和进行中小项目开发CH32V103系列凭借其不错的性能和极低的价格是一个非常务实的选择。最大的体会就是玩转一块板子三分在写代码七分在读懂原理图、数据手册和会排查问题。遇到问题别慌按电源、时钟、复位、配置、代码的逻辑一步步捋大部分都能解决。
返回列表