STM32HAL串口发送接收任意长度字符

使用printf函数

STM32 HAL库 UART使用printf
MDK设置:勾选Use Micro LIB(忘记勾选,结果半天没反应)
在这里插入图片描述

主函数中添加如下代码

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart3, &ch, 1, 0xffff);
  return ch;
}
/* USER CODE BEGIN 0 */

//1、首先要在你的main 文件中 包含“stdio.h” (标准输入输出头文件)
#include <stdio.h>

//2、在main文件中重定义<fputc>函数 如下:
// 发送数据
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch, 1, 0xFFFF);// USART1 可以换成 USART2 等
while (!(USART1->SR & UART_FLAG_TXE));
return (ch);
}
// 接收数据
int GetKey (void) {
while (!(USART1->SR & UART_FLAG_RXNE));
return ((int)(USART1->DR & 0x1FF));
}
/* USER CODE END 0 */
printf("\n\r while循环中!!!\n\r");

printf十六进制输出_printf函数
在这里插入图片描述

DMA串口接收发送数据

STM32—cubeMX+DMA+USART 接收任意长度的数据在这里插入图片描述

1、串口初始化

CubeMx自动生成,在USERcode添加

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能idle中断
	HAL_UART_Receive_DMA(&huart1,rx_buffer,buffsize);//打开DMA接收,数据存入rx_buffer数组中。
  /* USER CODE END USART1_Init 2 */

}

2、接收中断处理
/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
		temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		temp = huart1.Instance->DR; //读取数据寄存器中的数据
		HAL_UART_DMAStop(&huart1); //
		temp  = hdma_usart1_rx.Instance->NDTR;// 获取DMA中未传输的数据个数,NDTR寄存器分析见下面
		rx_len =  buffsize - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag = 1;	// 接受完成标志位置1	
	 }
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}
3、主循环函数
  while (1)
  {	
		

		if(recv_end_flag ==1)
		{
//			printf("\n\r while循环中!!!\n\r");
			printf("rx_len=%d\r\n",rx_len);//打印接收长度
//			PackageSendData((uint8_t *) rx_buffer, &rx_len);
			HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);//接收数据打印出来
			for(uint8_t i=0;i<rx_len;i++)
				{
					rx_buffer[i]=0;//清接收缓存
				}
			rx_len=0;//清除计数
			recv_end_flag=0;//清除接收结束标志位
		}
		HAL_UART_Receive_DMA(&huart1,rx_buffer,buffsize);//重新打开DMA接收	
}

在这里插入图片描述

打包发送数据

/***********************************************************************************************************
* 函数名称: PackageSendData()
* 输入参数: data,要发送的数据的首地址; *len,发送数据的总长度
* 返回值  : 无
* 功    能: 根据通信协议,封装要发送的数据
************************************************************************************************************/
void PackageSendData(u8* data, u8* len)
{
  u8 temp[64],temp1[64],i,j = 0;
  u16 crc;
  
  memset(&temp[0], 0, sizeof(temp));
  memset(&temp1[0], 0, sizeof(temp1));
  memcpy(&temp[2], data, *len); //复制传输数据
  temp[0] = FrameHeader; //加入帧头
  temp[1] = *len+3; //加入长度值
  crc = CRC16MODBUS(&temp[1], *len+1); //计算CRC16校验值
  memcpy(&temp[*len+2], &crc, 2); //复制校验值
  for(i=3; i < *len+3+j; )
  {
    if((temp[i]==FrameHeader)||(temp[i]==FrameEnd))//如果传输的数据中有和帧头或帧尾一样的数据则插入转义符
    {
      memset(&temp1[0], 0, sizeof(temp1));
      memcpy(&temp1[0], &temp[i], *len+3+j-i);
      temp[i] = 0x5C; //加入转义符 ‘\'
      memcpy(&temp[i+1], &temp1[0], *len+3+j-i);
      i = i+2;
      j++;
    }
    else
      i++;
  }
  temp[*len+4+j] = FrameEnd;
  memcpy(data, &temp[0], *len+5+j);
  *len = *len+5+j;
}
	/* UART_Transmit test BEGIN 串口数据发送测试*/
	u8 cnt;
	cnt = 5;
	u8 uart2BUF[32] = {0X2A,0X2B,0x2C,0x2D,0x2E,0x2F,0x21,0x22};
	PackageSendData((uint8_t *) uart2BUF, &cnt);
	HAL_UART_Transmit(&huart2,(uint8_t *)uart2BUF,cnt,0XFF);
		/* UART_Transmit test END*/

在这里插入图片描述

接收指定协议数据
验证接收数据有效性

发送 01 02
打包后数据为 9A 05 01 02 E1 90 9B
在这里插入图片描述

/***********************************************************************************************************
* 函数名称: UnpackReceivedData()
* 输入参数: data,要解包的数据的首地址,*len 要解包的数据的总长度(不包括帧头和帧尾)
* 返回值  : 1, 数据有效, 0,数据无效。
* 功    能: 解包接收到的数据并判断数据有效性
************************************************************************************************************/
u8 UnpackReceivedData(u8* data, u8* len)
{
  u16 crc,crctemp;
  
  memcpy(&crctemp,(data+*len-3),2); //复制数据中的CRC校验值
	printf("crctemp=%d\r\n",crctemp);
  crc = CRC16MODBUS(data, *len-3); //计算数据的CRC16校验值
	printf("crc=%d\r\n",crc);
  if(crctemp == crc) //校验值正确
    return 1;
  
  return 0;
}

CRC校验范围为数据长度位 + 数据 不包括帧头
在这里插入图片描述

STM32HAL中,串口接收数据的中断处理函数为UART_IRQHandler()。在该函数中,可以通过调用HAL_UART_Receive_IT()函数来启动下一次接收过程,并通过判断接收缓冲区中是否有数据来进行数据处理。 以下是一个简单的示例代码,可以在该代码的基础上进行修改,以实现接收字符串并进行处理: ```c #define MAX_STR_LEN 100 // 接收字符串的最大长度 char rx_buffer[MAX_STR_LEN]; // 接收缓冲区 int rx_index = 0; // 接收缓冲区当前位置 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (rx_index < MAX_STR_LEN - 1) { rx_buffer[rx_index++] = huart->Instance->DR; // 将接收到的字符存入接收缓冲区 if (rx_buffer[rx_index - 1] == '\n') { // 判断是否接收到了换行符,表示字符串接收完成 rx_buffer[rx_index - 1] = '\0'; // 将换行符替换为字符串结束符 // 在这里进行对接收到的字符串的处理 rx_index = 0; // 接收缓冲区指针归零,准备下一次接收 } } else { rx_index = 0; // 接收缓冲区满了,强制清空 } HAL_UART_Receive_IT(huart, (uint8_t *)&rx_buffer[rx_index], 1); // 启动下一次接收 } int main() { // 初始化串口等相关设置... HAL_UART_Receive_IT(&huart, (uint8_t *)&rx_buffer[rx_index], 1); // 启动第一次接收 while (1) { // 主程序循环处理... } } ``` 在上述代码中,我们通过定义一个接收缓冲区(rx_buffer)和一个接收缓冲区指针(rx_index),在中断处理函数中不断地将接收到的字符存入接收缓冲区,直到接收到换行符('\n')表示字符串接收完成。然后,在接收完成后,我们可以在接收缓冲区中对接收到的字符串进行处理。 需要注意的是,上述代码仅供参考,具体实现方式可以根据实际需求进行修改。同时,为了保证接收的稳定性,还需要在程序中加入一些错误处理代码,例如超时判断、缓冲区溢出处理等。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值