1. 项目概述:Pico-CAN-A是什么?
如果你玩过树莓派Pico,或者对微控制器上的CAN总线通信感兴趣,那么“Pico-CAN-A”这个项目标题很可能已经让你眼前一亮了。简单来说,这是一个基于树莓派Pico微控制器,旨在实现一个稳定、易用的CAN总线通信接口模块或开发板的项目。CAN,全称Controller Area Network,中文常叫控制器局域网,是汽车电子、工业自动化等领域里最核心的通信总线之一,以其高可靠性和实时性著称。而UART,作为最古老也最经典的串行通信接口,则是嵌入式开发中调试、配置、数据交换的“万金油”。
那么,Pico-CAN-A的核心价值在哪里?它试图解决一个非常实际的痛点:如何让开发者,尤其是学生、创客和嵌入式爱好者,能够以极低的门槛和成本,快速上手并深入实践CAN总线通信。树莓派Pico本身是一款性价比极高的双核ARM Cortex-M0+微控制器,但它原生并不支持CAN。Pico-CAN-A项目,很可能就是通过外接一个CAN收发器芯片(比如常见的MCP2551或TJA1050),并编写或集成相应的软件驱动库,将Pico的某个通信接口(如SPI或特定的GPIO)转换成一个功能完整的CAN节点。
这个项目适合谁?首先当然是嵌入式开发者,特别是那些需要与汽车ECU、工业控制器、机器人关节驱动器等设备打交道的工程师。其次,是电子工程、自动化等相关专业的学生,它提供了一个绝佳的、从理论到实践的CAN协议学习平台。最后,广大的硬件创客和DIY爱好者,也可以利用它来为自己的智能小车、数据采集系统或自定义控制网络添加可靠的通信能力。接下来,我将为你深度拆解这个项目背后的技术逻辑、实现细节以及那些只有真正动手做过才会知道的“坑”。
2. 核心方案设计与硬件选型解析
当我们决定用树莓派Pico来搞CAN通信时,摆在面前的第一个问题就是:硬件上怎么实现?Pico的RP2040芯片本身没有CAN控制器,所以我们必须借助外部芯片。这里主要有两条技术路线,选择哪一种,直接决定了项目的复杂度、成本和性能天花板。
2.1 核心方案对比:独立CAN控制器 vs. 软件模拟
方案一:使用独立的CAN控制器芯片(如MCP2515)这是最主流、最稳妥的方案。MCP2515是一颗独立的CAN控制器,它通过SPI接口与主控MCU(这里是Pico)通信。它内部集成了完整的CAN协议引擎,包括报文缓冲、过滤、错误处理等所有繁重工作。Pico只需要通过SPI发送简单的命令和读写数据,就能完成复杂的CAN报文收发。
- 优点:稳定、可靠、性能有保障。完全符合CAN规范,波特率设置精确,错误处理由硬件完成,不占用Pico过多的CPU资源。有大量成熟的Arduino、STM32等平台的驱动库可供参考或移植。
- 缺点:增加了额外的芯片和电路,BOM成本和PCB面积略有上升。需要编写或移植SPI驱动代码。
方案二:使用带SPI接口的CAN收发器(如MCP2551)并软件模拟(Bit-Banging)这是一条更“硬核”的路线。我们只使用一个基础的CAN收发器(如MCP2551),它只负责物理电平的转换。而CAN协议中复杂的位时序、仲裁、CRC校验等,全部由Pico的GPIO口通过软件精确控制来实现,也就是所谓的“Bit-Banging”。
- 优点:硬件电路最简单,成本最低。理论上只需要一颗CAN收发器和几个电阻电容。
- 缺点:实现极其复杂,对代码时序要求极为苛刻。CAN通信的位定时必须非常精确,软件模拟会消耗大量CPU资源,并且在高波特率(如1Mbps)下几乎无法稳定工作,可靠性差。这通常只用于理论验证或极低要求的场景。
注意:对于Pico-CAN-A这样一个旨在“实用”的项目,方案一(MCP2515)是毫无争议的选择。软件模拟CAN在工程实践中几乎不被采用,除非是芯片厂商提供的经过严格验证的软件IP。因此,我们后续的所有讨论都将基于“Pico + MCP2515 + CAN收发器”这个黄金组合。
2.2 关键硬件组件选型与电路设计要点
确定了核心芯片,我们来看看具体怎么把它们连接起来,以及选型时要注意什么。
CAN控制器:MCP2515
- 为什么是它?市场保有量大,资料极多,价格便宜,性能足以满足大部分应用(最高1Mbps)。它的SPI接口与Pico兼容性好。
- 关键引脚连接:
CS(片选): 接Pico任意GPIO。SO(MISO),SI(MOSI),SCK(SPI时钟): 分别接Pico的SPI接口。Pico有两组SPI (spi0,spi1),任选一组即可。INT(中断):强烈建议接到Pico的GPIO并配置为中断输入。这样当MCP2515收到报文或发生错误时,可以立即通知Pico处理,而不是让Pico不停地去查询,这是保证实时性和降低CPU负载的关键。
- 晶振:MCP2515需要一颗外部晶振(通常为8MHz或16MHz)来驱动其内部时钟。这颗晶振的精度直接影响CAN波特率的准确性,务必选择质量合格的。
CAN收发器:MCP2551 或 TJA1050
- 作用:将MCP2515输出的逻辑电平(CANH, CANL)转换为符合ISO 11898标准的差分信号,并驱动CAN总线。
- MCP2551 vs TJA1050:
- MCP2551:经典、常用,性价比高。需要注意其共模电压范围,在复杂的汽车电子环境中可能略显不足。
- TJA1050:性能更优,具有更好的EMC特性和总线保护能力,支持“静默模式”(监听模式,不干扰总线),是工业级和汽车级应用的更佳选择。对于新设计,我倾向于推荐TJA1050。
- 电路设计关键:
- 终端电阻:CAN总线两端必须各接一个120欧姆的电阻,用于阻抗匹配,消除信号反射。在Pico-CAN-A这样的单个节点上,通常板载一个120欧姆电阻,并通过跳线帽或开关选择是否接入总线。
- 电源隔离与保护:如果应用环境恶劣(如汽车、工厂),需要考虑对Pico、MCP2515和TJA1050进行电源隔离,并在CANH/CANL线上加入TVS管、共模电感等保护器件,防止浪涌和静电损坏。对于学习和一般室内应用,可以简化。
树莓派Pico
- 供电:可以通过USB供电,也可以通过VSYS引脚接入外部5V电源。注意MCP2515和TJA1050的工作电压通常是5V或3.3V,需要确认电平兼容性。Pico的GPIO是3.3V电平,MCP2515通常兼容3.3V,但最好查阅其数据手册。TJA1050的VCC一般是5V。
- 连接器:建议将CANH、CANL引出到一个标准的端子排(如螺丝端子或PH2.0-4P),方便连接总线。
一个典型的Pico-CAN-A模块框图如下:
[USB/外部电源] -> [树莓派Pico (RP2040)] | SPI | [MCP2515 CAN控制器] | CAN_TX, CAN_RX | [TJA1050 CAN收发器] | [CANH, CANL] -> [外部CAN总线]这个硬件框架清晰、可靠,是项目成功的基石。
3. 软件驱动与协议栈实现详解
硬件搭好了,接下来就是让它们“活”起来的软件部分。这部分是项目的灵魂,也是最能体现开发者功力的地方。
3.1 底层SPI驱动与MCP2515寄存器操作
首先,我们需要让Pico能够通过SPI与MCP2515对话。Pico的SDK提供了非常完善的SPI库,使用起来很方便。
// 示例:初始化Pico的SPI0接口 #include “hardware/spi.h” #define SPI_PORT spi0 #define PIN_MISO 16 #define PIN_CS 17 #define PIN_SCK 18 #define PIN_MOSI 19 void spi_init() { spi_init(SPI_PORT, 10 * 1000 * 1000); // 初始化SPI,时钟10MHz gpio_set_function(PIN_MISO, GPIO_FUNC_SPI); gpio_set_function(PIN_SCK, GPIO_FUNC_SPI); gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI); gpio_init(PIN_CS); gpio_set_dir(PIN_CS, GPIO_OUT); gpio_put(PIN_CS, 1); // 初始片选为高(不选中) }与MCP2515通信,本质上是读写其内部的一系列控制寄存器。我们需要封装几个核心函数:
mcp2515_write_register(uint8_t addr, uint8_t value): 向指定地址的寄存器写入一个值。操作时序是:拉低CS -> SPI发送写指令(0x02) -> 发送地址 -> 发送数据 -> 拉高CS。mcp2515_read_register(uint8_t addr): 从指定地址的寄存器读取一个值。操作时序:拉低CS -> 发送读指令(0x03) -> 发送地址 -> 接收数据 -> 拉高CS。mcp2515_bit_modify(uint8_t addr, uint8_t mask, uint8_t data): 这是MCP2515一个非常实用的指令,可以只修改寄存器中的特定位,而不影响其他位。这对于配置复杂的控制寄存器非常方便。
有了这些底层函数,我们就可以开始配置MCP2515了。
3.2 CAN控制器初始化与波特率配置
这是最关键也是最容易出错的一步。CAN总线所有节点必须使用相同的波特率才能通信。
bool mcp2515_init(uint32_t baudrate_kbps) { // 1. 进入配置模式 mcp2515_write_register(CANCTRL, 0x80); // 检查是否进入配置模式 if((mcp2515_read_register(CANSTAT) & 0xE0) != 0x80) { return false; // 进入配置模式失败 } // 2. 配置波特率 (以500kbps为例,使用8MHz晶振) // CNF1, CNF2, CNF3寄存器的设置需要根据晶振频率和所需波特率计算 // 计算公式参考MCP2515数据手册。这里给出一个8MHz晶振下500kbps的常用配置: mcp2515_write_register(CNF1, 0x00); // SJW=1, BRP=0 (预分频因子为1) mcp2515_write_register(CNF2, 0x90); // BTLMODE=1, SAM=0, PHSEG1=2, PRSEG=1 mcp2515_write_register(CNF3, 0x02); // PHSEG2=2 // 3. 配置接收过滤器与掩码(初始可以先全部接受,后续根据需求细化) // 例如,设置接收缓冲器0的掩码为0,过滤器为0,表示接收所有报文 mcp2515_write_register(RXM0SIDH, 0x00); mcp2515_write_register(RXM0SIDL, 0x00); mcp2515_write_register(RXF0SIDH, 0x00); mcp2515_write_register(RXF0SIDL, 0x00); // 4. 退出配置模式,进入正常模式(或监听模式) mcp2515_write_register(CANCTRL, 0x00); // 正常模式 // mcp2515_write_register(CANCTRL, 0x60); // 监听模式(只收不发,用于调试) // 5. 等待进入正常模式 sleep_ms(10); if((mcp2515_read_register(CANSTAT) & 0xE0) != 0x00) { return false; // 进入正常模式失败 } return true; }实操心得:波特率计算的坑波特率配置不对是导致“通信不上”的最常见原因。务必仔细阅读MCP2515数据手册中关于位定时(Bit Timing)的章节。你需要知道三个参数:同步跳转宽度(SJW)、时间段1(Tseg1)和时间段2(Tseg2)。它们与系统时钟、波特率的关系有固定公式。网上有很多在线的MCP2515波特率计算器,但最好自己理解原理。一个快速验证的方法是:将模块设置为“监听模式”(Loopback Mode),自发自收。如果这个模式下能成功,说明软件配置和SPI通信是好的,问题可能出在硬件连接或总线终端电阻上。
3.3 CAN报文收发功能封装
我们需要定义CAN报文的数据结构,并封装发送和接收函数。
typedef struct { uint32_t id; // CAN报文ID (11位或29位) bool ext; // 是否为扩展帧 (29位ID) bool rtr; // 是否为远程帧 uint8_t dlc; // 数据长度码 (0-8) uint8_t data[8]; // 数据域 } can_message_t; bool can_send(const can_message_t *msg) { // 1. 检查发送缓冲器状态 uint8_t status = mcp2515_read_status(); uint8_t txbn; // 选择空闲的发送缓冲器 (TXB0, TXB1, TXB2) if ((status & 0x04) == 0) txbn = 0; // TXB0空闲 else if ((status & 0x10) == 0) txbn = 1; // TXB1空闲 else if ((status & 0x40) == 0) txbn = 2; // TXB2空闲 else { return false; // 所有发送缓冲器都忙 } // 2. 装载报文ID和数据到选定的发送缓冲器 uint8_t addr = txbn * 0x10; // 发送缓冲器基地址偏移 // ... 根据标准帧/扩展帧,组装ID并写入SIDH, SIDL, EID8, EID0等寄存器 // ... 写入DLC寄存器 // ... 将data[0]-data[dlc-1]写入TXBxDm寄存器 // 3. 请求发送 mcp2515_rts(txbn); // 发送RTS指令 return true; } bool can_receive(can_message_t *msg) { // 1. 检查接收缓冲器状态(这里以RXB0为例) uint8_t status = mcp2515_read_status(); if ((status & 0x01) == 0) { // RXB0没有新报文 return false; } // 2. 从RXB0读取报文 // ... 从RXB0SIDH等寄存器读取并解析ID、扩展帧标志等 // ... 读取DLC // ... 从RXB0Dm寄存器读取数据 // 3. 清除接收中断标志(通过修改CANINTF寄存器) mcp2515_bit_modify(CANINTF, 0x01, 0x00); return true; }中断处理优化上面can_receive是查询方式,在实际应用中,我们应该使用中断。在初始化时,使能MCP2515的接收中断,并将它的INT引脚连接到Pico的一个支持中断的GPIO上。在Pico的中断服务程序(ISR)中,快速读取报文,然后放入一个环形队列(Ring Buffer)中。主循环从队列里取出报文处理。这样能极大地提高系统的实时响应能力,避免报文丢失。
// 伪代码示例 Queue can_rx_queue; // 环形队列 void gpio_irq_handler() { can_message_t msg; if(can_receive(&msg)) { // 这个函数内部已清除中断标志 queue_try_add(&can_rx_queue, &msg); // 非阻塞入队 } } int main() { // ... 初始化 gpio_set_irq_enabled_with_callback(PIN_INT, GPIO_IRQ_EDGE_FALL, true, &gpio_irq_handler); while(1) { if(queue_try_remove(&can_rx_queue, &msg)) { // 处理接收到的CAN报文 process_can_message(&msg); } // ... 其他任务 } }4. 应用层协议与实战案例
硬件通了,底层驱动也写好了,接下来就是如何用好它。CAN总线本身只定义了物理层和数据链路层,具体传输什么数据,需要我们自己定义应用层协议。
4.1 常见应用层协议简介
- CANopen:在工业自动化(特别是电机驱动、I/O模块)中应用极广。它定义了对象字典、网络管理、服务数据对象(SDO)、过程数据对象(PDO)等一套完整的机制。功能强大,但也相对复杂。
- J1939:重型车辆(卡车、工程机械)的标准协议。定义了参数组编号(PGN)、可疑参数编号(SPN)等,报文格式固定。
- 自定义简单协议:对于很多DIY和小型项目,定义一个自己简单明了的协议就足够了。
4.2 设计一个简单的自定义数据帧协议
假设我们要用Pico-CAN-A做一个智能电池监控模块,需要上报电压、电流、温度。
我们可以定义如下报文格式:
- CAN ID: 0x100 (模块的源地址)
- 数据域 8字节:
data[0]: 命令字,0x01表示上报数据。data[1], data[2]: 电压值(单位0.01V),大端格式。例如0x0B, 0xB8表示 3000 -> 30.00V。data[3], data[4]: 电流值(单位0.1A),有符号整型。例如0xFF, 0x9C表示 -100 -> -10.0A(放电)。data[5]: 温度(单位摄氏度)。例如0x25表示 37°C。data[6], data[7]: 保留或CRC校验。
发送端(Pico-CAN-A)代码:
can_message_t bat_msg; bat_msg.id = 0x100; bat_msg.ext = false; bat_msg.rtr = false; bat_msg.dlc = 8; bat_msg.data[0] = 0x01; // 命令字 bat_msg.data[1] = (voltage_raw >> 8) & 0xFF; // 电压高字节 bat_msg.data[2] = voltage_raw & 0xFF; // 电压低字节 // ... 填充其他数据 can_send(&bat_msg);接收端(可以是另一个Pico-CAN-A,或USB-CAN分析仪)解析代码:
void process_battery_msg(can_message_t *msg) { if(msg->id == 0x100 && msg->dlc >= 3 && msg->data[0] == 0x01) { uint16_t volt = (msg->data[1] << 8) | msg->data[2]; int16_t current = (msg->data[3] << 8) | msg->data[4]; int8_t temp = msg->data[5]; printf(“电压: %.2f V, 电流: %.1f A, 温度: %d C\n”, volt / 100.0, current / 10.0, temp); } }4.3 与上位机联调:USB-CAN工具链
开发调试离不开上位机。你需要一个工具来监控总线上的报文,并能够主动发送报文进行测试。
- 硬件:你可以用另一个Pico-CAN-A模块,或者购买一个成熟的USB-CAN适配器(如PCAN-USB, ZLG的USBCAN系列,或者更便宜的MCP2515 USB模块)。
- 软件:
- CANable / cantact项目配套的
cangaroo或candleLight软件,开源免费。 - ZLG USBCAN配套的ZCAN系列软件,功能强大。
- PCAN-View: PEAK公司官方软件,非常专业。
- SavvyCAN: 一款开源的、功能极其强大的跨平台CAN分析工具,支持多种硬件,且能进行逆向工程和模糊测试,强烈推荐。
- CANable / cantact项目配套的
将你的Pico-CAN-A接入总线,用USB-CAN适配器也接入同一总线,打开SavvyCAN,设置好相同的波特率,你就能看到Pico发出的报文了。你也可以用SavvyCAN向总线发送特定ID和数据的报文,来测试Pico的接收功能是否正常。这是验证整个系统是否工作的最终关卡。
5. 开发调试全流程与避坑指南
从零开始让Pico-CAN-A跑起来,可能会遇到各种问题。下面我梳理一个标准的调试流程和常见“坑点”。
5.1 系统调试四步法
第一步:电源与基础检查
- 现象:板子没反应,芯片发热。
- 检查:用万用表测量Pico的3.3V、MCP2515的VDD、TJA1050的VCC电压是否正常。检查所有电源和地线是否短路。确认晶振是否起振(用示波器测MCP2515的OSC引脚,应有正弦波或方波)。
第二步:SPI通信验证
- 现象:无法读写MCP2515寄存器。
- 检查:
- 先写一个简单的SPI测试程序,比如循环读写MCP2515的某个寄存器(如
CANSTAT),看返回值是否符合预期。MCP2515上电后CANSTAT寄存器默认值是可查的。 - 使用逻辑分析仪或示波器!这是最强大的调试工具。抓取SPI总线上的CS、CLK、MOSI、MISO波形,对照MCP2515数据手册的时序图,检查片选信号、时钟极性相位(CPOL, CPHA)是否设置正确。Pico的SPI默认模式是
(CPOL=0, CPHA=0),这与MCP2515的SPI模式0是兼容的,但务必确认。 - 检查GPIO引脚映射是否正确,有没有和其他功能冲突。
- 先写一个简单的SPI测试程序,比如循环读写MCP2515的某个寄存器(如
第三步:CAN控制器初始化与环回测试
- 现象:SPI通了,但CAN发不出或收不到。
- 检查:
- 将MCP2515设置为环回模式(Loopback Mode)。在这个模式下,它自己发送的报文会被自己接收,不经过收发器。修改初始化代码,进入配置模式后,设置
CNF3寄存器或直接使用CANCTRL = 0x40进入环回模式。 - 编写测试代码,让Pico通过CAN发送一帧数据,然后立刻去接收。如果在环回模式下能自发自收成功,证明你的SPI驱动、MCP2515配置、报文收发函数都是正确的。这是软件调试的里程碑。
- 将MCP2515设置为环回模式(Loopback Mode)。在这个模式下,它自己发送的报文会被自己接收,不经过收发器。修改初始化代码,进入配置模式后,设置
第四步:接入真实总线与物理层调试
- 现象:环回模式成功,但接入真实总线后通信失败。
- 检查:
- 终端电阻:这是新手第一杀手!用万用表测量总线CANH和CANL之间的电阻。如果总线上只有你的一个节点,你应该测量到约120欧姆(如果你板载了跳线电阻并接通)。如果总线上有两个带120欧姆终端电阻的节点,你应该测量到约60欧姆。如果电阻是无穷大或非常大,说明终端电阻没接。
- 总线波形:用示波器测量CANH和CANL对地的波形。在空闲时,CANH和CANL电压都应在2.5V左右。当传输数据时,应该是差分信号:CANH在3.5V和2.5V之间跳变,CANL在1.5V和2.5V之间跳变,两者变化方向相反。如果波形不对(比如幅值不对,或不是差分),检查TJA1050的电源、连接,或者芯片是否损坏。
- 波特率一致性:再次确认总线上所有节点的波特率设置是否完全一致,包括同步段、时间段1、时间段2的所有参数。
5.2 常见问题速查表
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 无法读写MCP2515寄存器 | 1. SPI连线错误 2. 片选(CS)信号问题 3. 时钟极性相位(CPOL/CPHA)不匹配 4. 电源问题 | 1. 检查接线 2. 用逻辑分析仪抓SPI时序 3. 尝试调整SPI模式 4. 测量芯片供电电压 |
| 环回模式自发自收失败 | 1. 波特率配置错误 2. 发送缓冲器配置错误 3. 中断标志未清除 | 1. 核对晶振频率与波特率计算值 2. 检查TXBnCTRL寄存器配置 3. 确保发送后检查TXBnCTRL.TXREQ位是否清零,接收后清除CANINTF.RXnIF |
| 接入总线后无通信 | 1. 终端电阻未接或错误 2. 总线有短路或开路 3. 节点地址/ID冲突 4. 收发器损坏 | 1. 测量总线差分电阻(应为60欧或120欧) 2. 测量CANH/CANL对地、彼此间是否短路 3. 用分析仪监听总线,看是否有其他节点报文 4. 更换TJA1050/MCP2551 |
| 通信不稳定,错误帧多 | 1. 波特率轻微不匹配 2. 总线布线过长,无终端电阻 3. 电磁干扰严重 4. 节点过多,负载重 | 1. 精确校准各节点波特率 2. 确保总线两端有终端电阻,使用双绞线 3. 增加共模电感、屏蔽层接地 4. 检查总线负载率,优化报文发送频率 |
| 只能收不能发,或反之 | 1. 收发器方向控制问题(如果使用带方向控制的型号) 2. MCP2515的TX/RX引脚与收发器接反 | 1. 检查收发器模式控制引脚(如TJA1050的STBY) 2. 核对MCP2515的TXCAN接收发器TXD,RXCAN接RXD |
5.3 进阶优化与扩展思路
当基础功能稳定后,可以考虑以下优化和扩展,让你的Pico-CAN-A更强大:
- 双CAN通道:一颗RP2040有两个核心,完全可以驱动两个独立的SPI接口,连接两个MCP2515,实现双CAN通道网关。一个通道连接车载网络,另一个连接调试设备或执行器,实现协议转换或数据过滤转发。
- 集成UART/RS-232/RS-485:利用Pico富余的UART接口,增加一个MAX3232或MAX485芯片,让模块同时具备CAN和串口通信能力,成为一个协议转换器(例如,将CAN总线数据转换成串口数据发给旧设备或上位机)。
- 添加SD卡存储:通过SPI或SDIO接口连接一个Micro SD卡槽,将接收到的关键CAN报文以日志形式存储下来,用于车载数据黑匣子或长期数据记录分析。
- 实现USB-CAN适配器:利用Pico优秀的USB功能,实现一个完整的USB转CAN适配器。Pico模拟成一个USB CDC设备(虚拟串口)或者更专业的自定义HID设备,上位机通过USB发送命令,Pico解析后通过CAN收发,并将收到的CAN数据通过USB回传。这需要编写上位机驱动和配套软件,复杂度较高,但价值也最大。
- 低功耗设计:对于电池供电的应用,可以深入研究MCP2515和TJA1050的低功耗模式(睡眠、监听),并结合RP2040的休眠功能,实现按需唤醒的超低功耗CAN监听节点。
从一颗小小的树莓派Pico出发,到构建一个稳定可靠的CAN网络节点,Pico-CAN-A项目贯穿了硬件设计、寄存器驱动、通信协议和系统调试的完整闭环。它不仅仅是一个模块,更是一个深入理解嵌入式通信核心技术的绝佳载体。我个人的体会是,调试CAN总线,示波器和逻辑分析仪的价值远大于代码本身,硬件层的问题必须用硬件工具来定位。最后一个小技巧:在项目初期,不妨先买一个现成的MCP2515模块进行软件验证,等驱动完全稳定后,再着手设计自己的PCB,这样可以有效降低起步难度和风险。