赞
踩
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()
对比上面两种方法,为了效率我们选择第二种
直接上cubemx配置
直接生成后,cubemx没有设置过滤器,需要自己添加,结合网上各资料总结代码如下
int main(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_t TxData[100] ; for(uint8_t i=0;i<100;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过滤器寄存器位宽类型定义 typedef union { __IO uint32_t value; struct { uint8_t REV : 1; ///< [0] :未使用 uint8_t RTR : 1; ///< [1] : RTR(数据帧或远程帧标志位) uint8_t IDE : 1; ///< [2] : IDE(标准帧或扩展帧标志位) uint32_t EXID : 18; ///< [21:3] : 存放扩展帧ID uint16_t STID : 11; ///< [31:22]: 存放标准帧ID } Sub; } CAN_FilterRegTypeDef; #define CAN_BASE_ID 0 ///< CAN标准ID,最大11位,也就是0x7FF #define CAN_FILTER_MODE_MASK_ENABLE 1 ///< CAN过滤器模式选择:=0:列表模式 =1:屏蔽模式 #define CAN_ID_TYPE_STD_ENABLE 1 ///< CAN过滤ID类型选择:=1:标准ID,=0:扩展ID void CAN_Filter_Config(void) { CAN_FilterTypeDef sFilterConfig; CAN_FilterRegTypeDef IDH = { 0}; CAN_FilterRegTypeDef IDL = { 0}; #if CAN_ID_TYPE_STD_ENABLE IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF; // 标准ID高16位 IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF); // 标准ID低16位 #else IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF; // 扩展ID高16位 IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF); // 扩展ID低16位 IDL.Sub.IDE = 1; // 扩展帧标志位置位 #endif sFilterConfig.FilterBank = 0; // 设置过滤器组编号 #if CAN_FILTER_MODE_MASK_ENABLE sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 屏蔽位模式 #else sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 列表模式 #endif sFilterConfig.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; // 过滤器组关联到FIFO0 sFilterConfig.FilterActivation = ENABLE; // 激活过滤器 sFilterConfig.SlaveStartFilterBank = 14; // 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效 if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK) { Error_Handler(); } } void CAN_Init(void) { CAN_Filter_Config(); HAL_CAN_Start(&hcan1); HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // 使能CAN接收中断 } void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle) { static CAN_RxPacketTypeDef packet; // CAN数据接收 if (canHandle->Instance == hcan1.Instance) { if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &packet.hdr, packet.payload) == HAL_OK
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。