文章目录
使用usart3实现printf
1 在CubeMX中配置USART
- Mode:USART可选模式(Mode)中有八种,具体每种模式可以参考《STM32F10XXX参考手册》,这里选用Asynchronous(异步通信)
- Hardware Flow Control(RS232) 硬件流控制,这里选择Disable,不使能硬件流控制。
nRTS:请求以发送(Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当USART接收器准备好接收新数据时就会将 nRTS变成低电平;当接收寄存器已满时,nRTS将被设置为高电平。
nCTS:清除以发送(Clear To Send),n表示低电平有效。如果使能 CTS流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。
- 基本的参数设定
1)Baud Rate:即每秒传输的位数;
2)Word Length:数据帧字长,可选8位或9位。它设定USART_CR1寄存器的 M 位的值。如果没有使能奇偶校验控制,一般使用 8 数据位;如果使能了奇偶校验则一般设置为 9 数据位;
3)Parity:奇 偶 校 验 控 制 选 择,这里选择无校验 , 可 选 USART_Parity_No( 无 校 验 ) 、USART_Parity_Even( 偶 校 验 ) 以 及 USART_Parity_Odd( 奇 校 验 ) , 它 设 定USART_CR1寄存器的 PCE位和 PS位的值;
奇校验:奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为:01101001,此时总共有 4 个“1”,为达到奇校验效果,校验位为“1”,最后传输的数据将是 8 位的有效数据加上 1 位的校验位总共 9 位。
偶校验:偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为 4 个,所以偶校验位为“0”。
如果启用奇偶校验,奇偶校验由硬件自动完成。启动了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收数据时如果出现奇偶校验位验证失败,会见 USART_SR 寄存器的 PE 位置 1,并可以产生奇偶校验中断。使能了奇偶校验控制后,每个字符帧的格式将变成:起始位+数据帧+校验位+停止位。
4)Stop Bits:停止位设置,可选 0.5 个、1 个、1.5 个和 2 个停止位,它设定USART_CR2寄存器的 STOP[1:0]位的值,一般我们选择 1 个停止位。2 个停止位适用于正常USART 模式、单线模式和调制解调器模式。0.5个和 1.5 个停止位用于智能卡模式。
5)Data Direction:数据传输方向,选择接收和发送
2 在CubeMX中配置NVIC
在生成代码中 HAL_Init() 函数默认系统优先级为 NVIC_PRIORITYGROUP_4;
MAL_MspInit(void)函数里根据CubeMX中设置优先级分组
3 在工程中实现相关功能
3.1 USART数据常规发送与接收
在usart.c文件中定义接收数据数组
uint8_t Uart1RxBuff[USART1_RX_LEN];
在usart.h文件中定义接收数据数组长度及声明接收数组
#define USART1_RX_LEN 10
extern uint8_t Uart1RxBuff[USART1_RX_LEN];
3.1.1 USART数据阻塞模式(blocking mode)发送与接收
阻塞模式(blocking mode)即USART数据发送或接收都会阻塞,阻塞时间可自定义,时间单位为ms
在main.h文件中开启测试
#define USART_BLOCKING_MODE_TEST 1 /*USART 阻塞模式下测试数据收发*/
在main.c文件中实现如下代码
HAL_StatusTypeDef user_hal_stauts;
#if (USART_BLOCKING_MODE_TEST == 1)
/*阻塞模式(blocking mode)下的USART数据接收,会停留在该函数,直到接收到USART1_RX_LEN长度的数据或者直到5000ms时间溢出*/
user_hal_stauts = HAL_UART_Receive(&huart1,Uart1RxBuff,USART1_RX_LEN,5000);
if(user_hal_stauts == HAL_OK)
{
/*阻塞模式(blocking mode)下的USART数据发送,发送完USART1_RX_LEN长度的数据或者直到5000ms时间溢出*/
HAL_UART_Transmit(&huart1,Uart1RxBuff,USART1_RX_LEN,5000);
}
else
{
printf("HAL_StatusTypeDef,%d \r\n",user_hal_stauts);
}
#endif
以上程序实现了阻塞模式(blocking mode)下的数据自发自收,如下图所示:
3.1.2 USART数据非阻塞模式(non blocking mode)发送与接收
非阻塞模式即将数据的发送接收放在中断处理
- 在
main
函数中使能接收中断
if(HAL_UART_Receive_IT(&huart1, Uart1RxBuff, USART1_RX_LEN) != HAL_OK)
{
Error_Handler();
}
在 **HAL_UART_Receive_IT ()**函数检查USART是否正忙,如果不忙则配置参数、使能中断等操作,可自行查看。
- 在stm32f1xx_it.c中的USART1_IRQHandler() 函数下实现函数HAL_UART_Receive_IT();
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
HAL_UART_Receive_IT(&huart1, Uart1RxBuff, USART1_RX_LEN);
/* USER CODE END USART1_IRQn 1 */
}
上电初始化中调用一次HAL_UART_Receive_IT(); 函数,即第一次开启接收中断使能;而每次中断接收完数据之后又要调用一次HAL_UART_Receive_IT(); 函数,是因为每次接收中断执行HAL_UART_IRQHandler函数之后,接收中断就会被关闭;进入 HAL_UART_IRQHandler 函数会找到 UART_Receive_IT 函数,该函数如下:
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
uint16_t *tmp;
/*省略了部分代码*/
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF); /*读取具体数据*/
if (--huart->RxXferCount == 0U) /*接收完成*/
{
/* Disable the UART Data Register not empty Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); /*接收完成后,失能接收中断*/
/* Rx process is completed, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY; /*改变USART状态*/
/*Call legacy weak Rx complete callback*/
HAL_UART_RxCpltCallback(huart); /*数据接收完成后,调用回调函数*/
}
}
}
而在 HAL_UART_Receive_IT 函数中,如下:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); /*使能接收中断*/
}
- 在
usart.c
中实现接收回调函数HAL_UART_RxCpltCallback,该函数在stm32f1xx_it.c中的**USART1_IRQHandler() —>HAL_UART_IRQHandler —> UART_Receive_IT ** 函数中调用, 每次接收到USART1_RX_LEN个字节后调用一次该回调函数,数据保存在Uart1RxBuff中
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
HAL_UART_Transmit_IT(&huart1,Uart1RxBuff,USART1_RX_LEN);
}
}
以上程序也实现了数据的自发自收
3.1.3 函数深入理解
常用数据发射函数
/*Send an amount of data in blocking mode,该函数发射数据处于阻塞模式,即MCU会一直处在该发射函数中直到数据发射完,才执行往下的程序*/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
/*Send an amount of data in non blocking mode,该函数发射数据处于非阻塞模式,即数据在中断中发射,在数据发射不需要MCU干预过程中,MCU会执行往下的程序,但是USART发射状态会处于忙,不能立即又调用函数发射数据*/
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
举例详解:
- HAL_UART_Transmit函数
uint8_t TX_Buff[] = "i am a test code ! \r\n";
/*这里的参数Timeout(100),即该函数可执行的最大时间,如果超过该时间数据还没有发射完,也会被强行退出*/
HAL_UART_Transmit(&huart1,TX_Buff,sizeof(TX_Buff),100);
- HAL_UART_Transmit_IT函数
该函数数据发射是在中断中完成的,不会被阻塞
uint8_t TX_Buff[] = "i am a test code ! \r\n";
HAL_UART_Transmit_IT(&huart1,TX_Buff,sizeof(TX_Buff));
对该函数发射深入代码详解
1)将发射数据、数据大小存储到 huart 结构体中,并将USART标记为忙;
2)使能发射中断;
3)在中断中发射数据;
4)计数发射数据是否发射完(若数据没有发射完会一直产生中断),发射完就失能发射中断,并将USART标记为准备;
按照 注释1~注释N 来理解
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
/*省略了部分代码*/
/* Process Locked */
__HAL_LOCK(huart);
huart->pTxBuffPtr = pData; /*注释1、要发射的数据*/
huart->TxXferSize = Size; /*注释2、要发射的数据大小*/
huart->TxXferCount = Size; /*注释3、要发射的数据计数*/
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX; /*注释4、标记发射状态忙*/
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Transmit data register empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TXE); /*注释5、使能发射中断,并产生中断,开始执行USART中断函数 HAL_UART_IRQHandler */
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR); /*注释6、获取 SR 寄存器的值*/
uint32_t cr1its = READ_REG(huart->Instance->CR1); /*注释7、获取 CR1 寄存器的值*/
/*省略了部分代码*/
/* UART in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET)) /*注释8、这里的USART_SR_TXE中断状态是在(注释5)中使能的,*/
{
UART_Transmit_IT(huart); /*注释9、实际的数据发射函数*/
return;
}
/* UART in mode Transmitter end --------------------------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart);/*注释15、数据发射完之后,这里将USART状态从忙变为准备*/
return;
}
}
static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
uint16_t *tmp;
/* Check that a Tx process is ongoing */
if (huart->gState == HAL_UART_STATE_BUSY_TX) /*注释10、在(注释4)中被标记为忙*/
{
if (huart->Init.WordLength == UART_WORDLENGTH_9B)
{
/*省略了部分代码*/
}
else
{
huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);/*注释11、发射数据,一个一个字节发送*/
}
if (--huart->TxXferCount == 0U)/*注释12、计数发射的数据,没有发射完会一直使能中断*/
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_TXE); /*注释13、数据发送完,失能发射中断,就不会再产生中断了;如果数据还没有发射完,就会一直使能中断,直到数据发射完*/
/* Enable the UART Transmit Complete Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TC); /*注释14、这里产生的是,数据发射完中断*/
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
3.1.4 疑问与解答
/*这里printf并没有打印数据出来,是HAL_UART_Transmit_IT为非阻塞模式,执行完该函数后立即返回,而数据正在中断中同步发射,此时USART正在被占用,所以printf打印不出数据,延时一定时间后,数据发射完了,所以又能打印数据了*/
ACK = HAL_UART_Transmit_IT(&huart1,TX_Buff,sizeof(TX_Buff));
printf("ACK: %d \r\n",ACK); /*不能打印数据*/
ACK = HAL_UART_Transmit_IT(&huart1,TX_Buff,sizeof(TX_Buff));
HAL_Delay(5);
printf("ACK: %d \r\n",ACK); /*可以打印数据*/
3.2 USART数据使用DMA发送与接收
在STM32CubeMX配置DMA,并生成工程
3.2.1 USART数据的DMA发送
DMA发送步骤如下:
- 在函数
HAL_UART_Transmit_DMA
中先封装数据、回调函数,调用HAL_DMA_Start_IT
配置外设源地址、目标地址等,再开启USART的DMA传输; HAL_DMA_Start_IT
函数中修改DMA状态,配置DMA通道、数据源地址、目标地址、数据长度,使能数据传输一半、传输完成、传输出错中断;- 数据传输完成一半,产生DMA中断,在中断函数中调用
UART_DMATxHalfCplt
函数,该函数里包含了HAL_UART_TxHalfCpltCallback
回调函数,用户代码就写在该函数里; - 数据传输完成,产生DMA中断,在中断函数中调用
UART_DMATransmitCplt
函数,该函数里会根据DMA配置的正常模式或循环模式做相应的处理,正常模式下,会产生USART中断,并执行HAL_UART_TxCpltCallback
回调函数;循环模式下,会直接调用HAL_UART_TxCpltCallback
回调函数,用户代码就写在该函数里。
在main函数实现如下函数:
uint8_t DMA_TX_Buff[] = "i am a DMA test code ! \r\n";
HAL_UART_Transmit_DMA(&huart1,DMA_TX_Buff,sizeof(DMA_TX_Buff));
在usart.c中实现如下代码:
/*数据发送完成一半时产生的中断*/
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
printf("huart1 send half \r\n");
}
}
/*数据发送完成全部时产生的中断*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
printf("huart1 send end \r\n");
}
}
串口调试助手显示如下:
注意一些问题:
如果DMA传输和printf使用同一串口(如都是用USART1),则调试过程中,不能用 printf 在HAL_UART_TxHalfCpltCallback
函数中打印信息,因为数据只传输了一半,USART通道还在被占用,所以不能将信息被打印出来
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
// printf("xxx"); /*这里不能用 printf 函数来查看是否执行到这里,因为数据只传输了一半,USART通道还在被占用*/
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
}
}
3.2.2 USART数据的DMA接收
DMA模式为循环模式下,只要在main函数中打开USART的DMA接收就可以
uint8_t DMA_RX_Buff[10]
int main(void)
{
HAL_UART_Receive_DMA(&huart1,USART_DMA_RX_Buff,USART1_RX_LEN);
while (1){}
}
其接收过程与DMA发射类似;
数据接收到一半和接收完成都会产生中断,如下函数:
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
printf("huart1 dma receive half \r\n");
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
printf("huart1 dma receive end \r\n");
/*将收到的数据重新发送*/
HAL_UART_Transmit_DMA(&huart1,USART_DMA_TX_Buff,USART1_RX_LEN);
}
}
接收数据大于定义的数据大小(USART1_RX_LEN)一半时才会产生中断并调用就会调用HAL_UART_RxHalfCpltCallback函数;
接收数据大于定义的数据大小(USART1_RX_LEN)时才会产生中断并调用就会调用HAL_UART_RxCpltCallback函数。
3.2.3 代码分析
- USART数据的DMA发送过程分析
/*该函数完成了外设源地址、目标地址、数据大小的配置*/
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
uint32_t *tmp;
/*省略了部分代码*/
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(huart);
huart->pTxBuffPtr = pData; /*注释1:将需要发射的数据存储到 huart 结构体中*/
huart->TxXferSize = Size; /*注释2:数据大小*/
huart->TxXferCount = Size; /*注释3:数据计数*/
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX; /*注释4:修改USART状态*/
/* Set the UART DMA transfer complete callback */
huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt; /*注释5:注册数据传输完成回调函数,数据传输完成后产生中断,会执行该函数*/
/* Set the UART DMA Half transfer complete callback */
huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt; /*注释6:注册数据传输一半回调函数,数据传输一半产生中断,会执行该函数*/
/* Set the DMA error callback */
huart->hdmatx->XferErrorCallback = UART_DMAError;
/* Set the DMA abort callback */
huart->hdmatx->XferAbortCallback = NULL;
/* Enable the UART transmit DMA channel */
tmp = (uint32_t *)&pData;
HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t *)tmp, (uint32_t)&huart->Instance->DR, Size); /*注释7:启动DMA传输*/
/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC); /*注释8:清零USART发射完成标志*/
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the UART CR3 register */
SET_BIT(huart->Instance->CR3, USART_CR3_DMAT); /*注释9:开启USART的DMA传输*/
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/*****************************************************************************************************************************/
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
uint32_t flag_it = hdma->DmaBaseAddress->ISR;
uint32_t source_it = hdma->Instance->CCR;
/* Half Transfer Complete Interrupt management ******************************/
if (((flag_it & (DMA_FLAG_HT1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_HT) != RESET)) /*注释6.1:数据传输完成一半时产生中断*/
{
/* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
/* Disable the half transfer interrupt */
__HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT); /*注释6.2:失能数据传输一半的中断*/
}
/* Clear the half transfer complete flag */
__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
/* DMA peripheral state is not updated in Half Transfer */
/* but in Transfer Complete case */
if(hdma->XferHalfCpltCallback != NULL)
{
/* Half transfer callback */
hdma->XferHalfCpltCallback(hdma); /*注释6.3:调用回调函数 UART_DMATxHalfCplt*/
}
}
/* Transfer Complete Interrupt management ***********************************/
else if (((flag_it & (DMA_FLAG_TC1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_TC) != RESET)) /*注释6.4:数据传输完成产生中断*/
{
if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
/* Disable the transfer complete and error interrupt */
__HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC);
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;
}
/* Clear the transfer complete flag */
__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
/* Process Unlocked */
__HAL_UNLOCK(hdma);
if(hdma->XferCpltCallback != NULL)
{
/* Transfer complete callback */
hdma->XferCpltCallback(hdma); /*注释6.5:调用回调函数 UART_DMATransmitCplt*/
}
}
/* Transfer Error Interrupt management **************************************/
else if (( RESET != (flag_it & (DMA_FLAG_TE1 << hdma->ChannelIndex))) && (RESET != (source_it & DMA_IT_TE)))
{
/*省略了部分代码*/
}
return;
}
/*****************************************************************************************************************************/
/*该函数位于DMA中断处理函数HAL_DMA_IRQHandler中被调用,在HAL_UART_Transmit_DMA函数中赋值*/
static void UART_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxHalfCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxHalfCpltCallback(huart); /*注释6.3.1:调用数据传输一半的回调函数,该函数由用户实现*/
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/*该函数位于DMA中断处理函数HAL_DMA_IRQHandler中被调用,在HAL_UART_Transmit_DMA函数中赋值*/
/*这里对DMA的正常模式和循环模式做了区分,正常模式下产生USART中断;循环模式下直接调用回调函数*/
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode*/
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
huart->TxXferCount = 0x00U;
/* Disable the DMA transfer for transmit request by setting the DMAT bit
in the UART CR3 register */
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT); /*注释6.5.1:关闭DMA传输*/
/* Enable the UART Transmit Complete Interrupt */
SET_BIT(huart->Instance->CR1, USART_CR1_TCIE); /*注释6.5.2:触发UART数据传输完成中断*/
}
/* DMA Circular mode */
else
{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxCpltCallback(huart); /*注释6.5.3:循环模式下,数据传输完成直接执行该回调函数*/
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
/*****************************************************************************************************************************/
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
HAL_StatusTypeDef status = HAL_OK;
/*省略了部分代码*/
/* Process locked */
__HAL_LOCK(hdma);
if(HAL_DMA_STATE_READY == hdma->State)
{
/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_BUSY; /*注释7.1:修改DMA状态*/
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
/* Disable the peripheral */
__HAL_DMA_DISABLE(hdma); /*注释7.2:失能DMA,为了配置参数*/
/* Configure the source, destination address and the data length & clear flags*/
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength); /*注释7.3:配置DMA通道、数据源地址、目标地址、数据长度*/
/* Enable the transfer complete interrupt */
/* Enable the transfer Error interrupt */
if(NULL != hdma->XferHalfCpltCallback) /*注释7.4:*/
{
/* Enable the Half transfer complete interrupt as well */
__HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE)); /*注释7.5:使能数据传输完成、数据传输一半、数据传输出错中断*/
}
else
{
__HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT); /*注释7.6:不开启数据传输一半中断*/
__HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_TE)); /*注释7.7:使能数据传输完成、数据传输出错中断*/
}
/* Enable the Peripheral */
__HAL_DMA_ENABLE(hdma); /*注释7.8:参数配置完成后,使能DMA*/
}
else
{
/* Process Unlocked */
__HAL_UNLOCK(hdma);
/* Remain BUSY */
status = HAL_BUSY;
}
return status;
}
/*****************************************************************************************************************************/
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
/* UART in mode Receiver -------------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
/*省略了部分代码*/
/* UART in mode Transmitter end --------------------------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart); /*注释5.2.1:USART的DMA数据传输完成*/
return;
}
}
/*****************************************************************************************************************************/
static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart)
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_TC);
/* Tx process is ended, restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY; /*注释5.2.1.1:对应(注释7.1),修改USART状态*/
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxCpltCallback(huart); /*注释5.2.1.1:执行数据传输完成回调函数*/
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
return HAL_OK;
}
4 工程链接
gitee平台: STM32F10xxx Learn