STM32实现UART-CAN融合式高速串口
创始人
2024-06-02 20:46:34
0

STM32实现UART-CAN融合式高速串口

STM32的UART硬件电路,在进行线接传输时,一般低于230400bps的波特率,因为单端信号传输的特性,限制了传输距离和传输速度。而在同一块PCB板內进行短距离UART传输,则可以达到2Mbps及至4Mbps的传输速率,所以STM32的UART接口,能支持配置为2M或4M波特率。

如果要实现接线方式的串口信号传输距离加长,常用的方式为采用RS232电平转换芯片,将UART的TTL电平转换为RS232电平,但因为RS232标准依然是单端信号标准,所以也不能有效提高传输速率,一些RS232电平转换芯片也只是支持到最高230400bps的信号转换。常见的替代方式为采用RS485/RS422电平转换芯片替代RS232电平转换芯片,RS485/RS422为差分传输方式,能够支持高速远距离传输,但RS485/RS422方式为差分强驱方式,RS485芯片需要控制方向管脚,因此增加了直接和UART接口连接的复杂性。RS422标准并不包含方向控制管脚,市面上有很多用两路RS485集成的RS422功能芯片,也就有了方向控制管脚,RS485芯片卖得多,从而导致不含方向控制RS422销量小而贵一些。

实际上,如果不是传输距离特别长,采用UART-CAN融合式高速串口方式,是大部分系统更适合的方式。当采用半双工模式时,比RS485减少了方向控制管脚的使用,当采用点对点全双工模式时,相当于RS422。

这里的高速是指Mbps级传输速率,相比于Kbps级传输速率,而当和高速差分如LVTTL等比较时,则不能称为高速。

UART-CAN融合式借用CAN的物理层收发器,而不采用CAN的数据链路层协议和电路,这部分用UART收发电路替代。CAN物理层的驱动高电平态(隐性)由上拉实现,所以不是强驱型而是Open-drain型驱动,不会出现总线上电平冲突导致短路,这也是CAN在传统汽车总线里应用比较广的原因。

UART的TX,在不发送数据时输出高电平态, 而CAN的TX单端侧,也是高电平态,对应差分线上的隐性。

UART-CAN融合式高速串口连接方式

1)UART-CAN融合式半双工网络
在这里插入图片描述
这种网络连接方式适用于一个主机,其它为从机。主机发送信息给各个从机,各个从机判断是否是发给自己的,确认是发给自己的信息或命令,再根据信息或命令的要求,发送信息给主机。主机的STM32在发送信息时,不打开接收中断,而在发送信息后,则清除之前的接收中断标志后,打开UART接收中断,等待并接收来自从机的回复,同时还开启一个时间计数器,如果超时没有接收到从机回复,则做相应处理,如果收到从机回复,则关闭时间计数器。

这种网络在协议上可升级为Y令牌循环式协议,从而去除主机和从机关系,提高总线的利用率。每个节点有从0递增开始的节点地址(常通过MCU读取外部硬件多位拨码开关状态识别地址)。上电之后,识别自己为0地址节点的STM32,可以向总线发送信息,而在得到对应节点的回复,且自身目前没有业务处理,则向总线发出将令牌递交给地址+1的节点的信息,在得到回复后,完成令牌移交。得到令牌的节点,则也是可以占用总线发送接收信息,然后再将令牌递交给下一个节点,如果下一个节点没有在有效时间内回复,则向地址为0的节点移交令牌。按照此网络协议,则任何节点都可以主动向任何另一个节点发送信息和接收回复,从而打破了单个主机查询,多个从机被动回复的模式。在需要减少总线交互的场景(如低功耗),可以由0节点进行控制,当0节点获得令牌并无事可做时,可以延时设定的时间再将令牌交出。
在这里插入图片描述
Y令牌网络逻辑只有1个节点0为发起节点,除此特性外和其他节点作用一样。需要注意在物理连接上,CAN物理层差分连接仍然采用菊花链方式。

2)UART-CAN融合式全双工连接
在这里插入图片描述
全双工为点对点模式,STM32的每个UART对应2个CAN收发器,CAN收发器标称支持到1Mbps速率,实际上在同速度级芯片还有一定能力冗余,因此在此模式下,STM32的UART可以配置为1Mbps,2Mbps或 4Mbps,基于差分接线实际长度验证即可。

STM32 UART-CAN融合式高速串口测试范例

