STM32HAL库串口处理---中断收发

STM32HAL库串口处理—中断收发


利用STM32串口中断收发和buffer机制(循环队列的原理)实现数据的准确接收和发送。为后续添加上层通信协议建立基础。为了方便使用,为函数接口统一标准

Arduino串口机制的接口函数

void begin(unsigned long baud);//初始化接口
void end(void);//关闭串口
int available(void);//获取缓存中可以读取的字节数
int peek(void);//从缓存中读取字节数据,但不删除该数据
int read(void);//从缓存中读取字节数据,并删除该数据
int availableWrite(void);//获取发送缓存还可以写入的字节数
void flush(void); //将发送缓存中的数据全部发送出去
void write(uint8_t c);//发送字节数据

代码实现

编写硬件层MSP支持代码

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
    /* USART1 clock enable */
    __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);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();
  
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  }
} 

定义新的串口结构体

#define SERIAL_RX_BUFFER_SIZE  64
#define SERIAL_TX_BUFFER_SIZE  64
typedef struct
{
  UART_HandleTypeDef handle;
  IRQn_Type irq;
  uint8_t recv;
  uint8_t rx_buffer[SERIAL_RX_BUFFER_SIZE];
  uint8_t tx_buffer[SERIAL_TX_BUFFER_SIZE];
  uint16_t rx_head;
  volatile uint16_t rx_tail;
  volatile uint16_t tx_head;
  uint16_t tx_tail;
}Serial_t;

接口函数实现

实例化对象
Serial_t serial1;
//UART_HandleTypeDef *huart1 = &(serial1.handle);
Serial_t serial2; //实际未用到
serial_init()
void serial_init(Serial_t *serial, uint32_t baud)
{
  UART_HandleTypeDef *huart = &(serial->handle);
  
  huart->Init.BaudRate = baud;
  huart->Init.WordLength = UART_WORDLENGTH_8B;
  huart->Init.StopBits = UART_STOPBITS_1;
  huart->Init.Parity = UART_PARITY_NONE;
  huart->Init.Mode = UART_MODE_TX_RX;
  huart->Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart->Init.OverSampling = UART_OVERSAMPLING_16;
  
  if(serial == &serial1)
  {
    huart->Instance = USART1;
    serial->irq = USART1_IRQn;
  }
  else if(serial == &serial2)
  {
    huart->Instance = USART2;
    serial->irq = USART2_IRQn;
  }
  if(HAL_UART_Init(huart) != HAL_OK)
  {
    Error_Handler();
  }
  //使能串口接收中断
  HAL_UART_Receive_IT(huart, &(serial->recv), 1);
}
serial_available()
int serial_available(Serial_t *serial)
{
  return (uint32_t)(SERIAL_RX_BUFFER_SIZE + serial->rx_head - serial->rx_tail) % SERIAL_RX_BUFFER_SIZE;
}
serial_peek()
int serial_peek(Serial_t *serial)
{
  if(serial->rx_head == serial->rx_tail)
  {
    return -1;
  }
  else
  {
    return serial->rx_buffer[serial->rx_tail];
  } 
}
serial_read()
int serial_read(Serial_t *serial)
{
  if(serial->rx_head == serial->rx_tail)
  {
    return -1;
  }
  else
  {
    uint8_t c = serial->rx_buffer[serial->rx_tail];
    serial->rx_tail = (uint16_t)(serial->rx_tail + 1) % SERIAL_RX_BUFFER_SIZE;
    return c;
  }
}
availableWrite()
int serial_availableForWrite(Serial_t *serial)
{
  return (uint32_t)(SERIAL_TX_BUFFER_SIZE + serial->tx_tail - serial->tx_head - 1) % SERIAL_TX_BUFFER_SIZE;
}
serial_flush
//只有在执行过serial_write()函数后才可使用该函数。
void serial_flush(Serial_t *serial)
{
  while ((serial->tx_head != serial->tx_tail)) {
    // nop, the interrupt handler will free up space for us
  }
  // If we get here, nothing is queued anymore (DRIE is disabled) and
  // the hardware finished tranmission (TXC is set).
}
serial_write()
void serial_write(Serial_t *serial, uint8_t c)
{
  //HAL_UART_Transmit(&(serial->handle),&c,1,1000);
  uint16_t i = (serial->tx_head + 1) % SERIAL_TX_BUFFER_SIZE;
  
  while(i == serial->tx_tail)  //发送缓冲区满
  {
    //什么也不做,等待缓冲区有空间
  }
  
  serial->tx_buffer[serial->tx_head] = c;
  serial->tx_head = i;
  
  if((HAL_UART_GetState(&(serial->handle)) & HAL_UART_STATE_BUSY_TX) != HAL_UART_STATE_BUSY_TX)
  {
    /* Must disable interrupt to prevent handle lock contention */
    HAL_NVIC_DisableIRQ(serial->irq);
    HAL_UART_Transmit_IT(&(serial->handle), &(serial->tx_buffer[serial->tx_tail]), 1);
    HAL_NVIC_EnableIRQ(serial->irq);
  }
}

中断服务函数

接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart == &(serial1.handle))
  {
    uint16_t i = (uint32_t)(serial1.rx_head +1) % SERIAL_RX_BUFFER_SIZE;
    
    if(i != serial1.rx_tail)
    {
      serial1.rx_buffer[serial1.rx_head] = serial1.recv;
      serial1.rx_head = i;
    }
    /* 使能下次接收中断 */
    HAL_UART_Receive_IT(huart, &(serial1.recv), 1);
  }
}
发送中断回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart == &(serial1.handle))
  {
    serial1.tx_tail = (serial1.tx_tail + 1) % SERIAL_TX_BUFFER_SIZE;
    if(serial1.tx_head == serial1.tx_tail)
    {
      return;
    }
    /* 发送完成后,再次使能中断发送直至发送缓冲区的数据全部发送完成 */
    if (HAL_UART_Transmit_IT(huart, &serial1.tx_buffer[serial1.tx_tail], 1) != HAL_OK) {
      return;
    }
  }
}
中断函数
/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&(serial1.handle));
}

测试

int main(void)
{
    /* 省略了初始化函数 */
    while(1)
    {
    	if(serial_available(&serial1))
    	{
        	uint8_t c = serial_read(&serial1);
        	serial_write(&serial1,c)
    	}    
    }    
}

利用该测试函数可以实现串口的回环接收。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值