STM32F103C8T6-CAN

2024-04-07 20:36
文章标签 stm32f103c8t6

本文主要是介绍STM32F103C8T6-CAN,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文内容

  • HAL库下printf重定向
  • 解决问题:Keil下调试可以正常运行,而下载后运行不了
  • CAN总线的回环测试,自发自收

printf重定向

实现printf重定向的目的是方便调试,通过UART查看打印的调试信息。
下面以STM32F103C8T6为例:
image.png
这些参数需要与串口调试程序约定一致,比如我的,只需要关注红框部分即可:
image.png
修改stm32f1xx_hal.c,添加以下代码:

#include "stdio.h"
extern UART_HandleTypeDef huart1;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;
}

image.png

接收中断

在main.c中添加:

#include <string.h>#define RXBUFFERSIZE  256
char RxBuffer[RXBUFFERSIZE];
uint8_t aRxBuffer;
uint8_t Uart1_Rx_Cnt = 0;

将下面代码添加到/* USER CODE BEGIN 2 */处。需要注意位置,必须要写在BEGIN和END之间,否则在通过CubeMX重新生成代码的时候会被删除。

HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);

这三个参数的含义在头文件中有说明:

  • @param huart Pointer to a UART_HandleTypeDef structure that containsthe configuration information for the specified UART module.
  • @param pData Pointer to data buffer (u8 or u16 data elements).
  • @param Size Amount of data elements (u8 or u16) to be received.

在官方库中,类似的命名的含义是中断处理函数。在执行结束后需要手动清除中断标志位。
在HAL库中,该函数的作用是开启串口1的接收中断,并准备接收一个字节的数据。
HAL库下,在执行完一次中断之后,会自动关闭该中断。如果要保持开启,那么需要在中断回调函数中再次执行HAL_UART_Receive_IT()
当串口1接收到一个字节的数据时,会触发接收中断。中断服务程序会将接收到的数据存入接收缓冲区,并调用用户指定的回调函数。
/* USER CODE BEGIN 4 */的部分添加如下代码:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(Uart1_Rx_Cnt >= 255){Uart1_Rx_Cnt = 0;memset(RxBuffer,0x00,sizeof(RxBuffer));HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF);}else{RxBuffer[Uart1_Rx_Cnt++] = aRxBuffer;if((RxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0x0D)){HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, Uart1_Rx_Cnt,0xFFFF);while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);Uart1_Rx_Cnt = 0;memset(RxBuffer,0x00,sizeof(RxBuffer));}}HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
}

这一部分的功能是,收到串口发来的数据会原文返回,也是为了方便调试。

MicroLIB

我出现的问题是,在keil里调试,可以正常输出,电脑上的串口调试程序可以正常接收。
但下载之后,电脑上的串口调试程序没有任何响应。
解决方式就是勾选“Use MicroLIB”:
image.png

单元测试

在main.c的while里定时打印hello,看串口调试程序能不能收到:
image.png
代码必须要写在/* USER CODE BEGIN 3 */之后!
因为在通过STM32CubeMX重新生成代码的时候,会清除其它部分的代码。
上文提到的修改stm32f1xx_hal.c默认不会被重置。

CAN内部回环测试

因为我只有一块自带CAN的板子,所以要调试的话,必须要用回环模式:自发自收。
image.png
对于CAN的用法,在stm32f1xx_hal_can.c头部的注释中已经给出:
image.png
这些库函数的内容随着bsp的更新可以会做修改。如果版本不一致,函数名和结构体可能也不一样,需要根据.c文件给出的官方文档修改。

发送数据

CAN在发送之前,需要先执行HAL_CAN_Start(&hcan)。F103C8T6自带一个CAN,所以CubeMX生成代码的时候有一个hcan变量。如果是其他板子,有多个CAN接口,那么生成的可能是hcan1hcan2
CAN发送的数据是不定长的,一块板子可能有多个CAN。
所以发送数据的时候,需要指定用哪个CAN接口,发送多长的数据。
各个参数的具体作用,头文件中也已给出,自行翻译即可,不再赘述:

  • @param hcan pointer to a CAN_HandleTypeDef structure that contains the configuration information for the specified CAN.
  • @param pHeader pointer to a CAN_TxHeaderTypeDef structure.
  • @param aData array containing the payload of the Tx frame.
  • @param pTxMailbox pointer to a variable where the function will return the TxMailbox used to store the Tx message.
    • This parameter can be a value of @arg CAN_Tx_Mailboxes.

其中,hcan在CubeMX中已经配好,直接&hcan取地址即可。
pHeader需要自行设置,我起的变量名叫CAN_TxHeaderTypeDefStructrue

CAN_TxHeaderTypeDef CAN_TxHeaderTypeDefStructrue;
CAN_TxHeaderTypeDefStructrue.StdId=0x123;
CAN_TxHeaderTypeDefStructrue.DLC=4;
CAN_TxHeaderTypeDefStructrue.ExtId=0x123;
CAN_TxHeaderTypeDefStructrue.IDE=CAN_ID_STD;
CAN_TxHeaderTypeDefStructrue.RTR=CAN_RTR_DATA;

