STM32串口通信+数据处理

一、初始化设置

配置能够输出、接收串口数据(ttl信号)的GPIO口,下方链接中有对应uart配置的引脚图。STM32F103X芯片PWM应用_tim_ocmode_pwm2-CSDN博客

这里我选用的是USART1。

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);

以上这段代码网上很多,其中含义大家自己去了解,我在此不多做介绍。

二、发送数据

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

在初始化时,我们设定了PA9是发送口(口),而在串口中高电平是1,低电平是0,(stm32的串口信号属于ttl,还有什么rs232,ch340这些串口类型,我下篇文章再介绍)所以配置是AF(浮空)状态不确定,防止误发信号,至于为什么是pp(推免:能输出一定电流)因为要驱动你外接设备的串口。

	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

第一行代码参数是发送数据的串口,和发送的数据(只要是8位就行,16位,32位它会只取低8位),第二行是循环检测标志位,直到数据发送完毕。

根据这个发送数据的原理,可以自行构造函数,发送文本,字符串或者数字。

三、接受数据

void USART1_IRQHandler(void)//串口中断
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//为1则没有读取完
	{
		RS232_RxData = USART_ReceiveData(USART1);//将读取的值赋给变量
		RS232_RxFlag = 1;
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

该中断函数会在有数据返回时,自动开启,读取标志位如果置零,我们将读取完的数据赋给变量,RS232_RxData,且我们手动添加一个标志位RS232_RxFlag置一,并再次构建俩个函数,用来保存RS232_RxData,RS232_RxFlag中的数据,因为这俩个变量在设计时就充当了中间变量的角色。

uint8_t RS232_GetRxFlag(void)
{
	if (RS232_RxFlag == 1)
	{
		RS232_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t RS232_GetRxData(void)
{
	return RS232_RxData;
}

最底层的8位数据我们已经可以拿到了,接下来开始缓存。

uint8_t Rx_Buffer[BUFFER_SIZE];//数据缓存的数组
uint32_t Rx_Index = 0;//缓存算法中的检索值
#define BUFFER_SIZE 100 //服务器发送数据的最大缓存数
#define RESPONSE_SIZE 8 //服务器与单片机数据交换的指定数据长度

#define HC_MODE 1
#define RS232_MODE 2
#define TTS_MODE 3
/*数据缓存*/
uint8_t* Data_Caching(uint8_t SERIAL_MODE)
{
	while(1)
	{
		//缓存开始
			if(GetRxFlag(SERIAL_MODE)==1)
		{
			Rx_Buffer[Rx_Index] = GetRxData(SERIAL_MODE);
			Rx_Index=(Rx_Index+1)%BUFFER_SIZE;
		}
		//缓存结束
		  if(Rx_Buffer[Rx_Index-1]==0xf4)
		{
			return getSubArray(Rx_Buffer,0,Rx_Index);//返回缓存片段,后续将缓存清空
		}
	}
}

这是我从我一个项目里摘抄的因为里面有三个串口,不要直接拿来用,SERIAL_MODE,你们要用这个函数的时候填2或RS232_MODE就行。参考这段代码

uint8_t GetRxFlag(uint8_t SERIAL_MODE)
{
	switch(SERIAL_MODE)
	{
		case 1:
			return HC_GetRxFlag();
			break;
		case 2:
			return RS232_GetRxFlag();
			break;
		case 3:
			return TTS_GetRxFlag();
			break;
	}
}

uint8_t GetRxData(uint8_t SERIAL_MODE)
{
	switch(SERIAL_MODE)
	{
		case 1:
			return HC_GetRxData();
			break;
		case 2:
			return RS232_GetRxData();
			break;
		case 3:
			return TTS_GetRxData();
			break;
	}
}

这里我设置最大能缓存100个字节,然后在缓存字节中有出现0xf4这个字节(这是我的需求你们也可以进行更改),缓存结束,然后我们截取0xf4之前的所有数据,组成一个数据片段。

/*结合数据缓存,将片段截取出去*/
uint8_t* getSubArray(uint8_t arr[], int start, int end) 
{
    int subArrayLength = end - start + 1;
    uint8_t* subArray = (uint8_t*)malloc(subArrayLength * sizeof(uint8_t));

    for (int i = 0; i < subArrayLength; i++) {
        subArray[i] = arr[start + i];
    }

    return subArray;
}

将参数带入这个函数,三个参数分别是,截取数据的数组,起,始位置。

这样我们就完成了对数据的缓存,和数据截取,接下来是数据比对。

/*数据比对*/
uint8_t Data_Comparison(uint8_t *str1,uint8_t *str2)
{
		if(Rx_Index==RESPONSE_SIZE)
		{
				for(int index=0;index<RESPONSE_SIZE;index++)
			{
				if(str1[index]!=str2[index])
				{
					return 0x00;
				}
			}
					return 0x01;
		}
		else
		{
			return 0x00;
		}
		
}

str1是你缓存的数据,str2是你任务需求自己设定的一个数据,如果返回数据中存在你预期设定的数据返回0x01,若没有则返回0x00。数据比对完后,别忘了清空缓存。

/*数据清空*/
void Data_Cleared()
{
	for(int index=0;index<Rx_Index;index++)
	{
		Rx_Buffer[index]=0x00;
	}
	Rx_Index=0;
}

以上我主要是介绍一个思路,部分代码是通用的。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值