目录
环形buffer的作用?不仅适用于共享内存,这样反复使用内存,能使得我们能使用更少的内存块做更多的事情,并且对内存的管理更加方便更加安全。
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个数据后,在接收中断回调函数中把得到的数据写入环形缓冲区,并重新使能
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