发新帖本帖赏金 150.00元(功能说明)我要提问
返回列表
打印
[APM32E1]

极海国产芯|CubeMX配置F103xE_CAN,兼容APM32E103xE双CAN的修改操作

[复制链接]
639|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一个人破|  楼主 | 2022-11-23 22:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 一个人破 于 2022-11-25 17:06 编辑

#申请原创# 文档说明:STM32F103xE芯片只有一个CAN,而APM32E103xE是有2个CAN,且相互独立。因此使用CubeMX生成的F103xE_CAN程序(HAL库),无法满足APM32E103xE的CAN2使用。故建立文档,进行程序修改说明,以供电子同胞们参考学习使用。
(我还是不习惯这个编辑器,后面的图片我就不发了。会在文章的最后放上PDF教程文件和程序包,方便你们观看和参考)
1)PDF教程文件:https://bbs.21ic.com/forum.php?mod=attachment&aid=MjAyODQwMnwzNmNlNGM5NmFjZjZmZDc1NTNiMTM0ZTU1NmM0YTQ2ZXwxNzE0MDQ1MzE0&request=yes&_f=.pdf
2)程序包(分2个,有文件大小限制):
https://bbs.21ic.com/forum.php?mod=attachment&aid=MjAyNjg5OHw5YjRiZjJmMWM5N2JiYTBkZTZhYWQ3NjM5YzkyODQ1YXwxNzE0MDQ1MzE0&request=yes&_f=.rarattach://2026912.rar

一、使用CubeMX生成STM32F103VET6的CAN工程
1、创建工程

2、选择STM32F103VET6型号

3、配置系统主频
我时钟源使用外部晶振HSE8MHz,经过9倍频,PLL72MHz

4、配置CAN
STM32F103xE芯片只有一个CAN,所以CubeMX只能先配置一个CAN,即CAN1。
a、使能接收中断
b、CAN1引脚我使用PB8和PB9
c、波特率配置500Kbps

5、配置串口,便于查看是否收发成功
这里我用的是串口1,记得使能串口接收中断

6、配置按键
配置2个IO当按键,作为CAN的收发开关。这里我用的是PC1、PC2,输入上拉模式。

7、选择一个调试模式
CubeMX默认配置的是No Debug,最好根据自身需求选择一个调试模式。我选的是Serial Wire(SW)

8、生成工程文件
a、我使用的是MDK软件,选择MDK-ARM
b、勾选单独生成.c/.h,便于修改调试
c、点击GENERATE CODE,生成工程

  
  
  
9、工程备份
打开工程存储的位置。万事备份,小心无大错。

  
二、工程过渡修改
刚生成的工程还不适合我们直接调试。为了便于串口输出调试,我们需要修改串口重定义。
在usart.c文件中加入以下代码

int fputc(int ch, FILE *f)

{

HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);

return ch;

}

  int fgetc(FILE * f)

{

uint8_t ch = 0;

HAL_UART_Receive(&huart1,&ch, 1, 0xffff);

return ch;

}

在usart.h文件中加入头文件

  
三、添加CAN2配置
STM32F103VET6是只有1个CAN,所以工程里只配置了1个CAN。如果我们想要使用APM32E103VET6的CAN2功能,就需要添加CAN2的相关配置。
大致有4个部分:CAN2基地址、时钟、引脚、中断。
1、添加CAN2初始化函数
a、can.c文件:更改并添加CAN2结构体定义
b、can.c文件:更改并添加CAN2初始化函数

    * USER CODE END 0 */

CAN_HandleTypeDef hcan1;

CAN_HandleTypeDef hcan2;

/* CAN init function */

void MX_CAN1_Init(void)

