CAN总线学习笔记 | STM32CubeMX配置CAN环回测试
创始人
2024-03-25 00:34:40
0

CAN基础知识介绍文中介绍了CAN协议的基础知识,以及STM32F4芯片的CAN控制器相关知识,下面将通过实例,利用STM32CubeMX图形化配置工具,来实现CAN通讯的环回测试

一、STM32CubeMX配置

  • CAN是挂载在APB1总线上,设置PCLK1时钟频率到最大45MHz

在这里插入图片描述

  • 激活CAN1,配置位时序参数,其他基本参数以及工作模式(此处设置为Loopback环回模式

在这里插入图片描述

CAN波特率的计算公式:只需要知道BS1和BS2的设置,以及APB1的时钟频率,就可以方便的计算出波特率。比如设置TS1=8、TS2=6和BRP=6,在APB1频率为45Mhz的条件下,即可得到CAN通信的波特率=45000/6/(8+6+1)=500Kbps
在这里插入图片描述

  • 激活USART1作为调试串口,配置相关LED对应的GPIO引脚作为指示灯

二、MDK-ARM编程

2.1 几个重要的结构体

  • CAN 初始化结构体:此结构体内容,可由STM32CubeMX工具进行配置
typedef struct
{uint32_t Prescaler;  					/* 配置 CAN 外设的时钟分频,可设置为 1-1024*/uint32_t Mode;       					/* 配置 CAN 的工作模式,回环或正常模式 */uint32_t SyncJumpWidth;  				/* 配置 SJW 极限值 */uint32_t TimeSeg1;   					/* 配置 BS1 段长度 */uint32_t TimeSeg2;   					/* 配置 BS2 段长度 */FunctionalState TimeTriggeredMode;   	/* 是否使能 TTCM 时间触发功能 */FunctionalState AutoBusOff;     		/* 是否使能 ABOM 自动离线管理功能 */FunctionalState AutoWakeUp;   		/* 是否使能 AWUM 自动唤醒功能 */FunctionalState AutoRetransmission;  	/* 是否使能 NART 自动重传功能 */FunctionalState ReceiveFifoLocked;   	/* 是否使能 RFLM 锁定 FIFO 功能 */FunctionalState TransmitFifoPriority;	/* 配置 TXFP 报文优先级的判定方法 */
} CAN_InitTypeDef;
  • 发送及接收头结构体:主要用于构造发送报文,以及接收报文。收发发文时,需要自定义头结构体变量
typedef struct
{uint32_t StdId;    			/* 存储报文的标准标识符 11 位,0-0x7FF. */uint32_t ExtId;    			/* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */uint32_t IDE;     			/* 存储 IDE 扩展标志 */uint32_t RTR;    				/* 存储 RTR 远程帧标志 */uint32_t DLC;    				/* 存储报文数据段的长度,0-8 */FunctionalState TransmitGlobalTime; 
} CAN_TxHeaderTypeDef;typedef struct
{uint32_t StdId;    			/* 存储报文的标准标识符 11 位,0-0x7FF. */uint32_t ExtId;    			/* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF. */uint32_t IDE;     			/* 存储 IDE 扩展标志 */uint32_t RTR;      			/* 存储 RTR 远程帧标志 */uint32_t DLC;     			/* 存储报文数据段的长度,0-8 */uint32_t Timestamp; uint32_t FilterMatchIndex; 
} CAN_RxHeaderTypeDef;
  • 过滤器结构体:STM32CubeMX不会初始化过滤器的相关内容,需要自己添加
typedef struct
{uint32_t FilterIdHigh;         	/*CAN_FxR1 寄存器的高 16 位 */uint32_t FilterIdLow;         	/*CAN_FxR1 寄存器的低 16 位 */uint32_t FilterMaskIdHigh;   		/*CAN_FxR2 寄存器的高 16 位 */uint32_t FilterMaskIdLow;    		/*CAN_FxR2 寄存器的低 16 位 */uint32_t FilterFIFOAssignment;  	/* 设置经过筛选后数据存储到哪个接收 FIFO */uint32_t FilterBank;            	/* 筛选器编号,范围 0-27,数据手册上说0-27是CAN1/CAN2共享,但是实测发现并不是这样,CAN1是0-13,CAN2是14-27 */uint32_t FilterMode;            	/* 筛选器模式 */uint32_t FilterScale;           	/* 设置筛选器的尺度 */uint32_t FilterActivation;      	/* 是否使能本筛选器 */uint32_t SlaveStartFilterBank;  	/* CAN2起始过滤器组 */
} CAN_FilterTypeDef;

4.2 程序编写

  • 生成工程后,打开can.c文件,可见STM32CubeMX已经对位时序参数、其他基本参数以及工作模式进行了初始化。但是并没有初始化过滤器的相关内容,因此需要我们自己添加,并在CAN初始化时调用
//下面的设置只使能了FIFO0,并不过滤任何消息
void CAN_Filter_Config(){CAN_FilterTypeDef sFilterConfig;sFilterConfig.FilterBank = 0;						//筛选器编号, CAN1是0-13, CAN2是14-27sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;	//采用掩码模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;	//设置筛选器的尺度, 采用32位sFilterConfig.FilterIdHigh = 0X0000;				//过滤器ID高16位,即CAN_FxR1寄存器的高16位sFilterConfig.FilterIdLow = 0X0000;					//过滤器ID低16位,即CAN_FxR1寄存器的低16位sFilterConfig.FilterMaskIdHigh = 0X0000;			//过滤器掩码高16位,即CAN_FxR2寄存器的高16位sFilterConfig.FilterMaskIdLow = 0X0000;				//过滤器掩码低16位,即CAN_FxR2寄存器的低16位sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;	//设置经过筛选后数据存储到哪个接收FIFOsFilterConfig.FilterActivation = ENABLE;			//是否使能本筛选器sFilterConfig.SlaveStartFilterBank = 14;			//指定为CAN1分配多少个滤波器组if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK){Error_Handler();}
}
  • 编写发送和接收数据函数:此处将格式固定为标准数据帧,ID为12
uint8_t CAN1_Send_Msg(uint8_t *msg, uint8_t len){uint16_t i = 0;uint32_t txMailBox;uint8_t send_buf[8];txHeader.StdId = 12;txHeader.ExtId = 12;txHeader.IDE = CAN_ID_STD;txHeader.RTR = CAN_RTR_DATA;txHeader.DLC = len;for(i = 0; i < len; i++)send_buf[i] = msg[i];if(HAL_CAN_AddTxMessage(&hcan1, &txHeader, send_buf, &txMailBox) != HAL_OK)return 1;	return 0;
}uint8_t CAN1_Recv_Msg(uint8_t *buf){uint16_t i = 0;	HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, buf);if(rxHeader.IDE == CAN_ID_STD)printf("StdId ID: %d\r\n", rxHeader.StdId);elseprintf("ExtId ID: %d\r\n", rxHeader.ExtId);printf("CAN IDE: %d\r\n", rxHeader.IDE);printf("CAN RTR: %d\r\n", rxHeader.RTR);printf("CAN DLC: %d\r\n", rxHeader.DLC);printf("Recv Data: ");for(i = 0; i < rxHeader.DLC; i++)printf("%c",buf[i]);printf("\n");return rxHeader.DLC;
}
  • 默认Cubemx生成的代码并没有can start,没有调用HAL_CAN_Start(&hcan1) 来使能CAN,因此需要在CAN初始化代码中添加
void MX_CAN1_Init(void){....../* USER CODE BEGIN CAN1_Init 2 */CAN_Filter_Config();HAL_CAN_Start(&hcan1);	/* USER CODE END CAN1_Init 2 */
}
  • 主函数main.c中,代码如下
int main(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_CAN1_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */uint8_t ret,i;printf("CAN Testing....!\r\n");uint8_t txdata[8] = {76, 79, 79, 80, 66, 65, 67, 75};uint8_t rxdata[8];/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);HAL_Delay(1000);printf("Start Send data...\r\n");ret = CAN1_Send_Msg(txdata, 8);if(ret == 0)printf("CAN Send success!\r\n");else printf("CAN Send failed!\r\n");CAN1_Recv_Msg(rxdata);	printf("+++++++++++++++++++++++++++++++\r\n");/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

三、下载测试

编译无误后下载到开发板,可以看到系统运行时D1指示灯不断闪烁,串口不断的打印CAN环回测试的数据

在这里插入图片描述

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...