CAN通讯的学习(三)

前言
前面已经学习完了CAN控制器的基本原理以及通信机制,这次我们来具体学习一下它的寄存器配置以及上手实践一次,学习资料均来自正点原子
寄存器部分
主控制器寄存器CAN_MCR

 这个寄存器用于负责CAN工作模式的配置(见第二篇),其起作用的位为第0位INRQ
软件对该位清零就可以使CAN从初始化模式进入正常工作模式
当CAN在接收端检测到连续的11个隐性位后CAN将完成同步,此时便可以开始正常的通信,这个时候硬件会自动将CAN_MSR寄存器(CAN主状态寄存器)中的INAK位置0
同样地,当软件对该位置1就可以使CAN进入初始化模式
一旦CAN上一个活动结束,CAN就会进入该模式,此时CAN_MSR中的INAK置1
一个正常的工作流程应该为:先将INRQ置1进入初始化模式,此时对各种寄存器进行配置,(例如通过配置CANBTR配置总线波特率),等到配置完成后将INRQ置0进入正常工作模式
位时序寄存器CAN_BTR

该寄存器用于设置分频、TBS1、TBS2、TSJW来控制波特率和配置CAN的测试模式
由上表不难看出,通过配置SILM&LBKM来配置不同的测试模式用于测试CAN的工作情况,剩下的位除了保留位外均是用于配置时序长度,注意在软件配置时要进行’+1‘操作
要注意的是位[0:9]用于配置分频器,这直接影响了最终的Tq
**标识符寄存器CAN(T/R)IxR
这个寄存器用于存放(待发送/接收)的报文ID、扩展ID、IDE位以及RTR位

 

作为发送端来说
寄存器用于配置不同邮箱内的报文信息,因此x的范围是1~3
作为接收端来说
寄存器用于配置不同FIFO内的报文信息,因此x的范围是1~2
数据长度和时间戳寄存器CAN(T/R)DTxR

该寄存器只需要配置DLC即可,控制的是帧的数据段的长度(0~8Byte)
高低位数据寄存器CAN(T/R)D(H/L)xR
低位寄存器就是用于存储低16位的数据,没什么好介绍的


下面重点看一下高字节数据寄存器

最值得留意的就是当CAN工作在时间戳模式下时DATA7和DATA6将不再代表数据而是代表时间戳
过滤器模式寄存器CAN_FMxR

这个寄存器很简单,通过配置不同位的数值来配置过滤器模式,每组过滤器严格对应自己的位,要注意的是不同型号的主控包含的寄存器组数量不同,例如F103ZET6是用不了FBM14组以上的寄存器的
过滤器位宽寄存器CAN_FSxR

这个在第二篇有提及,过滤器可以设置为16位和32位的数据
过滤器FIFO关联寄存器CAN_FFAxR



这个寄存器用于设定经过滤波器后的有效报文要去往的FIFO是FIFO0还是FIFO1
要注意的是该寄存器的配置也要在初始化模式下配置
过滤器激活寄存器CAN_FAxR

在前面也有提及,映射关系的不同决定了不同的滤波工作模式
搭建工程
这里我想提一个可能比较简单但是我个人理解了很久的一点:当我们在配置过滤器时如何取得扩展帧高16位的数据,教程给出的是>>13位,但以我的理解不应该是>>16位吗,后来翻看前面的笔记我才明白一个扩展帧最多才29位,并不是32位,因此只需要>>13位即可QAQ
现在我们来通过CUBEMX创建工程,首先配置时钟,拉满即可

此时CAN的时钟为36M,接下来将CAN开启,配置波特率相关参数

其他不需要开启的功能全部DISABLE即可,然后就可以创建工程

代码部分

CAN.c

/**  
  ******************************************************************************  * File Name          : CAN.c  * Description        : This file provides code for the configuration  *                      of the CAN instances.  ******************************************************************************  * @attention  *  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.  * All rights reserved.</center></h2>  *  * This software component is licensed by ST under BSD 3-Clause license,  * the "License"; You may not use this file except in compliance with the  * License. You may obtain a copy of the License at:  *                        opensource.org/licenses/BSD-3-Clause  *  ******************************************************************************  */  
/* Includes ------------------------------------------------------------------*/  
#include "can.h"  
  
/* USER CODE BEGIN 0 */  
  
/* USER CODE END 0 */  
  
CAN_HandleTypeDef hcan;  
  
