解决在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里面  链接在置顶

调用实例:

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

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

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

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

更多的自己去看把

物联沃分享整理
物联沃-IOTWORD物联网 » 解决在STM32中使用5个串口收发数据的问题

发表评论