STM32F4 UART HAL 驱动程序 [英] STM32F4 UART HAL Driver
问题描述
我正在研究如何使用这个新的 HAL 驱动程序.我想使用 HAL_UART_Receive_IT()
接收数据,它设置设备在接收到数据时运行中断函数.
I'm trying to figure out how to use this new HAL driver. I want to receive data using the HAL_UART_Receive_IT()
which sets up the device to run an interrupt function when data is received.
问题是你必须在中断触发之前指定要读取的数据长度.我计划发送控制台之类的不同长度的命令,因此不能有固定长度.我认为唯一的方法是一次读取单个字符并构建一个单独的字符串.
Problem is that you have to specify the length of data to read before the interrupt triggers. I plan on sending console like commands of varying length so can't have a fixed length. I assume the only way to do this would be to read single characters at a time and build up a separate string.
HAL 驱动程序似乎有问题,如果您将 HAL_UART_Receive_IT()
设置为接收 x
个字符,然后尝试发送超过 x
字符,会有错误.
The HAL driver seems to have a problem where if you set the HAL_UART_Receive_IT()
to receive x
number of characters, and then try to send more than x
characters, there will be an error.
目前我不知道我的做法是否正确,有什么想法吗?
Currently I have no idea if I'm going about it the right way, any ideas?
推荐答案
我决定使用 DMA 来让接收工作.我正在使用一个 1 字节的循环缓冲区来处理在发送器的串行终端上输入的数据.这是我的最终代码(只有接收部分,底部有更多关于传输的信息).
I decided to go with DMA to get the receive working. I'm using a 1 byte circular buffer to handle data as it is typed on the transmitter's serial terminal. Here's my final code (only the receive part, more info on transmit at the bottom).
一些定义和变量:
#define BAUDRATE 9600
#define TXPIN GPIO_PIN_6
#define RXPIN GPIO_PIN_7
#define DATAPORT GPIOB
#define UART_PRIORITY 6
#define UART_RX_SUBPRIORITY 0
#define MAXCLISTRING 100 // Biggest string the user will type
uint8_t rxBuffer = '\000'; // where we store that one character that just came in
uint8_t rxString[MAXCLISTRING]; // where we build our string from characters coming in
int rxindex = 0; // index for going though rxString
设置 IO:
__GPIOB_CLK_ENABLE();
__USART1_CLK_ENABLE();
__DMA2_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = TXPIN | RXPIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(DATAPORT, &GPIO_InitStruct);
设置 UART:
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
huart1.Instance = USART1;
huart1.Init.BaudRate = BAUDRATE;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);
设置 DMA:
extern DMA_HandleTypeDef hdma_usart1_rx; // assuming this is in a different file
hdma_usart1_rx.Instance = DMA2_Stream2;
hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_DISABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart1_rx);
__HAL_LINKDMA(huart, hdmarx, hdma_usart1_rx);
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, UART_PRIORITY, UART_RX_SUBPRIORITY);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
设置DMA中断:
extern DMA_HandleTypeDef hdma_usart1_rx;
void DMA2_Stream2_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA2_Stream2_IRQn);
HAL_DMA_IRQHandler(&hdma_usart1_rx);
}
启动 DMA:
__HAL_UART_FLUSH_DRREGISTER(&huart1);
HAL_UART_Receive_DMA(&huart1, &rxBuffer, 1);
DMA 接收回调:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_UART_FLUSH_DRREGISTER(&huart1); // Clear the buffer to prevent overrun
int i = 0;
print(&rxBuffer); // Echo the character that caused this callback so the user can see what they are typing
if (rxBuffer == 8 || rxBuffer == 127) // If Backspace or del
{
print(" \b"); // "\b space \b" clears the terminal character. Remember we just echoced a \b so don't need another one here, just space and \b
rxindex--;
if (rxindex < 0) rxindex = 0;
}
else if (rxBuffer == '\n' || rxBuffer == '\r') // If Enter
{
executeSerialCommand(rxString);
rxString[rxindex] = 0;
rxindex = 0;
for (i = 0; i < MAXCLISTRING; i++) rxString[i] = 0; // Clear the string buffer
}
else
{
rxString[rxindex] = rxBuffer; // Add that character to the string
rxindex++;
if (rxindex > MAXCLISTRING) // User typing too much, we can't have commands that big
{
rxindex = 0;
for (i = 0; i < MAXCLISTRING; i++) rxString[i] = 0; // Clear the string buffer
print("\r\nConsole> ");
}
}
}
这就是接收字符和构建显示用户输入内容的字符串(字符数组)的几乎所有代码.如果用户按退格键或删除键,数组中的最后一个字符将被覆盖,如果他们按回车键,该数组将被发送到另一个函数并作为命令处理.
So that's pretty much all the code to receive characters and build a string (char array) that shows what the user has entered. If the user hits backspace or del, the last character in the array is overwritten and if they hit enter, that array is sent to another function and processed as a command.
要查看命令解析和传输代码的工作原理,请参阅我的项目此处
To see how the command parsing and transmit code works, see my project Here
感谢@Flip 和@Dormen 的建议!
Thanks to @Flip and @Dormen for their suggestions!
这篇关于STM32F4 UART HAL 驱动程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!