通信代码分析讲解
PFC与LLC的SCI通信协议解析
PFC与LLC的SCI通信协议解析
在复杂的隔离型数字电源系统中,前级功率因数校正(PFC)与后级谐振变换器(LLC)通常由两颗独立的 DSP 控制器分别管理。为了实现系统的整机协同与保护联锁,两者之间必须建立高效且可靠的隔离通信机制。
本章将详细为您解析 PFC 与 LLC 之间的 SCI(串行通信接口)通信协议,从帧结构定义、宏观与微观时序控制,到中断收发逻辑的底层实现进行深度剖析。
隔离通信系统概述
在系统物理架构上,PFC与LLC控制器独立工作,其中PFC控制器位于电源初级侧,LLC控制器位于电源次级侧。
由于拓扑的级联关系,LLC工作基于PFC的运行状态,当PFC出现故障或由于PFC输入电压(电网电压)不满足合理范围时,LLC必须禁止输出。同时,通常电源模块会将输入电压电流等参数上报上位机,而实际负责与外部上位机通信的往往是次级侧的LLC控制器。因此,正常运行过程中,PFC控制器需要将自己的工作状态内容以及相关电压电流参数跨越隔离带传输至LLC控制器,即两者之间需建立隔离信息交互的通信电路。
为了实现这一目标,模块设计了隔离型SCI串行通信方式实现PFC控制器与LLC控制器之间的信息交互。
在通信主从关系上,定义LLC控制器为通信主机,PFC控制器为从机。从机(PFC)绝不主动发送信息,只有在接收到主机(LLC)的明确命令后,才回传对应的数据内容,避免了总线冲突。
考虑到隔离光耦的传输延迟以及对抗干扰能力的要求,配置SCI通信的波特率为稳定的 4800bit/秒。
SCI 通信帧格式设计
信息交互以固定的数据帧格式组成,为了兼顾传输效率与数据完整性,定义通信内容一帧由6个字节组成,其结构如下图所示:
- 帧头(Byte 0):其中Byte0为帧头字节,用以表示该数据帧的内容命令。为了在硬件底层直接区分帧头与普通数据,该字节传输时利用了 DSP 串口的多机通信模式,将其第九位设置为1。控制器在发送一帧数据的首字节地址时,使用TXWAKE寄存器添加第9位,用以代表这是一个全新的帧头。
- 有效数据载荷(Byte 1 ~ Byte 4):Byte1~Byte4为该帧的有效物理数据或状态信息。
- 校验和(Byte 5):Byte5为校验和字节,它是Byte0~Byte4五个数据累加和后取低八位的值,该字节用以校验数据在传输过程中无任何电磁干扰造成的差错。
校验逻辑: 任何发送方在组帧时,将Byte0~Byte4求和后作为Byte5数据发送;任何接收方在接收完一个完整帧后对该帧进行求校验和,当且仅当计算出的校验和与接收到的该帧Byte5相同时,才认为其为有效数据帧,否则直接将其丢弃,防止错误数据引发危险动作。
通信命令字与载荷定义
设计中,定义LLC(主机)向PFC发送两种数据命令,其帧头分别为 CMD1: 0x11 和 CMD2: 0x33。
因为主机的主要目的是“索要”数据,所以在LLC向PFC发送的这两种结构帧中,Byte1~Byte4有效数据均为0。
定义PFC(从机)在接收完对应的命令帧后,回复的数据内容格式如下:
- 回复 CMD1 帧数据(状态巡检):Byte0为PFC故障信息高位,Byte1为PFC故障信息低位,Byte2为PFC状态信息高位,Byte3为PFC状态信息低位。
- 回复 CMD2 帧数据(参数巡检):Byte0为输入电压有效值高位,Byte1为输入电压有效值低位,Byte2为输入电流有效值高位,Byte3为输入电流有效值低位。
宏观与微观通信时序
为了避免频繁的中断打断高频发波控制,SCI 的通信时序被精细地分为“宏观轮询间隔”与“微观字节间隔”。
宏观轮询时序 (Frame Timing)
PFC与LLC控制器的宏观通信时间间隔设定为 100mS。如下图所示为PFC与LLC通信帧的时间时序图:
- 首先,主机LLC向PFC发送命令帧CMD1(数据空),PFC在检测到CMD1帧并校验数据无错误后,立即回复CMD1帧(含PFC状态数据内容)。
- 主机LLC在发送完CMD1后,会静静等待100mS的间隔,然后再向PFC发送命令帧CMD2(数据空)。PFC在检测到CMD2帧并校验数据无错误后,回复CMD2帧(含PFC电压电流数据内容)。
- 主机LLC再等待100mS后重新发送命令帧CMD1(数据空),系统以此 200mS 为完整周期的节拍循环发送。
微观字节时序 (Byte Timing)
定义的每一帧数据由6个字节组成,由于 SCI 为单字节发送外设,即需要连续调用 6 个发送数据操作才能完成一帧数据发送。
考虑到波特率较慢,为了不让 CPU 死等串口发送完成,定义了 SCI 一帧中每个字节的微观通信时间间隔,如下图所示:
以LLC控制器向PFC控制器发送一帧数据为例,低字节Byte0优先被推送发送,随后 CPU 离开;等待 5mS 的定时器中断到来时再发送第 2 字节,以此 5ms 的时间间隔为节拍,从容地完成整帧数据发送。
LLC和PFC都可以巧妙地于 5mS 的慢速定时器中断中进行单字节发送操作,实现了极为高效的时分复用。
对于接收端而言,PFC在接收到Byte0字节(含地址位,第九位为1)后,开始组建帧操作;当累计接收满6个字节数据后,在数据校验无问题后才将6字节组建为一帧合法数据。
状态机驱动的发送事件逻辑
LLC 主机发送事件 (SciCom)
LLC 为主机,掌控着通信的绝对节奏,其程序流程图如下图所示:
在 SciCom 函数中,LLC 于每 100mS 时间间隔(即 5ms 中断的计数器累加大于 20 次)主动向 PFC 发起命令帧。当计数器大于 20,计数器清零,程序将需要发送的命令字装载进发送数组(此时载荷为空),并置位发送标志位。
当底层轮询检测到该发送标志为1时,进入 FrameSent() 状态机函数,将一帧数据(6字节)以每 5mS 发送 1 字节的时间间隔有条不紊地送出。
PFC 从机发送事件 (SciCom)
PFC 为从机,绝不主动发送数据,只有在接收完整一帧来自 LLC 控制器的合法命令后才回复数据帧。其程序流程图如下所示:
PFC 在串口接收中断中接收完 LLC 命令帧并校验正确后,置位自身的发送标志位。在主循环或 5ms 调度中检测到该标志位为1时,说明 PFC 需要回复对应命令帧的数据。此时,PFC 迅速将需要回复的电压/电流/状态数据装载进发送数组,进入 FrameSent() 函数,同样将一帧数据(6字节)以每 5mS 发送 1 字节的时间间隔安全送出。
硬件级中断接收与校验事件
为了保证接收的实时性,数据的捕获由底层 SCI 硬件接收中断完成。
PFC 中断接收 (ISR_SCI)
PFC在接收完 1 个完整字节后,硬件自动触发并进入 SCI 接收中断函数 __interrupt void ISR_SCI(void)。其程序流程图如下所示:
- 寻址与同步:进入接收中断后,首要任务是判断接收字节数据的第九位是否为1(以此判断是否为一帧数据的首字节/帧头)。若接收字节为首字节,则立即存储首字节命令,并将状态机
SciReg.cmd设置至对应值,同时将该数据保存至SciReg.RxFrame帧数组的第 0 位。 - 数据填入:随后再次接收到普通数据时(第九位为0),依次顺序保存接收数据至
SciReg.RxFrame帧数组中。 - 校验与动作:当累计接收到 6 个字节数据后,CPU 立即对
SciReg.RxFrame数组中的 Byte0~Byte4 进行求和,并与接收到的 Byte5 字节进行对比,以校验接收数据准确性。- 若校验和不对,说明遭遇干扰,数据立刻丢弃,防止误动作。
- 若校验数据准确无误,则置位发送标志位准备回传。由于PFC接收来自于LLC控制器的命令帧的数据载荷为空,因此无需进行额外的应用层数据转存操作。
LLC 中断接收
LLC 的中断接收程序流程图与 PFC 接收中断在底层架构上完全相同,均依靠第九位寻址和累加和校验。
不同之处在于应用层:LLC 接收来自于 PFC 的回复帧中含有极其重要的 PFC 运行状态、母线电压等信息。因此,在硬件帧校验准确通过后,LLC 必须立刻将数据帧中的 Byte1~Byte4 有效数据,按位解包并转存至对应的系统变量结构体中,供 StateM 状态机判断联锁保护条件使用。
PFC的SCI通信程序深度解析
PFC的SCI通信程序深度解析
在上一章中,我们详细探讨了 LLC(主机)与 PFC(从机)之间的 SCI 隔离通信协议架构及 LLC 侧的运行逻辑。本章将把视角切换到前级——PFC 侧(从机)的通信程序实现。
作为从机,PFC 控制器绝不主动发起通信,而是时刻“监听”总线。只有在准确接收并校验来自 LLC 的寻址命令帧后,才会将自身的电压、电流、故障标志及状态机等核心数据打包回传。这种“一问一答”的轮询机制,既保证了时序的确定性,又最大限度地避免了总线冲突。
下面我们将按照“接收中断 -> 数据解析 -> 数据组帧 -> 延时发送”的完整数据流行进路线,对 PFC 侧的 C 语言源代码进行逐行剖析。
通信宏定义与全局变量声明
在程序的最开始,定义了通信过程中的各种命令字宏以及核心的状态寄存器变量。
1 | /********************MESSAGE**********************/ |
1 | /**********************************************Variable declaration************************************************/ |
代码解析:
RCMD1 (0x11)和RCMD2 (0x33)是与 LLC 侧严格对应的命令帧头。Frame1和Frame2定义了完整的 6 字节物理发送缓冲区,且初始化时就已经把第 0 个字节固化为了对应的命令头,极大地简化了后续的组帧操作。
硬件级接收中断服务函数 (ISR_SCI)
PFC 侧的数据接收完全由底层 SCI 硬件中断驱动,确保任何来自 LLC 的指令都能在第一时间被捕获。该中断函数不仅要处理正常的数据接收,还要处理通信线路上的误码和硬件错误。
1 | /** =================================================================== |
接收缓存与校验状态机 (MesRxCmd & MesStore)
在中断函数中,根据接收到的是“帧头”还是“普通数据”,程序会分别调用 MesRxCmd 和 MesStore 来推进接收状态机。
1 | /* |
当帧头就绪后,后续连续到来的 5 个普通字节将通过 MesStore 函数进行累加并最终校验。
1 | /** =================================================================== |
发送任务调度与数据打包装载 (SciCom & TxDataRecord)
PFC 从机的发送操作并非在接收中断里死等,而是被推迟到了外部的后台轮询主函数(或慢速定时器中断)中,这种架构极大地提高了系统的实时性。
1 | /* |
在装载数据时,程序将 DSP 内部的 Q 格式定点数,逆向转换为适合串口传输的高低双字节整数(分别放大 10 倍或 100 倍以保留小数精度)。这里定义了一个专用的拆位结构体:1
2
3
4
5typedef struct
{
unsigned char high; // 高八位
unsigned char low; // 低八位
} sci_dg;
装载函数具体实现如下:
1 | /* |
组帧与硬件底层发送 (FrameSent & FrameBuild & SCI_TX)
数据准备就绪后,将由 FrameSent 状态机接管。为了防止堵塞 CPU,单帧数据的 6 个字节是按照定时器节拍“一字节一字节”地呼叫发送的。
1 | /* |
组帧与校验和计算:
在发送之前,将拆好的有效载荷按顺序填入帧数组 frame 中,并严格生成校验和字节(第 5 字节)。
1 | /** =================================================================== |
硬件级单字节发送:
最后一步,将数据交由 SCI 硬件发送缓冲寄存器。关键点在于:发送帧头时,必须通过硬件寄存器强制拉高第 9 位(TXWAKE)!
1 | /* |
至此,PFC 侧从“中断捕捉命令 -> 硬件级校验 -> 数据转码打包 -> 时分复用分发”的完整通信闭环代码分析完毕。这套协议保证了 LLC 与 PFC 之间的高效协同,是数字电源多机架构的经典实现。
LLC的SCI通信程序深度解析
LLC的SCI通信程序深度解析
在前面的章节中,我们已经了解了 PFC 与 LLC 之间的 SCI 通信协议架构以及 PFC 从机的应答逻辑。本章我们将视角切换回 LLC(主机)侧,详细剖析 LLC 是如何作为整个通信网络的主导者,有条不紊地向 PFC 发起轮询,并精准解析 PFC 跨越隔离带传回的工作状态与电压电流数据的。
作为主机,LLC 的通信程序设计需要统筹全局。它不仅要负责发起通信节拍(每 100ms 轮询一次),还要交替发送不同的命令(请求状态或请求参数),并在接收到 PFC 的回复后,将数据解包更新至本地的系统变量中,以供整机状态机进行联锁保护判断。
主机通信时间调度与发送触发 (SciCom & TxDataRecord)
LLC 侧的通信主调度函数 SciCom 通常放置在 5ms 的定时器中断中(或主循环中以 5ms 为基准进行时间片调度)。它的核心任务是维持 100ms 的主机宏观轮询节拍。
1 | /* |
在触发发送前,程序会调用 TxDataRecord 函数来装载数据。但细心的工程师会发现,这个函数里面是空的:
1 | /* |
交替发送逻辑与帧构建 (TxFlag & FrameSent & FrameBuild)
为了全面获取 PFC 的运行状态(如是否过压、过流)和实时工作参数(如交流电压、电流),LLC 必须交替发送这两种请求命令。程序中利用 TxFlag 变量实现了两种命令的“乒乓”切换机制。
1 | unsigned short TxFlag=SCI_TX1;//发送帧判断 |
FrameSent 函数是发送过程的核心状态机。为了防止串口发送过程死等而堵塞 CPU 运行,系统将帧发送拆解,每次调用仅发送一帧里的一个字节。
1 | /* |
组帧函数 FrameBuild 将领命执行载荷填充与校验和计算,确保数据传输的可靠性:
1 | /** =================================================================== |
变量初始化防呆机制 (SCIValueInit)
为了防止单片机上电时,残存的脏数据引发开机误动作,系统必须进行严密的初始化。这里有一个极其重要的安全设计:故意植入非零错误码。
1 | /* |
底层硬件发送驱动 (SCI_TX)
在单片机底层,串口是通过操作移位寄存器逐字节发送的。本系统为了实现多机环境下的帧头精准识别,利用了 DSP 的 地址唤醒位(TXWAKE) 功能。
1 | /* |
接收中断服务与多机通信寻址 (ISR_SCI & MesRxCmd)
当 LLC 发出请求后,PFC 会将自身数据打包回传。LLC 收到数据时会触发硬件接收中断。为了防止慢速的串口通信阻塞高频的 LLC 谐振腔闭环控制,该串口中断内部采用了中断嵌套机制,并在硬件级别拦截误码。
1 | /** =================================================================== |
当帧头锁定后,会立即触发初始化接收序列函数 MesRxCmd:
1 | /** =================================================================== |
接收数据校验与全局映射 (MesStore)
在 LLC 侧,最核心的一步就是将物理通信字节拆解、验证,并映射到系统的全局状态结构体 PFCData 中。
1 | /** =================================================================== |
至此,LLC 从发起通信请求、交替切换指令,到硬件嵌套接收、严格校验并最终解析存储数据的全过程已深度拆解完毕。
CAN通信协议解析与实现
CAN通信协议解析与实现
在现代数字电源系统中,除了电源内部各级控制器(如 PFC 与 LLC)之间需要进行 SCI 隔离通信外,电源模块作为一个整体,还需要与外部的上位机(如系统主控、BMS、测试平台等)进行可靠的参数交互与指令下发。
为了满足工业环境下的高可靠性与抗干扰要求,本系统采用了 CAN 2.0B 扩展帧协议进行外部通信。本章将详细解析这套 CAN 通信协议的帧结构定义、命令字典,并结合底层 C 语言中断和状态机代码,为您揭秘电源模块是如何与上位机实现“心跳保活”、“指令响应”及“状态上报”的。
CAN 协议基础配置与宏观设定
本系统 CAN 通信的底层硬件宏观配置遵循以下原则:
- 帧格式:采用 CAN 2.0B 通信协议,使用 29 位扩展标识符(ID)的数据帧。
- 字节序:所有 CAN 数据传送均采用低字节优先发送模式(小端模式)。
- 波特率:CAN 通信物理层速率定义为 $125\text{kbit/s}$。
- 地址分配:通信协议中明确划分了网络节点的固定地址,电源模块的固定地址(从机)为
0x80;上位机(主机)的地址为0xA0;上位机广播命令专用地址为0xFF。 - 接收过滤:电源模块底层的邮箱验收滤波机制被配置为:只接受与自身地址 (
0x80) 相同的目标 CAN 帧,以及目标地址为0xFF的广播命令帧,自动屏蔽总线上的无关数据。
通信时序与保活机制:
上位机在模块运行过程中,须以一定时间间隔发送相关心跳或控制命令。为了防止上位机死机或通信线缆断开导致电源失控,电源模块内部设有时钟看门狗:如果电源模块在上电后连续 6 秒内未收到来自上位机的任何命令信号,将触发 CANLost 保护,强制进入安全等待状态;直到再次收到上位机命令后才会恢复启动输出。
应答机制:
电源模块在收到上位机发送的设置命令时,必须回复上位机一条确认信息(ACK);但当收到上位机发送的广播命令时,则无需回复任何信息,以避免总线拥堵。
协议数据单元(PDU)结构拆解
每个 CAN 数据帧包含一个用户可自行编辑的协议数据单元(PDU)。扩展帧的 PDU 由 29 位 ID 和 8 个字节的数据载荷(DATA)组成。
29位扩展 ID 字段定义
为了在多机网络中实现精确路由与命令分类,29 位的 ID 字段被划分为以下四个功能区:
- 源地址 SA (0~7 bit):共 1 Byte,代表该 CAN 帧发送方的物理地址。
- 目标地址 PS (8~15 bit):共 1 Byte,代表该 CAN 帧接收方的物理地址。
- 命令 CMD (16~23 bit):共 1 Byte,代表该 CAN 帧的数据类型(下文有命令字典)。
- 保留位 DP (24~28 bit):共 5 Bits,该应用中将其定义为固定值
0x18。
通信路由举例:
- 当上位机发送 CAN 帧至电源模块时,ID 中的 源地址SA 为
0xA0,目标地址PS 为0x80。 - 当电源模块发送应答帧至上位机时,ID 中的 源地址SA 为
0x80,目标地址PS 为0xA0。 - 当上位机广播发送时,源地址SA 为
0xA0,目标地址PS 为广播专用地址0xFF。
CMD 命令字典定义
协议中定义了 4 种基本的 CMD 指令类型,控制着模块的行为:
| CMD 代码 | 指令描述 |
|---|---|
0x01 | 上位机发送至模块的设置命令(如开关机、改电压电流) |
0x02 | 模块发送至上位机的回复设置命令(即 ACK) |
0x20 | 上位机发送至模块的心跳信号帧(仅作保活,无实际动作) |
0x10 | 模块发送至上位机的状态上报帧(定期上传实时参数) |
8Bytes 载荷(DATA)数据域映射解析
8 Bytes 的数据内容(DATA)根据 CAN 帧中 CMD 命令字的类型不同,具有截然不同的映射关系。为了适应单片机的定点运算,所有发送的浮点参数(如电压 48.0V、电流 5.0A)均放大了 100 倍转化为整数(如 4800 和 500)传输。
1. 上位机发送设置命令至模块 (CMD=0x01):
- Byte 0: 预留
- Byte 1: 开关机指令(0 代表关机,1 代表开机)
- Byte 2, Byte 3: 参考电压设定值(Byte3 为高位)。例如设为 48V,则该十六进制数据对应的十进制为 4800。
- Byte 4, Byte 5: 参考电流设定值(Byte5 为高位)。例如设为 5A,则该数据为 500。
- Byte 6, Byte 7: 预留
2. 模块回复上位机设置命令 (CMD=0x02):
- Byte 0: 成功与否标志位(0 代表成功接收并执行;1 代表数值越界设置失败)
- Byte 1 ~ Byte 5: 均与上位机下发的命令原样一致,作为数据回显确认。
- Byte 6, Byte 7: 预留
3. 上位机发送心跳帧 (CMD=0x20):
- Byte 0 ~ Byte 7: 全部填充为 0,仅仅是为了让接收中断刷新
LostCnt防掉线计时器。
4. 模块发送状态上报帧 (CMD=0x10):
- Byte 0: PFC 状态信息(运行状态位合集)
- Byte 1: PFC 故障信息(错误码)
- Byte 2: LLC 状态信息
- Byte 3: LLC 故障信息
- Byte 4, Byte 5: 输出电压实际采样值(Byte5 为高位,实际值*100)。
- Byte 6, Byte 7: 输出电流实际采样值(Byte7 为高位,实际值*100)。
底层硬件中断接收流程
为了节约宝贵的 CPU 算力和中断响应时间,模块 CAN 通信对数据接收使用中断方式响应。为了不影响高频 LLC 控制环路,该中断的优先级被设置得较低。
在接收中断服务函数 __interrupt void sMailboxISR(void) 中,程序绝不做任何耗时的业务数据处理或参数校验,它的唯一任务就是:“将接收到的邮箱数据原封不动地搬运转存至内存中的 PDU 结构体中”,并置位“接收完成标志位”,唤醒主程序。
流程如下:当硬件邮箱发生接收中断时,CPU 读取产生中断的信箱号。接着,判断该邮箱收到的目标地址是否为广播地址。如果是广播邮箱,则置位“接收广播标志”;否则置位常规“接收标志”。随后,火速将数据拷贝至 PDU,结束中断。
CAN 主程序任务调度流
由于繁重的数据解析不能放在中断里,电源系统专门设计了后台 CAN 主调度程序来统筹一切。
如上图所示,CAN 主程序的运行逻辑如下:
- 首先检测全局接收标志位是否为 1(说明刚发生过中断,收到了新数据)。
- 如果有新数据,立刻将接收标志位清零,同时最关键的是:将 CAN 丢失保护计时器 (
CanDat.LostCnt) 清零,撤销通信掉线保护报警。 - 判断接收到的命令 CMD 类型。如果仅仅是心跳帧,则只刷新掉线时间不做动作。如果是设置命令 (
CMD=0x01),则调用下文的转设置命令子程序。 - 在处理完设置指令后,系统会检查此次接收的是否为广播命令。如果不是广播命令,按照协议规定,模块必须调用转回复设置命令子程序 (
CMD=0x02) 向上位机发送应答。如果是广播,则静默结束。 - 在没有收到上位机命令的时候,程序也没有闲着。调度器内部维护了一个 1 秒钟的定时器,当该计时器溢出时,模块会自动触发转状态上报程序 (
CMD=0x10),将自身的电压电流和故障码打包并向总线推送。
程序业务逻辑实现
转设置命令子程序 (CANSetCmd)
当主程序确定这是一条合法的设置指令后,进入该子流程。首先将 PDU 中的裸数据拷贝到用户态 CanDat 结构体中。
随后程序依次执行参数解码:
- 提取 Byte1,执行底层状态机的开/关机切换操作。
- 提取 Byte2, Byte3,将其拼装为 16 位整数,并除以 100 换算为物理参考电压,赋值给 LLC 闭环控制器的电压环基准变量。
- 提取 Byte4, Byte5 进行参考电流限幅阈值转换。
值得一提的是,在执行赋值前,程序必须执行越界安全校验。如果上位机下发的电压值超出了电源模块的硬件最大承受范围,程序会拒绝执行该指令,并将自身的设置应答标志位标记为“失败 (1)”。
回复设置命令子程序 (CANAck)
在参数设置完毕后,模块需组装应答帧 (CMD=0x02)。
组装流程极度格式化:
- 配置 PDU 标识符:设定
CMD=0x02,强制目标地址PS=0xA0(上位机),源地址SA=0x80(模块自身)。 - 装载 CAN ID 硬件寄存器。
- 将包含“成功/失败标志位”和原始指令回显数据填入 8 字节的数据发送寄存器中。
- 置位发送请求触发位,调用 CAN 底层外设发送完毕。
LED 状态机联动指示
由于 CAN 通信接管了模块的所有宏观控制,面板上的 LED 状态指示灯也会随着 CAN 下发的指令及保护状态实时变化。这段极其直观的 C 代码展示了电源外设如何与内部状态机 (DF.SMFlag) 紧密联动:
1 | /** =================================================================== |
CAN通信初始化与底层代码实现
CAN通信初始化与底层代码实现
在上一章中,我们详细解析了电源模块与上位机之间 CAN 通信的 29 位扩展帧协议架构以及宏观的控制逻辑。协议的完美运行,离不开 DSP 底层硬件外设的精准支撑。
本章将深入到 DSP 的底层寄存器级别,为您逐行剖析 CAN 通信模块的初始化流程。我们将从核心数据结构的定义出发,一步步揭秘如何配置 GPIO 复用、如何推导并设定 125kbit/s 的波特率,以及如何通过配置独立的发送与接收邮箱(Mailbox)来实现强大的硬件级报文过滤与中断管理。
核心数据结构与宏定义
为了在 C 语言中高效地打包、解包和管理上一章定义的 29 位扩展帧以及 8 字节有效载荷,系统定义了两个核心的全局结构体:_PDU(协议数据单元)和 _can_para(模块本机状态参数),以及对应的命令类型宏。
1 | extern struct _can_para CanDat; |
与之对应的,程序将常用的 CMD 命令字定义为了便于识别的宏:
1 |
CAN 初始化配置流程拆解
初始化 CAN 模块是一项涉及系统时钟、引脚复用和多重寄存器解锁的严谨工程。根据系统设计规范,CAN 初始化的标准流程严格包含以下步骤:
- 配置GPIO30上拉方式;
- 配置GPIO31上拉方式;
- 配置GPIO30上拉异步方式;
- 配置GPIO30为CAN接收功能;
- 配置GPIO31为CAN发送功能;
- 使能CAN发送功能;
- 使能CAN接收功能;
- 配置SCB位,增强型CAN2.0B模式;
- 清发送标志位;
- 清接收标志位;
- 清中断0标志位;
- 清中断1标志位;
- 关闭所有邮箱;
- 初始化复位32个邮箱,ID位和控制位,数据位为0,数据长度为8,无远程帧;
- 关闭邮箱中断功能;
- 所有邮箱都选择Int0中断;
- 异常中断在频道Int1;
- 配置CCR=1和ABO=1;
- 等待CCE标志位置1;
- 根据手册配置CAN通信速率为125kbit;
- 配置CCR=0,STM=0,DBO=0;
- 等待CCE标志位清0;
- 关闭所有邮箱功能;
- 配置邮箱0为发送邮箱;
- 配置邮箱1为接收邮箱;
- 配置邮箱2为接收邮箱;
- 配置邮箱0的初始ID;
- 配置邮箱1的初始ID;
- 配置邮箱2的初始ID;
- 使能邮箱1的屏蔽功能;
- 使能邮箱2的屏蔽功能;
- 配置邮箱1的屏蔽功能屏蔽位;
- 配置邮箱2的屏蔽功能屏蔽位;
- 配置邮箱0为拓展帧;
- 配置邮箱1为拓展帧;
- 配置邮箱2为拓展帧;
- 使能0为邮箱;
- 使能1为邮箱;
- 使能2为邮箱;
- 打开邮箱1和邮箱2的接收中断;
CAN 初始化代码深度解析 (CanInit)
上述的数十项严苛配置步骤,最终汇聚成了下面这段极其健壮的底层 C 语言初始化代码。其中波特率的推导与邮箱的寻址滤波配置是重中之重。
1 | /* |
CAN通信程序分析
CAN通信程序分析
在完成了 CAN 通信底层寄存器的初始化配置之后,系统已经具备了与上位机进行物理层和数据链路层交互的能力。本章将详细剖析 CAN 通信应用层的核心业务逻辑,包括:中断接收、指令分发调度、参数安全校验、应答机制,以及实时遥信遥测数据的组包与上报。
CAN 中断接收与数据转存 (sMailboxISR)
为了最大程度保证 LLC 高频控制环路的实时性,CAN 接收中断(sMailboxISR)被设计得极为精简。该中断函数内绝对不进行任何业务逻辑的判断与数据解析,它的唯一任务就是:在硬件产生接收中断的瞬间,将底层邮箱(Mailbox)中的数据快速“搬运”到全局协议数据单元结构体 PDU 中,并置位标志位交由主循环处理。
1 | /* |
CAN 数据处理与调度核心 (CANMessage)
主循环通过轮询 CANRxFlag 标志位来判断是否需要处理新数据。一旦检测到新数据,CANMessage 函数将作为中央调度器,执行掉线看门狗“喂狗”、指令散转以及应答触发。
同时,它也兼顾了在没有外部请求时,主动定时上报模块状态的任务。
1 | /* |
系统状态指示与超时看门狗 (LEDShow)
虽然该函数名为 LEDShow,但它不仅负责驱动前面板的红、黄、绿状态指示灯,更是整个 CAN 通信时间基准的“脉搏”。通信超时计数器(LostCnt)和上报周期计数器(RecordCnt)都是在这个按严格周期(5ms)调用的函数中进行累加的。
1 | /** =================================================================== |
设置命令解析与安全限幅检查 (CANSetCmd & SetCmdUpdate)
接收到上位机的控制指令后,必须先将 8 字节裸数据重组,然后进行严格的安全边界校验(防止上位机误发极值导致炸机),最后再将物理量转换为 DSP 内部的 Q 格式定点控制量。
1 | /* |
构造命令应答与发送引擎 (CANAck & CANTx)
只要模块收到非广播指令,就必须将执行结果(ERR_NULL 或 FAIL)封装并回送上位机。应答的核心在于目标地址与源地址的对调。
1 | /* |
周期性状态遥测与数据封装 (CanRecord)
主程序中维护的计时器溢出时,模块主动调用 CanRecord 进行运行状态广播。它将底层的故障代码、状态机状态以及实际采集的电压电流封装成一帧标准报文。
1 | /* |
