/* CAN init function */  
void MX_CAN_Init(void)  
{  
  
  hcan.Instance = CAN1;  
  hcan.Init.Prescaler = 4;  
  hcan.Init.Mode = CAN_MODE_LOOPBACK; //进入回环模式测试  
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;  
  hcan.Init.TimeSeg1 = CAN_BS1_9TQ;  
  hcan.Init.TimeSeg2 = CAN_BS2_8TQ;  
  hcan.Init.TimeTriggeredMode = DISABLE;  
  hcan.Init.AutoBusOff = DISABLE;  
  hcan.Init.AutoWakeUp = DISABLE;  
  hcan.Init.AutoRetransmission = DISABLE;  
  hcan.Init.ReceiveFifoLocked = DISABLE;  
  hcan.Init.TransmitFifoPriority = DISABLE;  
  if (HAL_CAN_Init(&hcan) != HAL_OK)  
  {  
    Error_Handler();  
  }  
  //过滤器的一些参数配置  
  CAN_FilterTypeDef canFilter_Config;  
  canFilter_Config.FilterMode = CAN_FILTERMODE_IDMASK;  //屏蔽模式  
  canFilter_Config.FilterScale = CAN_FILTERSCALE_32BIT; //32位模式  
  //暂时不启动过滤操作  
  canFilter_Config.FilterIdHigh = 0;  
  canFilter_Config.FilterIdLow = 0;  
  canFilter_Config.FilterMaskIdHigh = 0;  
  canFilter_Config.FilterMaskIdLow = 0;  
  //配置对应的过滤器组以及FIFO组  
  canFilter_Config.FilterBank = 0;  
  canFilter_Config.FilterFIFOAssignment = CAN_FilterFIFO0;  
  //配置从过滤器组以及开启过滤器  
  canFilter_Config.FilterActivation = CAN_FILTER_ENABLE;  
  canFilter_Config.SlaveStartFilterBank = 14;  
  //过滤器组初始化以及CAN的开启  
  HAL_CAN_ConfigFilter(&hcan,&canFilter_Config);  
  HAL_CAN_Start(&hcan);  
}  
  
void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)  
{  
  
  GPIO_InitTypeDef GPIO_InitStruct = {0};  
  if(canHandle->Instance==CAN1)  
  {  
  /* USER CODE BEGIN CAN1_MspInit 0 */  
  
  /* USER CODE END CAN1_MspInit 0 */    /* CAN1 clock enable */    __HAL_RCC_CAN1_CLK_ENABLE();  
  
    __HAL_RCC_GPIOA_CLK_ENABLE();  
    /**CAN GPIO Configuration  
    PA11     ------> CAN_RX    PA12     ------> CAN_TX    */    GPIO_InitStruct.Pin = GPIO_PIN_11;  
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;  
    GPIO_InitStruct.Pull = GPIO_NOPULL;  
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  
  
    GPIO_InitStruct.Pin = GPIO_PIN_12;  
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;  
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;  
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  
  
  /* USER CODE BEGIN CAN1_MspInit 1 */  
  
  /* USER CODE END CAN1_MspInit 1 */  }  
}  
  
void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)  
{  
  
  if(canHandle->Instance==CAN1)  
  {  
  /* USER CODE BEGIN CAN1_MspDeInit 0 */  
  
  /* USER CODE END CAN1_MspDeInit 0 */    /* Peripheral clock disable */    __HAL_RCC_CAN1_CLK_DISABLE();  
  
    /**CAN GPIO Configuration  
    PA11     ------> CAN_RX    PA12     ------> CAN_TX    */    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);  
  
  /* USER CODE BEGIN CAN1_MspDeInit 1 */  
  
  /* USER CODE END CAN1_MspDeInit 1 */  }  
}  
  
/* USER CODE BEGIN 1 */  
CAN_TxHeaderTypeDef g_can1_txheader;  
CAN_RxHeaderTypeDef g_can1_rxheader;  
//CAN数据的发送  
void can_send_message(uint32_t id, uint8_t *buf, uint8_t len)  
{  
  uint32_t tx_mail = CAN_TX_MAILBOX0; //邮箱0  
  g_can1_txheader.ExtId = id; //配置ID  
  g_can1_txheader.DLC = len;  //配置长度  
  g_can1_txheader.IDE = CAN_ID_EXT; //配置为扩展帧  
  g_can1_txheader.RTR = CAN_RTR_DATA; //配置为数据帧  
  
  HAL_CAN_AddTxMessage(&hcan,&g_can1_txheader,buf,&tx_mail);  //发送数据  
  
  while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3); //邮箱未溢出  
}  
uint8_t can_receive_message(uint8_t *buf)  
{  
  if(HAL_CAN_GetRxFifoFillLevel(&hcan,CAN_RX_FIFO0) == 0) //FIFO未存储数据  
  {  
    return 0;  
  }  
  HAL_CAN_GetRxMessage(&hcan,CAN_RX_FIFO0,&g_can1_rxheader,buf);  //若FIFO有数据则接收  
  return g_can1_rxheader.DLC;  
}  
/* USER CODE END 1 */  
  
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

CAN.h

/**  
  ******************************************************************************  * File Name          : CAN.h  * Description        : This file provides code for the configuration  *                      of the CAN instances.  ******************************************************************************  * @attention  *  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.  * All rights reserved.</center></h2>  *  * This software component is licensed by ST under BSD 3-Clause license,  * the "License"; You may not use this file except in compliance with the  * License. You may obtain a copy of the License at:  *                        opensource.org/licenses/BSD-3-Clause  *  ******************************************************************************  *//* Define to prevent recursive inclusion -------------------------------------*/  