这是CAN_TxHeaderTypeDef结构体的官方注释:

/*** @brief  CAN Tx message header structure definition*/
typedef struct
{uint32_t StdId;    /*!< Specifies the standard identifier.This parameter must be a number between Min_Data = 0 and Max_Data = 0x7FF. */uint32_t ExtId;    /*!< Specifies the extended identifier.This parameter must be a number between Min_Data = 0 and Max_Data = 0x1FFFFFFF. */uint32_t IDE;      /*!< Specifies the type of identifier for the message that will be transmitted.This parameter can be a value of @ref CAN_identifier_type */uint32_t RTR;      /*!< Specifies the type of frame for the message that will be transmitted.This parameter can be a value of @ref CAN_remote_transmission_request */uint32_t DLC;      /*!< Specifies the length of the frame that will be transmitted.This parameter must be a number between Min_Data = 0 and Max_Data = 8. */FunctionalState TransmitGlobalTime; /*!< Specifies whether the timestamp counter value captured on startof frame transmission, is sent in DATA6 and DATA7 replacing pData[6] and pData[7].@note: Time Triggered Communication Mode must be enabled.@note: DLC must be programmed as 8 bytes, in order these 2 bytes are sent.This parameter can be set to ENABLE or DISABLE. */} CAN_TxHeaderTypeDef;
  • StdId:标准帧ID
  • DLC:数据长度,单位为字节
  • ExtId:扩展帧ID
  • RTR:远程传输请求,0为数据帧,表示要发送数据
  • IDE:选择是标准帧还是扩展帧。

标准帧和扩展帧的区别在于帧ID长度不同,扩展帧支持更多的设备挂载。
aData指向的是要发送的数据数组。
我定义的是:uint8_t data[]={1,2,3,4};
pTxMailbox指向的变量,将存储,要发送的数据的邮箱。这个变量不需要初始化,作用是以回调的方式存储返回的部分数据。
在F103C8T6中,有三个邮箱,选取哪一个,在HAL库中实现,我们无需关心。
我声明的是:uint32_t pTxMailBox;
这个变量我没有进行初始化,也不需要初始化。会在函数执行结束时自动赋值。

接收数据

CubeMX并没有生成接收数据的代码。
接收到数据的中断也需要手动打开。
在开启之前,需要先配置过滤器。主要是读取约定好的消息格式。
这部分代码CubeMX并没有生成,需要在can.c下自行实现。

/* USER CODE BEGIN 0 */
void CAN_Filter_Configure(void){CAN_FilterTypeDef sFilterConfig;sFilterConfig.FilterActivation=ENABLE;sFilterConfig.FilterBank=1;sFilterConfig.FilterFIFOAssignment=CAN_FILTER_FIFO1;sFilterConfig.FilterIdHigh=0x0000;sFilterConfig.FilterIdLow=0x0000;sFilterConfig.FilterMaskIdHigh=0x0000;sFilterConfig.FilterMaskIdLow=0x0000;sFilterConfig.FilterMode=CAN_FILTERMODE_IDMASK;sFilterConfig.FilterScale=CAN_FILTERSCALE_16BIT;sFilterConfig.SlaveStartFilterBank=17;if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig)!=HAL_OK)Error_Handler();
}
uint8_t rxbuf[8];/* USER CODE END 0 */

通过HAL_CAN_ActivateNotification开启中断。

HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO1_MSG_PENDING);

该方法不同于UART处的HAL_UART_Receive_IT。不需要在CAN的中断处理函数中再次执行。
为了验证CAN通讯,在中断处理函数中打印字符串"can",也是写在can.c中:

/* USER CODE BEGIN 1 */
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan){CAN_RxHeaderTypeDef CAN_RxHeader;if (HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO1,&CAN_RxHeader,rxbuf) != HAL_OK)Error_Handler();elseprintf("can");
}
/* USER CODE END 1 */

单元测试

在while循环中每隔0.5s向CAN总线发送一次数据。

  /* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */HAL_CAN_AddTxMessage(&hcan,&CAN_TxHeaderTypeDefStructrue,data,&pTxMailBox);HAL_Delay(500);/* USER CODE BEGIN 3 */}

在CubeMX中配置的是回环模式,发送的数据会被自己接收,执行中断处理函数。
中断处理函数的内容已在上文实现,会向串口发送"can"字符串。

实验现象

image.png
也可以在keil中调试:
image.png
rxbuf的内容就是循环中往CAN总线上发送的{1,2,3,4}

Demo代码

f103t2.zip

参考

  • https://blog.csdn.net/as480133937/article/details/99073783
  • https://blog.csdn.net/qq_49520586/article/details/122745967
  • https://wlink.blog.csdn.net/article/details/116206252
  • https://blog.csdn.net/chen18221987993/article/details/109156084
  • https://doc.embedfire.com/mcu/stm32/h750prov/hal/zh/latest/book/CAN.html

