在STM32中使用5个串口收发数据的问题

这篇具有很好参考价值的文章主要介绍了在STM32中使用5个串口收发数据的问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

之前碰巧有个项目需要多个串口,用的是ST自带的5个串口没有用扩展芯片

百度网盘链接
链接:https://pan.baidu.com/s/1sC3zPWN2pGzrAn4cZ2sq9g?pwd=6666 
提取码:6666

介绍

1.MCU型号:STM32F103VET6

2.标准库

遇到的问题

1.5个中断同时开启接收数据,即使设置了优先级,还是会出现卡死现象

2.5个中断开启时,printf 重定义如何兼容5个串口

3.如何将5个串口实现通用配置,兼容STF10XXX系列

4.在单片机中截取字符串,比较字符串,查找字符串

下面开始一一解答

5个串口的GPIO配置:

void USART1_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// ´ò¿ª´®¿ÚGPIOµÄʱÖÓ
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// ´ò¿ª´®¿ÚÍâÉèµÄʱÖÓ
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

	// ½«USART TxµÄGPIOÅäÖÃΪÍÆÍ츴ÓÃģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

  // ½«USART RxµÄGPIOÅäÖÃΪ¸¡¿ÕÊäÈëģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);   
}


void USART2_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// ´ò¿ª´®¿ÚGPIOµÄʱÖÓ
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// ´ò¿ª´®¿ÚÍâÉèµÄʱÖÓ
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

	// ½«USART TxµÄGPIOÅäÖÃΪÍÆÍ츴ÓÃģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

  // ½«USART RxµÄGPIOÅäÖÃΪ¸¡¿ÕÊäÈëģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);   
}


void USART3_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// ´ò¿ª´®¿ÚGPIOµÄʱÖÓ
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	// ´ò¿ª´®¿ÚÍâÉèµÄʱÖÓ
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

	// ½«USART TxµÄGPIOÅäÖÃΪÍÆÍ츴ÓÃģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

  // ½«USART RxµÄGPIOÅäÖÃΪ¸¡¿ÕÊäÈëģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOB, &GPIO_InitStructure);   
}


void USART4_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// ´ò¿ª´®¿ÚGPIOµÄʱÖÓ
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	// ´ò¿ª´®¿ÚÍâÉèµÄʱÖÓ
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

	// ½«USART TxµÄGPIOÅäÖÃΪÍÆÍ츴ÓÃģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

  // ½«USART RxµÄGPIOÅäÖÃΪ¸¡¿ÕÊäÈëģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOC, &GPIO_InitStructure);   
}

void USART5_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	// ´ò¿ª´®¿ÚGPIOµÄʱÖÓ
	RCC_APB2PeriphClockCmd((RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD), ENABLE);
	
	// ´ò¿ª´®¿ÚÍâÉèµÄʱÖÓ
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);

	// ½«USART TxµÄGPIOÅäÖÃΪÍÆÍ츴ÓÃģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

  // ½«USART RxµÄGPIOÅäÖÃΪ¸¡¿ÕÊäÈëģʽ
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOD, &GPIO_InitStructure);   
}

5个串口的中断和分组配置

//根据输入的USART执行对应的串口GPIO配置  为了给下面函数提供调用
void USART_GPIO_Config(USART_TypeDef* USARTx)
{
if(USARTx==USART1)
{
 USART1_GPIO_Config();
}else if(USARTx==USART2)
{
 USART2_GPIO_Config();
}else if(USARTx==USART3)
{
  USART3_GPIO_Config();
}else if(USARTx==UART4)
{
 USART4_GPIO_Config();
}else if(USARTx==UART5)
{
 USART5_GPIO_Config();
}
}

