×
单片机 > 单片机程序设计 > 详情

STM32 USART 接收任意长度字符

发布时间:2020-06-16 发布时间:
|

近段时间学习到 STM32 USART 部分,基本上在接收数据的时候都是采用定长,所以一直想实现接收任意长度的字符串。这里的任意长度不是指的无限长,而是在自己定义的缓冲区范围之类。比如说缓冲区的大小是 1024 Byte,那么就能接收不大于 1024 个字符串。


当时有两个思路:

1、使用结尾标志,如 "rn" 什么的

2、定时判断接收数据的长度,如果在规定的时间内长度没有发生变化,证明已经接收完了任意长度的字符

因为思路 1 比较好实现,而且网上也有很多例程,所以着重讲思路 2



宏定义:


usart.h 文件



/****************************************************************************************************************/


#ifndef USART_H

#define USART_H

 

#include "stm32f4xx.h"

 

#define MAX_LENGTH 1024

#define USARTX USART3

#define USART_CLK RCC_APB1Periph_USART3

#define USART_BAUD_TATE 115200

 

#define USART_GPIO_PORT GPIOB

#define USART_GPIO_CLK RCC_AHB1Periph_GPIOB

#define USART_RX_PIN GPIO_Pin_11

#define USART_TX_PIN GPIO_Pin_10

#define USART_RX_PINSOURCE GPIO_PinSource11

#define USART_TX_PINSOURCE GPIO_PinSource10

#define GPIO_AF_USART GPIO_AF_USART3

 

#define USART_IRQN USART3_IRQn

#define USART_IRQ_HANDLDER USART3_IRQHandler

 

void USART_Init(void);

char* USART_GetString(void);

/******************************************************************************************************************/

注意:

本文中使用的是 STM32F405 系列的单片机,使用的是 USART3 ,请读者根据自己的单片机型号和 USART 做出相应更改


usart.c 文件


/****************************************************************************************************************/



#include "./XXX/usart.h" //XXX 代表存放 usart.h 文件的路径

 

volatitle char receiveBuffer[MAX_LENGTH];

volatitle uint16_t receiveLength = 0;

volatitle uint8_t rxFlag = 0;

static char str[MAX_LENGTH + 1];

 

static void GPIO_Config(void)

{

GIPO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(USART_GPIO_PORT, ENABLE);

 

GPIO_PinAFConfig(USART_GPIO_PORT, USART_RX_PINSOURCE, GPIO_AF_USART);

GPIO_PinAFConfig(USART_GPIO_PORT, USART_TX_PINSOURCE, GPIO_AF_USART);

 

GPIO_InitStructure.GPIO_Pin = USART_RX_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

GPIO_Init(USART_GPIO_PORT, &GPIO_InitStructure);

 

GPIO_InitStructure.GPIO_Pin = USART_TX_PIN;

GPIO_Init(USART_GPIO_PORT, &GPIO_InitStructure);

}

 

static void NVIC_Config(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

NVIC_InitStructure.NVIC_IRQChannel = USART_IRQN;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

}

 

static void delay_us(uint16_t time)

{

uint8_t count;

while(time--)

{

count = 10;

while(count--);

}

}

 

void USART_Init(void)

{

USART_InitTypeDef USART_InitStructure;

RCC_APB1PeriphClockCmd(USART_CLK, ENABLE);

 

GPIO_Config();

NVIC_Config();

 

USART_InitStructure.USART_BaudRate = USART_BAUD_TATE;

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_Rx | USART_Mode_Tx;

USART_Init(USARTX, &USART_InitStructure);

 

USART_ITConfig(USARTX, USART_IT_RXNE, ENABLE);

USART_Cmd(USARTX, ENABLE);

}

 

char* USART_GetString(void)

{

uint16_t temp;

while(!rxFlag); //等待接收数据,在串口接收到一帧数据时 rxFlag 将会被置 1 (USART3 中断服务函数中)

while(rxFlag)

{

temp = receiveLength;

delay_us(500); //等待 500us 

if(temp == receiveLength) //判断 receiveLength 是否发生变化(USART3 中断函数中 receiveLength 会有变化),如果没有,证明已经收完所有的数据,否则等待接收完成

{

rxFlag = 0;

}

}

 

for(temp = 0; temp < receiveLength; temp++)

{

str[temp] = receiveBuffer[temp];

}

 

receiveLength = 0;

str[temp] = "";

return str;

}

/****************************************************************************************************************/

stm32f4xx_it.c 文件

/****************************************************************************************************************/



#include "./XXX/usart.h" //XXX 代表存放 usart.h 文件的路径

 

extern volatitle char receiveBuffer[MAX_LENGTH];

extern volatitle uint16_t receiveLength;

extern volatitle uint8_t rxFlag;

 

/*USART3 中断服务函数*/

 

void USART_IRQ_HANDLDER(void)

{

char temp;

 

if(USART_GetITStatus(USARTX, USART_IT_RXNE))

{

USART_ClearITPendingBit(USARTX, USART_IT_RXNE);

temp = USART_ReceiveData(USARTX)

if(receiveLength == MAX_LENGTH)

{

return;

}

if(!rxFlag)

{

rxFlag = 1;

}

 

receiveBuffer[receiveLength++] = temp;

}

}

/****************************************************************************************************************/


main.c 文件


/****************************************************************************************************************/



#include "./XXX/usart.h" //XXX 代表存放 usart.h 文件的路径

 

int main()

{

char* temp = NULL;

USART_Init();

temp = USART_GetString();

while(1)

{

 

}

}

/****************************************************************************************************************/


总结:


       当 USART 接收到一个字符时进入中断服务函数,在中断服务函数中会将 rxFlag 标志置 1 ,然后判断接收缓冲区 receiveBuff 是否溢出。若没有溢出,则将字符存储到接收缓冲区中,接收长度 receiveLength 做自加运算。


       接收函数 GetString() 通过 500us 的间隔检测 receiveLength 是否发生改变,若没有发生改变,意味着 USART 已经接受完所有数据,则从接收缓冲区中取出接收到的数据。若发生改变,则意味着 USART 尚未接收完所有数据,所以等待其接收完所有数据。


       本程序中存在一些不足,首先是如果接收缓冲区溢出了并不会报错,不过只能接收和缓冲区长度一致的字符。还有就是 receiveLength 的检测时间,理论上来说只需要设定为 3 * 接收一位数据的时间,即 3 / Baud 秒,但是通过逐一调试,发现只有大于 500us 时才能出现正确的结果。

关键字:STM32  USART  任意长度字符 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机CO2检测显示程序解析