Как использовать OSTmrCreate таймера для реализации планирования задач с MicroC/OS II?
Я получил 2 задания в MicroC для моделирования движущегося транспортного средства: ControlTask и VehicleTask. Теперь мой проект должен заменить переключатель контекста таймером для более подходящего времени, но я не могу этого сделать. Программа теперь использует утверждение OSTimeDlyHMSM
для реализации периодов, но вместо них следует использовать мягкие таймеры с семафорами. OSTmr Создать в Справочном руководстве по C/OS-II (глава 16). Я могу запустить таймер, затем я могу поместить его в стартовый код, но мне не удается вызвать таймер и выполнить синхронизацию между двумя задачами, заменяя OSTimeDlyHMSM
с таймером. Я думаю, что мое решение становится более сложным, чем необходимое, потому что я не могу понять все детали, например, зачем мне семафоры и почему это более точно с таймером, чем встроенный OSTimeDlyHMSM
, Мое полное усилие на данный момент выглядит следующим образом:
#include <stdio.h>
#include "system.h"
#include "includes.h"
#include "altera_avalon_pio_regs.h"
#include "sys/alt_irq.h"
#include "sys/alt_alarm.h"
#define DEBUG 1
#define HW_TIMER_PERIOD 100 /* 100ms */
/* Button Patterns */
#define GAS_PEDAL_FLAG 0x08
#define BRAKE_PEDAL_FLAG 0x04
#define CRUISE_CONTROL_FLAG 0x02
/* Switch Patterns */
#define TOP_GEAR_FLAG 0x00000002
#define ENGINE_FLAG 0x00000001
/* LED Patterns */
#define LED_RED_0 0x00000001 // Engine
#define LED_RED_1 0x00000002 // Top Gear
#define LED_GREEN_0 0x0001 // Cruise Control activated
#define LED_GREEN_2 0x0002 // Cruise Control Button
#define LED_GREEN_4 0x0010 // Brake Pedal
#define LED_GREEN_6 0x0040 // Gas Pedal
/*
* Definition of Tasks
*/
#define TASK_STACKSIZE 2048
OS_STK StartTask_Stack[TASK_STACKSIZE];
OS_STK ControlTask_Stack[TASK_STACKSIZE];
OS_STK VehicleTask_Stack[TASK_STACKSIZE];
// Task Priorities
#define STARTTASK_PRIO 5
#define VEHICLETASK_PRIO 10
#define CONTROLTASK_PRIO 12
// Task Periods
#define CONTROL_PERIOD 300
#define VEHICLE_PERIOD 300
/*
* Definition of Kernel Objects
*/
// Mailboxes
OS_EVENT *Mbox_Throttle;
OS_EVENT *Mbox_Velocity;
// Semaphores
OS_EVENT *aSemaphore;
// SW-Timer
OS_TMR *SWTimer;
OS_TMR *SWTimer1;
BOOLEAN status;
/*
* Types
*/
enum active {on, off};
enum active gas_pedal = off;
enum active brake_pedal = off;
enum active top_gear = off;
enum active engine = off;
enum active cruise_control = off;
/*
* Global variables
*/
int delay; // Delay of HW-timer
INT16U led_green = 0; // Green LEDs
INT32U led_red = 0; // Red LEDs
int sharedMemory=1;
void ContextSwitch()
{
printf("ContextSwitch!\n");
sharedMemory=sharedMemory*-1;
}
int buttons_pressed(void)
{
return ~IORD_ALTERA_AVALON_PIO_DATA(DE2_PIO_KEYS4_BASE);
}
int switches_pressed(void)
{
return IORD_ALTERA_AVALON_PIO_DATA(DE2_PIO_TOGGLES18_BASE);
}
/*
* ISR for HW Timer
*/
alt_u32 alarm_handler(void* context)
{
OSTmrSignal(); /* Signals a 'tick' to the SW timers */
return delay;
}
static int b2sLUT[] = {0x40, //0
0x79, //1
0x24, //2
0x30, //3
0x19, //4
0x12, //5
0x02, //6
0x78, //7
0x00, //8
0x18, //9
0x3F, //-
};
/*
* convert int to seven segment display format
*/
int int2seven(int inval){
return b2sLUT[inval];
}
/*
* output current velocity on the seven segement display
*/
void show_velocity_on_sevenseg(INT8S velocity){
int tmp = velocity;
int out;
INT8U out_high = 0;
INT8U out_low = 0;
INT8U out_sign = 0;
if(velocity < 0){
out_sign = int2seven(10);
tmp *= -1;
}else{
out_sign = int2seven(0);
}
out_high = int2seven(tmp / 10);
out_low = int2seven(tmp - (tmp/10) * 10);
out = int2seven(0) << 21 |
out_sign << 14 |
out_high << 7 |
out_low;
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_HEX_LOW28_BASE,out);
}
/*
* shows the target velocity on the seven segment display (HEX5, HEX4)
* when the cruise control is activated (0 otherwise)
*/
void show_target_velocity(INT8U target_vel)
{
}
/*
* indicates the position of the vehicle on the track with the four leftmost red LEDs
* LEDR17: [0m, 400m)
* LEDR16: [400m, 800m)
* LEDR15: [800m, 1200m)
* LEDR14: [1200m, 1600m)
* LEDR13: [1600m, 2000m)
* LEDR12: [2000m, 2400m]
*/
void show_position(INT16U position)
{
}
/*
* The function 'adjust_position()' adjusts the position depending on the
* acceleration and velocity.
*/
INT16U adjust_position(INT16U position, INT16S velocity,
INT8S acceleration, INT16U time_interval)
{
INT16S new_position = position + velocity * time_interval / 1000
+ acceleration / 2 * (time_interval / 1000) * (time_interval / 1000);
if (new_position > 24000) {
new_position -= 24000;
} else if (new_position < 0){
new_position += 24000;
}
show_position(new_position);
return new_position;
}
/*
* The function 'adjust_velocity()' adjusts the velocity depending on the
* acceleration.
*/
INT16S adjust_velocity(INT16S velocity, INT8S acceleration,
enum active brake_pedal, INT16U time_interval)
{
INT16S new_velocity;
INT8U brake_retardation = 200;
if (brake_pedal == off)
new_velocity = velocity + (float) (acceleration * time_interval) / 1000.0;
else {
if (brake_retardation * time_interval / 1000 > velocity)
new_velocity = 0;
else
new_velocity = velocity - brake_retardation * time_interval / 1000;
}
return new_velocity;
}
/*
* The task 'VehicleTask' updates the current velocity of the vehicle
*/
void VehicleTask(void* pdata)
{
INT8U err;
void* msg;
INT8U* throttle;
INT8S acceleration; /* Value between 40 and -20 (4.0 m/s^2 and -2.0 m/s^2) */
INT8S retardation; /* Value between 20 and -10 (2.0 m/s^2 and -1.0 m/s^2) */
INT16U position = 0; /* Value between 0 and 20000 (0.0 m and 2000.0 m) */
INT16S velocity = 0; /* Value between -200 and 700 (-20.0 m/s amd 70.0 m/s) */
INT16S wind_factor; /* Value between -10 and 20 (2.0 m/s^2 and -1.0 m/s^2) */
printf("Vehicle task created!\n");
while(1)
{
err = OSMboxPost(Mbox_Velocity, (void *) &velocity);
OSTimeDlyHMSM(0,0,0,VEHICLE_PERIOD);
/* Non-blocking read of mailbox:
- message in mailbox: update throttle
- no message: use old throttle
*/
msg = OSMboxPend(Mbox_Throttle, 1, &err);
if (err == OS_NO_ERR)
throttle = (INT8U*) msg;
/* Retardation : Factor of Terrain and Wind Resistance */
if (velocity > 0)
wind_factor = velocity * velocity / 10000 + 1;
else
wind_factor = (-1) * velocity * velocity / 10000 + 1;
if (position < 4000)
retardation = wind_factor; // even ground
else if (position < 8000)
retardation = wind_factor + 15; // traveling uphill
else if (position < 12000)
retardation = wind_factor + 25; // traveling steep uphill
else if (position < 16000)
retardation = wind_factor; // even ground
else if (position < 20000)
retardation = wind_factor - 10; //traveling downhill
else
retardation = wind_factor - 5 ; // traveling steep downhill
acceleration = *throttle / 2 - retardation;
position = adjust_position(position, velocity, acceleration, 300);
velocity = adjust_velocity(velocity, acceleration, brake_pedal, 300);
printf("Position: %dm\n", position / 10);
printf("Velocity: %4.1fm/s\n", velocity /10.0);
printf("Throttle: %dV\n", *throttle / 10);
show_velocity_on_sevenseg((INT8S) (velocity / 10));
}
}
/*
* The task 'ControlTask' is the main task of the application. It reacts
* on sensors and generates responses.
*/
void ControlTask(void* pdata)
{
INT8U err;
INT8U throttle = 40; /* Value between 0 and 80, which is interpreted as between 0.0V and 8.0V */
void* msg;
INT16S* current_velocity;
printf("Control Task created!\n");
while(1)
{
msg = OSMboxPend(Mbox_Velocity, 0, &err);
current_velocity = (INT16S*) msg;
err = OSMboxPost(Mbox_Throttle, (void *) &throttle);
OSTimeDlyHMSM(0,0,0, CONTROL_PERIOD);
}
}
/*
* The task 'StartTask' creates all other tasks kernel objects and
* deletes itself afterwards.
*/
void StartTask(void* pdata)
{
INT8U err;
void* context;
static alt_alarm alarm; /* Is needed for timer ISR function */
/* Base resolution for SW timer : HW_TIMER_PERIOD ms */
delay = alt_ticks_per_second() * HW_TIMER_PERIOD / 1000;
printf("delay in ticks %d\n", delay);
/*
* Create Hardware Timer with a period of 'delay'
*/
if (alt_alarm_start (&alarm,
delay,
alarm_handler,
context) < 0)
{
printf("No system clock available!n");
}
/*
* Create and start Software Timer
*/
SWTimer = OSTmrCreate(0,
CONTROL_PERIOD/(4*OS_TMR_CFG_TICKS_PER_SEC),
OS_TMR_OPT_PERIODIC,
ContextSwitch,
NULL,
NULL,
&err);
if (err == OS_ERR_NONE) {
/* Timer was created but NOT started */
printf("SWTimer was created but NOT started \n");
}
status = OSTmrStart(SWTimer,
&err);
if (err == OS_ERR_NONE) {
/* Timer was started */
printf("SWTimer was started!\n");
}
/*
* Creation of Kernel Objects
*/
// Mailboxes
Mbox_Throttle = OSMboxCreate((void*) 0); /* Empty Mailbox - Throttle */
Mbox_Velocity = OSMboxCreate((void*) 0); /* Empty Mailbox - Velocity */
/*
* Create statistics task
*/
OSStatInit();
/*
* Creating Tasks in the system
*/
err = OSTaskCreateExt(
ControlTask, // Pointer to task code
NULL, // Pointer to argument that is
// passed to task
&ControlTask_Stack[TASK_STACKSIZE-1], // Pointer to top
// of task stack
CONTROLTASK_PRIO,
CONTROLTASK_PRIO,
(void *)&ControlTask_Stack[0],
TASK_STACKSIZE,
(void *) 0,
OS_TASK_OPT_STK_CHK);
err = OSTaskCreateExt(
VehicleTask, // Pointer to task code
NULL, // Pointer to argument that is
// passed to task
&VehicleTask_Stack[TASK_STACKSIZE-1], // Pointer to top
// of task stack
VEHICLETASK_PRIO,
VEHICLETASK_PRIO,
(void *)&VehicleTask_Stack[0],
TASK_STACKSIZE,
(void *) 0,
OS_TASK_OPT_STK_CHK);
printf("All Tasks and Kernel Objects generated!\n");
/* Task deletes itself */
OSTaskDel(OS_PRIO_SELF);
}
/*
*
* The function 'main' creates only a single task 'StartTask' and starts
* the OS. All other tasks are started from the task 'StartTask'.
*
*/
int main(void) {
printf("Cruise Control\n");
aSemaphore = OSSemCreate(1); // binary semaphore (1 key)
OSTaskCreateExt(
StartTask, // Pointer to task code
NULL, // Pointer to argument that is
// passed to task
(void *)&StartTask_Stack[TASK_STACKSIZE-1], // Pointer to top
// of task stack
STARTTASK_PRIO,
STARTTASK_PRIO,
(void *)&StartTask_Stack[0],
TASK_STACKSIZE,
(void *) 0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
OSStart();
return 0;
}
Запуск вышеуказанной программы обратного вызова contextswitch
выполняется, но это еще не решает проблему использования таймеров вместо встроенного выхода и как применять его с семафорами.
Cruise Control
delay in ticks 100
SWTimer was created but NOT started
SWTimer was started!
All Tasks and Kernel Objects generated!
Vehicle task created!
Control Task created!
ContextSwitch!
Position: 0m
Velocity: 0.5m/s
Throttle: 4V
ContextSwitch!
Position: 0m
Velocity: 1.0m/s
Throttle: 4V
Position: 0m
Velocity: 1.5m/s
Throttle: 4V
ContextSwitch!
Position: 0m
Velocity: 2.0m/s
Throttle: 4V
ContextSwitch!
Position: 1m
Velocity: 2.5m/s
Throttle: 4V
ContextSwitch!
Position: 2m
Velocity: 3.0m/s
Throttle: 4V
ContextSwitch!
Обновление 141001 15:57 CET
2 семафора + 2 таймера кажутся хорошим улучшением. Я надеюсь, что это можно проверить или проверить...
#include <stdio.h>
#include "system.h"
#include "includes.h"
#include "altera_avalon_pio_regs.h"
#include "sys/alt_irq.h"
#include "sys/alt_alarm.h"
#define DEBUG 1
#define HW_TIMER_PERIOD 100 /* 100ms */
/* Button Patterns */
#define GAS_PEDAL_FLAG 0x08
#define BRAKE_PEDAL_FLAG 0x04
#define CRUISE_CONTROL_FLAG 0x02
/* Switch Patterns */
#define TOP_GEAR_FLAG 0x00000002
#define ENGINE_FLAG 0x00000001
/* LED Patterns */
#define LED_RED_0 0x00000001 // Engine
#define LED_RED_1 0x00000002 // Top Gear
#define LED_GREEN_0 0x0001 // Cruise Control activated
#define LED_GREEN_2 0x0002 // Cruise Control Button
#define LED_GREEN_4 0x0010 // Brake Pedal
#define LED_GREEN_6 0x0040 // Gas Pedal
/*
* Definition of Tasks
*/
#define TASK_STACKSIZE 2048
OS_STK StartTask_Stack[TASK_STACKSIZE];
OS_STK ControlTask_Stack[TASK_STACKSIZE];
OS_STK VehicleTask_Stack[TASK_STACKSIZE];
// Task Priorities
#define STARTTASK_PRIO 5
#define VEHICLETASK_PRIO 10
#define CONTROLTASK_PRIO 12
// Task Periods
#define CONTROL_PERIOD 300
#define VEHICLE_PERIOD 300
/*
* Definition of Kernel Objects
*/
// Mailboxes
OS_EVENT *Mbox_Throttle;
OS_EVENT *Mbox_Velocity;
// Semaphores
OS_EVENT *aSemaphore;
OS_EVENT *aSemaphore2;
// SW-Timer
OS_TMR *SWTimer;
OS_TMR *SWTimer1;
BOOLEAN status;
/*
* Types
*/
enum active {on, off};
enum active gas_pedal = off;
enum active brake_pedal = off;
enum active top_gear = off;
enum active engine = off;
enum active cruise_control = off;
/*
* Global variables
*/
int delay; // Delay of HW-timer
INT16U led_green = 0; // Green LEDs
INT32U led_red = 0; // Red LEDs
int sharedMemory=1;
void TimerCallback(params)
{
// Post to the semaphore to signal that it's time to run the task.
OSSemPost(aSemaphore); // Releasing the key
}
void ContextSwitch()
{
printf("ContextSwitch!\n");
sharedMemory=sharedMemory*-1;
}
int buttons_pressed(void)
{
return ~IORD_ALTERA_AVALON_PIO_DATA(DE2_PIO_KEYS4_BASE);
}
int switches_pressed(void)
{
return IORD_ALTERA_AVALON_PIO_DATA(DE2_PIO_TOGGLES18_BASE);
}
/*
* ISR for HW Timer
*/
alt_u32 alarm_handler(void* context)
{
OSTmrSignal(); /* Signals a 'tick' to the SW timers */
return delay;
}
void release()
{
printf("release key!\n");
//OSSemPost(aSemaphore); // Releasing the key
OSSemPost(aSemaphore2); // Releasing the key
printf("released key!\n");
}
void release2()
{
printf("release2!\n");
OSSemPost(aSemaphore2); // Releasing the key
printf("release2!\n");
}
static int b2sLUT[] = {0x40, //0
0x79, //1
0x24, //2
0x30, //3
0x19, //4
0x12, //5
0x02, //6
0x78, //7
0x00, //8
0x18, //9
0x3F, //-
};
/*
* convert int to seven segment display format
*/
int int2seven(int inval){
return b2sLUT[inval];
}
/*
* output current velocity on the seven segement display
*/
void show_velocity_on_sevenseg(INT8S velocity){
int tmp = velocity;
int out;
INT8U out_high = 0;
INT8U out_low = 0;
INT8U out_sign = 0;
if(velocity < 0){
out_sign = int2seven(10);
tmp *= -1;
}else{
out_sign = int2seven(0);
}
out_high = int2seven(tmp / 10);
out_low = int2seven(tmp - (tmp/10) * 10);
out = int2seven(0) << 21 |
out_sign << 14 |
out_high << 7 |
out_low;
IOWR_ALTERA_AVALON_PIO_DATA(DE2_PIO_HEX_LOW28_BASE,out);
}
/*
* shows the target velocity on the seven segment display (HEX5, HEX4)
* when the cruise control is activated (0 otherwise)
*/
void show_target_velocity(INT8U target_vel)
{
}
/*
* indicates the position of the vehicle on the track with the four leftmost red LEDs
* LEDR17: [0m, 400m)
* LEDR16: [400m, 800m)
* LEDR15: [800m, 1200m)
* LEDR14: [1200m, 1600m)
* LEDR13: [1600m, 2000m)
* LEDR12: [2000m, 2400m]
*/
void show_position(INT16U position)
{
}
/*
* The function 'adjust_position()' adjusts the position depending on the
* acceleration and velocity.
*/
INT16U adjust_position(INT16U position, INT16S velocity,
INT8S acceleration, INT16U time_interval)
{
INT16S new_position = position + velocity * time_interval / 1000
+ acceleration / 2 * (time_interval / 1000) * (time_interval / 1000);
if (new_position > 24000) {
new_position -= 24000;
} else if (new_position < 0){
new_position += 24000;
}
show_position(new_position);
return new_position;
}
/*
* The function 'adjust_velocity()' adjusts the velocity depending on the
* acceleration.
*/
INT16S adjust_velocity(INT16S velocity, INT8S acceleration,
enum active brake_pedal, INT16U time_interval)
{
INT16S new_velocity;
INT8U brake_retardation = 200;
if (brake_pedal == off)
new_velocity = velocity + (float) (acceleration * time_interval) / 1000.0;
else {
if (brake_retardation * time_interval / 1000 > velocity)
new_velocity = 0;
else
new_velocity = velocity - brake_retardation * time_interval / 1000;
}
return new_velocity;
}
/*
* The task 'VehicleTask' updates the current velocity of the vehicle
*/
void VehicleTask(void* pdata)
{
INT8U err;
void* msg;
INT8U* throttle;
INT8S acceleration; /* Value between 40 and -20 (4.0 m/s^2 and -2.0 m/s^2) */
INT8S retardation; /* Value between 20 and -10 (2.0 m/s^2 and -1.0 m/s^2) */
INT16U position = 0; /* Value between 0 and 20000 (0.0 m and 2000.0 m) */
INT16S velocity = 0; /* Value between -200 and 700 (-20.0 m/s amd 70.0 m/s) */
INT16S wind_factor; /* Value between -10 and 20 (2.0 m/s^2 and -1.0 m/s^2) */
printf("Vehicle task created!\n");
// Create a semaphore to represent the "it's time to run" event.
// Initialize the semaphore count to zero because it's not time
// to run yet.
// Create a periodic software timer which calls TimerCallback()
// when it expires.
/*
* Create and start Software Timer
*/
SWTimer1 = OSTmrCreate(0,
CONTROL_PERIOD/(4*OS_TMR_CFG_TICKS_PER_SEC),
OS_TMR_OPT_PERIODIC,
TimerCallback,
NULL,
NULL,
&err);
if (err == OS_ERR_NONE) {
/* Timer was created but NOT started */
printf("SWTimer1 was created but NOT started \n");
}
status = OSTmrStart(SWTimer1,
&err);
if (err == OS_ERR_NONE) {
/* Timer was started */
printf("SWTimer1 was started!\n");
}
while(1)
{
OSSemPend(aSemaphore, 0, &err); // Trying to access the key
err = OSMboxPost(Mbox_Velocity, (void *) &velocity);
//OSTimeDlyHMSM(0,0,0,VEHICLE_PERIOD);
/* Non-blocking read of mailbox:
- message in mailbox: update throttle
- no message: use old throttle
*/
msg = OSMboxPend(Mbox_Throttle, 1, &err);
if (err == OS_NO_ERR)
throttle = (INT8U*) msg;
/* Retardation : Factor of Terrain and Wind Resistance */
if (velocity > 0)
wind_factor = velocity * velocity / 10000 + 1;
else
wind_factor = (-1) * velocity * velocity / 10000 + 1;
if (position < 4000)
retardation = wind_factor; // even ground
else if (position < 8000)
retardation = wind_factor + 15; // traveling uphill
else if (position < 12000)
retardation = wind_factor + 25; // traveling steep uphill
else if (position < 16000)
retardation = wind_factor; // even ground
else if (position < 20000)
retardation = wind_factor - 10; //traveling downhill
else
retardation = wind_factor - 5 ; // traveling steep downhill
acceleration = *throttle / 2 - retardation;
position = adjust_position(position, velocity, acceleration, 300);
velocity = adjust_velocity(velocity, acceleration, brake_pedal, 300);
printf("Position: %dm\n", position / 10);
printf("Velocity: %4.1fm/s\n", velocity /10.0);
printf("Throttle: %dV\n", *throttle / 10);
show_velocity_on_sevenseg((INT8S) (velocity / 10));
//OSSemPost(aSemaphore); // Releasing the key
}
}
/*
* The task 'ControlTask' is the main task of the application. It reacts
* on sensors and generates responses.
*/
void ControlTask(void* pdata)
{
INT8U err;
INT8U throttle = 40; /* Value between 0 and 80, which is interpreted as between 0.0V and 8.0V */
void* msg;
INT16S* current_velocity;
printf("Control Task created!\n");
while(1)
{
OSSemPend(aSemaphore2, 0, &err); // Trying to access the key
msg = OSMboxPend(Mbox_Velocity, 0, &err);
current_velocity = (INT16S*) msg;
printf("Control Task!\n");
err = OSMboxPost(Mbox_Throttle, (void *) &throttle);
//OSSemPost(aSemaphore2); // Releasing the key
//OSTimeDlyHMSM(0,0,0, CONTROL_PERIOD);
}
}
/*
* The task 'StartTask' creates all other tasks kernel objects and
* deletes itself afterwards.
*/
void StartTask(void* pdata)
{
INT8U err;
void* context;
static alt_alarm alarm; /* Is needed for timer ISR function */
/* Base resolution for SW timer : HW_TIMER_PERIOD ms */
delay = alt_ticks_per_second() * HW_TIMER_PERIOD / 1000;
printf("delay in ticks %d\n", delay);
/*
* Create Hardware Timer with a period of 'delay'
*/
if (alt_alarm_start (&alarm,
delay,
alarm_handler,
context) < 0)
{
printf("No system clock available!n");
}
/*
* Create and start Software Timer
*/
SWTimer = OSTmrCreate(0,
CONTROL_PERIOD/(4*OS_TMR_CFG_TICKS_PER_SEC),
OS_TMR_OPT_PERIODIC,
release,
NULL,
NULL,
&err);
if (err == OS_ERR_NONE) {
/* Timer was created but NOT started */
printf("SWTimer was created but NOT started \n");
}
status = OSTmrStart(SWTimer,
&err);
if (err == OS_ERR_NONE) {
/* Timer was started */
printf("SWTimer was started!\n");
}
/*
* Creation of Kernel Objects
*/
// Mailboxes
Mbox_Throttle = OSMboxCreate((void*) 0); /* Empty Mailbox - Throttle */
Mbox_Velocity = OSMboxCreate((void*) 0); /* Empty Mailbox - Velocity */
/*
* Create statistics task
*/
OSStatInit();
/*
* Creating Tasks in the system
*/
err = OSTaskCreateExt(
ControlTask, // Pointer to task code
NULL, // Pointer to argument that is
// passed to task
&ControlTask_Stack[TASK_STACKSIZE-1], // Pointer to top
// of task stack
CONTROLTASK_PRIO,
CONTROLTASK_PRIO,
(void *)&ControlTask_Stack[0],
TASK_STACKSIZE,
(void *) 0,
OS_TASK_OPT_STK_CHK);
err = OSTaskCreateExt(
VehicleTask, // Pointer to task code
NULL, // Pointer to argument that is
// passed to task
&VehicleTask_Stack[TASK_STACKSIZE-1], // Pointer to top
// of task stack
VEHICLETASK_PRIO,
VEHICLETASK_PRIO,
(void *)&VehicleTask_Stack[0],
TASK_STACKSIZE,
(void *) 0,
OS_TASK_OPT_STK_CHK);
printf("All Tasks and Kernel Objects generated!\n");
/* Task deletes itself */
OSTaskDel(OS_PRIO_SELF);
}
/*
*
* The function 'main' creates only a single task 'StartTask' and starts
* the OS. All other tasks are started from the task 'StartTask'.
*
*/
int main(void) {
printf("Cruise Control 2014\n");
aSemaphore = OSSemCreate(1); // binary semaphore (1 key)
aSemaphore2 = OSSemCreate(0); // binary semaphore (1 key)
OSTaskCreateExt(
StartTask, // Pointer to task code
NULL, // Pointer to argument that is
// passed to task
(void *)&StartTask_Stack[TASK_STACKSIZE-1], // Pointer to top
// of task stack
STARTTASK_PRIO,
STARTTASK_PRIO,
(void *)&StartTask_Stack[0],
TASK_STACKSIZE,
(void *) 0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
OSStart();
return 0;
}
Выход:
Cruise Control 2014
delay in ticks 100
SWTimer was created but NOT started
SWTimer was started!
All Tasks and Kernel Objects generated!
Vehicle task created!
SWTimer1 was created but NOT started
SWTimer1 was started!
Control Task created!
Position: 0m
Velocity: 0.4m/s
Throttle: 3V
release key!
released key!
Control Task!
Position: 0m
Velocity: 0.9m/s
Throttle: 4V
release key!
released key!
Control Task!
Position: 0m
Velocity: 1.4m/s
3 ответа
У меня сложилось впечатление, что у вас есть две задачи, которые вы хотите выполнять через регулярные промежутки времени. И вы хотите сделать это с помощью программного таймера и семафора. Если это правильно, то вы можете сделать это следующим образом.
Каждое задание будет использовать свой семафор и таймер. Семафор может использоваться как сигнал о том, что событие произошло. В этом случае используйте семафор, чтобы указать, что таймер истек и пора запустить задачу. Настройте программный таймер на периодическое истечение срока действия и вызов функции обратного вызова. Функция обратного вызова должна публиковать в семафор. Задача должна быть отложена на семафор в пределах цикла while. Таким образом, задача выполняет одну итерацию цикла каждый раз, когда истекает таймер.
Вот некоторый псевдо-код:
void TimerCallback(params)
{
// Post to the semaphore to signal that it's time to run the task.
}
void TaskFunction(void)
{
// Create a semaphore to represent the "it's time to run" event.
// Initialize the semaphore count to zero because it's not time
// to run yet.
// Create a periodic software timer which calls TimerCallback()
// when it expires.
while(1)
{
// Wait until it's time to run by pending on the semaphore.
// Do task specific stuff.
}
}
Периодический характер этой реализации программного таймера и семафора является более точным, чем использование OSTimeDlyHMSM(). Причина в том, что период программного таймера работает независимо от времени выполнения задачи. Но период OSTimeDlyHMSM () является дополнением ко времени выполнения задачи. И время выполнения задачи может варьироваться от одной итерации к следующей, если ей предшествуют другие задачи или прерывания. Поэтому использование OSTimeDlyHMSM () не очень точный способ получить периодическое событие.
Проблема с обоими OSTimeDlyHMSM()
а также OSTimeDly()
для периодических процессов это то, что они не учитывают время обработки остальной части потока. Например в:
// Task loop
for(;;)
{
OSTimeDly( 100 ) ;
doStuffHere() ;
}
Вы можете ожидать doStuffHere()
запускать каждые 100 тиков, что будет, если doStuffHere()
само по себе занимает больше времени 1 тика. Например, оно может содержать задержку или блокировать какое-либо другое событие.
// Task loop
for(;;)
{
OSTimeDly( 100 ) ;
doStuffHere() ;
}
С помощью таймера это можно преодолеть:
// Note this is illustrative and not uC/OS-II code
timer_handle = createTimer( 100, PERIODIC ) ;
// Task loop
for(;;)
{
waitForTimer( timer_handle ) ;
doStuffHere() ;
}
Вот, doStuffHere()
для того, чтобы цикл был точно периодическим, требуется всего менее 100 тиков - это намного лучше, чем один тик.
Все, что сказал, если вы можете гарантировать, что это doStuffHere()
займет меньше одного тика - даже если приоритет имеет более высокий приоритет, задержка будет намного проще.
Другое преимущество использования таймера, с другой стороны, состоит в том, что блокировка задержки может реагировать только на истечение задержки, в то время как блокировка задачи на семафоре может реагировать на любое событие, которое дает семафор, поэтому может быть вызвано для выполнения на несколько событий, включая таймер. Аналогично для других механизмов IPC, таких как очереди или флаги событий.
OSTimeDlyHMSM()
Этот вызов позволяет вам указать время задержки в тиках, часах, минутах, секундах и миллисекундах. Это означает, что вы не позволяете заданию работать, пока не истечет нужное время. Даже когда все другие задачи сработали и / или процессор "свободен", ваша задача не будет продолжать свою работу до тех пор, пока не истечет нужное время, в вашем случае секунды или что-то еще. Если вам действительно нужно событие, которое должно произойти после такого "большого" времени, его стоит, конечно, использовать.
Однако подход к использованию таймера не следует путать с семафорами. Последние используются против нарушения данных и для защиты общего ресурса или критических разделов кода от многократного повторного входа.
Не углубляясь в ваш код, я бы предложил попробовать организовать вашу систему с OSTimeDly()
где возможно. Что касается семафоров, используйте их, когда возникает ситуация, когда несколько задач могут асинхронно вызывать одну и ту же функцию или получать доступ к одному и тому же ресурсу, такому как память, регистры, шины данных или любое другое оборудование.