STM32 uC/OS_II practice of task scheduling process understanding and query events

Publisher:石头12345Latest update time:2016-10-06 Source: eefocusKeywords:STM32  query Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
First paste the entry function main, starting from here, from the file main.c

/*******************************************************************************
* Function Name : main
* Description : Main function, initialize the system and hardware, establish the main function and start the system
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{   
    CPU_IntDis(); // Disable CPU interrupt connection to assembly
    OSInit(); // uCOS system initialization
    BSP_Init(); // Hardware initialization
   
      
    OSTaskCreate // Establish the main task, the highest priority Another purpose of establishing this task is to use the statistical task later
            (
                 (void (*) (void *)) App_TaskStart, // Pointer to the task code
                 (void *) 0, // Pointer to the parameters passed to the task when the task starts executing
                 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1], // The top pointer of the stack allocated to the task, from (INT8U) APP_TASK_START_PRIO //The priority assigned to the task   
             );   
   
    OSTimeSet(0);
    OSStart();                            
   
    return(0);
}

 

Before starting the scheduling of uC/OS_II, we need to call the function OSInit(), which is responsible for establishing data structures such as the task control block list and the ready task list, and then initializing global variables. Then initialize the external devices needed, mainly clock initialization, interrupt nesting initialization, port initialization, and call the function BSP_Init(). uC/OS_II stipulates that at least one task has been established before the task scheduling begins, so we establish a task APP_TaskStart and assign priority and stack resources to this task. This is necessary. Then we use the OSTimeSet(0) function to initialize the system clock beats, and then call the OSStart() function to start task scheduling. The task will start executing from the highest priority among all established tasks.
Everyone still remembers that we just created an APP_TaskStart task. When the system starts task scheduling, this task is the only one registered in the system except for the default idle task with the lowest priority. So this task will run naturally. Let's first look at its related source code from the file task.c:


/*******************************************************************************
* Function Name : App_TaskStart
* Description : Main task
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void App_TaskStart(void* p_arg)
{
    (void) p_arg;

    OS_CPU_SysTickInit(); // Initialize system heartbeat
    
    #if (OS_TASK_STAT_EN > 0)
    OSStatInit(); // Statistics task initialization function                                      
    #endif

    App_TaskCreate(); // Create a new user task

    while(1)
    {
        LED4_HIGH;
        OSTimeDlyHMSM(0,0,1,0);
        LED4_LOW;
        OSTimeDlyHMSM(0,0,1,0);
    }

}

/***********************************************************************************
* Function Name : App_TaskCreate
* Description : Create user task
* Input : None
* Output : None
* Return : None
***************************************************************************/
void App_TaskCreate(void)
{
    //=========================================================================// Test task 1
    OSTaskCreateExt(
                        Task_Test1, // Pointer to the task code, that is, the task function name
                        (void *)0, // Parameters passed to the task when the task starts executing
                      (OS_STK *)&Task_Test1Stk[Task_Test1_STK_SIZE-1], // Top pointer assigned to the task stack, from top to bottom
                        Task_Test1_PRIO, // Priority assigned to the task
                        Task_Test1_PRIO, // Identifiers reserved for future versions, now the same as task priority
                        (OS_STK *)&Task_Test1Stk[0], // Pointer to the bottom of the task stack for stack verification
                        Task_Test1_STK_SIZE, // Specify the capacity of the stack for stack verification
                        (void *)0, // Pointer to the user additional data area, used to extend the task control block
                     OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR // Task options: Enable stack detection and clear the stack when creating a task
                   );
    //====================================================================// Test Task 2
    OSTaskCreateExt(
                        Task_Test2,
                        (void *)0,
                        (OS_STK *)&Task_Test2Stk[Task_Test2_STK_SIZE-1],
                        Task_Test2_PRIO,
                        Task_Test2_PRIO,
                        (OS_STK *)&Task_Test2Stk[0],
                        Task_Test2_STK_SIZE,
                        (void *)0,
                        OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR
                   );
    //==================================== ================================//Test Task 3
    OSTaskCreateExt(
                        Task_Test3,
                        (void *)0,
                        (OS_STK * )&Task_Test3Stk[Task_Test3_STK_SIZE-1],
                        Task_Test3_PRIO,
                        Task_Test3_PRIO,
                        (OS_STK *)&Task_Test3Stk[0],
                        Task_Test3_STK_SIZE,
                        (void *)0,
                        OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR
                   );
}

At the same time, the task priority and stack size information are given from the file app_cfg.h


 
//Task priority
#define APP_TASK_START_PRIO 10

#define Task_Test1_PRIO 7
#define Task_Test2_PRIO 8
#define Task_Test3_PRIO 9

//Task stack size
#define APP_TASK_START_STK_SIZE 64

#define Task_Test1_STK_SIZE 128
#define Task_Test2_STK_SIZE 128
#define Task_Test3_STK_SIZE 128
It can be seen that the priority of task APP_TaskStart is the lowest, so when creating other tasks in this task, it will be taken away by the task with a higher priority. In uC/OS_II, each task will be scheduled once after it is created. If the priority of the created task is higher, the system will execute the newly created task. If it is lower, it can only wait. So after creating Task_Test1, it will jump to execute this task. Now let's take a look at the source code of these three test tasks from the file app.c    


