hal库串口详解

HAL库外设初始化MSP回调机制

HAL_PPP_Init() PPP是任意外设,会自动调用MSP回调函数~>HAL_PPP_MspInit()

hal库串口详解_第1张图片

HAL_PPP_MspInit()配置外设,如USART1 PA9,PA10,可以重新定义,因为weak是弱定义        

如果HAL_PPP_Init() 被调用3次,则HAL_PPP_MspInit()也被调用3次,要根据外设寄存器基地址来区分

HAL库外设初始化MSP回调机制-USART为例

UART_HandleTypeDef *huart  是句柄
huart->Instance 基地址

hal库串口详解_第2张图片

HAL库中断回调机制

hal库串口详解_第3张图片

//中断服务函数
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);        //调用中断处理公用函数
}

void EXTI2_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);        //调用中断处理公用函数
}

void EXTI3_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);        //调用中断处理公用函数
}

void EXTI4_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);        //调用中断处理公用函数
}

//中断服务程序中需要做的事情
//在HAL库中所有的外部中断服务函数都会调用此函数
//GPIO_Pin:中断引脚号
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(100);      //消抖
    switch(GPIO_Pin)
    {
        case GPIO_PIN_0:
            if(WK_UP==1) 
            {
                LED1=!LED1;//控制LED0,LED1互斥点亮
                LED0=!LED1;
            }
            break;
        case GPIO_PIN_2:
            if(KEY2==0)  //LED1翻转
            {
                LED1=!LED1;    
            }
            break;
        case GPIO_PIN_3:
            if(KEY1==0)  //同时控制LED0,LED1翻转 
            {
                LED0=!LED0;
                LED1=!LED1;
            }
            break;
        case GPIO_PIN_4:
            if(KEY0==0)  
            {
                LED0=!LED0;//控制LED0翻转
            }
            break;
    }
}

中断函数在启动文件上找

以USART的例子

USARTxIRQHandler() 或者UARx_IRQHandler()用户调用中断共同处理函数

HAL_USART_IRQHandler()

则HAL库自己调用中断回调函数    hal库串口详解_第4张图片

回调函数与反回调函数

hal库串口详解_第5张图片

UART回调函数

hal库串口详解_第6张图片

外部中断函数

hal库串口详解_第7张图片

公共函数:清除中断函数标志位
UART_Receive_IT(huast)是接收完成标志位,再清除标志位,调用HAL_UART_RxCpltcallback()函数
UART_Receive_IT(huast)是发送,当为空的时候发送
UART_EndTransmit_IT(huast)是发送完成标志位,再清除标志,调HAL_UART_TxCpltcallback()函数
hal库串口详解_第8张图片
UART异步通信配置步骤
1,配置窗口工作函数        HAL_UART_Init()   会调用MSP回调函数
2,窗口底层初始化            HAL_UART_MspInit() 配置GPIO,NVIC,CLOCK等
3,开启串口异步接收中断 HAL_UART_Receive_IT() 看见_IT则开启相应中断
4.设置优先级,使能中断    HAL_NVIC_IRQHandler(),HAL_NVIC_EnalbeIRQ()
5,编写中断服务函数         UARTx_IRQHander() 在启动文件找
6,串口数据发送                 USART_DR,HAL_UART_Transmit()

_HandleTypeDef *huart   这样的结构体命名为句柄

注意:只看前俩个 *Instance , Init

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart) 

hal库串口详解_第9张图片1.Instance:指向UART寄存器基地址,实际上是USART1~USART3,USART4,USART5

注:基地址在stm32407xx.h里面

关键结构体(F1):

typedef struct

{    uint32_t BaudRate;   /* 波特率 */

     uint32_t WordLength;   /* 字长 */

     uint32_t StopBits;   /* 停止位 */

     uint32_t Parity;   /* 奇偶校验位 */

     uint32_t Mode;   /* UART 模式 */

     uint32_t HwFlowCtl;   /* 硬件流设置 */   可以不用管

     uint32_t OverSampling;   /* 过采样设置 */     可以选8或者16

}UART_InitTypeDef 

/* 字长 */

#define UART_WORDLENGTH_8B                  0x00000000U
#define UART_WORDLENGTH_9B                  ((uint32_t)USART_CR1_M)

/* 停止位 */

#define UART_STOPBITS_1                     0x00000000U
#define UART_STOPBITS_2                     ((uint32_t)USART_CR2_STOP_1)

/* 奇偶校验位 */

#define UART_PARITY_NONE                    0x00000000U
#define UART_PARITY_EVEN                    ((uint32_t)USART_CR1_PCE)
#define UART_PARITY_ODD                     ((uint32_t)(USART_CR1_PCE | USART_CR1_PS))

  /* UART 模式 */

#define UART_MODE_RX                        ((uint32_t)USART_CR1_RE)
#define UART_MODE_TX                        ((uint32_t)USART_CR1_TE)
#define UART_MODE_TX_RX                     ((uint32_t)(USART_CR1_TE | USART_CR1_RE))

