STM32CubeX开发日记---CAN通讯


前言

此篇为我个人工作时的学习笔记,其中包括STM32CubeX IDE的使用方法,以及STM32F405RGT6 CAN通讯的相关知识,和个人遇到的问题。

本次开发使用到的是基于STM32F405RGT6芯片的PCAN CAN卡的二次开发,通过ID筛选并转发,实现CAN网关功能。


一、STM32Cube IDE配置

1.新建项目File > new > STM32 project
2.在下面界面Series中选择芯片型号

在这里插入图片描述
3.配置SYS(烧录方式)
SYS > Debug > Serial Wire(我是用串口烧录的)
Timebase Source> SysTick(时基-系统时钟)
在这里插入图片描述
4.开启外设时钟
RCC > High Speed Clock (HSE) > Crystal/Ceramic Resonator
在这里插入图片描述
5.在Clock Configuration界面设置时钟分频
在这里插入图片描述
这里我使用的外部晶振频率8Mhz,所以最左边输入频率改为8,否则会引起CAN通讯位填充错误,具体原理有懂得大佬还请指教,最后输出的频率我定为低速时钟42Mhz,高速时钟为84Mhz,到此时钟部分设置完毕。

在这里插入图片描述
6.配置CAN节点,设置工作模式和波特率

  • 确定CAN1节点的引脚,我这里是复用了芯片的PB8和PB9引脚分别为RX和TX,STM32F405的正常CAN1引脚为PA10 PA11。
    捕获7.PNG
  • 按照原理图将PB8 PB9使能(要先进行引脚使能,Mode会自动打开,如果先“Activated”就会导致打开PA10 PA11,导致无法通讯)
    捕获6.PNG
  • 配置CAN通讯波特率
  • 波特率计算公式 :时钟频率/(TQ1+TQ2+SJW)=波特率,带入公式配置出500khz
  • 下面其他初始化配置暂时不用管
  • 打开中断 NVIC Setting > CAN1 R0 interrupt

7.上面配置完成,点击捕获8.PNG生成代码。

二、代码修改

1.CAN相关代码

can.c

#include "can.h"
#include <string.h>

/* USER CODE BEGIN 0 */
CAN_TxHeaderTypeDef   TxMessage1;        //GW_1
CAN_TxHeaderTypeDef   TxMessage2;        //GW_2
CAN_TxHeaderTypeDef   TxMessage3;        //GW_3
CAN_TxHeaderTypeDef   TxMessage4;        //GW_4

CAN_RxHeaderTypeDef   RxMessage1;
CAN_RxHeaderTypeDef   RxMessage2;

CAN_HandleTypeDef hcan1;
CAN_HandleTypeDef hcan2;

CAN_FilterTypeDef  CAN_FilterInitStructure1;
CAN_FilterTypeDef  CAN_FilterInitStructure2;

void MX_CAN1_Init(void)
{
  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 7;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_5TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_6TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CAN1_Init 2 */
	CAN_FilterInitStructure1.FilterActivation = ENABLE;//使能过滤器
	CAN_FilterInitStructure1.FilterBank = 1;//指定过滤器为1
	CAN_FilterInitStructure1.FilterMode = CAN_FILTERMODE_IDMASK;//指定过滤器为标识符屏蔽位模式
	CAN_FilterInitStructure1.FilterScale = CAN_FILTERSCALE_32BIT;//过滤器位宽为32位
	CAN_FilterInitStructure1.FilterFIFOAssignment = CAN_FILTER_FIFO0;//设定了指向过滤器的FIFO

	CAN_FilterInitStructure1.FilterIdHigh =0x0000 ;//要过滤的ID高位
	CAN_FilterInitStructure1.FilterIdLow = 0x0000;//要过滤的ID低位
	CAN_FilterInitStructure1.FilterMaskIdHigh = 0x0000;//过滤器屏蔽标识符的高16位值
	CAN_FilterInitStructure1.FilterMaskIdLow = 0x0000; //过滤器屏蔽标识符的低16位值

	HAL_CAN_ConfigFilter(&hcan1,&CAN_FilterInitStructure1);
}
static uint32_t HAL_RCC_CAN1_CLK_ENABLED=0;

void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(canHandle->Instance==CAN1)
  {
    HAL_RCC_CAN1_CLK_ENABLED++;
    if(HAL_RCC_CAN1_CLK_ENABLED==1){
      __HAL_RCC_CAN1_CLK_ENABLE();
    }
	__HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* CAN1 interrupt Init */
    HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
  }
  else if(canHandle->Instance==CAN2)
  {
    /* CAN2 clock enable */
    __HAL_RCC_CAN2_CLK_ENABLE();
    HAL_RCC_CAN1_CLK_ENABLED++;
    if(HAL_RCC_CAN1_CLK_ENABLED==1){
      __HAL_RCC_CAN1_CLK_ENABLE();
    }
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_CAN2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    /* CAN2 interrupt Init */
    HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn);  }
}
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_ENABLED--;
    if(HAL_RCC_CAN1_CLK_ENABLED==0){
      __HAL_RCC_CAN1_CLK_DISABLE();
    }

    /**CAN1 GPIO Configuration
    PB8     ------> CAN1_RX
    PB9     ------> CAN1_TX
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9);

    /* CAN1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
  /* USER CODE BEGIN CAN1_MspDeInit 1 */

  /* USER CODE END CAN1_MspDeInit 1 */
  }
  else if(canHandle->Instance==CAN2)
  {
  /* USER CODE BEGIN CAN2_MspDeInit 0 */

  /* USER CODE END CAN2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_CAN2_CLK_DISABLE();
    HAL_RCC_CAN1_CLK_ENABLED--;
    if(HAL_RCC_CAN1_CLK_ENABLED==0){
      __HAL_RCC_CAN1_CLK_DISABLE();
    }

    /**CAN2 GPIO Configuration
    PB5     ------> CAN2_RX
    PB6     ------> CAN2_TX
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_5|GPIO_PIN_6);

    /* CAN2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
  /* USER CODE BEGIN CAN2_MspDeInit 1 */

  /* USER CODE END CAN2_MspDeInit 1 */
  }
}

