[蓝桥杯嵌入式有手就行]7_串口

[蓝桥杯嵌入式有手就行]系列文章

第一章 开发环境的配置
第二章 从点灯开始
第三章 学会看手册
第四章 GPIO(上)
第五章 GPIO(下)
第六章 LCD
第七章 串口
第八章 I2C
第九章 ADC
第十章 TIM(上)
第十一章 TIM(下)
第十二章 RTC
第十三章 14届模拟题1
第十四章 14届模拟题2
第十五章 14届真题解析
未完待续…



前言

注:本系列基于2023年蓝桥杯实战情况就行编写,所有软件均采用2023年赛点资源包
STM32的串口通信接口有两种,分别是:UART(通用异步收发器)、USART(通用同步异步收发器)。UART是在 USART 基础上裁剪掉了同步通信功能(时钟同步),只有异步通信。简单区分同步和异步就是看通信时存不存在时钟线,两根线的一定是UART。
我们观察原理图,可以发现,板子上的连接应该属于UART,但我们在配置的时候还是选择的USART。


一、内部结构

1、结构框图

在这里插入图片描述
黄色为发送,红色为接收。
这里TX Shift Reg和RX Shift Reg后面有个交叉线,根据我查到的资料,意思是支持引脚互换功能,也就是接反了也可以正常工作。蓝桥杯的板子上没有引出tx和rx,我手头也没有其他支持的板子,这里就需要大家去验证了。

2、串口通信协议

在这里插入图片描述
串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备的RXD接口,这一点我们在下文的原理图中可以看到。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据。

1、波特率

在UART中,没有时钟线。因此需要提前约定好每个数据长度。我们常用的波特率是9600和115200。
举个例子,就像你和外地人进行交流,你们都讲方言,虽然大家讲的都是中国话,但是那场面你懂的。此时,波特率就相当于普通话,你们提前约定了一个波特率,现在你们就可以畅通的交流了。

2、起始位和停止位

起始位由一个逻辑0的数据位表示,而数据包的停止信号可由0.5、1、1.5或2个逻辑1的数据位表示,这个在下文的配置中都有说明。
就像我们见面准备开始聊天,我们的开始信号是“ori”,结束是“bye”一样。

3、数据有效内容

这里可以设置为7,8,9位长度。因为我们有起始位和停止位,所以不用提前通知对方。

4、奇偶效验位

为了防止传输过程中出现错误,通过校验的方法来避免。
印象中考过,但是需要自己写校验规则

二、串口模块分析

1、原理图

在这里插入图片描述

2、发送过程

1.向USART_CR1M位定义字长

37.8.1 USART_CR1寄存器(FIFO enabled)
在这里插入图片描述
注意:M0和M1必须同时使用,来确定字长,而且,只有在UE=0(即USART 没有使能)的时候才可以被修改。

M[1:0]=含义
001 start,8 Date bits,n stop bit
011 start,9 Date bits,n stop bit
101 start,7 Date bits,n stop bit

2.配置USART_BRR寄存器,设置波特率

37.8.5 USART_BRR寄存器
在这里插入图片描述
USART_BRR[15:4]是整数位,USART_BRR[3:0]是小数位。
至于计算方法,详见手册37.5.7和37.8.5节内容。
在这里插入图片描述
在这里插入图片描述

3.对USART_CR2的停止位进行编程

37.8.3 USART_CR2寄存器
在这里插入图片描述
必须在UE=0时才能修改

STOP[1:0]=含义
001 stop bit
010.5 stop bit
102 stop bit
111.5 stop bit

在这里插入图片描述

4.对DMA进行配置(可选)

DMA详细内容请看参考手册12节,在串口章节中找到了以下描述:

Select DMA enable (DMAT) in USART_CR3 if multibuffer communication must take place. Configure the DMA register as explained in Section 37.5.10: USART multiprocessor communication.

37.8.4 USART_CR3寄存器
在这里插入图片描述
TCBGTIE置1后会在发送完成后产生中断
DMAT(DMA enable transmitter)置1

5.向USART_CR1UE位置1,使能串口

