STM32-HAL

    为了使用STM32 cubeMX工具快速完成设计,打算从StdPeriph_Lib换成HAL_Driver。初使用cubeMX,感觉就像从DOS时代迈入图形界面时代,而且对STM的所有系列有最好的支持。

STM32-HAL_第1张图片

在HAL库中:

常用功能:

HAL_Delay()  //毫秒延时,精度还是可以的。
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);//GPIO_PIN_RESET而不是RESET了。


时钟配置:

    STM32-HAL_第2张图片

     如果懂得STM32的架构,配置起来简直不能太简单,但好像有个bug就是配置为HSI时钟无法DEBUG调试。


串口中断:

通过HAL_UART_GetState(&huart1)获得当前的状态,返回的类型有:

typedef enum
{
  HAL_UART_STATE_RESET             = 0x00,    /*!< Peripheral is not initialized                      */
  HAL_UART_STATE_READY             = 0x01,    /*!< Peripheral Initialized and ready for use           */
  HAL_UART_STATE_BUSY              = 0x02,    /*!< an internal process is ongoing                     */
  HAL_UART_STATE_BUSY_TX           = 0x12,    /*!< Data Transmission process is ongoing               */
  HAL_UART_STATE_BUSY_RX           = 0x22,    /*!< Data Reception process is ongoing                  */
  HAL_UART_STATE_BUSY_TX_RX        = 0x32,    /*!< Data Transmission and Reception process is ongoing */
  HAL_UART_STATE_TIMEOUT           = 0x03,    /*!< Timeout state                                      */
  HAL_UART_STATE_ERROR             = 0x04     /*!< Error                                              */
}HAL_UART_StateTypeDef;

在中断处理函数HAL_UART_IRQHandler(UART_HandleTypeDef *huart)中,逐个获取各种状态:

    tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
    tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE); 

    ......

    如果没有错误就再进入对应的收发处理函数:

    if((tmp_flag != RESET) && (tmp_it_source != RESET))   UART_Receive_IT(huart);

    在UART_Receive_IT(UART_HandleTypeDef *huart)函数中通过调用回调函数HAL_UART_RxCpltCallback(huart)进行相关接收数据的处理, HAL_UART_RxCpltCallback(huart)一般会被我们在APP中复习定义,其中非常重要的是需要在其末尾通过再次调用HAL_UART_Receive_IT(&huart1,(uint8_t *)RxBuffer,1)完成连续的中断接收。

 

串口状态的错误类型如下:
#define HAL_UART_ERROR_NONE      ((uint32_t)0x00)    /*!< No error            */
#define HAL_UART_ERROR_PE        ((uint32_t)0x01)    /*!< Parity error        */
#define HAL_UART_ERROR_NE        ((uint32_t)0x02)    /*!< Noise error         */
#define HAL_UART_ERROR_FE        ((uint32_t)0x04)    /*!< frame error         */
#define HAL_UART_ERROR_ORE       ((uint32_t)0x08)    /*!< Overrun error       */
#define HAL_UART_ERROR_DMA       ((uint32_t)0x10)    /*!< DMA transfer error  */

ST库中,USART Flags的定义:

#define USART_FLAG_CTS                       ((uint16_t)0x0200)
#define USART_FLAG_LBD                       ((uint16_t)0x0100)
#define USART_FLAG_TXE                       ((uint16_t)0x0080)
#define USART_FLAG_TC                        ((uint16_t)0x0040)
#define USART_FLAG_RXNE                      ((uint16_t)0x0020)
#define USART_FLAG_IDLE                      ((uint16_t)0x0010)
#define USART_FLAG_ORE                       ((uint16_t)0x0008)
#define USART_FLAG_NE                        ((uint16_t)0x0004)
#define USART_FLAG_FE                        ((uint16_t)0x0002)
#define USART_FLAG_PE                        ((uint16_t)0x0001)

     STM32存在的一个广为人知的硬件BUG就是一直进入ORE状态,在ST标准库中可以通过USART_ClearFlag或者ClearITPendingBit清掉错误标记来解决。

可以使用暴力解决办法,完全复写串口中断处理函数(将原来的注释掉):

void USART1_IRQHandler(void)
{
    unsigned char code; 
    printf("TEST for RX \n");
    if(USART1->SR&(1<<5))
    {    
       code=USART1->DR;     //串口数据寄存器读取数据后会自动清理掉接收中断标记,不需要再单独处理
       printf("GET from RX:%c \n",code);
    }
}

    感觉对于STM32的诸多bug,都可以通过直接操作寄存器来解决,而且操作寄存器最麻烦的是在外设的初始化阶段,后期需要管理的不过是些SR、DR之类的了。

   tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
      huart->ErrorCode |= HAL_UART_ERROR_ORE;
      printf("usart1 error Over-Run \n");
      //__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_ORE);  //也可以在此添加清标记的代码

  }

本文最后总结:

在HAL库的main文件中,第一次调用中断以使能中断时,接收的数量即size最好设1,如果不为1你在测试中断的时候又发一个字节,很难一下子发现问题。

    if(HAL_UART_Receive_IT(&huart1,(uint8_t *)rxBuffer, size) != HAL_OK)  Error_Handler();


ADC执行:

MX_ADC1_Init();

HAL_ADCEx_Calibration_Start(&hadc1); 

HAL_ADC_Start_DMA(&hadc1, ADC_Data,5); //DMA获取

或者是轮询获取方式:

//HAL_ADC_Start(&hadc1);
//while(__HAL_ADC_GET_FLAG(&hadc1,ADC_FLAG_EOC)==RESET);

//uint16_t adc= HAL_ADC_GetValue(&hadc1);

使用CUBE配置的DMA ADC多路采样:

adc 0 value: 103089701

adc 1 value: 103155237

adc 2 value: 1574

adc 3 value: 0

adc 4 value: 0

adc 5 value: 0 

采集的数据不对,根据网上获知的他人类似经验:可能是底层函数没有将CHANNEL清零导致。如下方式可以完成多通道的采集:

  while (1)
  {

     sConfig.Channel = ADC_CHANNEL_VREFINT;
    sConfig.Rank = 1;
     sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK);
    HAL_ADC_Start(&hadc1);
     HAL_ADC_PollForConversion(&hadc1,10);
    uint16_t adc= HAL_ADC_GetValue(&hadc1);
    printf("\n VREFINT value: %-4d",adc);
    HAL_ADC_Stop(&hadc1);
   
     sConfig.Channel = ADC_CHANNEL_1;
    sConfig.Rank = 1;                     //这个一定都是设置为1,不然每次获得的数据都是Rank = 1通道的数据
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK);
    HAL_Delay(100);
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1,10);
    adc= HAL_ADC_GetValue(&hadc1);
    printf("\n adc1 value: %-4d",adc);
    HAL_ADC_Stop(&hadc1);
}


你可能感兴趣的:(STM32)