/* USER CODE END 1 */

can.h


#ifndef __CAN_H__
#define __CAN_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

extern CAN_HandleTypeDef hcan1;
extern CAN_HandleTypeDef hcan2;

extern CAN_TxHeaderTypeDef TxMessage1;
extern CAN_TxHeaderTypeDef TxMessage2;
extern CAN_TxHeaderTypeDef TxMessage3;
extern CAN_TxHeaderTypeDef TxMessage4;

extern CAN_RxHeaderTypeDef RxMessage1;
extern CAN_RxHeaderTypeDef RxMessage2;

typedef struct
{
	uint8_t Data[8];
}CAN_RecvMsg;
void MX_CAN1_Init(void);
void MX_CAN2_Init(void);
void CAN1_Config(void);
void CAN2_Config (void);
void CAN_TRANSMIT1(void);
void CAN_TRANSMIT2(void);
#ifdef __cplusplus
}
#endif

#endif 


2.主函数部分

main.c

#include "main.h"
#include "can.h"
#include "gpio.h"

uint8_t               TxData[8] = {0};
uint32_t              TxMailbox;

void SystemClock_Config(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_CAN1_Init();
  if(HAL_CAN_Start(&hcan1)!=HAL_OK)
  {
	  Error_Handler();
  }

  /* USER CODE END 2 */
  TxMessage1.StdId = 0x00;
  TxMessage1.ExtId = 0x18f0010b;
  TxMessage1.RTR = CAN_RTR_DATA;
  TxMessage1.IDE = CAN_ID_EXT;
  TxMessage1.DLC = 8;
  TxMessage1.TransmitGlobalTime = DISABLE;

  TxMessage2.StdId = 0x00;
  TxMessage2.ExtId = 0x18febf0b;
  TxMessage2.RTR = CAN_RTR_DATA;
  TxMessage2.IDE = CAN_ID_EXT;
  TxMessage2.DLC = 8;
  TxMessage2.TransmitGlobalTime = DISABLE;

  TxMessage3.StdId = 0x00;
  TxMessage3.ExtId = 0x18fef100;
  TxMessage3.RTR = CAN_RTR_DATA;
  TxMessage3.IDE = CAN_ID_EXT;
  TxMessage3.DLC = 8;
  TxMessage3.TransmitGlobalTime = DISABLE;

  TxMessage4.StdId = 0x00;
  TxMessage4.ExtId = 0x18fed900;
  TxMessage4.RTR = CAN_RTR_DATA;
  TxMessage4.IDE = CAN_ID_EXT;
  TxMessage4.DLC = 8;
  TxMessage4.TransmitGlobalTime = DISABLE;

  TxMessage4.StdId = 0x00;
  TxMessage4.ExtId = 0x18fed930;
  TxMessage4.RTR = CAN_RTR_DATA;
  TxMessage4.IDE = CAN_ID_EXT;
  TxMessage4.DLC = 8;
  TxMessage4.TransmitGlobalTime = DISABLE;


//  uint8_t tdata[8] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
  uint8_t adata[8] = {0};
  uint32_t pTxMailbox = 0;
  while (1)
  {
	if(HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxMessage1, adata)!=1)
	{
		if(RxMessage1.ExtId == 0x18f0010b)
		{
			HAL_CAN_AddTxMessage(&hcan1, &TxMessage1, adata, &pTxMailbox);
		}
		else if(RxMessage1.ExtId == 0x18febf0b)
		{
			HAL_CAN_AddTxMessage(&hcan1, &TxMessage2, adata, &pTxMailbox);
		}
		else if(RxMessage1.ExtId == 0x18fef100)
		{
			HAL_CAN_AddTxMessage(&hcan1, &TxMessage3, adata, &pTxMailbox);
		}
		else if(RxMessage1.ExtId == 0x18fed900)
		{
			HAL_CAN_AddTxMessage(&hcan1, &TxMessage4, adata, &pTxMailbox);
		}
	}
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  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_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
}
#endif /* USE_FULL_ASSERT */

main.h

#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

#include "stm32f4xx_hal.h"

void Error_Handler(void);
#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */


烧录验证

将代码烧录到板子上验证功能

1.png

企业微信截图_16913696822616.png
使用DCB方式发送报文,可以看到发送了六条报文,只接收四条所需的,功能实现!


2.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炸弹气旋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值