一、首先HAL库真心的不好用,明明很简单的东西弄的那么复杂哎 基础部分:
串口初始化后: 同时开启接收与发送功能 [mw_shl_code=cpp,true] UartHandle->Instance = USART1;
UartHandle->Init.BaudRate = 115200;
UartHandle->Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle->Init.Mode = UART_MODE_TX_RX;
UartHandle->Init.OverSampling = UART_OVERSAMPLING_16;
UartHandle->Init.WordLength = UART_WORDLENGTH_8B;
UartHandle->Init.StopBits = UART_STOPBITS_1;
UartHandle->Init.Parity = UART_PARITY_NONE;
HAL_UART_Init(UartHandle);[/mw_shl_code]
引脚初始化MspInit:
[mw_shl_code=applescript,true] __HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);[/mw_shl_code]
中断优先级与接收中断开启:
[mw_shl_code=cpp,true] HAL_NVIC_SetPriority(USART1_IRQn, 3, 1);
NVIC_EnableIRQ(USART1_IRQn);
__HAL_UART_ENABLE_IT(UartHandle, UART_IT_RXNE);[/mw_shl_code]
关键部分1:
[mw_shl_code=cpp,true]// 数据结构部分
#define SERIAL_BUFFER_SIZE 128
/* 使用USING_IT_TXE条件编译,来确定是普通发送还是中断发送
* 细节见:write函数与发送中断
*/
#define USING_IT_TXE
struct Uart_Buffer{
uint32_t buffer_head;
uint32_t buffer_tail;
unsigned char buffer[SERIAL_BUFFER_SIZE];
};
struct Serial
{
UART_HandleTypeDef UartHandle;
IRQn_Type irq;
#ifdef USING_IT_TXE
volatile bool tx_enable;
#endif
volatile struct Uart_Buffer rx;
#ifdef USING_IT_TXE
volatile struct Uart_Buffer tx;
#endif
};[/mw_shl_code]
关键部分2:
[mw_shl_code=cpp,true]struct Serial serial1;
void init()
{
serial1.UartHandle.Instance = USART1;
serial1.irq = USART1_IRQn;
clear();
}
/* 这里是简单的循环队列:初始化部分
*/
void clear ()
{
rx.buffer_head = rx.buffer_tail = 0;
#ifdef USING_IT_TXE
tx.buffer_head = tx.buffer_tail = 0;
#endif
}
/* 这里是简单的循环队列:写操作
* 1、用来干什么呢,用于中断接收到数据,保存到rx.buffer[]数组中
* 2、此函数中断函数中调用
*/
void rx_int_irq (uint8_t ch)
{
uint32_t i = (unsigned int)(rx.buffer_head + 1) % SERIAL_BUFFER_SIZE;
if (i != rx.buffer_tail)
{
rx.buffer[rx.buffer_head] = ch;
rx.buffer_head = i;
}
}
/* 这里是简单的循环队列:数据个数查询操作
* 1、查询rx.buffer[]数组中,是否有数据
* 2、此函数用户调用
*/
uint32_t rx_available ()
{
return (SERIAL_BUFFER_SIZE + rx.buffer_head - rx.buffer_tail) % SERIAL_BUFFER_SIZE;
}
/* 这里是简单的循环队列:读操作
* 1、从rx.buffer[]数组中读取数据
* 2、此函数用户调用
*/
uint8_t read (void)
{
if (rx.buffer_head == rx.buffer_tail)
{
/* 这里只是个返回值,无实际意义,调用read函数前,
需要调用rx_available函数进行查询,确保有数据存在 */
return 0xFF;
} else
{
unsigned char c = rx.buffer[rx.buffer_tail];
rx.buffer_tail = (rx.buffer_tail + 1) % SERIAL_BUFFER_SIZE;
return c;
}
}
/* 这里是简单的循环队列:数据个数查询操作
* 1、查询tx.buffer[]数组中,是否有数据
* 2、此函数中断调用
*/
#ifdef USING_IT_TXE
uint32_t tx_available()
{
return (SERIAL_BUFFER_SIZE + tx.buffer_head - tx.buffer_tail) % SERIAL_BUFFER_SIZE;
}
/* 这里是简单的循环队列:读操作
* 1、从tx.buffer[]数组中读取数据写入DR寄存器
* 2、此函数中断调用
*/
uint8_t tx_int_irq (void)
{
if (tx.buffer_head == tx.buffer_tail)
{
return 0xFF;
} else
{
unsigned char c = tx.buffer[tx.buffer_tail];
tx.buffer_tail = (tx.buffer_tail + 1) % SERIAL_BUFFER_SIZE;
return c;
}
}
#endif
/* 这里是简单的循环队列:写操作
* 1、用来干什么呢,将数据写入rx.buffer[]数组中
* 2、此函数中断函数中调用
*/
uint8_t write (uint8_t c)
{
#ifdef USING_IT_TXE
uint32_t i = (unsigned int)(tx.buffer_head + 1) % SERIAL_BUFFER_SIZE;
if (i != tx.buffer_tail)
{
tx.buffer[tx.buffer_head] = c;
tx.buffer_head = i;
}
if(!tx_enable){
__disable_irq();
/* 发送完成的Flag,需要手动清除 */
__HAL_UART_CLEAR_FLAG(&UartHandle, UART_FLAG_TC);
/*
* tx.buffer[]有数据后,开启发送缓冲空的中断
*/
__HAL_UART_ENABLE_IT(&UartHandle, USART_IT_TXE);
tx_enable = true;
__enable_irq();
}
#else
/* 普通发送的书写方式,这种方式太耗MCU资源了,不建议采用 */
while((__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_TXE) == RESET));
UartHandle.Instance->DR = c;
#endif
return 1;
}[/mw_shl_code]
关键部分3:中断函数
/* 这里先对FLAG参数进行说明下,以免新手看不懂 * UART_FLAG_RXNE:接收到数据的Flag,需要手动清除,否则一直中断到MCU卡死
* UART_FLAG_TXE:发送缓冲空的Flag,往DR寄存器写数据后,硬件自动清除
* UART_FLAG_TC: 发送完成的Flag,需要手动清除,否则一直中断到MCU卡死
*/
void USART1_IRQHandler(void)
{
/* UART in mode Receiver -------------------------------------------------*/
if ((__HAL_UART_GET_FLAG(&(serial1.UartHandle), UART_FLAG_RXNE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&(serial1.UartHandle), UART_IT_RXNE) != RESET))
{
serial1.rx_int_irq(serial1.UartHandle.Instance->DR & 0xff);
/* Clear RXNE interrupt flag */
__HAL_UART_CLEAR_FLAG(&(serial1.UartHandle), UART_FLAG_RXNE);
}
#ifdef USING_IT_TXE
/* UART in mode ransmit_ -------------------------------------------------*/
if ((__HAL_UART_GET_FLAG(&(serial1.UartHandle), UART_FLAG_TXE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&(serial1.UartHandle), USART_IT_TXE) != RESET))
{
/*
* 查询tx.buffer中是否有数据:
* 1、有数据进行发送
* 2、没有数据关闭发送中断
*/
if(serial1.available_irq()){
serial1.UartHandle.Instance->DR = serial1.tx_int_irq();
}else{
__HAL_UART_DISABLE_IT(&(serial1.UartHandle), USART_IT_TXE);
serial1.tx_enable = false;
}
/* Clear TC interrupt flag */
__HAL_UART_CLEAR_FLAG(&(serial1.UartHandle), UART_FLAG_TC);
}
#endif
}
本实例的目的是:
1、这类数据传输怎么处理
2、中断发送相对于中断接收来说,需要注意是发送中断只有在需要的情况下(有数据的情况下)开启。
3、没有注意到 2的问题情况下,在初始化部分就开启中断发送后,MCU上电就死机的现象(这里并不是死机,是死锁,因为MCU一直在相应串口中断函数,导致MCU处理不了其他问题)。 |