{

    /* USER CODE BEGIN CAN_Init 0 */

    /* USER CODE END CAN_Init 0 */

    /* USER CODE BEGIN CAN_Init 1 */

    /* USER CODE END CAN_Init 1 */

hcan1.Instance = CAN1;

hcan1.Init.Prescaler = 12;

hcan1.Init.Mode = CAN_MODE_NORMAL;

hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;

hcan1.Init.TimeSeg1 = CAN_BS1_3TQ;

hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;

hcan1.Init.TimeTriggeredMode = DISABLE;

hcan1.Init.AutoBusOff = DISABLE;

hcan1.Init.AutoWakeUp = ENABLE;

hcan1.Init.AutoRetransmission = ENABLE;

hcan1.Init.ReceiveFifoLocked = DISABLE;

hcan1.Init.TransmitFifoPriority = DISABLE;

if (HAL_CAN_Init(&hcan1) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN CAN_Init 2 */

    /* USER CODE END CAN_Init 2 */

  }

  void MX_CAN2_Init(void)

{

    /* USER CODE BEGIN CAN_Init 0 */

    /* USER CODE END CAN_Init 0 */

    /* USER CODE BEGIN CAN_Init 1 */

    /* USER CODE END CAN_Init 1 */

hcan2.Instance = CAN2;

hcan2.Init.Prescaler = 12;

hcan2.Init.Mode = CAN_MODE_NORMAL;

hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;

hcan2.Init.TimeSeg1 = CAN_BS1_3TQ;

hcan2.Init.TimeSeg2 = CAN_BS2_2TQ;

hcan2.Init.TimeTriggeredMode = DISABLE;

hcan2.Init.AutoBusOff = DISABLE;

hcan2.Init.AutoWakeUp = ENABLE;

hcan2.Init.AutoRetransmission = ENABLE;

hcan2.Init.ReceiveFifoLocked = DISABLE;

hcan2.Init.TransmitFifoPriority = DISABLE;

if (HAL_CAN_Init(&hcan2) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN CAN_Init 2 */

    /* USER CODE END CAN_Init 2 */

  }

c、在can.h文件中做好函数声明,main.c中做好函数初始化。

   
d、CAN2之前是没有定义的,因此需要加宏定义
跳转“CAN1”,复制并添加CAN2定义
跳转“CAN1_BASE”,复制并添加CAN2_BASE定义
添加CAN2部分,其实就是改HAL库的过程。我们只需要知道,对所有寄存器的操作都是对地址的操作,那就很好理解了。在极海官网可以下载最新版的E103xE参考手册,对照手册修改相关寄存器的地址就OK了。


   
参考手册资料:


2、HAL_CAN_Msp初始化函数中添加CAN2部分
返回can.c文件,对Msp初始化函数进行修改,添加CAN2部分的判断。CAN2的引脚我复用了PB5和PB6。

修改前


修改后(添加CAN2部分后的代码)

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_GPIOB_CLK_ENABLE();

/**CAN1 GPIO Configuration

PB8     ------> CAN1_RX

PB9     ------> CAN1_TX

*/

GPIO_InitStruct.Pin = GPIO_PIN_8;

GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

      GPIO_InitStruct.Pin = GPIO_PIN_9;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

      __HAL_AFIO_REMAP_CAN1_2();

      /* CAN1 interrupt Init */

HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);

/* USER CODE BEGIN CAN1_MspInit 1 */

    /* USER CODE END CAN1_MspInit 1 */

}

else if(canHandle->Instance==CAN2)

{

/* USER CODE BEGIN CAN2_MspInit 0 */

    /* USER CODE END CAN2_MspInit 0 */

/* CAN2 clock enable */

__HAL_RCC_CAN2_CLK_ENABLE();

      __HAL_RCC_GPIOB_CLK_ENABLE();

/**CAN2 GPIO Configuration

PB5     ------> CAN2_RX

PB6     ------> CAN2_TX

*/

GPIO_InitStruct.Pin = GPIO_PIN_5;

GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

      GPIO_InitStruct.Pin = GPIO_PIN_6;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

      __HAL_AFIO_REMAP_CAN2_2();

        /* CAN2 interrupt Init */

HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn);

/* USER CODE BEGIN CAN2_MspInit 1 */

    /* USER CODE END CAN2_MspInit 1 */

}

}

软件会提示3个部分没有定义:时钟、复用引脚、中断


