STM32F103C8T6-CAN

news2024/11/17 8:29:37

本文内容

  • 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 start
                          of 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();
  else
		printf("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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1574747.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前沿模型解析】潜在扩散模 1 | LDM第一阶段-感知图像压缩总览

文章目录 0 开始~1 感知压缩的目的2 自回归编码器-解码器生成模型一览2.1 AE 自编码器2.2 VAE 变分自编码器2.3 VQ-VAE2.4 VQ-GAN 3 代码部分讲解总览 0 开始~ 从今天起呢&#xff0c;我们会剖析LDM&#xff08;潜在扩散模型&#xff09; 从去年开始&#xff0c;大量的生成模…

数学建模-------MATLAB分支循环断点调试

1.if语句 &#xff08;1&#xff09;分段函数的引入&#xff08;这里的数据表示的是分数的不同区间对应的等级&#xff09; (1)这个就是一个十分简单的if语句&#xff0c;无论是if还是elseif后面都是不能添加任何分号的&#xff0c;这个例子就是一个分段的函数&#xff0c;在不…

基础总结篇:Activity生命周期

private int param 1; //Activity创建时被调用 Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, “onCreate called.”); setContentView(R.layout.lifecycle); Button btn (Button) findViewById(R.id.…

医药行业痛点以及OKR解决方案

一、背景 随着医药行业的快速发展和市场竞争的加剧&#xff0c;企业面临着前所未有的挑战和机遇。为了在激烈的市场竞争中立于不败之地&#xff0c;某知名医药企业决定引入OKR&#xff08;Objectives and Key Results&#xff0c;目标与关键成果&#xff09;管理模式&#xff0…

Gradle入门初探

一、Gradle简介&#xff1a; 我们都创建过基于Maven的项目&#xff0c;maven可以很好的管理项目的依赖&#xff0c;编译和打包项目&#xff0c;Gradle是一个和Maven类似的自动化构建工具&#xff0c;Maven是基于xml文件格式&#xff0c;而Gradle是基于Groovy的语言&#xff0c…

dm8数据迁移工具DTS

dm8数据迁移工具DTS DTS工具介绍 DM数据迁移工具提供了主流大型数据库迁移到DM、DM到DM、文件迁移到DM以及DM迁移到文件的功能。DM数据迁移工具采用向导方式引导用户通过简单的步骤完成需要的操作。 DM数据迁移工具支持&#xff1a; ◆ 主流大型数据库Oracle、SQLServer、MyS…

Advanced RAG 01:讨论未经优化的 RAG 系统存在的问题与挑战

编者按&#xff1a; 自 2023 年以来&#xff0c;RAG 已成为基于 LLM 的人工智能系统中应用最为广泛的架构之一。由于诸多产品的关键功能严重依赖RAG&#xff0c;优化其性能、提高检索效率和准确性迫在眉睫&#xff0c;成为当前 RAG 相关研究的核心问题。 我们今天为大家带来的这…

【无标题】【Android】Android中Intent的用法总结

2.显示地图: Java代码 Uri uri Uri.parse(“geo:38.899533,-77.036476”); Intent it new Intent(Intent.Action_VIEW,uri); startActivity(it); 3.从google搜索内容 Java代码 Intent intent new Intent(); intent.setAction(Intent.ACTION_WEB_SEARCH); intent.pu…

SAP操作教程第16期:SAP B1关于审批模块的设置

工作效率是企业的生存之本&#xff0c;也是员工能够在企业中发展之本。自动化和规范化的审批流程可以减少手动操作以及沟通环节、节约时间和资源从而提高工作效率。 所以&#xff0c;今天我们就一起来了解一下SAP B1中关于审批模块的设置。 01关于审批模块的设置 第一步&#x…

数据结构基础:双链表结构、实现

继续和颦颦学C语言呀.......> 双链表的结构 这里的head 为头节点&#xff0c;是‘哨兵位’&#xff0c;实际不存储任何有效的数据 它的存在是为了遍历环链表避免死循环 双链表的实现 typedef int LTDataType; typedef struct ListNode { struct ListNode* next; //指针保存…

为什么使用MQ????

1、异步处理 场景说明&#xff1a;用户注册后&#xff0c;需要发注册邮件和注册短信,传统的做法有两种 1.串行的方式 2.并行的方式。 串行方式: 将注册信息写入数据库后,发送注册邮件,再发送注册短信,以上三个任务全部完成后才返回给客户端。 这有一个问题是,邮件,短信并不是…

2024/4/1—力扣—二叉树的最近公共祖先

代码实现&#xff1a; 思路&#xff1a; 递归判断左子树和右子树&#xff0c;查找p或者q是否在当前节点的子树上 1&#xff0c;在同一子树上&#xff0c;同一左子树&#xff0c;返回第一个找到的相同值&#xff0c;同一右子树上&#xff0c;返回第一个找到的相同值 2&#xff0…

【每日刷题】Day4

【每日刷题】Day4 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; 目录 1. 83. 删除排序链表中的重复元素 - 力扣&#xff08;LeetCode&#xff09; 2. 88. 合并两个有序数组 - 力扣&#xff08;LeetCode&…

Windows SDK(六)组合框与列表框控件

组合框和列表框同样也是控件&#xff0c;所以我们在应用组合框和列表框时同样也需要父窗口&#xff0c;现在我们以 创建项目时程序自行创建的窗口作为父窗口展开如下的控件创建与应用 在进行组合框与列表框的讲解前&#xff0c;我们首先在程序中定义几个宏作为我们在编写程序…

C语言:顺序表专题

目录 一、数据结构之顺序表/链表1.数据结构相关概念1.1什么是数据结构1.2为什么需要数据结构 二、顺序表1.顺序表的概念及结构2.顺序表分类3.动态顺序表的实现 一、数据结构之顺序表/链表 1.数据结构相关概念 1.1什么是数据结构 数据结构是由“数据”和“结构”两词组合而来…

【优选算法专栏】专题十六:BFS解决最短路问题(一)

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

云his系统源码 java源码saas模式 二甲医院his系统全套源码 数据库MySQL + MyCat

基层医院云HIS系统源码 一款满足基层医院各类业务需要的云HIS系统。该系统能帮助基层医院完成日常各类业务&#xff0c;提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等一系列常规功能&#xff0c;还能与公卫、PACS等各类外部系统融合&…

0基础学习python

0基础如何进入IT行业&#xff1f; 建议先掌握以下&#xff1a; 编程环境的安装和使用输出输入语句、变量、表达式的理解和使用选择结构、循环结构的理解和使用列表的使用文件的操作函数的调用库的安装和使用 编程&#xff0c;其实就是利用特定的语言控制计算机、或者就是与计算…

如何把音乐播放速度慢下来?享受慢音乐的两个方法

一&#xff0c;前言 在现代社会&#xff0c;我们生活在一个快节奏的环境中&#xff0c;时间仿佛被压缩成了碎片&#xff0c;每个人都在匆匆忙忙地追求着速度和效率。然而&#xff0c;有时放慢脚步&#xff0c;让心灵回归宁静&#xff0c;成为了一种难得的奢侈。 音乐&#xf…

民航电子数据库:在有分组统计的语句中,输出表达式含有非分组统计项

目录 一、场景二、报错信息三、排查四、原因五、解决 一、场景 1、对接民航电子数据库 2、执行SQL语句报错 二、报错信息 三、排查 查看数据库def_group_by_mode配置 show def_group_by_mode四、原因 def_group_by_mode设置为0导致&#xff0c;相当于mysql的sql_modeonly_…