使用的是STM32f750
1:printf的使用
//在usart.h文件中包含头文件:记得勾选Use Microlib
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
HAL_UART_Transmit( &huart6 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
2:相关常用函数的介绍:
2.1 HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。
参数:
UART_HandleTypeDef *huart UATR的别名 如 : UART_HandleTypeDef huart1; 别名就是huart1
*pData 需要发送的数据
Size 发送的字节数
Timeout 最大发送时间,发送数据超过该时间退出发送 ,堵塞发送
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
const uint8_t *pdata8bits;
const uint16_t *pdata16bits;
uint32_t tickstart;
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
__HAL_LOCK(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
huart->TxXferSize = Size;
huart->TxXferCount = Size;
/* In case of 9bits/No Parity transfer, pData needs to be handled as a uint16_t pointer */
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (const uint16_t *) pData;
}
else
{
pdata8bits = pData;
pdata16bits = NULL;
}
__HAL_UNLOCK(huart);
while (huart->TxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (pdata8bits == NULL)
{
huart->Instance->TDR = (uint16_t)(*pdata16bits & 0x01FFU);
pdata16bits++;
}
else
{
huart->Instance->TDR = (uint8_t)(*pdata8bits & 0xFFU);
pdata8bits++;
}
huart->TxXferCount--;
}
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
/* At end of Tx process, restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
2.2 HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
执行中:发送pData指针指向空间的信息+使能“发送寄存器空”中断;
执行结束后:立即进入中断;
在中断里,先自动调用 UART_EndTransmit_IT(UART_HandleTypeDef *huart) 函数(该函数会失能“发送完成”中断。不过无所谓,可以不用在意);
中断里,之后再自动调用 HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) 回调函数(用户自定义其功能),退出中断,等待下一次信息的发送。;
//HAL_UART_Transmit_IT()执行函数(非阻塞)后进去回调函数
//比如我发送完一次数据后进入回调函数执行一次LED的反转
while(1)
{
HAL_UART_Transmit_IT( &huart1, &"zjy", sizeof("zjy"));
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if( huart == &huart1 )
{
//HAL_UART_Transmit_IT( &huart1, &"2222", 1);
HAL_GPIO_TogglePin(GPIOB,LED0_Pin);
}
}
2.3 HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint8_t *pdata8bits;
uint16_t *pdata16bits;
uint16_t uhMask;
uint32_t tickstart;
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
__HAL_LOCK(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
huart->RxXferSize = Size;
huart->RxXferCount = Size;
/* Computation of UART mask to apply to RDR register */
UART_MASK_COMPUTATION(huart);
uhMask = huart->Mask;
/* In case of 9bits/No Parity transfer, pRxData needs to be handled as a uint16_t pointer */
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (uint16_t *) pData;
}
else
{
pdata8bits = pData;
pdata16bits = NULL;
}
__HAL_UNLOCK(huart);
/* as long as data have to be received */
while (huart->RxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (pdata8bits == NULL)
{
*pdata16bits = (uint16_t)(huart->Instance->RDR & uhMask);
pdata16bits++;
}
else
{
*pdata8bits = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
pdata8bits++;
}
huart->RxXferCount--;
}
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
判断是否忙-->锁住-->标记接收忙-->获取tick计数
-->赋值RxXferCount有多少数据要接收-->每次从DR内获取一个Byte存在pData指向的空间
2.4 HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
用户在 main() 和回调函数 HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 中都调用一次该函数;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_DMA_Init();
HAL_UART_Receive_IT(&huart1, Rxbuf, 1);
/*没有在main()里调用 HAL_UART_Receive_IT(),usart是不会进入中断
*去接收信息的。——阅读了stm32f1xx_hal_uart.c文件中对uart外设的说明,
*发现了该问题并解决。*/
执行中:指定未来接收到的信息要存入的空间,即pData指针指向的空间就是之后接收到的信息要存入的空间+使能“奇偶校验错误”中断+使能“其它uart错误”中断+使能“接收寄存器非空”中断;(特别注意:该函数是不会接收信息的,只是指定信息要存入的空间)
执行结束后:等待接收寄存器非空,然后进入中断;
在中断里,先自动调用 UART_Receive_IT(UART_HandleTypeDef *huart) 函数(该函数会接收信息并存入上一步已经预备好的空间中+失能“奇偶校验错误”中断+失能“其它uart错误”中断+失能“接收寄存器非空”中断);
//确保中断线与uart以对应
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)//如果是串口1
{
printf("11\r\n");
HAL_UART_Transmit(&huart1,Txbuf ,sizeof(Txbuf),0xFFFF);
}
HAL_UART_Receive_IT(&huart1,Rxbuf ,1);
}
/*没有在 HAL_UART_RxCpltCallback() 中再次调用 HAL_UART_Receive_IT(),
*usart只会响应一次中断去接*收信息,之后再来新的信息就不会进入中断去接收了,
*更不会进入 HAL_UART_RxCpltCallback() 函数里了。**——通过软件的单步调试
*功能和网上海量教程,发现了该问题并解决*/
中断里,之后再自动调用 HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 回调函数(用户自定义其功能,但是用户在该函数中必须自行添加 HAL_UART_Receive_IT() 函数,以指定下一次信息待存入的空间并再次使能对应的中断功能);
退出中断,等待下一次接收寄存器非空
2.5总结
1、HAL_UART_Receive_IT和HAL_UART_Receive的区别就是:中断接收是有数据到了才去读;直接接收是直接读取,如果超时就返回
2、HAL_UART_Receive_IT配置后,有数据来,计数会在调用中断函数之后自动减1。只有到计数为0时,才会关闭中断并调用回调函数。至此有数据来不再调用中断函数,因为中断已经失效。
3、HAL_UART_Receive_IT在计数未至0之前,应该可以读取之前接收到的数据,但这样做应该比较危险。
4、在开源电子的例程中,使用 HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, 1); 即Size设置为1,只接收1Byte数据,在每次中断结束后重新配置来使能中断。