#ifndef __can_H  
#define __can_H  
#ifdef __cplusplus  
 extern "C" {  
#endif  
  
/* Includes ------------------------------------------------------------------*/  
#include "main.h"  
  
/* USER CODE BEGIN Includes */  
uint8_t can_receive_message(uint8_t *buf);  
void can_send_message(uint32_t id, uint8_t *buf, uint8_t len);  
/* USER CODE END Includes */  
  
extern CAN_HandleTypeDef hcan;  
  
/* USER CODE BEGIN Private defines */  
  
/* USER CODE END Private defines */  
  
void MX_CAN_Init(void);  
  
/* USER CODE BEGIN Prototypes */  
  
/* USER CODE END Prototypes */  
  
#ifdef __cplusplus  
}  
#endif  
#endif /*__ can_H */  
  
/**  
  * @}  */  
/**  
  * @}  */  
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

MAIN.c

/* USER CODE BEGIN Header */  
/**  
  ******************************************************************************  * @file           : main.c  * @brief          : Main program body  ******************************************************************************  * @attention  *  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.  * All rights reserved.</center></h2>  *  * This software component is licensed by ST under BSD 3-Clause license,  * the "License"; You may not use this file except in compliance with the  * License. You may obtain a copy of the License at:  *                        opensource.org/licenses/BSD-3-Clause  *  ******************************************************************************  *//* USER CODE END Header */  
/* Includes ------------------------------------------------------------------*/  
#include "main.h"  
#include "can.h"  
#include "usart.h"  
#include "gpio.h"  
  
/* Private includes ----------------------------------------------------------*/  
/* USER CODE BEGIN Includes */  
  
/* USER CODE END Includes */  
  
/* Private typedef -----------------------------------------------------------*/  
/* USER CODE BEGIN PTD */  
  
/* USER CODE END PTD */  
  
/* Private define ------------------------------------------------------------*/  
/* USER CODE BEGIN PD */  
/* USER CODE END PD */  
  
/* Private macro -------------------------------------------------------------*/  
/* USER CODE BEGIN PM */  
  
/* USER CODE END PM */  
  
/* Private variables ---------------------------------------------------------*/  
  
/* USER CODE BEGIN PV */  
  
/* USER CODE END PV */  
  
/* Private function prototypes -----------------------------------------------*/  
void SystemClock_Config(void);  
/* USER CODE BEGIN PFP */  
  
/* USER CODE END PFP */  
  
/* Private user code ---------------------------------------------------------*/  
/* USER CODE BEGIN 0 */  
  
/* USER CODE END 0 */  
  
/**  
  * @brief  The application entry point.  * @retval int  */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_CAN_Init();  
  MX_USART1_UART_Init();  
  /* USER CODE BEGIN 2 */  
  
  uint8_t can_buf[8] = "hello"; //can要发送的数据信息  
  uint8_t rec_len = 0;  //接收到的数据长度  
  uint8_t rec_buf[8]; //接收到的数据  
  /* USER CODE END 2 */  
  
  /* Infinite loop */  /* USER CODE BEGIN WHILE */  while (1)  
  {  
    /* USER CODE END WHILE */  
  
    /* USER CODE BEGIN 3 */    can_send_message(0x12345678,can_buf,8); //发送数据  
    rec_len = can_receive_message(rec_buf); //接收数据  
    if(rec_len)  
    {  
      for(uint8_t i = 0;i < rec_len;i++)  
      {  
        HAL_UART_Transmit(&huart1,&rec_buf[i],8,10000); //通过串口显示到串口助手上  
      }  
    }  
  }  
  /* USER CODE END 3 */  
}  
  
/**  
  * @brief System Clock Configuration  * @retval None  */void SystemClock_Config(void)  
{  
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};  
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};  
  
  /** Initializes the RCC Oscillators according to the specified parameters  
  * in the RCC_OscInitTypeDef structure.  */  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;  
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;  
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;  
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;  
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;  
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;  
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;  
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)  
  {  
    Error_Handler();  
  }  
  /** Initializes the CPU, AHB and APB buses clocks  
  */  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK  
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;  
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;  
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;  
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;  
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  
  
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)  
  {  
    Error_Handler();  
  }  
}  
  
/* USER CODE BEGIN 4 */  
  
/* USER CODE END 4 */  
  
/**  
  * @brief  This function is executed in case of error occurrence.  * @retval None  */void Error_Handler(void)  
{  
  /* USER CODE BEGIN Error_Handler_Debug */  
  /* User can add his own implementation to report the HAL error return state */  
  /* USER CODE END Error_Handler_Debug */}  
  
#ifdef  USE_FULL_ASSERT  
/**  
  * @brief  Reports the name of the source file and the source line number  *         where the assert_param error has occurred.  * @param  file: pointer to the source file name  * @param  line: assert_param error line source number  * @retval None  */void assert_failed(uint8_t *file, uint32_t line)  
{  
  /* USER CODE BEGIN 6 */  /* User can add his own implementation to report the file name and line number,     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */  /* USER CODE END 6 */}  
#endif /* USE_FULL_ASSERT */  
  
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

验证部分



此时串口已经可以发送数据 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值