3、添加CAN2时钟宏定义
a、跳转“__HAL_RCC_CAN1_CLK_ENABLE“,复制并定义CAN2时钟使能函数
每个CAN1字眼都改为CAN2

  
b、跳转“RCC_APB1ENR_CAN1EN”,复制并定义CAN2时钟的偏移量

  
通过参考手册可知,CAN2时钟是bit26



修改前:
  修改后:警报消除
  
4、添加CAN2引脚复用的宏定义
a、跳转“__HAL_AFIO_REMAP_CAN1_2”,复制并定义CAN2引脚复用

  
b、跳转“AFIO_MAPR_CAN_REMAP_REMAP2”,复制并定义CAN2引脚复用

  通过手册可知,CAN2RMP为bit22
  
c、跳转“AFIO_MAPR_CAN_REMAP”,复制并定义CAN2引脚复用

  
修改前
  修改后:警报消除
  
5、添加CAN2接收中断
通过参考手册,查看中断向量表

  
在文件”startup_stm32f103xe.s“添加3处中断内容
在文件”stm32f103xe.h“添加1处中断内容
在文件”stm32f1xx_it“中添加CAN2接收中断的函数

文件”startup_stm32f103xe.s“
         
文件”stm32f103xe.h“
  
在文件“stm32f1xx_it”中添加CAN2接收中断的函数
  
修改前:
  修改后:
  
6、过滤器配置
a、在“can.c“文件,添加过滤器函数
b、在“can.h“做好函数申明
c、在“main.c”初始化

void CAN1_Filter_Init(CAN_HandleTypeDef* canHandle)
{
   CAN_FilterTypeDef sFilterConfig;
   sFilterConfig.FilterActivation = ENABLE;//打开过滤器
sFilterConfig.FilterBank = 1;//过滤器0 这里可设0-13
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//采用掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;//采用32位掩码模式
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO0
sFilterConfig.FilterIdHigh = 0x0000;//设置过滤器掩码高16位
sFilterConfig.FilterIdLow = 0x0000;//设置过滤器掩码低16位
sFilterConfig.FilterMaskIdHigh = 0x0000;//设置过滤器掩码高16位
sFilterConfig.FilterMaskIdLow = 0x0000;//设置过滤器掩码低16位
   if(HAL_CAN_ConfigFilter(canHandle,&sFilterConfig) != HAL_OK)//初始化过滤器
{
  Error_Handler();
}
if(HAL_CAN_Start(canHandle) != HAL_OK)//打开can
{
  Error_Handler();
}
if(HAL_CAN_ActivateNotification(canHandle,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)//开启接收中断
{
  Error_Handler();
}
}
  void CAN2_Filter_Init(CAN_HandleTypeDef* canHandle)
{
   CAN_FilterTypeDef sFilterConfig;
   sFilterConfig.FilterActivation = ENABLE;//打开过滤器
sFilterConfig.FilterBank = 1; //过滤器13 这里可设0-13
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//采用掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;//采用32位掩码模式
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO1
sFilterConfig.FilterIdHigh = 0x0000;//设置过滤器掩码高16位
sFilterConfig.FilterIdLow = 0x0000;//设置过滤器掩码低16位
sFilterConfig.FilterMaskIdHigh = 0x0000;//设置过滤器掩码高16位
sFilterConfig.FilterMaskIdLow = 0x0000;//设置过滤器掩码低16位
if(HAL_CAN_ConfigFilter(canHandle,&sFilterConfig) != HAL_OK)//初始化过滤器
{
  Error_Handler();
}
if(HAL_CAN_Start(canHandle) != HAL_OK)//打开can
{
  Error_Handler();
}
if(HAL_CAN_ActivateNotification(canHandle,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)//开启接收中断
{
  Error_Handler();
}
}
在can.h做好函数申明
  
在main.c初始化
  
7、CAN数据传输的准备
在main.c添加数据变量和传输验证

CAN_TxHeaderTypeDef Can_Tx;
CAN_RxHeaderTypeDef Can_Rx;
  uint8_t tdata[8] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
uint32_t pTxMailbox = 0;
  void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);
  void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
  uint8_t aRxData[8], i;
  Can_Rx.StdId = 0xFFF;
  Can_Rx.ExtId = 0xFFF;
  Can_Rx.IDE = CAN_ID_EXT;//CAN_ID_STD 标准帧  CAN_ID_EXT 扩展帧
  Can_Rx.RTR = CAN_RTR_DATA;
  Can_Rx.DLC = 8;
  if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &Can_Rx, aRxData) == HAL_OK)
  {
      if(hcan->Instance ==CAN1)
      {
      printf("1Get Rx Message Success\r\n\r\n");
//        HAL_CAN_AddTxMessage(&hcan1,&Can_Tx,tdata,&pTxMailbox);
      }
      else
      {
      printf("2Get Rx Message Success\r\n\r\n");
//        HAL_CAN_AddTxMessage(&hcan2,&Can_Tx,tdata,&pTxMailbox);
      }
  }
}
8、注释掉自动生成的CAN2宏

