1.5 Cubmx_STM32 CAN通讯,多包数据收发送的处理

一、遇到的问题1、发送单包数据,我想都非常简答,例子一大堆包括,demo。但是发送多包数据怎么处理?2、发送多包数据,网上基本上就两种说发*两个数据之间加延时*查询邮箱是否满了HAL_CAN_GetTxMailboxesFreeLevel()对比上面两种方法,为了效率我们选择第二种二、配置与代码直接上cubemx配置直接生成后,cubemx没有设置过滤器,需要自己添加,结合网上各资料总结代码如下int main(void){ /* USER CODE BEGIN 1 */
摘要由CSDN通过智能技术生成

一、介绍

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
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您提供一个简单的CAN接数据处理程序,如下所示: ```c #include "stm32f10x.h" #include "stm32f10x_can.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" GPIO_InitTypeDef GPIO_InitStructure; CAN_InitTypeDef CAN_InitStructure; CAN_FilterInitTypeDef CAN_FilterInitStructure; CanRxMsg RxMessage; void GPIO_Configuration(void); void CAN_Configuration(void); void NVIC_Configuration(void); int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); GPIO_Configuration(); CAN_Configuration(); NVIC_Configuration(); while (1) { if (CAN_MessagePending(CAN1, CAN_FIFO0) != 0) { CAN_Receive(CAN1, CAN_FIFO0, &RxMessage); if (RxMessage.StdId == 0xB4 && RxMessage.IDE == CAN_ID_STD && RxMessage.DLC == 8) { if (RxMessage.Data[0] == 0x00 && RxMessage.Data[1] == 0x00 && RxMessage.Data[2] == 0x00 && RxMessage.Data[3] == 0x01 && RxMessage.Data[4] == 0x00 && RxMessage.Data[5] == 0x00 && RxMessage.Data[6] == 0x00 && RxMessage.Data[7] == 0x00) { GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); } else { GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); } } } } } void GPIO_Configuration(void) { GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); } void CAN_Configuration(void) { CAN_DeInit(CAN1); 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; CAN_InitStructure.CAN_TXFP = DISABLE; CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; CAN_InitStructure.CAN_BS1 = CAN_BS1_4tq; CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq; CAN_InitStructure.CAN_Prescaler = 8; CAN_Init(CAN1, &CAN_InitStructure); CAN_FilterInitStructure.CAN_FilterNumber = 0; CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterIdLow = 0x00B4 << 5; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x07FF << 5; CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0; CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; CAN_FilterInit(&CAN_FilterInitStructure); } void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; 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); CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); } void USB_LP_CAN1_RX0_IRQHandler(void) { if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) { CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0); } } ``` 这个程序可以在PA0引脚上输出CAN接到的数据是否为"00 00 00 01 00 00 00 00",您可以在程序中修改GPIO配置,以便在PA0引脚上输出高电平或低电平。如果您需要修改CAN波特率或帧ID,可以在程序中修改CAN的初始化和滤波器配置。希望这个程序可以帮到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值