Ham*_*Fet 18 hal stm32 stm32f4discovery
我正在试图弄清楚如何使用这个新的HAL驱动程序.我希望使用HAL_UART_Receive_IT()设置设备的数据来接收数据时运行中断功能.
问题是你必须在中断触发之前指定要读取的数据长度.我计划像不同长度的命令一样发送控制台,因此不能有固定的长度.我假设唯一的方法是一次读取单个字符并构建一个单独的字符串.
HAL驱动程序似乎有一个问题,如果您设置HAL_UART_Receive_IT()接收x字符数,然后尝试发送多个x字符,将出现错误.
目前我不知道我是否正确的方式,任何想法?
Ham*_*Fet 15
我决定使用DMA来使接收工作.我正在使用一个1字节的循环缓冲区来处理数据,因为它是在变送器的串行终端上输入的.这是我的最终代码(只有接收部分,底部传输的更多信息).
一些定义和变量:
#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
Run Code Online (Sandbox Code Playgroud)
设置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);
Run Code Online (Sandbox Code Playgroud)
设置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);
Run Code Online (Sandbox Code Playgroud)
设置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);
Run Code Online (Sandbox Code Playgroud)
设置DMA中断:
extern DMA_HandleTypeDef hdma_usart1_rx;
void DMA2_Stream2_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA2_Stream2_IRQn);
HAL_DMA_IRQHandler(&hdma_usart1_rx);
}
Run Code Online (Sandbox Code Playgroud)
启动DMA:
__HAL_UART_FLUSH_DRREGISTER(&huart1);
HAL_UART_Receive_DMA(&huart1, &rxBuffer, 1);
Run Code Online (Sandbox Code Playgroud)
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> ");
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以这几乎是接收字符的所有代码并构建一个显示用户输入内容的字符串(char数组).如果用户命中backspace或del,则会覆盖数组中的最后一个字符,如果它们按Enter键,则该数组将被发送到另一个函数并作为命令处理.
要查看命令解析,以及如何传递代码的作品,看到我的项目在这里
感谢@Flip和@Dormen的建议!
在数据寄存器(DR)已满时接收数据将导致溢出错误.问题是,UART_Receive_IT(UART_HandleTypeDef*)一旦收到足够的数据,该功能将停止读取DR寄存器.任何新数据都将导致溢出错误.
我所做的是宁愿使用循环DMA接收结构.然后,您可以使用它currentPosInBuffer - uart->hdmarx->Instance->NDTR来确定尚未处理的数据量.
它有点复杂,因为当DMA执行循环缓冲时,如果超过缓冲区的末尾,则必须手动将环回实现到开头.
我还发现了一个故障,控制器说它已经传输了数据(即NDTR已经减少了),但数据还没有在缓冲区中.它可能是一些DMA /总线访问争用问题,但它很烦人.