”stm32f1xx_hal_can.c“文件,2处
      
”stm32f1xx_hal_can.h“文件,1处
  
9、配置按键与CAN收发逻辑
PC1拉低,CAN1发送,CAN2接收。
PC2拉低,CAN2发送,CAN1接收。

main.c添加按键引脚定义:
#define KEY1_BUTTON_PIN                   GPIO_PIN_1
#define KEY1_BUTTON_GPIO_PORT             GPIOC
#define KEY1_BUTTON_GPIO_CLK              RCM_APB2_PERIPH_GPIOC
  #define KEY2_BUTTON_PIN                   GPIO_PIN_2
#define KEY2_BUTTON_GPIO_PORT             GPIOC
#define KEY2_BUTTON_GPIO_CLK              RCM_APB2_PERIPH_GPIOC
主循环中添加按键判断语句:
if (HAL_GPIO_ReadPin(KEY1_BUTTON_GPIO_PORT,KEY1_BUTTON_PIN) == RESET)
     {
    printf("CAN1 Transmit !\r\n");
    HAL_CAN_AddTxMessage(&hcan1,&Can_Tx,tdata,&pTxMailbox);
    while(HAL_GPIO_ReadPin(KEY1_BUTTON_GPIO_PORT,KEY1_BUTTON_PIN)== RESET);
     }
       if (HAL_GPIO_ReadPin(KEY2_BUTTON_GPIO_PORT,KEY2_BUTTON_PIN) == RESET)
     {
    printf("CAN2 Transmit !\r\n");
    HAL_CAN_AddTxMessage(&hcan2,&Can_Tx,tdata,&pTxMailbox);
    while(HAL_GPIO_ReadPin(KEY2_BUTTON_GPIO_PORT,KEY2_BUTTON_PIN)== RESET);
     }
四、硬件连接
使用2个CAN收发器,分别连接CAN1(PB8、PB9)与CAN2(PB5、PB6)
CANL与CANL相连,CANH与CANH相连
3.3V供电,记得共地

CAN收发器
  
五、测试验证
PC1拉低,CAN1发送,CAN2接收,测试正常。
PC2拉低,CAN2发送,CAN1接收,测试正常。

  




APM32E103VE_CAN_20221114.part02.rar (4.88 MB)

APM32E103VE_CAN_20221114.part01.rar (8 MB)





CubeMX配置F103xE_CAN,兼容APM32E103xE双CAN的修改操作_20221125.pdf

2.37 MB

使用特权

评论回复

打赏榜单

Gfan 打赏了 150.00 元 2022-12-05
理由:恭喜获得极海国产芯悬赏贴活动的“最佳国产芯文博主”称号,感谢您的支持,期待下次的干货分享哦!

沙发
WuKaiLi| | 2022-11-25 15:00 | 只看该作者
好文,点赞

使用特权

评论回复
板凳
一个人破|  楼主 | 2022-11-25 15:49 | 只看该作者

惊现大佬

使用特权

评论回复
地板
一个人破|  楼主 | 2022-11-25 17:07 | 只看该作者
将PDF教程文件更新:添加目录,调整排版

使用特权

评论回复
发新帖 本帖赏金 150.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

45

帖子

0

粉丝