Structure of front and rear table
--------------------------------------------------------------------------------------------------------------- ----------------------
Development environment: AVR Studio 4.19 + avr-toolchain-installer-3.4.1.1195-win32.win32.x86
Chip Model: ATMEGA16
Chip Frequency: 8MHz
--------------------------------------------------------------------------------------------------------------- ----------------------
I. Overview 1, front and rear reception: Used to process input and output, generally in the interruption
Backstage: Used to deal with logical judgment, task calculation, etc., generally referred to
CPUProcessing
Events: Use events to communicate with each other between the front and back tables to inform the occurrence and end of events, also known as message management
Event/Message management is the core of the pre-background.
For event/message management, refer to this article (
application of message mechanism in software design): http://www.xuebuyuan.com/1777265.html
--------------------------------------------------------------------------------------------------------------- ----------------------
2, before the running process of the background The following example contains three parts: [key input, IR input, digital tube output] + [Event Management] + [numerical calculation and storage]
In this example, the timer 0 will be used
OCF0Interrupt timing Detection button and refresh the digital tube, using timer 1
ICP1Interrupts the receiving infrared signal.
If the interrupt is monitored when the key 1 is pressed, the "event _ Key 1 Press" is set to 1, indicating that this event occurred, otherwise 0.
If an infrared code 2 is received in the interrupt, the "event _ Receive Infrared 2" is set to 1, indicating that this event occurred, otherwise 0.
The remaining events are generated in the same way, and all events are saved in the event queue for
CPUReal-time queries.
These events do not directly invoke the corresponding task
API, but just set the message flag.
To this, the front desk interrupted the end of the task, no longer participate in subsequent operations.
In the background,
CPUWill cycle through the message queue, if found "event _ Key 1 Press" flag is 1, the dispatch
API"Task _ Show 001" to execute.
At the same time, if the background
CPUAfter processing the numerical calculation, and not directly to the foreground of the digital tube display, but set the "event _ Calculate End" Flag is 1, and then this ends.
CPUMonitoring the "event _ Calculation End" Flag is 1 o'clock, the digital tube is dispatched
API"Task _ Update Display" To execute, modify the digital tube display data.
In the interrupt, the digital tube in real-time refresh, you can see the results of the numerical calculation.
In other words, the foreground message passes through the message queue, passing the information to
CPU。
and
CPUWith the foreground task associated with the
APITo control and transmit data to the foreground task.
The front and rear stations are isolated from each other, but you can also use Message Queuing to contact the front and rear stations.
--------------------------------------------------------------------------------------------------------------- ----------------------
3. Event/message mechanism the benefits of such a design, the various task modules are isolated from each other, forming a loose connection, the software structure is very clear.
Reduce the overall complexity of the system, that is, the system is split into a lot of small modules, they are independent of each other.
Independent modules can easily be individually modified and replaced without affecting other modules.
--------------------------------------------------------------------------------------------------------------- ----------------------
Second, the Code implementation description:
1, the following will be implemented in several steps of the above example:
The first step: the front-time interrupt scheduling module, using the timer 0-time scheduling each scheduled task, including digital tube and key scanning, and give the operation of the task
API。
The second step: the Event/message management module, as a communication module between the front and rear stations.
The third step: foreground real-time tasks, including infrared reception, and give the operation of the task
API。
Fourth step: Background numeric calculation task.
The first step: the front-desk scheduled task scheduling module Description:
1, here will establish a time-sharing scheduling module, used for time-sharing scheduling of 3 scheduled Tasks
Code:
config.hSome of the definitions used in:
#ifndef _countof#define _countof (_array) (sizeof (_array)/sizeof (_array[0]) #endif #ifndef null#define NULL 0# endif
sys.timer.cIn the Scheduler module:
#include <avr/interrupt.h> #include "drv_timer.h" #include "sys_timer.h" typedef void (*p_task_funtion) (void); typedef struct {uint8_t delay; Task delay count uint8_t period; Task run interval p_task_funtion task; Task function}t_sys_task, *pt_sys_task;//This array is used to register and manage task queue static T_sys_task sys_task_ctrl[10];static Pt_sys_task p_sys_task_ CTRL = Sys_task_ctrl;//========================================================================================= =================//initializing the System task queue////=============================================================================== ===========================void sys_task_init (void) {uint8_t index = 0; for (index = 0; index < _countof (Sys_task_ctrl); index++) {(P_sys_task_ctrl + index)->delay = 0; (P_sys_task_ctrl + index)->period = 0; (P_sys_task_ctrl + index)->task = NULL; }}// ==========================================================================================================/ /Add Task to Task queue////==========================================================================================================void Sys_task_add (uint8_t delay, uint8_t period, p_task_funtion Task) {uint8_t index = 0; for (index = 0; index < _countof (Sys_task_ctrl); index++) {if (NULL = = (P_sys_task_ctrl + index)->task) {b Reak; }} if (Index >= _countof (Sys_task_ctrl)) {return;} (P_sys_task_ctrl + index)->delay = delay; (P_sys_task_ctrl + index)->period = period-1; (P_sys_task_ctrl + index)->task = task;} ==========================================================================================================//System Tasks Timer///(1). 1MS markers///==================================================================================== with Timer0 OCF0 interrupt generation ======================void sys_timer_init (void) {///Timer 0 Initialization: CTC mode, OC0 pin not connected, 64 Prescaler drv_timer0_init (T0_WGM_CTC, Com_mo De_none, t0_clk_source_clk_64); Set initial value: Tcnt0=0, ocr0=122 drv_timer0_set_tcnt0_ocr0 (0, 122); Enable OCF0 interrupt drv_timer0_int_enable (INT_MODE_OCF, enable);} ==========================================================================================================//System Timing Interrupt cycle =1ms)///(1). Use Timer0 's CTC interrupt to schedule each task//(2). Sys_task_add delay is initialized to 0, which means that the 1th time to enter this interrupt, will perform this task///============================================================ ==============================================volatile uint8_t temp2016; Debug with ISR (timer0_comp_vect) {uint8_t index = 0; for (index = 0; index < _countof (Sys_task_ctrl); index++) {temp2016 = index; if (NULL! = (P_sys_task_ctrl + index)->task) {if (0 = = (P_sys_task_ctrl + index)->delay) {(P_sys_task_ctrl + index)->delay = (P_sys_task_ctrl + index)->period; (P_sys_task_ctrl + index)->task (); } else {(P_sys_task_ctrl + index)->delay--; } } }}
mod_led_display.cIn the Digital tube task:
==========================================================================================================//Number of LEDs The code tube displays the refresh of the data////(1). Timed refresh in System timer////================================================================================================ ==========void mod_led_display_update (void) {PORTD ^= (1 << PD0); Run time mark//extinguish current digital tube and keep 3 clock cycle off to avoid glow *p_led_display_ctrl->seg_code = Segment_code[_countof (Segment_code)-1] ; Switch to the next 1 digital tube p_led_display_ctrl->index++; if (P_led_display_ctrl->index > (_countof (Segment_index)-1)) {p_led_display_ctrl->index = 0; }//Modify the bit selection, modify the display *p_led_display_ctrl->seg_index |= segment_index[_countof (Segment_index)-1]; *p_led_display_ctrl->seg_index &= segment_index[p_led_display_ctrl->index]; *p_led_display_ctrl->seg_code = segment_code[p_led_display_ctrl->data[segment_index[p_led_display_ctrl- >index]];}
main.cInitialize 3 tasks in:
==========================================================================================================//main function ========================================================================================================== #include <avr/io.h> #include "mod_led_displayer.h" #include "sys_timer.h" #include "system.h" #include "config.h" void Mod_ test01 (void) {PORTD ^= (1 << PD1); Run time marker}void mod_test02 (void) {PORTD ^= (1 << PD2); Run time marker}//==================================================================================================== ======//main function//=============================================================================================== ===========int Main (void) {//----------------------------------------------------------------------------------- -------------------//Off Global Interrupt cli (); System initialization sys_init (); Open Global Interrupt sei (); PD[2:0] initialized to output 0 ddrd |= (1 << DDD0) | (1 << DDD1) | (1 << DDD2); PORTD &= ~ ((1 << PD0) | (1 << PD1) | (1 << PD2)); Register 3 Tasks Sys_task_add (0, 3, mod_led_display_update); Run from moment 0, run once every 3 hours (one moment is 1ms) Sys_task_add (1, 3, mod_test01); Run from moment 1, ... sys_task_add (2, 3, mod_test02); Run from time 2, ...//CPU numerical calculation mod_led_display (123456789); ------------------------------------------------------------------------------------------------------while ( 1) {} return 0;}
Operation Result: 1,
Task 1: Digital Tube Display
23456789, while
PD0Output pulses with a period of
3ms
Task 2:
PD1Pin every
3msFlip One level
Task 3:
PD2Pin every
3msFlip One level
2.
3Each task is a separate
3msBe dispatched once, but they are spaced between each other
1msis dispatched:
Task 1Time of Operation:
0, 3, 6, 9, ...
Task 2Time of Operation:
1, 4, 7, 10, ...
Task 3Time of Operation:
2, 5, 8, one, ...
The scheduling time for 3 tasks is as follows:
In other words, the same
Ms, only 1 tasks are scheduled to run, which guarantees
1msThere is very little time to run the foreground task, and the remaining time is given to
CPUTo do background tasks.
The oscilloscope output is as follows:
CH1Is
PD0The output,
CH2Is
PD1The output,
PD1Lag
PD0 1ms。
This means
Task 2Lag
Task 1 1msAfter being dispatched, the period is
3ms, stating that 2 tasks are every
3msBe dispatched once.
CH1Is
PD0The output,
CH2Is
PD2The output,
PD2Lag
PD0 2ms。
This means
Task 3Lag
Task 1 2msAfter being dispatched, i.e.,
Task 3Lag
Task 2 1msAfter being dispatched.
The cycle of task scheduling is consistent with the expected
3ms。
This enables scheduled scheduling tasks and supports
TenTasks, you can set the time at which each task is scheduled to run.
Two or more tasks can be scheduled at the same time, or they can be dispatched several times apart.
For
more time-consuming tasks, it should be placed separately in 1 hours to dispatch.
Test task time is used below
PD0A rough measurement of the time spent on a digital tube refresh task
Code:
mod_led_display.cChanges in the digital tube task in
PD0As follows:
==========================================================================================================//Number of LEDs The code tube displays the refresh of the data////(1). Timed refresh in System timer////================================================================================================ ==========void mod_led_display_update (void) {PORTD |= (1 << PD0); Run time mark//extinguish current digital tube and keep 3 clock cycle off to avoid glow *p_led_display_ctrl->seg_code = Segment_code[_countof (Segment_code)-1] ; Switch to the next 1 digital tube p_led_display_ctrl->index++; if (P_led_display_ctrl->index > (_countof (Segment_index)-1)) {p_led_display_ctrl->index = 0; }//Modify the bit selection, modify the display *p_led_display_ctrl->seg_index |= segment_index[_countof (Segment_index)-1]; *p_led_display_ctrl->seg_index &= segment_index[p_led_display_ctrl->index]; *p_led_display_ctrl->seg_code = segment_code[p_led_display_ctrl->data[segment_index[p_led_display_ctrl- >index]]]; PORTD &= ~ (1 << PD0); Run time Tag}
When Task 1 starts
PD0At high level, after Task 1 is finished
PD0is low, i.e.,
PD0The high-level time is the time that task 1 consumes.
This time does not include the time to enter and exit the task function, so the real time will be slightly longer, but not much worse.
The oscilloscope output is as follows:
High-level time is
8.12usIn
8MHzEach instruction below is
0.125us, so here's probably the execution.
theInstructions.
While
8.12usRelative to
1ms, it was extremely short, and only accounted for the
8.2%Time, so there's
91.8%The free time can be given to
CPUTo handle background tasks.
--------------------------------------------------------------------------------------------------------------- ----------------------
Step two: Message management module
--------------------------------------------------------------------------------------------------------------- ----------------------
Step three: Foreground real-time task (infrared reception)
--------------------------------------------------------------------------------------------------------------- ----------------------
Fourth step: Background numeric calculation task 0
0
000
a005-software architecture-front and rear structure