一、介绍CAN运用与汽车计算机系统和嵌入式公用控制局域网的标准总线。CAN不是以时钟信号来同步的,它是一种异步通讯,只具有CAN_H,CAN_L两条信号,共同构成一组差分信号线,以差分信号的形式进行通讯。1、闭环总线网络特点:高速,短距离。总线最大长度40m, 通讯速度最高位1Mbps,要求总线两端各一个120欧姆的电阻。2、开环总线网络特点:低速、远距离最大传输距离1Km,最高通讯速率为125kbps,两根总线式独立的,不形成闭环,要求每根总线上各串联一个2.2K欧姆的电阻。CAN通讯点由一个CAN控制器及CAN收发器组成,控制器与收发器通过CAN_Tx,CAN_Rx信号线连接,收发器与CAN总线之间使用CAN_H,CAN_L信号线连接。其中CAN_Tx及CAN_Rx使用普通的类似与TTL逻辑信号,而CAN_H,CAN_L是一对差分信号线。3、CAN的四种模式各个工作模式介绍如下: 正常模式正常模式下就是一个正常的 CAN 节点,可以向总线发送数据和接收数据。 静默模式静默模式下,它自己的输出端的逻辑 0 数据会直接传输到它自己的输入端,逻辑1 可以被发送到总线,所以它不能向总线发送显性位(逻辑 0),只能发送隐性位(逻 辑 1)。输入端可以从总线接收内容。由于它只可发送的隐性位不会强制影响总线的状态,所以把它称为静默模式。这种模式一般用于监测,它可以用于分析总线上的流量,但又不会因为发送显性位而影响总线。 回环模式回环模式下,它自己的输出端的所有内容都直接传输到自己的输入端,输出端的内容同时也会被传输到总线上,即也可使用总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。使用回环模式可以进行自检。 回环静默模式回环静默模式是以上两种模式的结合,自己的输出端的所有内容都直接传输到自己的输入端,并且不会向总线发送显性位影响总线,不能通过总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。这种方式可以在“热自检”时使用,即自我检查的时候,不会干扰总线。4、STM32 CAN框架5、筛选器图 24-5 中的 CAN 外设框图,在标号处的是 CAN 外设的验收筛选器,一共有 28 个筛选器组,每个筛选器组有 2 个寄存器,CAN1 和 CAN2 共用的筛选器的。在 CAN 协议中,消息的标识符与节点地址无关,但与消息内容有关。因此,发送节点将报文广播给所有接收器时,接收节点会根据报文标识符的值来确定软件是否需要该消息,为了简化软件的工作,STM32 的 CAN 外设接收报文前会先使用验收筛选器检查,只接收需要的报文到 FIFO 中。过滤的方法分为以下两种模式:(1) 标识符列表模式,它把要接收报文的 ID 列成一个表,要求报文 ID 与列表中的某一个标识符完全相同才可以接收,可以理解为白名单管理。(2) 掩码模式,它把可接收报文 ID 的某几位作为列表,这几位被称为掩码,可以把它理解成关键字搜索,只要掩码(关键字)相同,就符合要求,报文就会被保存到接收 FIFO。二、遇到的问题1、发送单包数据,我想都非常简答,例子一大堆包括,demo。但是发送多包数据怎么处理?2、发送多包数据,网上基本上就两种说发*两个数据之间加延时*查询邮箱是否满了HAL_CAN_GetTxMailboxesFreeLevel()对比上面两种方法,为了效率我们选择第二种三、配置与代码 STM32F429直接上cubemx配置直接生成后,cubemx没有设置过滤器,需要自己添加,结合网上各资料总结代码如下intmain(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_CAN1_Init();/* USER CODE BEGIN 2 */CAN_Init();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */uint8_tTxData[100];for(uint8_ti=0;i100;i++)TxData[i]=i;CAN_SendStdMsg(hcan1,TxData,sizeof(TxData));HAL_Delay(100);}/* USER CODE END 3 */}bsp_can.c#include"bsp_can.h"/// CAN过滤器寄存器位宽类型定义typedefunion{__IOuint32_tvalue;struct{uint8_tREV:1;/// [0] :未使用uint8_tRTR:1;/// [1] : RTR(数据帧或远程帧标志位)uint8_tIDE:1;/// [2] : IDE(标准帧或扩展帧标志位)uint32_tEXID:18;/// [21:3] : 存放扩展帧IDuint16_tSTID:11;/// [31:22]: 存放标准帧ID}Sub;}CAN_FilterRegTypeDef;#defineCAN_BASE_ID0/// CAN标准ID,最大11位,也就是0x7FF#defineCAN_FILTER_MODE_MASK_ENABLE1/// CAN过滤器模式选择:=0:列表模式 =1:屏蔽模式#defineCAN_ID_TYPE_STD_ENABLE1/// CAN过滤ID类型选择:=1:标准ID,=0:扩展IDvoidCAN_Filter_Config(void){CAN_FilterTypeDef sFilterConfig;CAN_FilterRegTypeDef IDH={0};CAN_FilterRegTypeDef IDL={0};#ifCAN_ID_TYPE_STD_ENABLEIDH.Sub.STID=(CAN_BASE_ID16)0xFFFF;// 标准ID高16位IDL.Sub.STID=(CAN_BASE_ID0xFFFF);// 标准ID低16位#elseIDH.Sub.EXID=(CAN_BASE_ID16)0xFFFF;// 扩展ID高16位IDL.Sub.EXID=(CAN_BASE_ID0xFFFF);// 扩展ID低16位IDL.Sub.IDE=1;// 扩展帧标志位置位#endifsFilterConfig.FilterBank=0;// 设置过滤器组编号#ifCAN_FILTER_MODE_MASK_ENABLEsFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK;// 屏蔽位模式#elsesFilterConfig.FilterMode=CAN_FILTERMODE_IDLIST;// 列表模式#endifsFilterConfig.FilterScale=CAN_FILTERSCALE_32BIT;// 32位宽sFilterConfig.FilterIdHigh=IDH.value;// 标识符寄存器一ID高十六位,放入扩展帧位sFilterConfig.FilterIdLow=IDL.value;// 标识符寄存器一ID低十六位,放入扩展帧位sFilterConfig.FilterMaskIdHigh=IDH.value;// 标识符寄存器二ID高十六位,放入扩展帧位sFilterConfig.FilterMaskIdLow=IDL.value;// 标识符寄存器二ID低十六位,放入扩展帧位sFilterConfig.FilterFIFOAssignment=CAN_RX_FIFO0;// 过滤器组关联到FIFO0sFilterConfig.FilterActivation=ENABLE;// 激活过滤器sFilterConfig.SlaveStartFilterBank=14;// 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效if(HAL_CAN_ConfigFilter(hcan1,sFilterConfig)!=HAL_OK){Error_Handler();}}voidCAN_Init(void){CAN_Filter_Config();HAL_CAN_Start(hcan1);HAL_CAN_ActivateNotification(hcan1,CAN_IT_RX_FIFO0_MSG_PENDING);// 使能CAN接收中断}voidHAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef*canHandle){staticCAN_RxPacketTypeDef packet;// CAN数据接收if(canHandle-Instance==hcan1.Instance){if(HAL_CAN_GetRxMessage(canHandle,CAN_RX_FIFO0,packet.hdr,packet.payload)==HAL_OK)// 获得接收到的数据头和数据{// printf("\r\n\r\n\r\n################### CAN RECV ###################\r\n");// printf("STID:0x%X\r\n",packet.hdr.StdId);// printf("EXID:0x%X\r\n",packet.hdr.ExtId);// printf("DLC :%d\r\n", packet.hdr.DLC);// printf("DATA:");// for(int i = 0; i packet.hdr.DLC; i++)// {// printf("0x%02X ", packet.payload[i]);// }HAL_CAN_ActivateNotification(canHandle,CAN_IT_RX_FIFO0_MSG_PENDING);// 再次使能FIFO0接收中断}}}uint8_tCAN_Transmit(CAN_TxPacketTypeDef*packet){if(HAL_CAN_AddTxMessage(hcan1,packet-hdr,packet-payload,packet-mailbox)!=HAL_OK)return1;return0;}CAN_TxHeaderTypeDef TxMeg;uint16_tTimsRepeat;uint8_tCAN_SendStdMsg(CAN_HandleTypeDef*__hcan,uint8_t*pData,uint16_tLen){uint16_tSendCNT=0;