stm32CubeMX HAL庫中延時的幾種方式解析
阿新 • • 發佈:2018-12-29
/* * 本檔案包括四種延時方式: * 1. 原來的HAL庫函式HAL_Delay() 2. 採用定時器2設定延時函式 3. 採用系統滴答中斷方式的ms和us級延時 * 4. 採用系統滴答非中斷方式的ms和us級延時(在一次計數值範圍內的延時) */ /* Includes ------------------------------------------------------------------*/ #include "stm32l1xx_hal.h" #include "tim.h" #include "usart.h" #include "gpio.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ volatile unsigned int timenum; //必須要加volatile!!! volatile unsigned long time_delay; // 延時時間,注意定義為全域性變數 /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); void Error_Handler(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ HAL_StatusTypeDef delay_10us(uint32_t num); void delay_us(volatile unsigned long nms); void delay_ms(volatile unsigned long nms); void delay_ms2(int32_t nms); /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart2 , (uint8_t *)&ch, 1, 0xFFFF); return ch; } /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM2_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ /*##-1- Start the TIM Base generation in interrupt mode ####################*/ //HAL_TIM_Base_Start_IT(&htim2); printf("Testing timer2\n"); HAL_Delay(1000); printf("Testing timer2\n"); HAL_Delay(1000); printf("Testing timer2\n"); HAL_Delay(1000); printf("Testing timer2\n"); HAL_Delay(1000); printf("Testing timer2\n"); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET); delay_ms2(500); printf("12\n"); //HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET); //delay_us(500000); } /* USER CODE END 3 */ } /** System Clock Configuration */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12; RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV3; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_1); HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); //注意這裡HAL庫重灌了系統計數器的值,使美1ms中斷一次!! HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* USER CODE BEGIN 4 */ /** * @brief Period elapsed callback in non blocking mode * @param htim: TIM handle * @retval None */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定時器2中斷處理函式 { if (htim->Instance == htim2.Instance) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8); if(timenum) { timenum--; //printf("%d\n", timenum); } } } HAL_StatusTypeDef delay_10us(uint32_t num)//自定義的定時器2實現延時的函式 { timenum = num; HAL_TIM_Base_Start_IT(&htim2); while(timenum) //為什麼一直停在這個迴圈中???3-2-1-2-3……怎麼會這樣!!!--volatile! ; HAL_TIM_Base_Stop_IT(&htim2); return HAL_OK; } //SysTick實現延時n_ms,中斷方式 void delay_ms(volatile unsigned long nms) { //SYSTICK分頻--1ms的系統時鐘中斷 if (SysTick_Config(HAL_RCC_GetHCLKFreq()/1000)) { while (1); } time_delay=nms;//讀取定時時間 while(time_delay); SysTick->CTRL=0x00; //關閉計數器 SysTick->VAL =0X00; //清空計數器 } //SysTick實現延時n_us,中斷方式 void delay_us(volatile unsigned long nus) { //SYSTICK分頻--1us的系統時鐘中斷 if (SysTick_Config(HAL_RCC_GetHCLKFreq()/1000000)) { while (1); } time_delay=nus;//讀取定時時間 while(time_delay); SysTick->CTRL=0x00; //關閉計數器 SysTick->VAL =0X00; //清空計數器 } //SysTick實現延時中斷方式的中斷處理函式 //在中斷中將time_delay遞減。實現延時 //void SysTick_Handler(void) //{ // if(time_delay) // time_delay--; //} //void HAL_SYSTICK_Callback(void)//原cube HAL庫中中斷處理回撥函式重寫 //{ // if(time_delay) // time_delay--; //} //void HAL_IncTick(void)//原cube HAL庫中,重寫 //{ // if(time_delay) // time_delay--; //} /********************************* 優選的方式 ***********************************************************************/ /*一次填充系統計時器以實現非中斷延遲,受限系統計時器stmtick只有24位,所以最長計時有所限制*/ void delay_ms2(int32_t nms) { int32_t temp; SysTick->LOAD = 8000*nms; SysTick->VAL=0X00;//清空計數器 SysTick->CTRL=0X01;//使能,減到零是無動作,採用外部時鐘源 do { temp=SysTick->CTRL;//讀取當前倒計數值 }while((temp&0x01)&&(!(temp&(1<<16))));//等待時間到達 SysTick->CTRL=0x00; //關閉計數器 SysTick->VAL =0X00; //清空計數器 } /* USER CODE END 4 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ /*********************************************************************************************************************/ /*********************************************************************************************************************/ /*********************************************************************************************************************/ /*如果自寫系統時鐘中斷處理函式,需要在stml1xx_it.c中註釋掉一下函式*/ /** * @brief This function handles System tick timer. */ #if 1 void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); HAL_SYSTICK_IRQHandler(); /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ } #endif