HAL_StatusTypeDef      HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

作用:以中断的方式接收指定字节的数据

形参1:是 UART_HandleTypeDef结构体类型的指针变量  句柄

形参2:是指向接收数据缓冲区

形参3:是要接收数据的大小, 以字节为单位

句柄就是个指针,判断中断来源,比如usart1,usart2等

HAL_StatusTypeDef         HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

没有IT,没有开启中断

作用:以阻塞的方式发送指定字节的数据  阻塞:(干不完,不能出来)

形参 1 :UART_HandleTypeDef 结构体类型指针变量

形参 2:指向要发送的数据地址

形参 3:要发送的数据大小,以字节为单位

形参 4:设置的超时时间,以ms单位

IO口引脚复用功能:

7.1何为复用?

1,通用:IO端口的输入或输出是由GPIO外设控制,我们称为为通用 (控制ODR,BSRR,IDR寄存器)

2.复用:IO端口的输入或输出是由其它非GPIO外设控制(由USART,TIM,ADC,DAC控制)

7.2STM32F1IO引脚复用

1.各IO支持什么复用功能 可查芯片数据手册

2.IO复用功能冲突问题:同一时间只能用作一种复用功能,否则冲突

3.遇到IO复用功能冲突,考虑重映射

7.3STM32F4/F7/H7IO引脚复用

hal库串口详解_第10张图片

只能一个连接,俩个不行,否则都无效

为了解决F1系列存在的IO复用功能冲突问题,F4往后的系列都加入了复用器

复用器特点:

1每个 IO 引脚都有一个复用器

2、复用器采用 16 路复用功能输入(AF0 AF15) 16选1        

3、复用器一次仅允许一个外设的复用功能 (AF) 连接到 IO 引脚

4、通过GPIOx_AFRLGPIOx_AFRH寄存器进行配置

32位,8引脚,所以由4个位控制

hal库串口详解_第11张图片

hal库串口详解_第12张图片

hal库串口详解_第13张图片

hal库串口详解_第14张图片

PA10直接复用,可以不用设置

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_Initure;
    
    if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();            //使能GPIOA时钟
        __HAL_RCC_USART1_CLK_ENABLE();            //使能USART1时钟
    
        GPIO_Initure.Pin=GPIO_PIN_9;            //PA9
        GPIO_Initure.Mode=GPIO_MODE_AF_PP;        //复用推挽输出
        GPIO_Initure.Pull=GPIO_PULLUP;            //上拉
        GPIO_Initure.Speed=GPIO_SPEED_FAST;        //高速
        GPIO_Initure.Alternate=GPIO_AF7_USART1;    //复用为USART1
        HAL_GPIO_Init(GPIOA,&GPIO_Initure);           //初始化PA9

        
        GPIO_Initure.Pin=GPIO_PIN_10;            //PA10
        HAL_GPIO_Init(GPIOA,&GPIO_Initure);           //初始化PA10

        }

}

hal库串口详解_第15张图片

hal库串口详解_第16张图片

hal库串口详解_第17张图片

错了,不知道原因

#include "bsp_uart.h"
uint8_t g_rx_buffer[1]; //一个字节 HAl库使用的串口接收数据缓冲区
uint8_t g_uart1_rx_flag=0; /*串口接收到数据标志*/

UART_HandleTypeDef uart1_handeler;    /*句柄*/

void bsp_uart(uint32_t baudrate)
{
    uart1_handeler.Instance=USART1;
    uart1_handeler.Init.BaudRate=baudrate;
    uart1_handeler.Init.HwFlowCtl=UART_HWCONTROL_NONE;
    uart1_handeler.Init.Mode=UART_MODE_TX_RX;
    uart1_handeler.Init.OverSampling=UART_OVERSAMPLING_16;
    uart1_handeler.Init.Parity=UART_PARITY_NONE;
    uart1_handeler.Init.StopBits=UART_STOPBITS_1;
    uart1_handeler.Init.WordLength=UART_WORDLENGTH_8B;
    HAL_UART_Init(&uart1_handeler);
    
    HAL_UART_Receive_IT(&uart1_handeler, g_rx_buffer,1);/*开启接收中断*/
    /*使能数据寄存器非空中断
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);*/
}

/*串口MSP回调函数 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    if(huart->Instance==USART1)
    {
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE() ;
        GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;  /*推挽式复用*/ 
        GPIO_InitStruct.Pin=GPIO_PIN_9;            
        //GPIO_InitStruct.Pull=GPIO_PULLUP;            /*上下拉不用管*/
        GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;   /*高速*/
        HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
        ;
        GPIO_InitStruct.Mode=GPIO_MODE_INPUT;  /*推挽式复用*/ 
        GPIO_InitStruct.Pin=GPIO_PIN_10;            
        GPIO_InitStruct.Pull=GPIO_PULLUP;            /*空闲是上拉高电平*/
        //GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;   /*速度不用管*/
        HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
    
        
        HAL_NVIC_SetPriority(USART1_IRQn, 2 , 2 );
        HAL_NVIC_EnableIRQ(USART1_IRQn);
    }

}
/*串口中断服务函数*/
void USART1_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart1_handeler); /*这个会清除中断标志,失能,并且进入 */
    HAL_UART_Receive_IT(&uart1_handeler, g_rx_buffer,1);/*再调用一次*/
}
/*串口数据接收完成回调函数*/
void HAL_USART_RxCpltCallback(USART_HandleTypeDef *husart)
{
    g_uart1_rx_flag=1;

}


 

