STM32串口认识

常用函数介绍

串口发送/接收函数

HAL_UART_Transmit(); 串口发送数据,使用超时管理机制(即在发送成功前一直阻塞,相当于有个delay()在卡住主函数

HAL_UART_Receive(); 串口接收数据,使用超时管理机制

HAL_UART_Transmit_IT(); 串口中断模式发送  

HAL_UART_Receive_IT(); 串口中断模式接收

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size, uint32_t Timeout)
作用:以 阻塞 的方式发送指定字节的数据

UART_HandleTypeDef *huart串口的编号(结构体类型指针变量)

uint8_t *pData指向要发送的数据地址

uint16_t Size:要发送的数据大小,以字节为单位

uint32_t Timeout设置的超时时间,以ms为单位

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size)
作用:以中断的方式接收指定字节的数据

UART_HandleTypeDef *huart串口的编号(结构体类型指针变量)

uint8_t *pData是指向接收数据缓冲区

uint16_t Size要接收的数据大小,以字节为单位

此函数执行完后将清除中断,需要再次调用以重新开启中断

串口中断回调函数

HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数

HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送中断回调函数

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收中断回调函数

状态标记变量

USART_RX_STA(可自命名)

从0开始,串口中断接收到一个数据(一个字节)就自增1。当数据读取全部OK时候(回车和换行 符号来的时候),那么 USART_RX_STA的最高位置1,表示串口数据接收全部完毕了,然后main 函数里面可以处理数据了。

 串口接收中断流程

串口实验(非中断)

需求: 接受串口工具发送的字符串,并将其发送回串口工具。
硬件接线: 使用之前用到的CH340接到STM32的1号串口:
TX -- A10
RX -- A9

一. 打开CubeMX:

1.0 惯例配置,不再展示

1.1 选择左侧的Connectivity--> USART1(共有三路口,随便选一路).

1.2 在右侧设置为 异步通信(Asynchronous)

1.3 在上图的下侧可以看到参数,暂时不做修改
1.4 惯例配置,生成项目

2. 打开Keil

2.1 实现方式1,直接用刚刚UART(使用超时管理机制)的接收和发送的函数

#include "string.h"
 
int main()
{
    unsigned char buff[20] = {0};
 
    while (1)
    {	
		HAL_UART_Receive(&huart1, buff, 19, 100);//19是因为我定义了20位字节的缓冲区,但实际字符串的发送结束会有\0,所以要预留一位,也就是说最多接收19个字符
		HAL_UART_Transmit(&huart1, buff, strlen(buff), 100);
		memset(buff,0,strlen(buff));//如果不清空buff,单片机则会一直发送buff存储的数据
    }
}

2.2 实现方式2,通过重写printf 

2.2.1 首先要打开MicroLIB的库

2.2.2

#include "stdio.h"
#include "string.h"
 
int fputc(int a,FILE *f)//一个字符一个字符发送
{
	unsigned char temp[1] = {a};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);
	return a;
}
 
int main(void)
{
  unsigned char buff[20] = {0};
  
  while (1)
  {	
	HAL_UART_Receive(&huart1, buff, 19, 100);//19是因为我定义了20位字节的缓冲区,但实际字符串的发送结束会有\0,所以要预留一位,也就是说最多接收19个字符
	printf(buff);
	memset(buff,0,strlen(buff));
  }
 
}

使用中断的串口实验

需求:通过中断的方法接受串口工具发送的字符串,并将其发送回串口工具。

接线:同上。

1. CubeMX配置,同上,在之前的基础上打开中断:

在这两个地方打开哪个都行

2. 打开Keil 

通过stm32f1xx_it.c --> USART1_IRQHandler() --> HAL_UART_IRQHandler() --> UART_Receive_IT() / UART_Transmit_IT()

UART_Receive_IT()UART_Transmit_IT()就是本节开篇提到的“ 串口中断模式 接收发送 ”,这也是本节提到的串口接收中断流程的第三步,下一步就是回调函数:

HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送中断回调函数

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收中断回调函数

  而其中的“接收中断回调函数”,就是要在main函数中需要重写的函数了:

#include "stdio.h"
 
#define UART1_REC_LEN 200 //定义最大接收字节数 200,可根据需求调整
 
uint8_t buf=0; //串口接收缓存(1字节)
uint8_t UART1_RX_Buffer[UART1_REC_LEN];//接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
 
uint16_t UART1_RX_STA=0; //bit15,接收完成标志 //bit14,接收到0x0d //bit13~0,接收到的有效字节数目
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) // 接收完成回调函数,每收到一个字符(字节)后,就会在这里处理
{
	if(huart->Instance == USART1){ // 判断中断是由哪个串口触发的
		if((UART1_RX_STA & 0x8000) == 0){ // 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
			if(UART1_RX_STA & 0x4000){ // 如果已经收到了 0x0d (回车)
				// 则接着判断是否收到 0x0a (换行)
				if(buf == 0x0a){ // 如果 0x0a 和 0x0d 都收到,
					UART1_RX_STA |= 0x8000; //则将 bit15 位 置为1
				}else{ // 否则认为接收错误,重新开始
					UART1_RX_STA = 0;
				}
			}else{ // 如果没有收到 0x0d (回车)
				//则先判断收到的这个字符是否是 0x0d (回车)
				if(buf == 0x0d){ // 是的话则将 bit14 位置为1
					UART1_RX_STA |= 0x4000;
				}else{ // 否则将接收到的数据保存在缓存数组里
					UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf; //因为UART1_RX_STA只有前14位为有效数据,所以缓存数组UART1_RX_Buffer[X]中的X作为16位的二进制数,最高两位的判断应该写在前面代码的判断中,在此处不用
          UART1_RX_STA++;
					if(UART1_RX_STA > UART1_REC_LEN - 1){ //如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
							UART1_RX_STA = 0;
					}
				}
			 }
			}
	HAL_UART_Receive_IT(&huart1, &buf, 1); // 重新开启中断
			
	}
}
 
int fputc(int a, FILE *f) //一个字符一个字符发送
{
	unsigned char temp[1] = {a};
	HAL_UART_Transmit(&huart1, temp, 1, 0xffff);
	return a;
}
 
 
int main(void)
{
 
  HAL_UART_Receive_IT(&huart1, &buf, 1);//开启中断,并把数据存到buf里
 
  while (1)
  {
		if(UART1_RX_STA & 0x8000){//不断的判断串口是否接收完成
			printf("收到数据:"); 
			HAL_UART_Transmit(&huart1, UART1_RX_Buffer, UART1_RX_STA & 0x3fff, 0xffff);// 将收到的数据发送到串口(此处也可以使用printf)
 
			while(huart1.gState != HAL_UART_STATE_READY);// 等待发送完成
			printf("\r\n");
			
			UART1_RX_STA = 0;// 重新开始下一次接收
		}
		printf("hello shion\r\n");
		HAL_Delay(1000);
  }
 
}

 PS:重新定义了printf函数一定要记得打开MicroLIB的库(打开方法在上方有说明)

3. 打开之前使用到的串口助手

按照刚刚的设置,调整波特率,打开串口,可以看到每秒从单片机发来的心跳包:

并且如果此时发送字符串给单片机,也会立刻收到单片机回传的这个字符串:

注意,此时必须勾选上“发送新行”,原因是在单片机的函数中,判断字符串是否传输完毕的方法就是检测最后的换行!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值