1. 项目概述
在工业自动化领域,CAN总线因其高可靠性和实时性成为设备间通信的首选方案。这个基于STM32的双机控制系统项目,是我在去年为某自动化产线改造时设计的核心控制单元。系统采用主从架构,通过CAN总线实现两台STM32控制器之间的数据交互和协同控制,最终实现了对产线12个工位的精准同步控制,通信误码率低于0.001%。
选择STM32F407作为主控芯片主要基于三点考虑:首先其内置双CAN控制器,硬件上支持同时连接两条CAN总线;其次168MHz主频能轻松处理工业场景下的实时控制需求;最后丰富的GPIO资源可以满足多路IO控制需求。实际测试中,系统在波特率1Mbps下稳定传输距离达到120米,完全覆盖了产线设备分布范围。
2. 硬件设计要点
2.1 核心器件选型
主控制器选用STM32F407ZGT6,其关键特性包括:
- 双CAN2.0B控制器(兼容CAN2.0A)
- 12个定时器(其中2个高级定时器)
- 3个12位ADC(16通道)
- 114个GPIO引脚
CAN收发器采用TI的SN65HVD230,这款芯片具有:
- 最高1Mbps通信速率
- ±36V总线故障保护
- 热关断保护功能
- 典型工作电流5mA
注意:收发器与MCU之间必须加装高速光耦隔离(如6N137),隔离电压建议不低于2500Vrms。我们在初期测试中曾因未做隔离导致一批芯片被浪涌击穿。
2.2 电路设计细节
CAN总线接口电路需要特别注意:
- 终端电阻:在总线两端各接一个120Ω电阻,我们使用1%精度的金属膜电阻
- 滤波电路:在CANH/CANL线上并联30pF电容,并串联10Ω电阻
- 保护电路:TVS管选用SMBJ6.0CA,响应时间<1ns
电源部分采用两级设计:
- 第一级:24V转5V(LM2596)
- 第二级:5V转3.3V(AMS1117)
每路电源都配有100μF电解电容和0.1μF陶瓷电容滤波
3. 软件架构设计
3.1 通信协议制定
自定义的应用层协议包含以下字段:
| 字段名 | 长度(byte) | 说明 |
|---|---|---|
| SOF | 1 | 帧头0xAA |
| CMD | 1 | 指令类型 |
| LEN | 1 | 数据长度 |
| DATA | 0-8 | 有效载荷 |
| CRC | 1 | 校验和 |
| EOF | 1 | 帧尾0x55 |
CRC校验采用多项式0x31(x^8 + x^5 + x^4 + 1),初始值0xFF。我们在协议中定义了6类基本指令:
- 0x01:心跳包(主从机每500ms交互一次)
- 0x02:IO控制命令
- 0x03:参数读取请求
- 0x04:参数返回响应
- 0x05:报警信息
- 0x06:同步时间戳
3.2 主控制器程序设计
使用FreeRTOS创建三个核心任务:
- CAN通信任务(优先级最高)
c复制void CAN_Task(void *pvParameters) {
CAN_FilterTypeDef filter;
filter.FilterIdHigh = 0x0000;
filter.FilterIdLow = 0x0000;
filter.FilterMaskIdHigh = 0x0000;
filter.FilterMaskIdLow = 0x0000;
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
filter.FilterBank = 0;
filter.FilterMode = CAN_FILTERMODE_IDMASK;
filter.FilterScale = CAN_FILTERSCALE_32BIT;
filter.FilterActivation = ENABLE;
HAL_CAN_ConfigFilter(&hcan1, &filter);
while(1) {
if(HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0) > 0) {
CAN_RxHeaderTypeDef header;
uint8_t data[8];
[HAL](https://taotoken.net/?utm_source=hardware)_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &header, data);
xQueueSend(can_rx_queue, &data, portMAX_DELAY);
}
osDelay(1);
}
}
- 控制逻辑处理任务
- 实现有限状态机处理各工位流程
- 每50ms扫描一次所有输入状态
- 采用事件驱动方式触发输出
- 人机交互任务
- 处理LCD显示和按键输入
- 通过消息队列与其他任务通信
4. 关键问题解决方案
4.1 通信同步问题
初期测试发现两个严重问题:
- 从机响应延迟不稳定(20-150ms波动)
- 多包连续传输时会出现丢包
解决方案:
- 硬件层面:在CANH/CANL线增加磁环抑制高频干扰
- 软件层面:
- 采用分时隙通信机制,为每个从机分配固定时间窗口
- 实现重传机制,3次重传失败则触发报警
- 添加时间戳同步功能,主从机每10分钟同步一次RTC
优化后的时序控制代码:
c复制void CAN_TimeSlot_Scheduler(void) {
static uint32_t last_sync = 0;
uint8_t sync_pkg[8] = {0};
if(HAL_GetTick() - last_sync > 600000) { // 10分钟同步
sync_pkg[0] = 0xAA;
sync_pkg[1] = 0x06;
sync_pkg[2] = 6;
*(uint32_t*)&sync_pkg[3] = HAL_GetTick();
CAN_Send_Msg(sync_pkg);
last_sync = HAL_GetTick();
}
for(int i=0; i<SLAVE_NUM; i++) {
if((HAL_GetTick() % CYCLE_TIME) < TIME_SLOT*i) {
Process_Slave_Data(i);
}
}
}
4.2 抗干扰设计
现场测试时发现的典型干扰现象:
- 变频器启动导致CAN通信中断
- 大功率设备开关造成误动作
采取的防护措施:
- 电缆选用双层屏蔽双绞线(Belden 3105A)
- 总线走线与动力线保持30cm以上距离
- 所有IO端口增加RC滤波(100Ω+0.1μF)
- 软件上实现数字滤波算法:
c复制#define FILTER_DEPTH 5
uint8_t Digital_Filter(uint8_t new_val) {
static uint8_t buf[FILTER_DEPTH] = {0};
static uint8_t index = 0;
uint16_t sum = 0;
buf[index++] = new_val;
if(index >= FILTER_DEPTH) index = 0;
for(int i=0; i<FILTER_DEPTH; i++) {
sum += buf[i];
}
return (uint8_t)(sum/FILTER_DEPTH);
}
5. 系统测试与优化
5.1 通信压力测试
搭建测试环境:
- 主从机间距80米
- 波特率1Mbps
- 持续发送随机数据包
测试结果:
| 测试项目 | 指标要求 | 实测结果 |
|---|---|---|
| 误码率 | <0.01% | 0.0027% |
| 最大延迟 | <10ms | 4.8ms |
| 吞吐量 | >800帧/秒 | 920帧/秒 |
| 连续工作时间 | 72小时 | 168小时无异常 |
5.2 控制精度优化
通过以下措施将控制周期从100ms压缩到20ms:
- 优化CAN报文处理流程,采用DMA传输
- 将控制算法从浮点运算改为定点运算(Q15格式)
- 预编译常用查询表,减少实时计算量
- 使用__attribute__((section(".ccmram")))将关键代码放入CCM RAM
定时器中断配置示例:
c复制void TIM3_IRQHandler(void) {
static uint32_t counter = 0;
if(__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE) != RESET) {
__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_UPDATE);
if(++counter >= 5) { // 20ms控制周期
counter = 0;
Control_Task();
}
}
}
6. 现场部署经验
在三个不同工厂部署后总结的关键经验:
- 接地处理:
- 所有设备单点接地,接地电阻<4Ω
- CAN屏蔽层在控制器端接地
- 避免形成接地环路
- 布线规范:
- 总线拓扑采用直线型,避免星型连接
- 分支长度不超过30cm
- 接头使用符合ISO11898标准的9针D-Sub
- 参数配置:
- 采样点设置在75%-80%位时间
- 同步跳转宽度设为1个时间量
- 重同步补偿范围±4个时间量
实测发现:当总线负载超过70%时,需要将报文优先级细分。我们将报警信息设为最高优先级(ID最小),参数同步设为中等,状态查询设为最低。