HAL库轮询方式

#include "bsp_uart.h"

/*全局变量,句柄在哪都用,也就是总结构体*/ 
UART_HandleTypeDef uart1;

void Ul_Init(uint32_t bandrate)
{
    uart1.Instance=USART1;
    uart1.Init.BaudRate=bandrate;
    uart1.Init.WordLength=UART_WORDLENGTH_8B;
    uart1.Init.StopBits=UART_STOPBITS_1;        //一个停止位
    uart1.Init.Parity=UART_PARITY_NONE;            //无奇偶校验位
    uart1.Init.HwFlowCtl=UART_HWCONTROL_NONE;   //无硬件流控
    uart1.Init.Mode=UART_MODE_TX_RX;            //收发模式
    HAL_UART_Init(&uart1);
    /* Init the low level hardware : GPIO, CLOCK 
     HAL_UART_MspInit(huart); HAL_UART_Init(&uart1);会自动调用回调函数
    */
    
    
    
}
/*回调函数*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef GPIO_Initure;
    if(huart->Instance==USART1)
    {
        
        __HAL_RCC_GPIOA_CLK_ENABLE();            //使能GPIOA时钟
        __HAL_RCC_USART1_CLK_ENABLE();            //使能USART1时钟
    
        GPIO_Initure.Pin=GPIO_PIN_9;            //PA9
        GPIO_Initure.Mode=GPIO_MODE_AF_PP;        //复用推挽输出
        GPIO_Initure.Pull=GPIO_PULLUP;            //上拉
        GPIO_Initure.Speed=GPIO_SPEED_FAST;        //高速
        //必须是这样操作
        GPIO_Initure.Alternate=GPIO_AF7_USART1;    //复用为USART1
        
        HAL_GPIO_Init(GPIOA,&GPIO_Initure);           //初始化PA9

        GPIO_Initure.Pin=GPIO_PIN_10;            //PA10
        HAL_GPIO_Init(GPIOA,&GPIO_Initure);           //初始化PA10
    }

}

#define RX_SIZE    200
uint8_t buff[256];
int main(void){
    HAL_Init();
    RccClock_Init();
    U1_Init(921600);
    while(1){
        switch(HAL_UART_Receive(&uart1,buff,RX_SIZE,200)){
            case HAL_OK:     
                                HAL_UART_Transmit(&uart1,buff,RX_SIZE,200);
                                break;
            case HAL_TIMEOUT:    

                                 if(uart1.RxXferCount != (RX_SIZE - 1)){
                                 HAL_UART_Transmit(&uart1,buff,(RX_SIZE - 1 - uart1.RxXferCount),200);
                                }else{
                                    HAL_Delay(1);
                                }
                                break;
        }
        
    }
        
}

接收函数

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) 

typedef enum
{
  HAL_OK       = 0x00U,
  HAL_ERROR    = 0x01U,
  HAL_BUSY     = 0x02U,
  HAL_TIMEOUT  = 0x03U
} HAL_StatusTypeDef;

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint16_t *tmp;
  uint32_t tickstart = 0U;

  /* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return  HAL_ERROR; //表示没有收到,返回错误
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;

    /* Init tickstart for timeout managment */
    tickstart = HAL_GetTick();

    huart->RxXferSize = Size; //接收的容量大小
    huart->RxXferCount = Size; //计数

    /* Check the remain data to be received */
    while (huart->RxXferCount > 0U)
    {
      huart->RxXferCount--;
      if (huart->Init.WordLength == UART_WORDLENGTH_9B)
      {
        if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
        {
          return HAL_TIMEOUT;//超时
        }
        tmp = (uint16_t *) pData;
        if (huart->Init.Parity == UART_PARITY_NONE)
        {
          *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
          pData += 2U;
        }
        else
        {
          *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
          pData += 1U;
        }

      }
      else
      {
        if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
        {
          return HAL_TIMEOUT;
        }
        if (huart->Init.Parity == UART_PARITY_NONE)
        {
          *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
        }
        else
        {
          *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
        }

      }
    }

    /* At end of Rx process, restore huart->RxState to Ready */
    huart->RxState = HAL_UART_STATE_READY;

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    return HAL_OK;//OK
  }
  else
  {
    return HAL_BUSY;//繁忙
  }
}

你可能感兴趣的:(网络)