当前位置:   article > 正文

3.串口(UART)

3.串口(UART)

串口理论部分可看51部分:链接

数据帧 = 帧头(2字节,例如AA、BB) + 数据长度(2字节)+ 数据 + CRC16校验(2字节) + 帧尾(2字节)

代码编写

串口一发送命令控制LED灯(PB5、PE5)

LED灯、串口、串口打印浮点数据、串口重定向配置

LED灯配置请看:链接

串口配置:

串口配置

配置中断NVIC(嵌套向量中断控制器)

配置中断NVIC

配置DMA:

配置DMA

Cube IDE中串口打印浮点数据配置方法(参考):进入“Project→Properties”;显示界面如下。按照图片中的设置完成即可!

打印浮点数配置

串口重定向配置:

uint8_t u_buf[256];	//usart.c,24行

#include <stdio.h>	//usart.h,32行
extern uint8_t u_buf[256];	//usart.h,38行
#define printf(...)  HAL_UART_Transmit(&huart1, (uint8_t *)u_buf, sprintf((char*)u_buf, __VA_ARGS__), 0xffff)	//usart.h,39行
  • 1
  • 2
  • 3
  • 4
  • 5

轮询方式

缺点:

    必须要等待数据发送完或者等待时间超时,代码才会往下走

    必须要等待数据接收到固定的字节长度,超时,代码才往下走

Cube IDE代码

mian.c

/* USER CODE BEGIN Includes */
#include <string.h>	//26行
#include <stdio.h>	//27
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
uint8_t UART_Recv[5];	//48行
char UART_Str[30];		//49行
/* USER CODE END PV */

//参数1:UART 模块的配置信息的指针,参数2:数据缓冲区的指针,参数3:接收字节长度,参数4:接收超时时间(单位为毫秒)
HAL_UART_Receive(&huart1, UART_Recv, 4, 1000);	//接收数据函数
if(strcmp("LED1", (char *)UART_Recv) == 0)	//字符串比较函数
{
	HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
	memset(UART_Recv,'\0',5);	//替换字符函数,常用于清除指定空间
}

if(!strcmp("LED2", (char *)UART_Recv))	//字符串比较函数
{
	HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
	memset(UART_Recv,'\0',5);
}

sprintf(UART_Str, "%f\n", 666.6);
//参数1:UART 模块的配置信息的指针,参数2:发送的字符串或字符数组,参数3:发送字节长度,参数4:接收超时时间(单位为毫秒)
HAL_UART_Transmit(&huart1, (char *)UART_Str, strlen(UART_Str), 1000);	//发送数据
printf("xinzai\n");	//配置串口重定向后才可使用
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

中断(IT)方式

Cube IDE代码


HAL_UART_RxCpltCallback(huart);	//stm32f1xx_hal_uart.c,3660行

//stm32f1xx_hal_uart.c,2619行
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)	//中断回调函数

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

main.c

/* USER CODE BEGIN Includes */
#include <string.h>	//26行
#include <stdio.h>	//27行
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
uint8_t UART_Recv_IT[5];	//48行
char UART_Str[30];	//49行
/* USER CODE END PV */

/* USER CODE BEGIN 2 */
//参数1:UART 模块的配置信息的指针,参数2:数据缓冲区的指针,参数3:接收字节长度
HAL_UART_Receive_IT(&huart1, UART_Recv_IT, 4);	//串口中断接收函数,95行
/* USER CODE END 2 */

//while函数里
sprintf(UART_Str, "%d\n", 666);	//102
HAL_UART_Transmit_IT(&huart1, UART_Str, strlen(UART_Str));	//串口中断发送函数,103
HAL_Delay(1000);	//104

//151行开始
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)	//串口中断接收触发函数
{
	if(huart == &huart1)	//判断传进来的串口是哪个
	{
		if(strcmp("LED1", (char *)UART_Recv_IT) == 0)	//字符串比较函数
		{
		  HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		  memset(UART_Recv_IT,'\0',5);	//替换字符函数,常用于清除指定空间
		}

		if(!strcmp("LED2", (char *)UART_Recv_IT))	//字符串比较函数
		{
		  HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
		  memset(UART_Recv_IT,'\0',5);
		}
		//因为只能接受一次串口中断,所以在串口中断触发函数需要重新调用
		HAL_UART_Receive_IT(&huart1, UART_Recv_IT, 4);
	}
}
/* USER CODE END 4 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

空闲中断(IDLE) + DMA

不受接收字符长度影响,可以随意接收字符长度并判断

空闲状态:在多个字节传输结束后,通信线路将会维持高电平,这个状态称为空闲状态(没有数据传输时的空闲状态,数据传输刚结束的空闲状态)

空闲中断产生条件:在数据传输过程中,当CPU检测到通信线路处于空闲状态时,且空闲状态的持续时间大于一个字节传输时间时,空闲状态标志IDLE将由硬件置1,产生空闲中断

Cube IDE代码

//stm32f1xx_hal_uart.h,2710行
__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)	//空闲中断接收回调函数
  • 1
  • 2

main.c

/* USER CODE BEGIN Includes */
#include <string.h>		//27行
/* USER CODE END Includes */

/* USER CODE BEGIN PD */
#define RECV_Size 100	//37行
/* USER CODE END PD */

/* USER CODE BEGIN 2 */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART_Recv_IDLE, RECV_Size);	//空闲中断接收函数,94行
//数据接收RECV_Size一半时会重新触发中断,需要关闭DMA接收中断使能
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn);	//96行
/* USER CODE END 2 */

//150行
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)	//空闲中断接收触发函数
{
	if(huart == &huart1)	//判断传进来的串口是哪个
	{
		if(strcmp("LED1", (char *)UART_Recv_IDLE) == 0)	//字符串比较函数
		{
		  HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		  memset(UART_Recv_IDLE,'\0',Size);	//替换字符函数,常用于清除指定空间
		}

		if(!strcmp("LED2ON", (char *)UART_Recv_IDLE))	//字符串比较函数
		{
		  //HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
		  HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, 0);
		  memset(UART_Recv_IDLE,'\0',Size);
		}else if(!strcmp("LED2OFF", (char *)UART_Recv_IDLE))
		{
			HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, 1);
			memset(UART_Recv_IDLE,'\0',Size);
		}
		//因为只能接受一次串口中断,所以在串口中断触发函数需要重新调用
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, UART_Recv_IDLE, RECV_Size);
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/942201
推荐阅读
相关标签
  

闽ICP备14008679号