串口通信中一些常用的小工具

本文总结下串口通信的一些小技巧

1、逻辑分析仪下的串口数据

首先我们还是先配置一个串口,一般正常情况下都默认是可以的
在这里插入图片描述
上面参数的意思:

  • 波特率 115200
  • 字长 8
  • 校验 无校验
  • 停止位 1位

那我们先来看下串口通信具体是什么样的,串口的数据包组成如下:
在这里插入图片描述
我们在来看下用串口发下数据到逻辑i分析仪里面读取的数据,相关说明我已经在图片中标出来了
在这里插入图片描述
这是我串口发送的数据
在这里插入图片描述
那我们再来看下波特率,这里我们选的波特率是115200,那就是1秒钟可以发送115200byte的数据,那一个数据的时间可以计算如下所示:
在这里插入图片描述
而我们可以在逻辑分析仪中测量下这个时间的准确性,可以看到是非常准确的(废话,这用的不是硬件串口吗,哈哈哈
在这里插入图片描述
这样就可以帮我么更清楚的认识串口了!

2、数字转字符串函数

通信过程中一般都是发送字符串偏多,因为字符串就是char类型的,可以直接匹配串口的数据,方便转化,所以一个常用的小工具就是数字转字符串了!

u32 Pow(u32 num,u8 count)
{
	u8 i;
	u32 result = 0;
	if(count == 0)
	{
		num = 1;
		return num;
	}
	else
	{
		result = num;
		for(i = 0;i<count-1;i++)
		{
			result *= num;	
		}
	}
	return result;
}

void NumToString(u32 num,u8 numbit,u8 *string)
{
	u8 i=0,z=0;
	u32 temp = 0;
	u8 changestart = 0;
	u8 j = numbit-1;

	for(i = 0;i<numbit;i++)
	{
		temp = num/Pow(10,j);

		if(changestart)
		{
			string[z++] = temp+0x30;
		}
		if((temp>0)&&(changestart == 0))
		{
			string[z++] = temp+0x30;	
			changestart = 1;
		}

		temp = Pow(10,j);
		num %= temp;
		j--;
	}
	string[z] = 0;
}

那么如果是浮点数怎么办呢,就只能是先转为整数在处理了,就是先把他变为整数,再用这个函数来处理!

更好的办法还可以采用官方函数的方法,可以无视整数和浮点数的差异,该函数的用法如下所示,因为后面一个参数是格式化的数据,那%d就是整形数据,%f就是单精度浮点型了。
在这里插入图片描述

3、字符串转整数

这也是比较常用的一种数据类型,有很多时候接收到的数据是以字符串的方式发过来的,我们要获取其中的整形数据,就可以用这个方法,flag是分隔符,比如一组数据13,23,23这样就是以,为分隔符了

int32_t str2int(uint8_t * str, uint8_t flag, uint8_t no)
{
	uint8_t No = 1;
	uint8_t * Str = str;
	uint8_t NumTemp[TempIntLen];
	while(No!=no)
	{
		if(*Str == flag)
			No++;
		Str++;
	}
	No = 0;
	while(*Str != flag && *Str != '\r' && *Str != '\n' && *Str != '\0' && No < (TempIntLen - 1))
	{
		NumTemp[No] = *Str;
		Str++;
		No++;
	}
	NumTemp[No] = '\0';
	return atoi(NumTemp);
}

4、字符串转浮点数

这个就是获取其中的浮点型数据了,flag是分隔符

void str2double(uint8_t * str, uint8_t flag, uint8_t no, double * Output)
{
	uint8_t No = 1;
	uint8_t * Str = str;
	uint8_t NumTemp[TempDoubleLen];
	uint8_t NumTemp_int[TempDoubleLen];
	double OutputNum;
	while(No!=no)
	{
		if(*Str == flag)
			No++;
		Str++;
	}
	No = 0;
	while(*Str != flag && *Str != '\r' && *Str != '\n' && *Str != '\0' && No < (TempDoubleLen - 1))
	{
		NumTemp[No] = *Str;
		Str++;
		No++;
	}
	NumTemp[No] = '\0';
	NumTemp[(TempDoubleLen - 1)] = 0;
	No = 0;
	while(NumTemp[NumTemp[(TempDoubleLen - 1)]] != '\0' && NumTemp[(TempDoubleLen - 1)] < (TempDoubleLen - 1))
	{
		if(NumTemp[NumTemp[(TempDoubleLen - 1)]] == '.')
		{
			NumTemp[(TempDoubleLen - 1)]++;
			NumTemp_int[(TempDoubleLen - 1)] = NumTemp[(TempDoubleLen - 1)];
		}
		NumTemp_int[No] = NumTemp[NumTemp[(TempDoubleLen - 1)]];
		No++;
		NumTemp[(TempDoubleLen - 1)]++;
	}
	NumTemp_int[No]='\0';
	NumTemp[(TempDoubleLen - 1)] = NumTemp_int[(TempDoubleLen - 1)]++;
	OutputNum = (double)atoi(NumTemp_int);
	while(NumTemp[NumTemp[(TempDoubleLen - 1)]] != '\0')
	{
		OutputNum /= 10;
		NumTemp[(TempDoubleLen - 1)] ++;
	}
	*Output = OutputNum;
}

5、测试转换方法

以上四种转换方法的测试如下所示:

int num=1253423456;
u8 str[20]= {0};
char str1[]="112,233,41";
char str2[]="112.32,233.34,343.45";
double dat[3];

int main(void)
{
	NumToString(num,10,str);
	printf("%s\n",str);
	printf("%d\n%d\n%d\n",str2int(str1,',',1),str2int(str1,',',2),str2int(str1,',',3));
	str2double(str2,',',1,dat);
	str2double(str2,',',2,dat+1);
	str2double(str2,',',3,dat+2);
	printf("%f\n%f\n%f",dat[0],dat[1],dat[2]);
}

打印结果如下所示,可以看到,结果是非常顺利的!
在这里插入图片描述

6、空闲中断DMA接收不定长数据

在需要接收大量数据的情况下这个是比较常用的,比如解析物联网开发时候云下发的json命令,一般数据梁都比较大而且不是固定长度的数据,这个时候这个东西就变得很有必要了

开启串口,并设置参数,一般情况默认即可
在这里插入图片描述
配置中断和DMA
在这里插入图片描述
配置DMA发送和接收函数模式

在这里插入图片描述
初始化中开启串口空闲中断
在这里插入图片描述
对中断函数进行处理
在这里插入图片描述
空闲中断处理函数如下所示
在这里插入图片描述

源代码如下:

UART_DMA.c

/*
 * UART_DMA.c
 *
 *  Created on: Mar 18, 2022
 *      Author: LX
 */

#include "UART_DMA.h"

#include "string.h"
#include "stdarg.h"
#include "stdio.h"



#define USART_DMA_TX_BUFFER_MAXIMUM			128    // DMA缓冲区大小
#define USART_DMA_RX_BUFFER_MAXIMUM			128    // DMA缓冲区大小

extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;

extern UART_HandleTypeDef huart1; //UART句柄
uint8_t usart1_rx_buffer[USART_DMA_RX_BUFFER_MAXIMUM]; //串口1的DMA接收缓冲区
uint8_t usart1_tx_buffer[USART_DMA_TX_BUFFER_MAXIMUM]; //串口1的DMA发送缓冲区
uint16_t usart1_rx_len; //DMA一次空闲中断接收到的数据长度
uint8_t receive_data[USART_DMA_RX_BUFFER_MAXIMUM];	  //DMA接收数据缓存区

void HAL_UART_ReceiveIdle(UART_HandleTypeDef *huart)
{
  //当触发了串口空闲中断
  if((__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET))
  {
    if(huart->Instance == USART1)
    {
      __HAL_UART_CLEAR_IDLEFLAG(huart);
      HAL_UART_DMAStop(huart);
      usart1_rx_len = USART_DMA_RX_BUFFER_MAXIMUM - (__HAL_DMA_GET_COUNTER(&hdma_usart1_rx));
      memcpy(receive_data, usart1_rx_buffer, USART_DMA_RX_BUFFER_MAXIMUM);
      memset(usart1_rx_buffer,0,128);
      while (HAL_UART_Receive_DMA(&huart1,(uint8_t *)usart1_rx_buffer, USART_DMA_RX_BUFFER_MAXIMUM)!=HAL_OK);

//      Debug_printf("%s",receive_data); // 是否添加回环检测函数
    }
    //下面添加其他串口的处理函数

  }
}
void UART1_TX_DMA_Send(uint8_t *buffer, uint16_t length)
{
  while(HAL_DMA_GetState(&hdma_usart1_tx) != HAL_DMA_STATE_READY);
  //while(__HAL_DMA_GET_COUNTER(&hdma_usart1_tx));
  __HAL_DMA_DISABLE(&hdma_usart1_tx);
  HAL_UART_Transmit_DMA(&huart1, buffer, length);
}

void Debug_printf(const char *format, ...)
{
  uint32_t length = 0;
  va_list args;

  va_start(args, format);

  length = vsnprintf((char *)usart1_tx_buffer, sizeof(usart1_tx_buffer), (char *)format, args);
  UART1_TX_DMA_Send(usart1_tx_buffer, length);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1)
  {
    __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_TC4);
//    HAL_UART_DMAStop(&huart1);
  }
}

UART_DMA.h

#include "main.h"


void HAL_UART_ReceiveIdle(UART_HandleTypeDef *huart);
void UART1_TX_DMA_Send(uint8_t *buffer, uint16_t length);
void Debug_printf(const char *format, ...);

7、高频数据收发测试

下面可以对数据接收进行暴力测试:

在串口助手中设置高频率的大量数据进行发送,并在单片机端设置数据回传,测试结果如下:
在这里插入图片描述
正常情况下回环接收
在这里插入图片描述
周期加大会开始出现错误
在这里插入图片描述
经过测试我得到的结论大概如下:

  • 不要把数据发送频率设置的过高。115200的波特率数据量上去50hz的频率都受不了
  • 提高波特率可以在更高的频率下进行数据收发,我这里用的92个数据,在100khz的情况下是没有什么问题的,提高到200khz出现了部分数据不完整的现象
  • 这只是个测试,单片机仅仅只是跑了一个程序,实际情况下可能会出现比如其他程序中断的问题等等,都会对接收效果造成影响
  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃成蹊2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值