这里用STM32F103C6T6开发板,用两个UART连接两个CAN收发器模块,通过环回方式进行测试:
在这里插入图片描述

在这里插入图片描述
测试方案如下:
在这里插入图片描述

测试逻辑为UART1定时发送数据,UART2收到数据后通过USB虚拟串口转发到PC测试工具。测试时的UART速率为2Mbps。电路连接时需注意CAN收发器模块的TX和RX具体对应的方向。

STM32工程配置

这里以STM32CUBEIDE为开发环境,STM32F103C6T6为例进行工程配置和代码实现,首先建立基本工程并设置时钟:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
设置USB串口:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
设置UART1和UART2, UART1能支持到4Mbps, UART2只能支持到2Mbps,这里环回测试模式,也就设置为2Mbps:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

保存并生成基本工程代码:
在这里插入图片描述

STM32工程代码

编译时需要采用节省存储的编译方式,可参考: STM32 region `FLASH‘ overflowed by xxx bytes 问题解决
STM32虚拟串口的设置 ,可参考: STM32 USB VCOM和HID的区别,配置及Echo功能实现(HAL)
代码里用到的延时函数,可参考: STM32 HAL us delay(微秒延时)的指令延时实现方式及优化

设置USB虚拟串口收到数据时回发,此处用于接口测试:
在这里插入图片描述

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{/* USER CODE BEGIN 6 */CDC_Transmit_FS(Buf, *Len);USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);USBD_CDC_ReceivePacket(&hUsbDeviceFS);return (USBD_OK);/* USER CODE END 6 */
}

main.c文件里则设置UART2接收中断函数收到数据时,通过USB虚拟串口发送出去:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart=&huart2){CDC_Transmit_FS(&U2_RX, 1);HAL_UART_Receive_IT(&huart2, &U2_RX, 1);}}

main.c文件里则运行后启动UART2的接收中断,并定时从UART1发送数据:

  HAL_UART_Receive_IT(&huart2, &U2_RX, 1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){PY_Delay_us_t(1000000);U1_TX = 0x55;HAL_UART_Transmit(&huart1, &U1_TX, 1, 2700);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

完整的main.c文件如下:

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2023 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO float usDelayBase;
void PY_usDelayTest(void)
{__IO uint32_t firstms, secondms;__IO uint32_t counter = 0;firstms = HAL_GetTick()+1;secondms = firstms+1;while(uwTick!=firstms) ;while(uwTick!=secondms) counter++;usDelayBase = ((float)counter)/1000;
}void PY_Delay_us_t(uint32_t Delay)
{__IO uint32_t delayReg;__IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);delayReg = 0;while(delayReg!=usNum) delayReg++;
}void PY_usDelayOptimize(void)
{__IO uint32_t firstms, secondms;__IO float coe = 1.0;firstms = HAL_GetTick();PY_Delay_us_t(1000000) ;secondms = HAL_GetTick();coe = ((float)1000)/(secondms-firstms);usDelayBase = coe*usDelayBase;
}void PY_Delay_us(uint32_t Delay)
{__IO uint32_t delayReg;__IO uint32_t msNum = Delay/1000;__IO uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);if(msNum>0) HAL_Delay(msNum);delayReg = 0;while(delayReg!=usNum) delayReg++;
}
/* 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 ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;/* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t U1_TX;
uint8_t U1_RX;
uint8_t U2_TX;
uint8_t U2_RX;
/* 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_USART1_UART_Init();MX_USART2_UART_Init();MX_USB_DEVICE_Init();/* USER CODE BEGIN 2 */PY_usDelayTest();PY_usDelayOptimize();HAL_UART_Receive_IT(&huart2, &U2_RX, 1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){PY_Delay_us_t(1000000);U1_TX = 0x55;HAL_UART_Transmit(&huart1, &U1_TX, 1, 2700);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {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();}PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}
}/*** @brief USART1 Initialization Function* @param None* @retval None*/
static void MX_USART1_UART_Init(void)
{/* USER CODE BEGIN USART1_Init 0 *//* USER CODE END USART1_Init 0 *//* USER CODE BEGIN USART1_Init 1 *//* USER CODE END USART1_Init 1 */huart1.Instance = USART1;huart1.Init.BaudRate = 2000000;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN USART1_Init 2 *//* USER CODE END USART1_Init 2 */}/*** @brief USART2 Initialization Function* @param None* @retval None*/
static void MX_USART2_UART_Init(void)
{/* USER CODE BEGIN USART2_Init 0 *//* USER CODE END USART2_Init 0 *//* USER CODE BEGIN USART2_Init 1 *//* USER CODE END USART2_Init 1 */huart2.Instance = USART2;huart2.Init.BaudRate = 2000000;huart2.Init.WordLength = UART_WORDLENGTH_8B;huart2.Init.StopBits = UART_STOPBITS_1;huart2.Init.Parity = UART_PARITY_NONE;huart2.Init.Mode = UART_MODE_TX_RX;huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart2.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart2) != HAL_OK){Error_Handler();}/* USER CODE BEGIN USART2_Init 2 *//* USER CODE END USART2_Init 2 */}/*** @brief GPIO Initialization Function* @param None* @retval None*/
static void MX_GPIO_Init(void)
{/* GPIO Ports Clock Enable */__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();}/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart=&huart2){CDC_Transmit_FS(&U2_RX, 1);HAL_UART_Receive_IT(&huart2, &U2_RX, 1);}}/* 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 */__disable_irq();while (1){}/* 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,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

STM32代码测试

将STM32F103C6T6通过USB连接PC后,打开串口工具连接,这里的虚拟串口波特率随便设置,不是UART1和UART2的波特率。代码里UART1定时发送0x55, UART2收到后转发虚拟串口:
在这里插入图片描述

STM32例程下载

STM32F103C6T6 UART-CAN融合式高速串口例程

–End

相关内容

热门资讯

求经典台词和经典旁白 求经典台词和经典旁白谁有霹雳布袋戏里的经典对白和经典旁白啊?朋友,你尝过失去的滋味吗? 很多人在即将...
小王子第二章主要内容概括 小王子第二章主要内容概括小王子第二章主要内容概括小王子第二章主要内容概括
爱情睡醒了第15集里刘小贝和项... 爱情睡醒了第15集里刘小贝和项天骐跳舞时唱的那首歌是什么谢谢开始找舞伴的时候是林俊杰的《背对背拥抱》...
世界是什么?世界是什么概念?可... 世界是什么?世界是什么概念?可以干什么?物质的和意识的 除了我们生活的地方 比方说山 河 公路 ...
全职猎人中小杰和奇牙拿一集被抓 全职猎人中小杰和奇牙拿一集被抓动画片是第五十九集,五十八集被发现,五十九被带回基地,六十逃走
“不周山”意思是什么 “不周山”意思是什么快快快快......一座山,神话里被共工撞倒了。
《揭秘》一元一分15张跑得快群... 一元一分麻将群加群主微【ab120590】【tj525555】 【mj120590】等风也等你。喜欢...
玩家必看手机正规红中麻将群@2... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
始作俑者15张跑的快群@24小... 微信一元麻将群群主微【ab120590】 【tj525555】【mj120590】一元一分群内结算,...
《重大通知》24小时一元红中麻... 加V【ab120590】【tj525555】【mj120590】红中癞子、跑得快,等等,加不上微信就...
盘点一下正规一块红中麻将群@2... 一元一分麻将群加群主微:微【ab120590】 【mj120590】【tj525555】喜欢手机上打...
(免押金)上下分一元一分麻将群... 微【ab120590】 【mj120590】【tj525555】专业麻将群三年房费全网最低,APP苹...
[解读]正规红中麻将跑的快@群... 微信一元麻将群群主微【ab120590】 【tj525555】【mj120590】一元一分群内结算,...
《普及一下》全天24小时红中... 微【ab120590】 【mj120590】【tj525555】专业麻将群三年房费全网最低,APP苹...
优酷视频一元一分正规红中麻将... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
《火爆》加入附近红中麻将群@(... 群主微【ab120590】 【mj120590】【tj525555】免带押进群,群内跑包包赔支持验证...
《字节跳动》哪里有一元一分红中... 1.进群方式-[ab120590]或者《mj120590》【tj525555】--QQ(QQ4434...
全网普及红中癞子麻将群@202... 好运连连,全网推荐:(ab120590)(mj120590)【tj525555】-Q号:(QQ443...
「独家解读」一元一分麻将群哪里... 1.进群方式《ab120590》或者《mj120590》《tj525555》--QQ(4434063...
通知24小时不熄火跑的快群@2... 1.进群方式《ab120590》或者《mj120590》《tj525555》--QQ(4434063...