STM32 USART 接收任意长度字符

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


当时有两个思路:
1、使用结尾标志,如 "\r\n" 什么的
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 文件的路径

volatile char receiveBuffer[MAX_LENGTH];
volatile uint16_t receiveLength = 0;
volatile 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] = "\0";
	return str;
}

stm32f4xx_it.c 文件

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

extern volatile char receiveBuffer[MAX_LENGTH];
extern volatile uint16_t receiveLength;
extern volatile 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 时才能出现正确的结果。

  • 32
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值