Bootstrap

UART编程

目录

Q:为什么使用串口前要先在电脑上安装CH340驱动?

中断的作用?让CPU暂停当前任务,处理更高优先级任务的机制

环形buffer的作用?不仅适用于共享内存,这样反复使用内存,能使得我们能使用更少的内存块做更多的事情,并且对内存的管理更加方便更加安全。

static和valitate的作用

三种编程方式简介​编辑

编程方式改进 

三种方式对比

一、查询方式进行编程 

二、官方中断方式进行编程 

二、中断方式改造

三、DMA方式进行编程 


Q:为什么使用USB串口前要先在电脑上安装CH340驱动?http://t.csdnimg.cn/hxWQS

中断的作用?让CPU暂停当前任务,处理更高优先级任务的机制

环形buffer的作用?不仅适用于共享内存,这样反复使用内存,能使得我们能使用更少的内存块做更多的事情,并且对内存的管理更加方便更加安全。

static和valitate的作用

三种编程方式简介

 

也可以通过DMA方式减小CPU资源的消耗

直接把数据在SRAM内存和UART模块进行传输 ,流程:

  • 把数据在DMA中配置好
  • 数据传输
  • 产生中断,CPU介入

编程方式改进 

1、查询方式对应的读写会存在时间延迟

比如接收:没来得及保存RDR寄存器中接受到的数据时,RDR寄存器的值就已经被覆盖;

2、中断方式:事先在发送buffer中存好数据,使能发送空中断;把接受的数据存入buffer

发送

  • char tx_buf[100];存数据
  • enable TXE
  • TXE_ISR:中断来取出数据发给TDR

接收

  • 使能RXNE(接收非空)
  • RXNE_ISR:利用中断从RDR中取数据到缓冲区

3、用环形缓冲区改进中断

4、用DMA方式减小CPU资源的消耗

三种方式对比

  • 查询方式的传输函数可以实现子串口处数据的发送给和接收,会读取状态寄存器并发送数据到DR;
  • 但因打印耗时,传输函数不能及时调用会造成接收数据时的数据丢失。官方的中断方式因不能及时使能中断也存在此问题。

一、查询方式进行编程 

核心:判断TDR和RDR寄存器的状态

缺点:当接收时,若没有来得及读取数据,RDR中的值容易被覆盖,进而丢失数据

实现:

  • 发送:先判断发送寄存器是否为空(借助状态寄存器中的TXE),若为空,往里面(DR)写入数据,自己的存储器地址++(pdata16bits++)
  • 接收:判断RXNE是否收到数据(非空RXNE),若非空,读取DR,存进自己的存储器

 

二、官方中断方式进行编程 

while(1){

调用HAL_UART_Transmit_IT使能中断(中断处理进行接收)14

等待中断处理(接收)完毕

打印1(23)

}

核心:通过使能中断,有字节就会

缺点:必须有函数及时调用HAL_UART_Transmit_IT,若未及时调用,数据也会丢失,实际场景中不会使用。。。。。所以HAL_UART_Transmit_IT没有什么作用

步骤:cubeMX,选择UART1串口,使能中断

代码逻辑:初始化串口时,同样使能了中断和设置了中断的优先级;在中断文档中,增加了串口1 的中断处理函数。(但只是使能串口1的中断总开关,没使能发送或接收中断,中断的管理还需要自己实现)

代码实现:

  • 调用HAL_UART_Transmit_IT函数,使能中断UART_IT_TXE,使能后就返回,并不处理数据(中断UART_IT_TXE,把数据发给寄存器)
  • 在中断处理函数中,若发送1000字节,则启动999次TXE中断和1次TC中断(调用HAL_UART_TxCpltCallback)

在接收时,因打印比较耗时,若每及时的调用HAL_UART_Transmit_IT函数使能中断,数据仍然会丢失

要发送数据时,使能“TXE”中断(发送寄存器空中断)。在 TXE 中断处理函数里,从程序的发送 buffer 里取出一个数据,写入 TDR;(TDR为空时:buffer---TDR---移位寄存器

对于接收数据,在一开始就使能“RXNE”中断(接收寄存器非空)。这样,UART 接收到一个数据就会触发中断,在中断程序里读取 RDR 得到数据,存入程序的接收 buffer。(RDR非空时:移位寄存器---RDR---buffer

和查询相比:多了对事件的实时相应

TXE中断:TDR中的数据放入移位寄存器

TC中断:移位寄存器中的数据全部发送出去

二、中断方式改造

① 一开始就使能接收中断
② 接收中断处理函数里,把数据存入环形 buffer,并再次使能接收中断

1、一开始就1、初始化环形缓冲区(声明环形缓冲区结构体和对应的Buffer),2、调用HAL_UART_Receive_IT传入buffer和使能中断

2、得到1个数据后,在接收中断回调函数中把得到的数据写入环形缓冲区,并重新使能

fb235060541f4101b48d5685377c0003.jpg

 

while(1){

HAL_UART_Transmit_IT;

等待数据传输完毕;

while(没收到circle_buf_read(&g_uart1_rx_bufs, pVal);//从缓冲区接收到

HAL_UART_Transmit(&huart1,&c,1,1000)

}

三、DMA方式进行发送编程 

优点:在数据传输的过程中不使用CPU的资源 

设置好 DMA(源、目的、地址增减方向、每次读取数据的长度、读取次数)后,DMA 就
会自动地在 SRAM 和 UART 之间传递数据:
① 发送时:DMA 从 SRAM 得到数据,写入 UART 的 TDR 寄存器
② 接收时:DMA 从 UART 的 RDR 寄存器得到数据,写到 SRAM 去
③ 指定的数据传输完毕后,触发 DMA 中断;在数据传输过程中,没有中断,CPU 无需处理。

配置DMA,进而实现在UART串口的TDR,RDR寄存器芯片内存SRAM之间的直接数据传输。

当指定目标数量的数据传输完成后才会产生中断,进而让CPU介入。

中断和查询方式是CPU从存储器RAM中取数据到CPU中,然后再写入TDR寄存器:RAM---CPU-----UART(TDR)

DMA:RAM---DMA-----UART(TDR),数据传输完再产生中断告知CPU

三、DMA+idle中断进行接收编程 

DMA要读1000个数据,但是实际只有100个,要怎么知道100个数据是完整的

DMA 传输结束的条件有 3:
① 接收完指定数量的数据了,比如收到了 100 字节的数据了,HAL_UART_RxCpltCallback
被调用
② 总线空闲了:HAL_UARTEx_RxEventCallback 被调用
③ 发生了错误:HAL_UART_ErrorCallback 被调用

查询方式:HAL_UARTEx_ReceiveToIdle(想接收多少数据,实际接收多少数据,串口,数据保存位置)

while(没有接收到足够的数据){

如果(发生了空闲的状态):跳出,返回OK

检查是否接收到数据:接收到的话就把数据保存到buffer;}

中断方式:HAL_UARTEx_ReceiveToIdle_IT 

{

启动接收HAL_UART_Receive_IT,使能接收中断

使能IDLE中断ATOMIC_SET_BIT(hurt->Instance->CR1,USART_CR1_IDLE)

}

IDLE中断解读,他也在UART_IRQHandler中,

如果是DMA,保存数据,清除DMA,调用HAL_UARTEx_RxEventCallback(收到的字符)

中断:禁止中断,调用HAL_UARTEx_RxEventCallback(收到的字符)

若是中途退出,可通过DMA回调函数HAL_UARTEx_RxEventCallback;记得在回调函数中使能HAL_UARTEx_ReceiveToIdle_DMA

 

;