/*******************************************************************************
* Function Name : Task_Test1
* Description : Task 1
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Task_Test1(void* p_arg)
{
    (void) p_arg ;
    while(1)
    {
        if(KEY_WKUP == 0)
        {
            LED1_HIGH;   
        }
        else
        {
            LED1_LOW;
        }
        OSTimeDlyHMSM(0,0,0,100); // Delay to leave room for other low-priority tasks to execute
    }
}
/***********************************************************************************
* Function Name : Task_Test2
* Description : Task 2
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Task_Test2(void* p_arg)
{
    (void) p_arg ;
    while(1)
    {
        LED2_HIGH;
        OSTimeDlyHMSM(0,0,0,500);
        LED2_LOW;
        OSTimeDlyHMSM(0,0,0,500);
    }
}
/*****************************************************************************
* Function Name : Task_Test3
* Description : Task 3
* Input : None
* Output : None
* Return : None
*****************************************************************************/
void Task_Test3(void* p_arg)
{
    (void) p_arg ;
    while(1)
    {
        LED3_HIGH;
        OSTimeDlyHMSM(0,0,0,500);
        LED3_LOW;
        OSTimeDlyHMSM(0,0,0,500);
    }
}

Where were we just now? Yes, now we are starting to execute the Task_Test1 task. Obviously, this task is to detect a key. After the detection is completed, a 100ms delay function is entered. In uC/OS_II, the role of the delay function is much greater than before. When the delay function is called in a task in uC/OS_II, the task is exited from the task ready table, and then the system scheduler OS_Sched() is called once to find the highest priority task to execute again. At this time, our system has only registered two tasks, so we can only continue to execute the task APP_TaskStart. The first test task created in this function just now was robbed of the CPU occupancy right. Now come back to create the second test task Task_Test2. The priority of this second test task is also higher than that of the start task, so naturally it is robbed of the CPU occupancy right. In the second test task, you will see a delay function again, and the function must be the same. By analogy, the third test task will be much clearer. At this time, there is another problem, which is the system operation after the delay. After the test task 1 enters the delay, it will not be called by the system. Its delay variable OSTCBDly is decremented with the heartbeat of the system. If there are two tasks in the delay at the same time, as long as the delay variable in their task control block is not 0, it will be reduced by 1 in the heartbeat interrupt service function. When it is reduced to 0, the system will put the task back into the task ready list and run the system scheduling function OS_Sched() once. This mechanism ensures that the system is always running the highest priority task. In this way, the scheduling problem of the system is explained. When interrupts and semaphores are used later, they also have an impact on the execution order of the system. How they participate in the scheduling of the system will be explained later.


Just now we talked about the role of the delay function. If I ignore the yellow highlighted part in the code above, what will happen? The result is that the other three tasks cannot run, and the system will always process the task Task_Test1. If we increase the delay parameter of the yellow highlighted part to 1s, the result is not satisfactory. Although I gave the task enough running time, I have to wait for a long time every time I detect it, which greatly reduces my detection accuracy and makes the buttons extremely difficult to use. At this time, we should think about it. In a real-time embedded operating system like uC/OS_II, the most terrible thing is aimless waiting, so we try to use interrupts to process interface information. Interrupts and real-time systems complement each other.



Keywords:STM32  query Reference address:STM32 uC/OS_II practice of task scheduling process understanding and query events

Previous article:STM32 uCOS_II practice of external interrupt events and system operation process
Next article:STM32 debugging using SWD

Recommended ReadingLatest update time:2024-11-15 14:32

The influence of signal source characteristics on conversion results in STM32 ADC applications
All chips in the STM32 family have built-in successive approximation register ADC modules. The internal framework is as follows:   Each ADC conversion is first sampled and held, and then compared and output in multiple steps. The number of steps is equal to the number of ADC bits, and each ADC clock generates one d
[Microcontroller]
The influence of signal source characteristics on conversion results in STM32 ADC applications
STM32 memory usage and allocation
Heap space and stack space configuration Stack Size, generally 0X400 is enough for small projects, and we set 0X1000 for comprehensive experiments, so there is no need to set it too large by default. The value of Stack_Size is calculated according to the maximum size of local variables in your program.  Heap Size, i
[Microcontroller]
Do STM32 global variables occupy program storage space?
Whether global variables occupy the storage space of the final program, this question has actually been answered as early as when we learned C language. I vaguely remember that when I first learned C language, the book told us: Global automatic variables - stored in the read-write data segment Global static variable
[Microcontroller]
Do STM32 global variables occupy program storage space?
Understand the basics of stm32 SPI bus and programming
SPI is widely used, it is a synchronous serial bus, and of course it needs a clock signal to unify the synchronization, so that the two parties can communicate more tacitly and without much delay (dumbness). It is used in medium and low speed occasions. Where should we start learning? Here are some tips: SPI con
[Microcontroller]
Use and calculation of STM32 internal temperature sensor
Temperature (in ℃) = {(V - V) / Avg_Slope} + 25 The V in the formula is the value read at ADC_IN16. Avg_Slope is the slope of the conversion between temperature and ADC value. Imagine an XY coordinate system, where the X-axis is the ADC voltage reading, the Y-axis is the temperature, and there is a straight line bet
[Microcontroller]
STM32 uses SPI bus to operate external Flash
Standard development board: Atom STM32F103RBT6 SPI: The four lines MISO, MOSI, SCLK, CS are a high-speed, full-duplex, communication bus. Reading and writing are done at the same time. If you only want to write, just ignore the read.    If you want to read, just send a dummy byte to trigger the slave's transmission.
[Microcontroller]
stm32-led-serial-port-PWM
Because of the project needs, I learned about the GPIO, serial port, PWM, and interrupt parts of stm32. Here is a summary for us to learn together. All programs have been tested in practice and the output is correct. Paste the configuration program of GPIO, serial port, PWM (timer) as follows 1. Enable the periphe
[Microcontroller]
Stm32 TFT LCD display control study notes
Learning STM32, TFT LCD display control is a very important chapter. I encountered many difficulties in the initial learning of STM32, so I listed some important knowledge points accumulated in the study. At present, the commonly used TFT LCD internal driver chips are ILI9320 and ILI9325 series. The internal principles
[Microcontroller]
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号