接上篇:STM32超低功耗平台上的RTOS应用--PDF课件
根据培训的视频讲解,继续学习FreeRTOS,编译成功后来简单分析一下工程和代码。
这里使用的工程师STM32L4HAL库自带的例程,实现了一个简单的FreeRTOS的低功耗功能。
工程的主函数文件main.c内容如下,注释中做了简单的分析。
- /**
- ******************************************************************************
- * @file FreeRTOS\FreeRTOS_LowPower\Src\main.c
- * @author MCD Application Team
- * @brief Main program body
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
- * All rights reserved.</center></h2>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted, provided that the following conditions are met:
- *
- * 1. Redistribution of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of other
- * contributors to this software may be used to endorse or promote products
- * derived from this software without specific written permission.
- * 4. This software, including modifications and/or derivative works of this
- * software, must execute solely and exclusively on microcontroller or
- * microprocessor devices manufactured by or for STMicroelectronics.
- * 5. Redistribution and use of this software other than as permitted under
- * this license is void and will automatically terminate your rights under
- * this license.
- *
- * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
- * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
- * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- ******************************************************************************
- */
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "cmsis_os.h"
- /* Private typedef -----------------------------------------------------------*/
- /* Private define ------------------------------------------------------------*/
- /* Private macro -------------------------------------------------------------*/
- #define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
- #define QUEUE_SIZE (uint32_t) 1 //消息队列大小
- /* Private variables ---------------------------------------------------------*/
- osMessageQId osQueue; //消息队列句柄
- /* The number of items the queue can hold. This is 1 as the Rx task will
- remove items as they are added so the Tx task should always find the queue
- empty. */
- #define QUEUE_LENGTH (1) //消息队列的长度
- /* The rate at which the Tx task sends to the queue. */
- #define TX_DELAY (500) //发送消息队列任务的延时长度
- /* The value that is sent from the Tx task to the Rx task on the queue. */
- #define QUEUED_VALUE (100) //发送消息队列的值
- /* The length of time the LED will remain on for. It is on just long enough
- to be able to see with the human eye so as not to distort the power readings too
- much. */
- #define LED_TOGGLE_DELAY (20) //LED灯的翻转延时
- //私有函数声明
- /* Private function prototypes -----------------------------------------------*/
- static void QueueReceiveThread(const void *argument); //队列接收线程
- static void QueueSendThread(const void *argument); //队列发送线程
- static void GPIO_ConfigAN(void); //GPIO配置
- void SystemClock_Config(void); //系统时钟配置
- /* Private functions ---------------------------------------------------------*/
- /**
- * @brief Main program.
- * @param None
- * @retval None
- */
- int main(void) //主函数
- {
- /* STM32L4xx HAL library initialization:
- - Configure the Flash prefetch
- - Systick timer is configured by default as source of time base, but user
- can eventually implement his proper time base source (a general purpose
- timer for example or other time source), keeping in mind that Time base
- duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
- handled in milliseconds basis.
- - Set NVIC Group Priority to 4
- - Low Level Initialization
- */
- HAL_Init(); //初始化HAL库
- /* Configure the System clock to 80 MHz */
- SystemClock_Config(); //系统时钟配置
- /* Configure GPIO's to AN to reduce power consumption */
- GPIO_ConfigAN(); //配置GPIO到模拟模式以降低功耗
- /* Initialize LED */
- BSP_LED_Init(LED1);//初始化开发板的LED1
- /* Create the queue used by the two threads */
- osMessageQDef(osqueue, QUEUE_LENGTH, uint16_t);
- osQueue = osMessageCreate(osMessageQ(osqueue), NULL);//创建队列
- /* Note the Tx has a lower priority than the Rx when the threads are
- spawned. */
- osThreadDef(RxThread, QueueReceiveThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
- osThreadCreate(osThread(RxThread), NULL); //创建接收队列线程(任务)
- osThreadDef(TxThread, QueueSendThread, osPriorityBelowNormal, 0, configMINIMAL_STACK_SIZE);
- osThreadCreate(osThread(TxThread), NULL); //创建发送队列线程(任务)
- /* Start scheduler */
- osKernelStart(); //开启任务调取器
- /* We should never get here as control is now taken by the scheduler */
- for (;;);
- }
- /**
- * @brief Message Queue Producer Thread.
- * @param argument: Not used
- * @retval None
- */
- static void QueueSendThread(const void *argument) //发送消息队列线程
- {
- for (;;)
- {
- /* Place this thread into the blocked state until it is time to run again.
- The kernel will place the MCU into the Retention low power sleep state
- when the idle thread next runs. */
- osDelay(TX_DELAY); //延时
- /* Send to the queue - causing the queue receive thread to flash its LED.
- It should not be necessary to block on the queue send because the Rx
- thread will already have removed the last queued item. */
- osMessagePut(osQueue, (uint32_t)QUEUED_VALUE, 0); //发送消息队列
- }
- }
- /**
- * @brief Message Queue Consumer Thread.
- * @param argument: Not used
- * @retval None
- */
- static void QueueReceiveThread(const void *argument) //接收消息队列线程
- {
- osEvent event;
- for (;;)
- {
- /* Wait until something arrives in the queue. */
- event = osMessageGet(osQueue, osWaitForever); //获取消息队列,死等
- /* To get here something must have arrived, but is it the expected
- value? If it is, turn the LED on for a short while. */
- if (event.status == osEventMessage)
- {
- if (event.value.v == QUEUED_VALUE) //如果获得消息队列,并且消息值正确
- {
- BSP_LED_On(LED1);
- osDelay(LED_TOGGLE_DELAY); //闪烁LED1
- BSP_LED_Off(LED1);
- }
- }
- }
- }
- /**
- * @brief Pre Sleep Processing
- * @param ulExpectedIdleTime: Expected time in idle state
- * @retval None
- */
- void PreSleepProcessing(uint32_t * ulExpectedIdleTime) //进入睡眠模式前的处理函数
- {
- /* Called by the kernel before it places the MCU into a sleep mode because
- configPRE_SLEEP_PROCESSING() is #defined to PreSleepProcessing().
- NOTE: Additional actions can be taken here to get the power consumption
- even lower. For example, peripherals can be turned off here, and then back
- on again in the post sleep processing function. For maximum power saving
- ensure all unused pins are in their lowest power state. */
- /*
- (*ulExpectedIdleTime) is set to 0 to indicate that PreSleepProcessing contains
- its own wait for interrupt or wait for event instruction and so the kernel vPortSuppressTicksAndSleep
- function does not need to execute the wfi instruction
- */
- *ulExpectedIdleTime = 0;
-
- /*Enter to sleep Mode using the HAL function HAL_PWR_EnterSLEEPMode with WFI instruction*/
- HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); //调用HAL库函数进入睡眠模式
- }
- /**
- * @brief Post Sleep Processing
- * @param ulExpectedIdleTime: Not used
- * @retval None
- */
- void PostSleepProcessing(uint32_t * ulExpectedIdleTime)//睡眠模式唤醒后处理函数
- {
- /* Called by the kernel when the MCU exits a sleep mode because
- configPOST_SLEEP_PROCESSING is #defined to PostSleepProcessing(). */
- /* Avoid compiler warnings about the unused parameter. */
- (void) ulExpectedIdleTime;
- }
- /**
- * @brief Configure all GPIO's to AN to reduce the power consumption
- * @param None
- * @retval None
- */
- static void GPIO_ConfigAN(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- /* Configure all GPIO as analog to reduce current consumption on non used IOs */
- /* Enable GPIOs clock */
- __HAL_RCC_GPIOA_CLK_ENABLE();
- __HAL_RCC_GPIOB_CLK_ENABLE();
- __HAL_RCC_GPIOC_CLK_ENABLE();
- __HAL_RCC_GPIOD_CLK_ENABLE();
- __HAL_RCC_GPIOE_CLK_ENABLE();
- __HAL_RCC_GPIOF_CLK_ENABLE();
- __HAL_RCC_GPIOG_CLK_ENABLE();
- __HAL_RCC_GPIOH_CLK_ENABLE();
- __HAL_RCC_GPIOI_CLK_ENABLE();
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Pin = GPIO_PIN_All;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
- HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
- /* Disable GPIOs clock */
- __HAL_RCC_GPIOA_CLK_DISABLE();
- __HAL_RCC_GPIOC_CLK_DISABLE();
- __HAL_RCC_GPIOC_CLK_DISABLE();
- __HAL_RCC_GPIOD_CLK_DISABLE();
- __HAL_RCC_GPIOE_CLK_DISABLE();
- __HAL_RCC_GPIOF_CLK_DISABLE();
- __HAL_RCC_GPIOG_CLK_DISABLE();
- __HAL_RCC_GPIOH_CLK_DISABLE();
- __HAL_RCC_GPIOI_CLK_DISABLE();
- }
- /**
- * @brief System Clock Configuration
- * The system Clock is configured as follows :
- * System Clock source = PLL (MSI)
- * SYSCLK(Hz) = 80000000
- * HCLK(Hz) = 80000000
- * AHB Prescaler = 1
- * APB1 Prescaler = 1
- * APB2 Prescaler = 1
- * MSI Frequency(Hz) = 4000000
- * PLL_M = 1
- * PLL_N = 40
- * PLL_R = 2
- * PLL_P = 7
- * PLL_Q = 4
- * Flash Latency(WS) = 4
- * @param None
- * @retval None
- */
- void SystemClock_Config(void)
- {
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- /* MSI is enabled after System reset, activate PLL with MSI as source */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
- RCC_OscInitStruct.MSIState = RCC_MSI_ON;
- RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
- RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
- RCC_OscInitStruct.PLL.PLLM = 1;
- RCC_OscInitStruct.PLL.PLLN = 40;
- RCC_OscInitStruct.PLL.PLLR = 2;
- RCC_OscInitStruct.PLL.PLLP = 7;
- RCC_OscInitStruct.PLL.PLLQ = 4;
- if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- /* Initialization Error */
- while(1);
- }
-
- /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
- clocks dividers */
- RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | 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_4) != HAL_OK)
- {
- /* Initialization Error */
- while(1);
- }
- }
- #ifdef USE_FULL_ASSERT
- /**
- * @brief Reports the name of the source file and the source line number
- * where the assert_param error has occurred.
- * @param file: pointer to the source file name
- * @param line: assert_param error line source number
- * @retval None
- */
- void assert_failed(char *file, uint32_t line)
- {
- /* User can add his own implementation to report the file name and line number,
- ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
- /* Infinite loop */
- while (1)
- {}
- }
- #endif
- /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
下载到STM32L469ZE Nucleo开发板后,就可以看到闪烁的LED灯了,证明FreeRTOS已经跑起来了。
|