基于STM32F105系列使用CAN总线实现双机通信代码
基于STM32F105系列使用CAN总线实现双机通信代码,包含初始化、发送和接收功能。这里使用标准外设库,并假设使用CAN1。
1. CAN总线初始化
#include"stm32f10x.h"#include"stm32f10x_can.h"#include"stm32f10x_gpio.h"#include"stm32f10x_rcc.h"#include"misc.h"// CAN初始化结构体CAN_InitTypeDef CAN_InitStructure;CAN_FilterInitTypeDef CAN_FilterInitStructure;CanTxMsg TxMessage;CanRxMsg RxMessage;voidCAN_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;// 使能GPIO和CAN时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);// 配置CAN引脚: PA11->RX, PA12->TXGPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;// TXGPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;// 推挽复用输出GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;// RXGPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;// 上拉输入GPIO_Init(GPIOA,&GPIO_InitStructure);}voidCAN_NVIC_Config(void){NVIC_InitTypeDef NVIC_InitStructure;// 配置CAN接收中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);}voidCAN_Mode_Config(void){CAN_DeInit(CAN1);CAN_StructInit(&CAN_InitStructure);// CAN工作模式配置CAN_InitStructure.CAN_TTCM=DISABLE;// 禁止时间触发通信模式CAN_InitStructure.CAN_ABOM=DISABLE;// 禁止自动离线管理CAN_InitStructure.CAN_AWUM=DISABLE;// 禁止自动唤醒模式CAN_InitStructure.CAN_NART=DISABLE;// 禁止自动重传CAN_InitStructure.CAN_RFLM=DISABLE;// 禁止FIFO锁定CAN_InitStructure.CAN_TXFP=DISABLE;// 禁止发送FIFO优先级// 配置波特率// CAN波特率 = APB1时钟 / ((CAN_BS1 + CAN_BS2 + 1) * CAN_Prescaler)// 假设APB1时钟为36MHz,波特率设为500kbpsCAN_InitStructure.CAN_BS1=CAN_BS1_9tq;// 时间段1CAN_InitStructure.CAN_BS2=CAN_BS2_4tq;// 时间段2CAN_InitStructure.CAN_Prescaler=6;// 分频系数// 总时间片 = 1 + 9 + 4 = 14// 波特率 = 36MHz / (14 * 6) = 428.57kHz (接近500k)CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;// 正常工作模式CAN_Init(CAN1,&CAN_InitStructure);// 配置CAN过滤器CAN_FilterInitStructure.CAN_FilterNumber=0;// 使用过滤器0CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;// 掩码模式CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;// 32位模式CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 要过滤的ID高位CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// 要过滤的ID低位CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;// 掩码高位CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 掩码低位CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 关联到FIFO0CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 启用过滤器CAN_FilterInit(&CAN_FilterInitStructure);// 使能CAN接收中断CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);}2. CAN数据发送函数
uint8_tCAN_Send_Msg(uint8_t*msg,uint8_tlen,uint32_tid){uint8_ti=0;uint8_ttransmit_mailbox=0;TxMessage.StdId=id;// 标准IDTxMessage.ExtId=0x00;// 扩展IDTxMessage.IDE=CAN_Id_Standard;// 标准帧TxMessage.RTR=CAN_RTR_Data;// 数据帧TxMessage.DLC=len;// 数据长度(最大8字节)// 填充数据for(i=0;i<len;i++){TxMessage.Data[i]=msg[i];}// 发送数据transmit_mailbox=CAN_Transmit(CAN1,&TxMessage);// 等待发送完成i=0;while((CAN_TransmitStatus(CAN1,transmit_mailbox)!=CANTXOK)&&(i<0xFF)){i++;}if(i>=0xFF){return1;// 发送失败}return0;// 发送成功}3. CAN数据接收中断服务函数
voidUSB_LP_CAN1_RX0_IRQHandler(void){staticuint8_treceive_buffer[8];if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)!=RESET){// 读取接收到的数据CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);// 清除中断标志CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);// 处理接收到的数据if(RxMessage.IDE==CAN_Id_Standard){uint8_ti;// 复制接收到的数据for(i=0;i<RxMessage.DLC;i++){receive_buffer[i]=RxMessage.Data[i];}// 在这里处理接收到的数据// 例如:将数据发送到串口或进行其他处理// Process_Received_Data(receive_buffer, RxMessage.DLC, RxMessage.StdId);}}}4. 主函数示例
intmain(void){uint8_tsend_data[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};uint32_tmessage_id=0x123;// CAN消息ID// 初始化系统时钟SystemInit();// 配置GPIOCAN_GPIO_Config();// 配置NVIC中断CAN_NVIC_Config();// 配置CAN模式CAN_Mode_Config();// 主循环while(1){// 每隔1秒发送一次数据Delay(1000);// 自定义延时函数// 发送CAN消息CAN_Send_Msg(send_data,8,message_id);// 可以在这里添加其他处理逻辑}}参考代码 stm32f105系列使用can总线实现双机通信源代码www.youwenfan.com/contentcsv/70917.html
5. 双机通信配置说明
设备A配置(发送设备):
// 设置设备A的ID为0x100uint32_tdevice_a_id=0x100;设备B配置(接收设备):
// 配置过滤器只接收来自设备A的消息CAN_FilterInitStructure.CAN_FilterIdHigh=0x0100<<5;// ID高16位CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;// ID低16位CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;// 掩码高位CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;// 掩码低位6. 完整的工程配置步骤
硬件连接:
- CAN_H 连接 CAN_H
- CAN_L 连接 CAN_L
- 两个设备的GND相连
- 在总线的两端接120Ω终端电阻
软件配置:
// 波特率计算// 假设系统时钟为72MHz,APB1时钟为36MHz// 500kbps配置:BS1=9, BS2=4, Prescaler=6// 1Mbps配置:BS1=9, BS2=4, Prescaler=3编译和下载:
- 使用Keil MDK或STM32CubeIDE
- 确保包含正确的头文件
- 配置正确的系统时钟
注意事项
- 终端电阻:必须在CAN总线的两端各接一个120Ω的终端电阻
- 波特率:两个设备的波特率必须相同
- 中断优先级:根据实际应用需求合理配置中断优先级
- 错误处理:在实际应用中应添加错误检测和重发机制
- ID冲突:确保每个设备的CAN ID唯一,避免冲突
