以下代码是如何在c中使用microcos III创建任务的示例。我正在试图找出如何在c++中创建类似的代码。我的问题是如何实例化对象以及如何使用成员函数来表示任务。在create任务例程中,函数的地址作为参数传递。我如何在c++中做到这一点?我需要多上一节课吗?嵌入式c++新功能。
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "includes.h"
#include "protectedled.h"
#include "protectedlcd.h"
#include "pushbutton.h"
#include "lcd.h"
// Relative Task Priorities (0 = highest; 15 = idle task)
#define STARTUP_PRIO 1 // Highest priority, to launch others.
#define DEBOUNCE_PRIO 7 // Every 50 ms, in a timed loop.
#define SW1_PRIO 8 // Up to every 50 ms, when held down.
#define SW2_PRIO 12 // Up to every 150 ms, if retriggered.
#define LED6_PRIO 13 // Every 167 ms, in a timed loop.
#define LED5_PRIO 14 // Every 500 ms, in a timed loop.
// Allocate Task Stacks
#define TASK_STACK_SIZE 128
static CPU_STK g_startup_stack[TASK_STACK_SIZE];
static CPU_STK g_led5_stack[TASK_STACK_SIZE];
static CPU_STK g_led6_stack[TASK_STACK_SIZE];
static CPU_STK g_debounce_stack[TASK_STACK_SIZE];
static CPU_STK g_sw1_stack[TASK_STACK_SIZE];
static CPU_STK g_sw2_stack[TASK_STACK_SIZE];
// Allocate Task Control Blocks
static OS_TCB g_startup_tcb;
static OS_TCB g_led5_tcb;
static OS_TCB g_led6_tcb;
static OS_TCB g_debounce_tcb;
static OS_TCB g_sw1_tcb;
static OS_TCB g_sw2_tcb;
// Allocate Shared OS Objects
OS_SEM g_sw1_sem;
OS_SEM g_sw2_sem;
/*!
* @brief LED Flasher Task
*/
void
led5_task (void * p_arg)
{
OS_ERR err;
(void)p_arg; // NOTE: Silence compiler warning about unused param.
for (;;)
{
// Flash LED at 1 Hz.
protectedLED_Toggle(5);
OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
/*!
*
* @brief LED Flasher Task
*
*/
void
led6_task (void * p_arg)
{
OS_ERR err;
(void)p_arg; // NOTE: Silence compiler warning about unused param.
for (;;)
{
// Flash LED at 3 Hz.
protectedLED_Toggle(6);
OSTimeDlyHMSM(0, 0, 0, 167, OS_OPT_TIME_HMSM_STRICT, &err);
}
}
/*!
* @brief Button SW1 Catcher Task
*/
void
sw1_task (void * p_arg)
{
uint16_t sw1_counter = 0;
char p_str[LCD_CHARS_PER_LINE+1];
OS_ERR err;
(void)p_arg; // NOTE: Silence compiler warning about unused param.
// Draw the initial display.
sprintf(p_str, "SW1: % 4u", sw1_counter);
protectedDisplayLCD(LCD_LINE1, (uint8_t *) p_str);
for (;;)
{
// Wait for a signal from the button debouncer.
OSSemPend(&g_sw1_sem, 0, OS_OPT_PEND_BLOCKING, 0, &err);
// Check for errors.
assert(OS_ERR_NONE == err);
// Increment button press counter.
sw1_counter++;
// Format and display current count.
sprintf(p_str, "SW1: % 4u", sw1_counter);
protectedDisplayLCD(LCD_LINE1, (uint8_t *) p_str);
}
}
/*!
* @brief Button SW2 Catcher Task
*/
void
sw2_task (void * p_arg)
{
uint16_t sw2_counter = 0;
char p_str[LCD_CHARS_PER_LINE+1];
OS_ERR err;
(void)p_arg; // NOTE: Silence compiler warning about unused param.
// Draw the initial display.
sprintf(p_str, "SW2: % 4u", sw2_counter);
protectedDisplayLCD(LCD_LINE2, (uint8_t *) p_str);
for (;;)
{
// Wait for a signal from the button debouncer.
OSSemPend(&g_sw2_sem, 0, OS_OPT_PEND_BLOCKING, 0, &err);
// Check for errors.
assert(OS_ERR_NONE == err);
// Increment button press counter.
sw2_counter++;
// Format and display current count.
sprintf(p_str, "SW2: % 4u", sw2_counter);
protectedDisplayLCD(LCD_LINE2, (uint8_t *) p_str);
}
}
/*!
* @brief A task to create all of the other tasks and their shared objects.
*/
void
startup_task (void * p_arg)
{
OS_ERR err;
(void)p_arg; // NOTE: Silence compiler warning about unused param.
// Perform hardware initializations that should be after multitasking.
BSP_Init();
CPU_Init();
OS_CPU_TickInit();
// Initialize the reentrant LED driver.
protectedLED_Init();
// Create the LED flasher tasks.
OSTaskCreate((OS_TCB *)&g_led5_tcb,
(CPU_CHAR *)"LED5 Flasher",
(OS_TASK_PTR ) led5_task,
(void *) 0,
(OS_PRIO ) LED5_PRIO,
(CPU_STK *)&g_led5_stack[0],
(CPU_STK_SIZE) TASK_STACK_SIZE / 10u,
(CPU_STK_SIZE) TASK_STACK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT ) 0,
(OS_ERR *)&err);
assert(OS_ERR_NONE == err);
OSTaskCreate((OS_TCB *)&g_led6_tcb,
(CPU_CHAR *)"LED6 Flasher",
(OS_TASK_PTR ) led6_task,
(void *) 0,
(OS_PRIO ) LED6_PRIO,
(CPU_STK *)&g_led6_stack[0],
(CPU_STK_SIZE) TASK_STACK_SIZE / 10u,
(CPU_STK_SIZE) TASK_STACK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT ) 0,
(OS_ERR *)&err);
assert(OS_ERR_NONE == err);
// Create the semaphores signaled by the button debouncer.
OSSemCreate(&g_sw1_sem, "Switch 1", 0, &err);
assert(OS_ERR_NONE == err);
OSSemCreate(&g_sw2_sem, "Switch 2", 0, &err);
assert(OS_ERR_NONE == err);
// Create the button debouncer.
OSTaskCreate((OS_TCB *)&g_debounce_tcb,
(CPU_CHAR *)"Button Debouncer",
(OS_TASK_PTR ) debounce_task,
(void *) 0,
(OS_PRIO ) DEBOUNCE_PRIO,
(CPU_STK *)&g_debounce_stack[0],
(CPU_STK_SIZE) TASK_STACK_SIZE / 10u,
(CPU_STK_SIZE) TASK_STACK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT ) 0,
(OS_ERR *)&err);
assert(OS_ERR_NONE == err);
// Initialise the LCD driver.
protectedInitialiseLCD();
// Create the tasks to catch the button semaphores.
OSTaskCreate((OS_TCB *)&g_sw1_tcb,
(CPU_CHAR *)"Button 1 Catcher",
(OS_TASK_PTR ) sw1_task,
(void *) 0,
(OS_PRIO ) SW1_PRIO,
(CPU_STK *)&g_sw1_stack[0],
(CPU_STK_SIZE) TASK_STACK_SIZE / 10u,
(CPU_STK_SIZE) TASK_STACK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT ) 0,
(OS_ERR *)&err);
assert(OS_ERR_NONE == err);
OSTaskCreate((OS_TCB *)&g_sw2_tcb,
(CPU_CHAR *)"Button 2 Catcher",
(OS_TASK_PTR ) sw2_task,
(void *) 0,
(OS_PRIO ) SW2_PRIO,
(CPU_STK *)&g_sw2_stack[0],
(CPU_STK_SIZE) TASK_STACK_SIZE / 10u,
(CPU_STK_SIZE) TASK_STACK_SIZE,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT ) 0,
(OS_ERR *)&err);
assert(OS_ERR_NONE == err);
// Delete the startup task (or enter an infinite loop like other tasks).
OSTaskDel(NULL, &err);
// We should never get here.
assert(0);
}
/*!
* @brief The starting point for the entire C program.
*/
void
main (void)
{
OS_ERR err;
// Disable all interrupts.
CPU_IntDis();
// Initialize the operating system's internal data structures.
OSInit(&err);
assert(OS_ERR_NONE == err);
// Install application-specific OS hooks.
App_OS_SetAllHooks();
// Create the alarm task.
OSTaskCreate((OS_TCB *)&g_startup_tcb,
(CPU_CHAR *)"Startup Task",
(OS_TASK_PTR ) startup_task,
(void *) 0,
(OS_PRIO ) STARTUP_PRIO,
(CPU_STK *)&g_startup_stack[0],
(CPU_STK_SIZE) TASK_STACK_SIZE / 10u,
(CPU_STK_SIZE) TASK_STACK_SIZE ,
(OS_MSG_QTY ) 0u,
(OS_TICK ) 0u,
(void *) 0,
(OS_OPT ) 0,
(OS_ERR *)&err);
assert(OS_ERR_NONE == err);
// Start multitasking.
OSStart(&err);
// We should never get here.
assert(0);
}
如果你想把你的C代码编译成c++,只需要很少的改动。如果它被编译为c++,那么它就是c++。也就是说,这并不能从OOP中获益。在面向对象的意义上,任务可以被视为对象,因此您将拥有一个抽象任务类,可以从中创建任务。
我在过去创建了一个完整的类库来抽象RTOS原语(任务,信号量,互斥锁,计时器等),并将其移植到许多RTOS -不是uC/OS-III,但足以让人相信它几乎可以移植到任何RTOS。任务入口点必须是一个普通函数或静态成员函数——解决方案是使用一个静态成员函数作为所有任务的入口点,但它接受一个指向任务对象的指针,并调用它的入口点,该入口点是一个虚成员。
在我的例子中,静态入口点是这样定义的(非常精简-只是基本的):
void cTask::taskRoot( void* arg )
{
cTask* instance = reinterpret_cast<cTask*>(arg) ;
// Call task entry point
instance->threadMain() ;
}
其中cTask::threadMain()
为纯虚函数。一个具体的任务类必须继承cTask
,实现threadMain()
。
要启动任务,有一个定义的成员函数,再次大幅削减到只是基本的,我省略了实际的任务创建,因为我的代码不是uC/OS-III特定的)。
bool cTask::spawn( int taskpriority, int stack_size, void* stack_ptr )
{
bool spawned = false ;
if( !task_spawned )
{
if( stack_ptr != 0 )
{
// create OS task using native API
// using taskRoot() as the entry point and
// passing the `this` pointer as the user argument
OSTaskCreate( ... ) ;
spawned = (OS_ERR_NONE == err) ;
}
}
return spawned ;
}
那么使用这个,你可能会有如下的代码:
class cMyTask : public cTask
{
virtual void threadMain()
{
// Task loop
for(;;)
{
... // do stuff
}
}
}
:
cMyTask mytask ;
static CPU_STK stack[TASK_STACK_SIZE];
mytask.spawn( MYTASK_PRIORITY, sizeof(stack), stack ) ;
当然还有更多的,我的cTask
包括延迟,调度锁定,传递任务事件,改变优先级等成员。
您将注意到本机线程可用的一个user参数用于将任务对象实例传递给taskRoot()
,因此线程不能将其用于其他目的。这在c++中并不是一个真正的问题,因为您可以将这些数据传递给子类构造函数并将其存储在成员数据中,以便threadMain()
可以使用。