//NVIC分组  为了给下面函数提供调用
 void NVIC_Configuration(USART_TypeDef* USARTx,uint32_t NVIC_PriorityGroup,uint8_t PreemptionPriority,uint8_t SubPriority)
{
int DEBUG_USART_IRQ=0;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup);
if(USARTx==USART1)
{
 DEBUG_USART_IRQ=USART1_IRQn;
}else if(USARTx==USART2)
{
 DEBUG_USART_IRQ=USART2_IRQn;
}else if(USARTx==USART3)
{
 DEBUG_USART_IRQ=USART3_IRQn;
}else if(USARTx==UART4)
{
 DEBUG_USART_IRQ=UART4_IRQn;
}else if(USARTx==UART5)
{
 DEBUG_USART_IRQ=UART5_IRQn;
}

 
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
 
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
 
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = SubPriority;
 
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 
  NVIC_Init(&NVIC_InitStructure);
}


//这个函数基本就兼容了5个串口的所有配置了
void initUARTIQR(USART_TypeDef* USARTx, 
								uint32_t baudRate,
								uint32_t NVIC_PriorityGroup,
								uint8_t PreemptionPriority,
								uint8_t SubPriority) 
{
 USART_InitTypeDef USART_InitStructure;


    USART_Info usartInfo;
    usartInfo.USARTx = USARTx;
    usartInfo.baudRate = baudRate;


    int index = 0;
    while (index < MAX_NUM_USART && usartArray[index].USARTx != NULL) {
        index++;
    }
    if (index < MAX_NUM_USART) {
        usartArray[index] = usartInfo;
    }


			USART_GPIO_Config(USARTx);


    if (USARTx == USART1) {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    } else if (USARTx == USART2) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    }

    USART_InitStructure.USART_BaudRate = baudRate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; 
    USART_Init(USARTx, &USART_InitStructure);


		NVIC_Configuration(USARTx,NVIC_PriorityGroup,PreemptionPriority,SubPriority);

		USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);	
		USART_Cmd(USARTx, ENABLE);
}

兼容5个串口的printf 配置

