A Brief Discussion on the Application Program Architecture of Single Chip Microcomputer

Publisher:nu23Latest update time:2016-03-29 Source: eefocusKeywords:MCU Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
       Everyone is familiar with MCU programs, but not many people actually use or consider architecture. With the increasing number of program development, I think architecture is very necessary. I posted a thread not long ago to discuss " How to structure your MCU program " with everyone, and found that not many people actually use architecture, and there are basically no books on this topic.

       After some exploration and experimentation, I concluded that there are three general application architectures:

1. Simple foreground and background sequential execution of the program. This type of writing is the method used by most people. There is no need to think about the specific architecture of the program. You can directly write the application program through the execution sequence.

2. Time slice polling method, this method is between sequential execution and operating system.

3. Operating system, this method should be the highest level of application programming.

Let’s talk about the advantages, disadvantages and application scope of these three methods respectively. . . . . . . . . . . . .

1. Sequential execution method:

 

      This method is a good method when the application is relatively simple and the real-time and parallel requirements are not too high. The program design is simple and the ideas are relatively clear. However, when the application is more complex, if there is no complete flowchart, it may be difficult for others to understand the running status of the program. Moreover, as the program functions increase, the brains of the engineers who write the application programs also begin to be confused. This is not conducive to upgrade maintenance, nor is it conducive to code optimization. I wrote a few more complex applications and used this method at the beginning. Although I was able to realize the functions in the end, my thinking was always in a state of confusion. As a result, the program has never satisfied me.

 

      This method is adopted by most people, and the education we receive is basically based on this method. For us MCU engineers who have basically not learned data structure and program architecture, it is undoubtedly difficult to make a big improvement in application design, which also makes it difficult for applications written by different engineers to benefit and learn from each other.

 

 

      I suggest that if you like to use this method, if you want to write a more complex application, you must first clear your mind and design a complete flowchart before writing the program, otherwise the consequences will be serious. Of course, if the program itself is very simple, this method is still a very necessary choice.

 

Let's write a sequential execution program model to compare it with the following two methods:

Code:


int main(void)

    uint8 keyValue;

 

   InitSys();                  // Initialization

 

    while (1)
    {
        TaskDisplayClock();
        keyValue = TaskKeySan();
        switch (keyValue)
       {
            case x: TaskDispStatus(); break;
            ...
            default: break;
        }
    }
}

2. Time Slice Polling Method

 

      The time slice polling method is mentioned in many books, and it often appears together with the operating system, that is, it is often used in the operating system. However, the time slice polling method we are going to talk about here is not hung under the operating system, but used in the foreground and background programs. This is also the method that this post will explain and introduce in detail.

 

      Although there are many books that introduce the time slice polling method, most of them are not systematic and just mention the concept. Below I will introduce my own mode in detail and refer to other people's code to build a time slice polling architecture program. I think it will be of some reference to beginners.

 

      I remember that I posted a post not long ago titled " The problem of multiplexing a timer ". Due to time constraints, I did not explain in detail how to achieve multiplexing of a timer. Here we first introduce the multiplexing function of the timer. . .

 

Use 1 timer, which can be any timer. No special instructions are given here. Assuming there are 3 tasks, we should do the following:

 

1. Initialize the timer. Here we assume that the timer interrupt is 1ms (of course you can change it to 10ms. This is the same as the operating system. If the interrupt is too frequent, the efficiency will be low. If the interrupt is too long, the real-time performance will be poor).

 

2. Define a value:

 

Copy content to clipboard
Code:

#define TASK_NUM   (3)                   //  The number of tasks defined here is 3, indicating that three tasks will use this timer for timing.

 

uint16 TaskCount[TASK_NUM]           //  Here are three variables defined for three tasks to store timing values

uint8  TaskMark[TASK_NUM];              //  Also corresponds to three flag bits, 0 means the time has not arrived, 1 means the scheduled time has arrived.

3. Add in the timer interrupt service function:

Copy content to clipboard
Code:

void TimerInterrupt(void)
{
    uint8 i;

    for (i=0; i     {
        if (TaskCount[i])
        {
              TaskCount[i]--;
              if (TaskCount[i] == 0)
              {
                    TaskMark[i] = 0x01;
              }
        }
   }
}

 

Code explanation: The timer interrupt service function judges one by one in the interrupt. If the timer value is 0, it means that the timer is not used or the timer has completed the timing and no processing is required. Otherwise, the timer is reduced by one. When it reaches zero, the corresponding flag value is 1, indicating that the timer value of this task has expired.

 

4. In our application, add the following code where the application timing is required. Let’s take Task 1 as an example:

Copy content to clipboard
Code:

TaskCount[0] = 20;        // Delay 20ms

TaskMark[0]   = 0x00;     // Start the timer for this task

At this point, we only need to determine whether TaskMark[0] is 0x01 in the task  . Add other tasks in the same way, and the multiplexing problem of a timer has been solved. Friends who need it can try it, the effect is good. . . . . . . . . . . . .

 

Through the above multiplexing of a timer, we can see that while waiting for a timing to arrive, we can loop to judge the flag bit and execute other functions at the same time.

 

Loop judgment flag:

So we can think about it, if the loop judges the flag bit, is it the same as the sequential execution program introduced above? A large loop, but this delay is more accurate than the ordinary for loop, and can achieve precise delay.

 

Execute other functions:

So if we execute other functions when a function is delayed, making full use of CPU time, isn't it similar to the operating system? However, the task management and switching of the operating system is very complicated. Next, we will use this method to build a new application.

 

The architecture of the time slice polling method:

 

1. Design a structure:

 

Copy content to clipboard
Code:

//Task structure
typedef struct _TASK_COMPONENTS
{
   uint8 Run;                 //Program run flag: 0-not running, 1 running
   uint8 Timer;              //Timer
   uint8 ItvTime;               //Task running interval
   void (*TaskHook)(void);     //Task function to run
} TASK_COMPONENTS;        //Task definition

 

The design of this structure is very important. It uses 4 parameters and the comments are very detailed, so I will not describe it here.

 

2. The task running mark is displayed. This function is equivalent to the interrupt service function. This function needs to be called in the interrupt service function of the timer. It is separated here for easy transplantation and understanding.

 

Copy content to clipboard
Code:


void TaskRemarks(void)
{
    uint8 i;

   for (i=0; i        // Process task time one by one
   {
         if (TaskComps[i].Timer)          // The time is not 0
       {
           TaskComps[i].Timer--;         // Subtract one beatif
           (TaskComps[i].Timer == 0)       // The time is subtracted
            {
                TaskComps[i].Timer = TaskComps[i].ItvTime;       // Restore the timer value and start again next time
                TaskComps[i].Run = 1;           // The task can run
           }
       }
  }
}

 

Please compare this function carefully to see if it is the same as the timed multiplexing function above.

 

3. Task processing

 

Copy content to clipboard
Code:


void TaskProcess(void)
{
    uint8 i;

   for (i=0; i         // Process task time one by one
   {
        if (TaskComps[i].Run)           // Time is not 0
       {
            TaskComps[i].TaskHook();         // Run task
            TaskComps[i].Run = 0;          // Clear flag to 0
       }
    
}

 

This function is used to determine when to execute a task and implement task management operations. The user only needs to call this function in the main() function and does not need to call and process task functions separately.

 

At this point, the architecture of a time-slice polling application has been built. Do you think it is very simple? This architecture only requires two functions and a structure. For application purposes, an enumeration variable will be created below.

 

Now I will talk about how to apply it. Suppose we have three tasks: clock display, key scanning, and working status display.

 

1. Define a structure variable like the one defined above

Copy content to clipboard
Code:


static TASK_COMPONENTS TaskComps[] =
{
   {0, 60, 60, TaskDisplayClock},            // Display clock
   {0, 20, 20, TaskKeySan},               // Key scan
   {0, 30, 30, TaskDispStatus},            // Display work status

    // Add your tasks here. . . .

};

 

When defining variables, we have initialized the values. The initialization of these values ​​is very important and is related to the specific execution time priority, etc. You need to master this yourself.

 

① The general meaning is that we have three tasks, and the following clock display is executed every 1s. Because the minimum unit of our clock is 1s, it is enough to display it once after the second changes.

② Since the key will jitter when it is pressed, and we know that the jitter of a general key is about 20ms, then we usually extend it by 20ms in the sequential execution function. Here we scan once every 20ms, which is a very good result. It achieves the purpose of de-jittering and will not miss the key input.

③ In order to display other prompts and work interfaces after pressing the key, we design it to display once every 30ms. If you think the response is slow, you can make these values ​​smaller. The names behind are the corresponding function names. You must write these functions and the same three tasks in the application.

 

2. Task List

Copy content to clipboard
Code:

//Task list
typedef enum _TASK_LIST
{
   TAST_DISP_CLOCK,            //Display clock
   TAST_KEY_SAN,             //Key scan
   TASK_DISP_WS,             //Work status display
    //Add your task here...
    TASKS_MAX                                           //The total number of scheduled tasks available for allocation
} TASK_LIST;

 

Take a closer look. The purpose of defining this task list here is actually the value of the parameter TASKS_MAX. Other values ​​have no specific meaning and are only for the purpose of clearly showing the relationship between the surface tasks.

 

3. Write task functions

 

Copy content to clipboard
Code:


void TaskDisplayClock(void)
{

 

}


void TaskKeySan(void)
{


}


void TaskDispStatus(void)
{


}

 

// Add other tasks here. . . . . . . .

 

Now you can write tasks according to your needs.

 

4. Main function

 

Copy content to clipboard
Code:


int main(void)

   InitSys();                  // Initialization

   while (1)
   {
       TaskProcess();             // Task processing
   }
}

 

At this point, the architecture of our time slice polling application is complete. You only need to add your own task function where we prompt. Isn't it very simple? Does it have a bit of operating system feeling in it?

 

      Why not try it and see if the tasks do not interfere with each other? What about running in parallel? Of course, it is also important to note that when transferring data between tasks, global variables need to be used. In addition, it is also necessary to pay attention to the division of tasks and the execution time of tasks. When writing tasks, try to complete the tasks as soon as possible. . . . . . . . . .


 

3. Operating System

 

      The operating system itself is a relatively complex thing. We don't need to understand the management and execution of tasks. However, transplantation alone is very difficult. Although some people say "If you have used the system, you will not use the foreground and background programs again", there are not many people who can really use the operating system, not only because the use of the system itself is very complicated, but also because you need to buy a license (UCOS is no exception if it is used commercially).

 

      I don't want to introduce the operating system itself in detail here, because it cannot be explained in just one or two sentences. The following is a model for writing applications under UCOS. You can compare the advantages and disadvantages of these three methods.

 

Copy content to clipboard
Code:


int main(void)

   OSInit();                // Initialize uCOS-II

   OSTaskCreate((void (*) (void *)) TaskStart,        // Task pointer
               (void   *) 0,            // Parameters
               (OS_STK *) &TaskStartStk[TASK_START_STK_SIZE - 1], // Stack pointer
               (INT8U   ) TASK_START_PRIO);        // Task priority

   OSStart();                                       // Start multitasking environment
                                       
   return (0); 
}

 

Copy content to clipboard
Code:


void TaskStart(void* p_arg)
{
    OS_CPU_SysTickInit();                                       // Initialize the SysTick.

#if (OS_TASK_STAT_EN > 0)
   OSStatInit();                                               // This thing can measure CPU usage
#endif

 OSTaskCreate((void (*) (void *)) TaskLed,      // Task 1
               (void   *) 0,               // Without parameters
               (OS_STK *) &TaskLedStk[TASK_LED_STK_SIZE - 1],  // Stack pointer
               (INT8U   ) TASK_LED_PRIO);         // Priority

 // Here the task of creating your
               
    while (1)
    {
        OSTimeDlyHMSM(0, 0, 0, 100);
    }
}

 

It is not difficult to see that the time slice polling method has great advantages, that is, it has the advantages of the sequential execution method and the operating system. The structure is clear, simple, and very easy to understand. . . . . . . . . .


Keywords:MCU Reference address:A Brief Discussion on the Application Program Architecture of Single Chip Microcomputer

Previous article:UART serial communication between two microcontrollers
Next article:Principle and Application of DS18B20

Recommended ReadingLatest update time:2024-11-23 10:59

Design of household heating bathing device based on single chip microcomputer control
introduction A key technology of the household electric hot water circulation heating bath introduced in this article is the nano material far infrared thin film electric heating tube. More than 20 materials such as tin chloride, silver carbonate, ferric chloride, aluminum oxide, zinc oxide, t
[Microcontroller]
Application of Digital Signal Controller in Automobile Design
  Introduction   Automotive design has come a long way from the purely mechanical systems of the past to modern cars that often contain up to 100 microprocessors. The only electronics in traditional cars were entertainment features, most commonly the car radio. Electronic control of automotive functions did not becom
[Microcontroller]
Application of Digital Signal Controller in Automobile Design
How to send data on PIC microcontroller
The program runs on the p18f458 PIC microcontroller to implement a self-test mode in which the send buffer 0 sends data to the receive buffer 0, where the reception adopts an interrupt mode. //Send using query method #include "p18f458.h" intCAN_FLAG; //define flag register //**************Initialization subroutine**
[Microcontroller]
How to send data on PIC microcontroller
LCD touch screen control design based on single chip microcomputer
1 Introduction Embedded touch screen device is a human-computer interaction device. Generally, the touch screen is installed on the LCD screen. The microprocessor is used to control the touch screen and the LCD screen, so that the touch screen can control the LCD screen. It is convenient and intuitive, replacin
[Microcontroller]
LCD touch screen control design based on single chip microcomputer
PIC MCU 4x4 keyboard scanning program
//The program does not perform key debounce, nor does it consider the situation where multiple keys are pressed at the same time.  //The lowest two digits of the digital tube display the corresponding key (e.g., if S10 is pressed, 10 is displayed; if S25 is pressed, 25 is displayed)  //FF is displayed when no key is p
[Microcontroller]
Detailed explanation of the pin functions of the 80C51 microcontroller
    MCS-51 is a standard 40-pin dual in-line integrated circuit chip. Please refer to the figure for the pin arrangement.     P0.0 ~ P0.7: P0 port 8-bit bidirectional port line.     P1.0 ~ P1.7: P1 port 8-bit bidirectional port line.     P2.0 ~ P2.7: P2 port 8-bit bidirectional port line.     P3.0 ~ P3.7:
[Microcontroller]
Detailed explanation of the pin functions of the 80C51 microcontroller
10BitDA Sine Signal Generator Controlled by Single Chip Microcomputer
Function: MCU drives 10BitDA sine signal generator Measuring String Waveforms with an Oscilloscope The program C language source code is as follows: #include reg52.h //Interface definition sbit DA = P1^1; sbit CK = P1^2; sbit CS = P1^4; //10-bit sampling, 1024-point sine lookup table data unsigned int code s
[Microcontroller]
10BitDA Sine Signal Generator Controlled by Single Chip Microcomputer
Single chip heart rate meter source code
Place your index finger gently on the sensor, and you will see the LED indicator light flashing with your heartbeat. The arteries in the fingertips of the human body are well developed. When the arteries contract and relax periodically with the heart, the blood volume in the blood vessels will also change. The abo
[Microcontroller]
Single chip heart rate meter source code
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号