基于CubeMX的串口收发笔记

基于CubeMX的串口收发笔记

一、什么是串口通信

串口通信是一种通信协议,有些宝子们可能会疑惑什么是通信协议,那么我先说一下通信协议是什么。

通信协议就是通信双方在数据传输过程中需要共同遵守的规定。数据的发送方按照某种协议把数据调制成可以被传输的信号,接收方就可以使用相同的协议从信号中解析出数据。举个栗子~,我们人在对话的过程中,语言就可以看作是一种通信协议。说话的人会把想说的话调制在声波上进行传输,收听方就会从声波上解析出这句话。这个过程就是用到了 “语言” 这个协议。

言归正传,通过百度百科我们知道,串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。典型地,串口用于ASCII码字符的传输。通信使用3根线完成,分别是地线、发送、接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

二、三种方式使用串口通信

2.1 阻塞方式

2.1.1 工程的配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.1.2 工程代码(发送)
  1. 法1: 阻塞式发送:当要发送的数据都传输完了,这个函数才会执行结束。
/*一个参数(&huart):串口句柄
第二个参数:要发送的数据首地址,这里填入一个字符串常量
第三个参数是我们要发送的数据长度,这里填入字符串的长度
第四个参数是超时时间,单位毫秒
*/
while (1)
  {	  
	HAL_UART_Transmit(&huart1, (uint8_t*)"hello", 5, 200);
     HAL_Delay(1000);
     
    /* USER CODE BEGIN 3 */
  }

每隔一秒钟就会发送一次hello
在这里插入图片描述

  1. 法2: printf函数来进行串口的输出

    第一步: 引用标准库的头文件

    /* USER CODE BEGIN Includes */
    #include "stdio.h"
    /* USER CODE END Includes */
    

    第二步:重写fputc函数,printf内部就是调用这个函数来进行单个字符输出的

    /* USER CODE BEGIN 0 */
    int fputc(int c, FILE *stream)
    {
    	uint8_t ch[1] = {c};
    	HAL_UART_Transmit(&huart1, ch, 1, 0xffff);
    	return c;
    }
    /* USER CODE END 0 */
    
    //在主函数中使用printf
       while (1)
        {
      	  printf("Hello %d\r\n", 123);
      	  HAL_Delay(1000);
          /* USER CODE END WHILE */
            /* USER CODE BEGIN 3 */
    }
    

在这里插入图片描述

2.1.3 工程代码(接收)
  1. 方法1:
 while (1)
     {
   	  uint8_t buf[5];
   	  HAL_UART_Receive(&huart1, buf, 3, 0xffff);//接受3个字节
   	  HAL_UART_Transmit(&huart1, buf, 3, 0xffff);
       /* USER CODE END WHILE */

       /* USER CODE BEGIN 3 */
     }

在这里插入图片描述

  1. 方法2:使用scanf这个函数来进行串口的接收

    /* USER CODE BEGIN 0 */
    int fputc(int c, FILE *stream)
    {
    	uint8_t ch[1] = {c};
    	HAL_UART_Transmit(&huart1, ch, 1, 0xffff);
    	return c;
    }
    
    int fgetc(FILE *stream)
    {
    	uint8_t ch[1];
    	HAL_UART_Receive(&huart1, ch, 1, 0xffff);
    	return ch[0];
    }
    
    /* USER CODE END 0 */
    
    
     //在主函数中
       while (1)
         {
       	  int val = 0;
       	  scanf("%d", &val);//读入数组
       	  printf("%d\r\n", val);//发送回来
           /* USER CODE END WHILE */
            /* USER CODE BEGIN 3 */
     	}
    

    在这里插入图片描述

2.2 中断方式

2.2.1 工程配置

在这里插入图片描述

2.2.2 工程代码
/* USER CODE BEGIN 0 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Transmit_IT(&huart1, buffer, 3);
	HAL_UART_Receive_IT(&huart1, buffer, 3);

}

/* USER CODE END 0 */



//主函数中
 /* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, buffer, 3);
  /* USER CODE END 2 */

在这里插入图片描述

2.3 DMA方式

2.3.1 什么是DMA

DMA是单片机中的一个数据搬运的助手,它可以在内存和内存之间或者内存与外设之间进行数据的搬运。

2.3.2 工程配置

在这里插入图片描述
在这里插入图片描述

2.3.3 工程代码
/* USER CODE BEGIN 0 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Transmit_DMA(&huart1, buffer, 3);
	HAL_UART_Receive_DMA(&huart1, buffer, 3);

}

/* USER CODE END 0 */



//主函数中
 /* USER CODE BEGIN 2 */
HAL_UART_Receive_DMA(&huart1, buffer, 3);
  /* USER CODE END 2 */

在这里插入图片描述

三、不定长接收

根据上面的学习,宝子们可能会发现,只有我们发送三个字符的时候,才能进入回调。我们知道,与单片机进行通信的设备并不都是发送固定长度的数据的,而单片机需要对这些数据都做出及时的响应,这个就是不定长接收。要做到不定长接收就需要用到空闲中断。开启这个中断之后,当传输线变成空闲状态的时候,就会进入中断,这个时候我们就知道对方发送过来的数据已经传输完了,可以进行处理了。下面我们就在DMA的基础上进行修改。

3.1 工程代码(main.c)

/* USER CODE BEGIN 2 */
	HAL_UART_Receive_DMA(&huart1, buffer, 3);
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//开启空闲中断

  /* USER CODE END 2 */

3.2 工程代码(stm32f1xx_it.c)

/* USER CODE BEGIN PV */
extern uint8_t buffer[30];
/* USER CODE END PV */

//串口1的中断函数服务中进行手动修改
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除空闲中断标志位
		HAL_UART_DMAStop(&huart1);
		uint8_t len = 3 - __HAL_DMA_GET_COUNTER(huart1.hdmarx);//获取DMA计数值
		HAL_UART_Transmit_DMA(&huart1, buffer, len);
		HAL_UART_Receive_DMA(&huart1, buffer, 3);
	}
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

在这里插入图片描述

本篇文章是在b站学习后整理的笔记,希望帮助更多的宝子。

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值