6.发送器对USART_CR1TE位置1,发送一个空闲帧作为第一次数据发送

7.把要发送的数据写入USART_TDR寄存器,硬件自动发送TXE清零

USART_TDR寄存器
在这里插入图片描述
USART_ISR寄存器(FIFO mode disabled)
在这里插入图片描述
当USART_TDR寄存器的内容被传送到移位寄存器时,由硬件设置TXE。
TXE是TDR寄存器数据是否为空的标志。

8.在写入最后一个数据后,等待TC=1(表示最后一个数据帧传输完毕)

在这里插入图片描述

如果USART_CR1中的TCIE位被置位(即为1),则会产生中断。

3、串口DMA发送过程

  1. Write the USART_TDR register address in the DMA control register to
    configure it as the destination of the transfer. The data is moved
    to this address from memory after each TXE (or TXFNF if FIFO mode is
    enabled) event.

  2. Write the memory address in the DMA control register to configure it
    as the source of the transfer. The data is loaded into the USART_TDR
    register from this memory area after each TXE (or TXFNF if FIFO mode
    is enabled) event.

  3. Configure the total number of bytes to be transferred to the DMA control register.

  4. Configure the channel priority in the DMA register.

  5. Configure DMA interrupt generation after half/ full transfer as required by the application.

  6. Clear the TC flag in the USART_ISR register by setting the TCCF bit in the USART_ICR register.

  7. Activate the channel in the DMA register.
    在这里插入图片描述

4、接收过程

大部分内容和上面发送过程一样,就不再重复了。

1.向USART_CR1M位定义字长

2.配置USART_BRR寄存器,设置波特率

3.对USART_CR2的停止位进行编程

4.对DMA进行配置(可选)

5.向USART_CR1UE位置1,使能串口

6.将USART_CR1中的RE位置1

RE位置1后,接收功能使能,开始搜索起始位。
USART_CR1(FIFO disabled)寄存器
在这里插入图片描述

在上面发送部分,我们在发送前发送了一个空闲帧,在接收的时候,我们收到这个空闲帧信号就代表接收开始。

7.接收到字符后,USART_ISR寄存器的RXNE硬件置1

USART_ISR寄存器(FIFO mode disabled)
在这里插入图片描述表示USART_RDR移位寄存器的内容被传送到USART_RDR寄存器

8.如果RXNEIE置1,产生接收中断

9.软件读取USART_RDR寄存器,RXNE清零

USART_RDR寄存器
在这里插入图片描述

5、串口DMA接收过程

  1. Write the USART_RDR register address in the DMA control register
    to configure it as the source of the transfer. The data is moved
    from this address to the memory after each RXNE (RXFNE in case FIFO
    mode is enabled) event.

  2. Write the memory address in the DMA
    control register to configure it as the destination of the transfer.
    The data is loaded from USART_RDR to this memory area after each
    RXNE (RXFNE in case FIFO mode is enabled) event.

  3. Configure the total number of bytes to be transferred to the DMA control register.

  4. Configure the channel priority in the DMA control register

  5. Configure interrupt generation after half/ full transfer as required by the application.

  6. Activate the channel in the DMA control register.

在这里插入图片描述

三、代码示例

1、cubemx配置

关于波特率,一般题目要求都是9600,cubemx默认115200,记得看题呀。
在这里插入图片描述

别忘了开启中断(我这里开了DMA,因此会多两个中断)
在这里插入图片描述
如果你需要使用DMA
在这里插入图片描述
这里其实我们只需要开启RX就行,但是对强迫症来说,不好看,因此我也开了TX。

2、代码时刻

1、发送(无DMA)

这里我们发送的是之前按键章节获取到的按下的键的值。

unsigned char tx[100];

void usart_tx_proc(void)
{
	sprintf(tx,"key is %d\r\n",uckey_down);//不要忘了\r\n,否则不会换行
	HAL_UART_Transmit(&huart1,(unsigned char *)tx,strlen(tx),50);
}

2、中断接收

注意,这种方法在接收到一个数据后就会产生一个中断。也就是接收多少数据就会产生多少中断。因此只适合程序简单,要求不高的场合。