void uartSendChar(USART_TypeDef* USARTx, char ch) {
    if (USARTx == USART1) {
        USART_SendData(USART1, ch);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    } else if (USARTx == USART2) {
        USART_SendData(USART2, ch);
        while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
    }else if (USARTx == USART3) {
        USART_SendData(USART3, ch);
        while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
    }else if (USARTx == UART4) {
        USART_SendData(UART4, ch);
        while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
    }else if (USARTx == UART5) {
        USART_SendData(UART5, ch);
        while (USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
    }
}

//以后所有打印函数都可以用这个调用
void Serial_Printf(USART_TypeDef* USARTx,char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	
	Usart_SendString(USARTx,String);
}

配置调用

//5个串口的配置 参数1 串口 ,参数2 波特率,参数3 分组几,参数4和参数5就是分组号了
	 initUARTIQR(USART1,115200,NVIC_PriorityGroup_1,1,1);
	
	 initUARTIQR(USART2,115200,NVIC_PriorityGroup_1,1,2);
	
	 initUARTIQR(USART3,115200,NVIC_PriorityGroup_1,1,3);
	
	 initUARTIQR(UART4,115200,NVIC_PriorityGroup_1,1,4);
	
	 initUARTIQR(UART5,115200,NVIC_PriorityGroup_1,1,5);

//5个函数的打印
  Serial_Printf( USART1,"%d\n",1);
  Serial_Printf( USART2,"%d\n",2);
  Serial_Printf( USART3,"%d\n",3);
  Serial_Printf( UART4,"%d\n",4);
  Serial_Printf( UART5,"%d\n",5);

下面提一下为什么5个串口开启中断后,正确分组还是卡死

先来一个错误示范

//Interput5是一个标志位 进入中断后会置1 

void UART5_IRQHandler(void)
{
  uint8_t ucTemp;
	if((USART_GetITStatus(UART5,USART_IT_RXNE)!=RESET)&&(Interput5==0))
	{		
	char ch =(char) USART_ReceiveData(UART5);
		
    //USART_SendData(UART5,ucTemp);  
        if (ch == '\n' || rxIndex >= RX_BUFFER_SIZE - 1) {
       
            rxBuffer5[rxIndex] = '\0';     
            rxIndex = 0;
           Interput5=1;
        } else {
         
            if (rxIndex < RX_BUFFER_SIZE - 1) {
                rxBuffer5[rxIndex++] = ch;								
            }
				}	 
	
  }
}

是不是觉得没什么大问题还可以,????实际上单独测试这个个串口中断服务函数也确实没有问题,但是5个串口一起跑就出现了奇奇怪怪的问题???为什么呢?

看正确代码, (原因是串口进入中断后并没有执行清除标志位操作,这里是取读取DR寄存器的值来清除标志位的,如果把标志位清除放前面,判断是否进入中断放后边就行了)

void UART5_IRQHandler(void)
{
  uint8_t ucTemp;
	if((USART_GetITStatus(UART5,USART_IT_RXNE)!=RESET))
	{		
	char ch =(char) USART_ReceiveData(UART5);
		if(Interput5==0){
    //USART_SendData(UART5,ucTemp);  
        if (ch == '\n' || rxIndex >= RX_BUFFER_SIZE - 1) {
       
            rxBuffer5[rxIndex] = '\0';     
            rxIndex = 0;
           Interput5=1;
        } else {
         
            if (rxIndex < RX_BUFFER_SIZE - 1) {
                rxBuffer5[rxIndex++] = ch;								
            }
				}	 
	}}
}

综上所诉还是会卡死及时代码正确执行,这又是为什么?

(我总结的原因是因为串口抢占优先级频繁进入,导致卡死)

后边改成轮询的方式一次循环执行一个中断服务函数的数据

看代码

while(1){
if(Interput1){
			IsUsrtx(rxBuffer1);
			Interput1=0;//´®¿Ú±ê־λ¸´Î»
			clearCharArray(rxBuffer1);//Çå¿Õ»º´æÇøÊý×é	
}else if(Interput2) { 
			IsUsrtx(rxBuffer2);
			Interput2=0;//´®¿Ú±ê־λ¸´Î»
			clearCharArray(rxBuffer2);//Çå¿Õ»º´æÇøÊý×é	
}else if(Interput3){
			IsUsrtx(rxBuffer3);
			Interput3=0;//´®¿Ú±ê־λ¸´Î»
			clearCharArray(rxBuffer3);//Çå¿Õ»º´æÇøÊý×é	
}else if(Interput4){
			IsUsrtx(rxBuffer4);
			Interput4=0;//´®¿Ú±ê־λ¸´Î»
			clearCharArray(rxBuffer4);//Çå¿Õ»º´æÇøÊý×é	
}else if(Interput5){
			IsUsrtx(rxBuffer5);
			Interput5=0;//´®¿Ú±ê־λ¸´Î»
			clearCharArray(rxBuffer5);//Çå¿Õ»º´æÇøÊý×é	
}
}
//这样就一次循环只处理一次中断接收内容,实际验证5个串按照10ms间隔不停发送,单片机完全能处理过来

好了下一个

如何在单片机中获取字符串长度,截取字符串,查找字符串,比较字符串,替换字符串呢?

我全部方法都放到了stringbuder.C里面  链接在置顶

stm32 cdc 虚拟多个串口,stm32,单片机,嵌入式硬件

stm32 cdc 虚拟多个串口,stm32,单片机,嵌入式硬件

调用实例:文章来源地址https://www.toymoban.com/news/detail-834328.html

//Strs是单片机收到的字符串

//截取字符串  从第0位开始截取2位
char* SbStr= SubString(Strs,0,2);
//释放内存  一定不能少
    free(SbStr);

//判断是否等于字符串 U2
if (strcmp(SbStr, "U2") == 0)
{}

//判断是否查找到字符串AYUOK
if (String_IndexStr(Strs, "AYUOK") != -1)
{}

更多的自己去看把

到了这里,关于在STM32中使用5个串口收发数据的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM-32:串口收发数据包—串口收发HEX数据包/串口收发文本数据包

    1、包头包尾和数据载荷重复的问题,传输的数据本身是FF和FE,可能引起误判 解决:限制载荷数据的范围,限幅(例如只发送0~100) 如果无法避免数据与包头包尾重复,则尽量使用固定长度的数据包 增加包头包尾的数量,尽量是其呈现出载荷数据出现不了的状态 2、包头包尾并

    2024年02月03日
    浏览(35)
  • STM32系列——串口收发数据基础

    串行接口相关知识 两种通信方式:并行通信与串行通信,并行通信传输速度快但是占用的引脚资源多,串行通信传输速度慢但是占用的引脚资源少。 三种模式:单工、半双工、全双工 异步串行通信:通信双方在没有同步时钟的前提下,将一个字符(包括特定的附加位)按位进

    2024年02月11日
    浏览(22)
  • 第10课【STM32 USB通讯协议实战】HID键盘+CDC虚拟串口组合设备

    文章中的部分概念可参考第9课【USB协议】USB总线 接口 端点 管道 数据包 枚举 STM32_USB-FS-Device_Lib V4.1.0 USB协议中为了提供对多样设备的支持,定义了许多外部设备子类,常见的包括: 人机交互类设备HID(Human Interface Device) 通信类设备CDC(Communicate Device Class) 大容量存储设备

    2024年02月04日
    浏览(50)
  • 【STM32笔记】STM32的串口数据收发基础(四)(USART DMA模式)

         在STM32中编写串口通信数据收发有三种方式: 轮询模式 (阻塞方式), 中断模式 (非阻塞方式)以及 DMA模式 。      打开STM32CubeMX,前部分配置流程如串口数据收发基础(三)节里一样。配置好USART1的基本参数,开启定时器中断后,接下来就要开启USART1的DMA。

    2024年02月03日
    浏览(27)
  • 【STM32】STM32学习笔记-USART串口收发HEX和文本数据包(29)

    串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式, 电子工程师在调试设备时也经常使用该通讯方式输出调试信息。 在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和

    2024年01月19日
    浏览(36)
  • 【STM32】STM32F103C8T6串口通信,实现3个串口收发数据

    串口通信(Serial Communications)实现单片机与电脑或者其它外设进行通信,通信时只需两根线(TX,RX)就可以实现数据传输。STM32f103有三个串口,分别为串口1(RX PA10, TX PA 9),串口2(RX PA3,TX PA2),串口3(RX PB11,TX PB10)。 以下代码是配置三个串口: usart.c usart.h main.c 注意,

    2024年02月12日
    浏览(36)
  • stm32和python实现DMA+串口数据收发

    1-0 串口配置 1-1 DMA发送模式配置 1-2 通过DMA传输数据到USART1的发送寄存器 1-3 串口数据发送 将usart1_dma_tx_data()函数放在main函数中或者中断处理函数中即可,如下所示: 2-1 DMA接收模式配置 2-2 串口结束中断 2-3 对串口接收的数据进行处理 3 完整程序

    2024年02月14日
    浏览(27)
  • 【STM32学习】——USART串口数据包&HEX/文本数据包&收发流程&串口收发HEX/文本数据包实操

    声明:学习笔记根据b站江科大自化协stm32入门教程编辑,仅供学习交流使用!

    2024年02月06日
    浏览(38)
  • 野火指南者(STM32F103VET6)应用:实现USB虚拟串口(CDC_VPC)

    MCU:STM32F103VET6 开发环境:STM32CubeMX+MDK5   实现USB的虚拟串口不需要去理解USB的底层驱动,只需要STM32CubeMX去配置生成工程即可。在野火的指南者中,是没有这一类的视频和示例的,博主使用这款开发板实现USB虚拟串口。 首先需要打开STM32CubeMX工具。输入开发板MCU对应型号,找

    2024年02月08日
    浏览(36)
  • 【STM32通讯系列--串口通讯】使用标准库、HAL库实现任意长度数据的收发(包含帧头、帧尾校验,配套完整开源程序)

    【数据组成】串口的通讯协议由开始位,数据位,校验位,结束位构成。 【数据结构】一般以一个低电平作为一帧数据的起始,接着跟随 8 位或者 9 位数据位,之后为校验位,分为奇校验,偶校验和无校验,最后以一个先高后低的脉冲表示结束位,长度可以设置为 0.5,1,

    2024年02月14日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包