这篇关于STM32F103C8T6-CAN的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/883607

相关文章

智能家居系统(基于STM32F103C8T6标准库+FreeRTOS+Qt串口开发实现)

视频演示:基于STM32F103C8T6标准库+FreeRTOS+Qt串口开发实现的智能家居项目_哔哩哔哩_bilibili 基于STM32F103C8T6标准库+FreeRTOS+Qt串口开发实现的智能家居项目: https://pan.baidu.com/s/1f41gAfOOnlcQoKoMx3o84A?pwd=6j2g 提取码: 6j2g  注:本项目为学习完《江科大STM32教

STM32F103C8T6移植U8g2图形库及基于I2C协议的OLED显示(HAL库方式)【U8g2】【STM32开发板】【STM32CubeMX】

STM32F103C8T6移植U8g2图形库及基于I2C协议的OLED显示(HAL库方式)【U8g2】【STM32开发板】【STM32CubeMX】 实验说明 利用STM32F103的GPIO管脚、VCC和GND连接OLED屏的I2C接口,采用CubeMX设计一个HAL库程序框架,然后下载U8g2源码,针对STM32F103和0.96寸的I2C接口OLED屏,进行代码裁剪,然后移植到HAL程序

STM32F103RCT6换STM32F103C8T6后delay函数延时了10倍

更换单片机步骤: 1、型号选择 2、启动文件,将HD改为MD。 3、引入对应的启动文件。 4、后面发现delay比之前延时了差不多10倍,解决办法:在初始化后加入SystemInit();即可。

STM32F103C8T6 HAL库 USART1 DMA方式接收数据

前言:                 前面的两篇文章都说关于发送的,HAL库发送数据可以调用现成的函数,而接收数据,现成函数不太好用。这里为了记录了一下自己参考了网上几个大佬的代码,整理了一下USART1 DMA方式接受数据的代码,这里亲测了一下,传输比较稳定,也没有出现发送数据过快导致串口反应不过来的情况。 正文开始:         Cubemx配置         这里跟上一篇博客

STM32F103C8T6 HAL库串口重定向

前言:         这里仅用做个人记录,实现USART1串口通信,并通过printf重定向输出“串口打印测试” 正文开始:         首先在STM32CubeMX上对串口进行配置,其实方法也非常简单。         按照箭头顺序,先点击Connectivity找到USART1,然后将工作方式配置为Asynchronous(异步方式),配置默认即可,如果需要修改波特率,可以自行修

STM32F103C8T6 HAL库 printf重定向 USART1 DMA方式发送数据

前言:         在上一篇文章里,我采用printf重定向为usart1,但是这样发送,对于MPU的负载比较大,所以本篇文章采用DMA方式,解放MPU资源,去做其他的事情,这里仅做为自己的记录。 正文开始:         Cubemx配置         先是在Cubemx里对单片机进行配置,跟上一篇文章同样的配置         增加DMA通道,并且将RX引脚置为上拉模式,因为

STM32F103C8T6 HC-SR04超声波模块——超声波障碍物测距(HAl库)

超声波障碍物测距 一、HC-SR04超声波模块(一)什么是HC-SR04?(二)HC-SR04工作原理(三)如何使用HC-SR04(四)注意事项 二、程序编写(一)CubeMX配置1.芯片选择2.配置RCC、SYS、时钟树![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8e04c33ec7fe4fdbbd1a9ef7593e74d8.png)3

【STM32CubeMX】配置STM32F103C8T6

一、MCU选择器建立项目 二、配置系统参数 三、配置外设 四、项目管理 五、生成项目源程序 一、MCU选择器建立项目 1、打开CubeMX以后,选“通过MCU选择器来建立新项目” 找到STM32F103C8T6,并开始项目 二、配置系统参数 2、RCC 系统时钟是晶振频率,外部晶振和内部晶振(根据需求来) 3、SYS 系统时钟 和 选择调试模式Debug(根据需求来)

在STM32F103C8T6上移植UCOS系统

网上看到有的人也在STM32F103C8T6上移植过UCOSII系统,各有各的说辞,有的说在STM32F103C8T6上移植UCOSII系统,不能用startup_stm32f103x_hd.s,要用startup_stm32f103x_md.s,不然会报错或跑不起来,我就纳闷了,hd是比md更大内存,更大FLASH的,怎么会用不了,再说系统能不能跑起来,最主要的还是取决你的芯片的

使用STM32F103C8T6与蓝牙模块HC-05连接实现手机蓝牙控制LED灯

导言: 在现代智能家居系统中,远程控制设备变得越来越普遍和重要。本文将介绍如何利用STM32F103C8T6单片机和蓝牙模块HC-05实现远程控制LED灯的功能。通过这个简单的项目,可以学会如何将嵌入式系统与蓝牙通信技术相结合,实现远程控制的应用。 目录 导言: 准备工作: 硬件设计: HC-05蓝牙串口模块介绍: 引脚: 手机蓝牙APP: 物理连接: 通信协议: A