我们需要先在main函数,while(1)之前进行初始化

MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1,&rx_buffer,1);

然后编写中断回调函数
当接收到数据后,灯会熄灭0.3秒。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	LED_Disp(0xff);
	HAL_Delay(300);
	LED_Disp(0x00);	
	
	HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);
}

3、DMA接收

申明几个变量,用来储存数据

uint8_t rx1_buf[100];
volatile uint8_t rx1_len = 0;
volatile uint8_t rx1_end_flag = 0;

我们需要先在main函数,while(1)之前进行初始化

__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, rx1_buf, 100);

然后编写中断处理函数
本段代码接收串口1的数据,然后将数据原样发送出去

// 删除stm32g4xx_it.c中的USART1_IRQHandler
// 在usart.h中添加以下代码
// extern DMA_HandleTypeDef hdma_usart1_rx;
void USART1_IRQHandler(void)
{
    HAL_UART_IRQHandler(&huart1);
    uint8_t tmp_flag = __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE); // 获取IDLE标志位
    if ((tmp_flag != RESET))                                         // 通过标志位判断接收是否结束
    {
        rx1_end_flag = 1;                   // 置1表明接收结束
        __HAL_UART_CLEAR_IDLEFLAG(&huart1); // 清除标志位
        HAL_UART_DMAStop(&huart1);
        uint8_t temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
        rx1_len = 100 - temp;                             // 计算出数据长度
        HAL_UART_Transmit_DMA(&huart1, rx1_buf, rx1_len); // 将受到的数据发送出去
        HAL_UART_Receive_DMA(&huart1, rx1_buf, 100);      // 开启DMA接收,方便下一次接收数据
    }
}

四、问题

1、什么是空闲帧

简单的说,空闲帧是一个高电平,起始位是一个低电平,当硬件检测到电平信号发生了1➡0的变化,就代表开始传输数据,此时就开始接收。
实际我们需要考虑过采样的问题,如下图所示。
在这里插入图片描述

2、什么是移位寄存器

图中蓝色的就是发送和接收的移位寄存器。
在这里插入图片描述
移位寄存器是一种时序逻辑电路,能够存储和传输数据。它们由触发器组成,这些触发器的连接方式使得一个触发器的输出可以作为另一个触发器的输入,具体取决于所创建的移位寄存器的类型。
移位寄存器基本上是一种能够传输(“移位”)数据的寄存器。寄存器通常是存储设备,它们是通过将特定数量的触发器串联在一起而创建的,并且寄存器可以存储的数据量(位数)始终与触发器的数量成正比,因为每个触发器一次只能存储一个bit。当寄存器中的触发器以这样的方式连接时,一个触发器的输出成为另一个触发器的输入,就会创建一个移位寄存器。

3、重定向输出

记得添加stdio.h头文件。

int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
int fgetc(FILE *fp)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;
}

之后我们就可以使用以下命令来接收和发送了

printf("enter :%s\r\n",str);//发送
scanf("%s",str);//接收

4、清空接收缓存数据

我们可以使用错误标志位或者闲时处理,定义一个标志位,定时清空接收缓存

memset(rx_date,0,sizeof(rx_date);//全部以0填充

5、常用的字符串处理函数

1、sscanf

从一个字符串中按照指定格式提取数据
用法:

void str_scanf()
{
	char str[]="age:28,name:Tom";
	char name[10];
	int age;
	sscanf(str,"age:%d,name:%s",&age,name);
	printf("name:%s,age:%d",name,age);
}

2、strcmp

比较两个字符串是否相等,忽略大小写。
用法:

if(strcmp(str1,str2))
	printf("1");
else
	printf("0");

6、FIFO

默认配置如下,一般我们不需要更改。
在DMA传输中,FIFO模式可以用来缓存数据,减小传输延迟,提高DMA传输速度。
在这里插入图片描述

总结

以上就是蓝桥杯新板子的串口相关内容,其实还有许多没有仔细分析的,串口内容实在多,可能会有疏忽,欢迎大家可以在评论区指正。

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

工具人呵呵

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

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

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

打赏作者

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

抵扣说明:

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

余额充值