目录
[1. 差分信号](#1. 差分信号)
[2. CAN收发器](#2. CAN收发器)
[3. CAN帧结构](#3. CAN帧结构)
[4. CAN波特率设置](#4. CAN波特率设置)
[5. 标识符筛选](#5. 标识符筛选)
一、CAN总线
CAN(Controller Area Network,控制器局域网络)是一种用于车辆、工业自动化等领域的通信协议,由德国BOSCH公司开发。CAN总线通过两条差分信号线(CAN-H和CAN-L)进行数据传输,具有较强的抗干扰能力和高效的通信性能。
1. 差分信号
CAN总线的通信是通过CAN-H和CAN-L两条信号线之间的电位差来实现的。总线电平分为两种逻辑状态:
- 显性电平:表示逻辑"0",此时CAN-H电压约为3.5V,CAN-L电压约为1.5V。
- 隐性电平:表示逻辑"1",此时CAN-H和CAN-L电压均为约2.5V,差分电压近似为零。
2. CAN收发器
在本实验中,使用了SN65HVD230作为CAN收发器,其主要作用是将微控制器的TTL电平转换为CAN总线电平。CAN收发器的主要引脚包括:
- D(发送):连接到微控制器的CAN_TX引脚。
- R(接收):连接到微控制器的CAN_RX引脚。
- CAN-H 和 CAN-L:连接到CAN总线。
3. CAN帧结构
CAN通信的帧结构主要分为以下几种类型:
- 数据帧:携带实际数据的帧,由7个域组成,包括帧开始、仲裁域、控制域、数据域、CRC域、ACK域和帧结束。
- 远程帧:用于请求发送具有相同识别符的数据帧。
- 错误帧:当检测到总线错误时发送的帧,由错误标志和错误界定组成。
- 过载帧:用于延迟下一帧的发送,通常在接收器还未准备好时发送。
4. CAN波特率设置
CAN波特率设置涉及到多个参数,包括同步段(SYNC_SEG)、位段1(BS1)、位段2(BS2)和同步跳转宽度(SJW)。波特率的计算公式为:
例如,在系统时钟为72MHz,APB1时钟为36MHz,Prescaler为9,BS1为4,BS2为3,SJW为1的情况下,CAN波特率计算如下:
5. 标识符筛选
在CAN通信中,接收节点根据帧的标识符(ID)来判断是否接收该帧。通过设置过滤器,接收器可以选择性地接收所需的数据帧,而忽略无关的帧。
二、CubeMX配置
确保cubemx最新版本,cubemx无法更新,退出使用管理员权限
打开调试
选择高速时钟
配置时钟树
配置LED引脚PD5
配置CAN
接收中断配置
打开串口4 和 PD5LED
生成工程
三、Keil代码
1.can发送数据
main.c
uint8_t TxData[8] = {0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x10};
自定义发送函数
// 发送 CAN 消息函数
void CAN_SendMessage(uint32_t id, uint8_t *data, uint8_t len) {
CAN_TxHeaderTypeDef TxHeader; // 定义 CAN 发送头
uint32_t TxMailbox; // 邮箱标识
TxHeader.DLC = len; // 数据长度,最大 8 字节
TxHeader.StdId = id; // 标准标识符
TxHeader.IDE = CAN_ID_STD; // 使用标准 ID
TxHeader.RTR = CAN_RTR_DATA; // 数据帧
TxHeader.TransmitGlobalTime = DISABLE; // 关闭全局时间戳
// 发送 CAN 消息,使用 HAL 库提供的函数
if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailbox) != HAL_OK) {
// 如果发送失败,调用错误处理函数
Error_Handler();
}
}
while循环中
CAN_SendMessage(0x02,TxData,8);
HAL_Delay(1000);
CAN_SendMessage(0x01,TxData,8);
can.c中配置过滤器启动CAN外设和中断 并在CAN初始化调用函数
void CAN_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
/*配置CAN过滤器*/
sFilterConfig.FilterBank = 0; //过滤器0
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000; //32位ID
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000; //32位MASK
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;//过滤器0关联到FIFO0
sFilterConfig.FilterActivation = ENABLE; //激活滤波器0
sFilterConfig.SlaveStartFilterBank = 14;
if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器
{
Error_Handler();
}
if(HAL_CAN_Start(&hcan) != HAL_OK)//打开can
{
Error_Handler();
}
if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)//开启接受邮邮箱0挂起中断
{
Error_Handler();
}
}
Can分析仪显示数据
2.中断接收数据函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
CAN_RxHeaderTypeDef RxHeader; // CAN 接收头
uint8_t RxData[8]; // 数据缓存,最大 8 字节
// 获取接收到的消息
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) {
// 如果接收失败,直接返回(避免执行后续无效操作)
Error_Handler();
return;
}
// 发送接收到的数据通过 UART
if (HAL_UART_Transmit(&huart4, RxData, RxHeader.DLC, 0xFFFF) != HAL_OK) {
// UART 传输失败的错误处理
Error_Handler();
}
// 切换 GPIO 引脚状态,控制 LED 状态改变(指示接收到消息)
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_5);
}
发送
接收
例程:
链接: https://pan.baidu.com/s/1s4_dWpP1but54HLcP7herg?pwd=sahk 提取码: sahk