使用队列功能, 令A任务和C任务产生数据(改变数值),令B任务消费A C任务的数据(打印数值)。
这次测试代码如下:
// //-- main.c // #include <stdio.h> #include <stdlib.h> #include "stm32f10x.h" #include "tn.h" //-- 空闲任务栈的大小,以字为单位 17+32个字,即49个字 #define IDLE_TASK_STACK_SIZE (TN_MIN_STACK_SIZE + 32) //-- 中断堆栈大小,以字为单位 #define INTERRUPT_STACK_SIZE (TN_MIN_STACK_SIZE + 32) //-- 用户任务的堆栈大小 #define TASK_A_STK_SIZE (TN_MIN_STACK_SIZE + 32) #define TASK_B_STK_SIZE (TN_MIN_STACK_SIZE + 32) #define TASK_C_STK_SIZE (TN_MIN_STACK_SIZE + 32) //-- 用户任务优先级,0最高 #define TASK_A_PRIORITY 2 #define TASK_B_PRIORITY 3 #define TASK_C_PRIORITY 4 //-- 消费者信息队列中的项目数量 #define CONS_QUE_BUF_SIZE 50 //-- 等待内存和空闲信息的最大超时时间 #define WAIT_TIMEOUT 10 /******************************************************************************* * DATA ******************************************************************************/ //-- Allocate arrays for stacks: stack for idle task // and for interrupts are the requirement of the kernel; // others are application-dependent. // 不是创建任务时,会分配堆栈吗? 这里要做一次? // We use convenience macro TN_STACK_ARR_DEF() for that. TN_STACK_ARR_DEF(idle_task_stack, IDLE_TASK_STACK_SIZE); TN_STACK_ARR_DEF(interrupt_stack, INTERRUPT_STACK_SIZE); TN_STACK_ARR_DEF(task_a_stack, TASK_A_STK_SIZE); TN_STACK_ARR_DEF(task_b_stack, TASK_B_STK_SIZE); TN_STACK_ARR_DEF(task_c_stack, TASK_C_STK_SIZE); //-- 任务结构, 当成C++公有的类,task_a b c 是类实列化的对像 struct TN_Task task_a; struct TN_Task task_b; struct TN_Task task_c; //-- 为其定义队列和缓冲器 struct TN_DQueue cons_que; void *cons_que_buf[ CONS_QUE_BUF_SIZE ]; /******************************************************************************* * FUNCTIONS ******************************************************************************/ //-- to printf int fputc(int c, FILE *stream) { return ITM_SendChar(c); } //-- init system timer void hw_init(void) { SysTick_Config(SYS_FREQ / SYS_TMR_FREQ); // 配置SysTick } //-- system timer 中断 void SysTick_Handler(void) { tn_tick_int_processing(); // 周期性执行 } //-- 测试IO口 void gpio_test(void) { /* GPIOD Periph clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); /* Configure PC6 in output pushpull mode */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); } //-- a task void task_a_body(void *par) { printf("New task a is OK!\n"); int data = 0; enum TN_RCode tn_rc; for(;;) { tn_rc = tn_queue_send(&cons_que, (void*)&data, WAIT_TIMEOUT); //传入变量的地址,或者指针 if (tn_rc == TN_RC_OK) { tn_task_sleep(500); data++; } } } //-- b task void task_b_body(void *par) { printf("New task b is OK!\n"); enum TN_RCode rc; int* dat; for(;;) {// dat是指针,还要取指针的地址! rc = tn_queue_receive(&cons_que, (void*)&dat, TN_WAIT_INFINITE); if (rc == TN_RC_OK) printf("data:%d\n",(int)*dat); //打印接收到的值 } } //-- c task void task_c_body(void *par) { char x=0; enum TN_RCode tn_rc; int data=100; printf("New task c is OK!\n"); tn_task_activate(&task_b); // 在C任务中激活B任务 for(;;) { GPIO_WriteBit(GPIOC, GPIO_Pin_6, x^=1); // 反转一个IO口 // 传入变量的地址,或者指针 tn_rc = tn_queue_send(&cons_que, (void*)&data, WAIT_TIMEOUT); if (tn_rc == TN_RC_OK) { tn_task_sleep(500); data++; } } } //-- 空闲回调,从空闲任务中定期调用 void idle_task_callback (void) { ; } //-- 创建应用任务, void init_task_create(void) { //-- 初始化各种板载外围设备,如闪存、显示器,等等。 //-- 初始化各种程序模块,----- 免去再见一个APP_init函数,没必要 gpio_test(); //-- 测试IO口初始化 //-- 创建队列 tn_queue_create(&cons_que, (void *)cons_que_buf, CONS_QUE_BUF_SIZE); //-- 以下是任务建立,推介只激活一个任务,然后在该任务依次激活所有任务. tn_task_create( &task_a, //-- task structure 任务a对像的地址 task_a_body, //-- task body function 任务A的回调函数 TASK_A_PRIORITY, //-- task priority 任务A的优先级 task_a_stack, //-- task stack 任务A的堆栈地址,类似数组 TASK_A_STK_SIZE, //-- task stack size (in words) 任务A的堆栈长度 NULL, //-- task function parameter 函数参数 TN_TASK_CREATE_OPT_START //-- creation option 任务创建后是否应立即激活 ); tn_task_create( &task_b, task_b_body, TASK_B_PRIORITY, task_b_stack, TASK_B_STK_SIZE, NULL, 0//TN_TASK_CREATE_OPT_START 不激活,在C中进行激活 ); tn_task_create( &task_c, task_c_body, TASK_C_PRIORITY, task_c_stack, TASK_C_STK_SIZE, NULL, TN_TASK_CREATE_OPT_START // 激活 ); } /******************************************************************************* * 主程序入口 ******************************************************************************/ int main(void) { //-- 无条件关中断,初始化OS心跳 tn_arch_int_dis(); hw_init(); //-- call to tn_sys_start() never returns 对tn_sys_start()的调用从不返回 tn_sys_start( idle_task_stack, // 空闲堆栈地址 IDLE_TASK_STACK_SIZE, // 空闲堆栈大小 interrupt_stack, // 中断栈 INTERRUPT_STACK_SIZE, // 中断栈大小 init_task_create, // 用户任务回调 idle_task_callback // 空闲任务回调 ); //-- unreachable 无法到达 return 1; }
接上STM32开发板,在线仿真如下:
【发送】---- tn_queue_send(&cons_que, (void*)&data, WAIT_TIMEOUT);
data的定义是为int data=xx; 这是一个变量,因为send第二个参数是要求传入一个指针,
所以要写成&data
【接收】---- tn_queue_receive(&cons_que, (void*)&dat, TN_WAIT_INFINITE);
这里的dat是指针,看看它的定义为int* dat; &dat就是把指针自身地址丢进去了.
所以queue是利用(void*)指针在操作了,接下来试试传入字符看看:
一个小改变,完成A B C三个任务后:
//-- a task void task_a_body(void *par) { printf("New task a is OK!\n"); char data = 'a'; enum TN_RCode tn_rc; for(;;) { tn_rc = tn_queue_send(&cons_que, (void*)&data, WAIT_TIMEOUT); //传入变量的地址,或者指针 if (tn_rc == TN_RC_OK) { tn_task_sleep(500); data++; } } } //-- b task void task_b_body(void *par) { printf("New task b is OK!\n"); enum TN_RCode rc; char* dat; for(;;) { // dat是指针,还要取指针的地址! rc = tn_queue_receive(&cons_que, (void*)&dat, TN_WAIT_INFINITE); if (rc == TN_RC_OK) printf("data:%c\n",(char)*dat); //打印接收到的值 } } //-- c task void task_c_body(void *par) { char x=0; enum TN_RCode tn_rc; char data = 'A'; printf("New task c is OK!\n"); tn_task_activate(&task_b); // 在C任务中激活B任务 for(;;) { GPIO_WriteBit(GPIOC, GPIO_Pin_6, x^=1); // 反转一个IO口 // 传入变量的地址,或者指针 tn_rc = tn_queue_send(&cons_que, (void*)&data, WAIT_TIMEOUT); if (tn_rc == TN_RC_OK) { tn_task_sleep(500); data++; } } }
STM32开发板在线仿真如下:
哪么如何传放字符串呢?实现代码如下:
//-- a task void task_a_body(void *par) { printf("New task a is OK!\n"); char msg1[] = "message for message1"; enum TN_RCode tn_rc; for(;;) { tn_rc = tn_queue_send(&cons_que, (void*)msg1, WAIT_TIMEOUT); //传入变量的地址,或者指针 if (tn_rc == TN_RC_OK) { tn_task_sleep(500); } } } //-- b task void task_b_body(void *par) { printf("New task b is OK!\n"); enum TN_RCode rc; char* dat; for(;;) {// dat是指针,还要取指针的地址! rc = tn_queue_receive(&cons_que, (void*)&dat, TN_WAIT_INFINITE); if (rc == TN_RC_OK) printf("data:%s\n",(char*)dat); //打印接收到的值 } } //-- c task void task_c_body(void *par) { char x=0; enum TN_RCode tn_rc; char *msg2 = "message for message2"; printf("New task c is OK!\n"); tn_task_activate(&task_b); // 在C任务中激活B任务 for(;;) { GPIO_WriteBit(GPIOC, GPIO_Pin_6, x^=1); // 反转一个IO口 // 传入变量的地址,或者指针 tn_rc = tn_queue_send(&cons_que, (void*)msg2, WAIT_TIMEOUT); if (tn_rc == TN_RC_OK) { tn_task_sleep(500); } } }
在线仿真如下:
对比下单字符和字符串打印函数:
printf("data:%c\n",(char)*dat); //单字符时(char)*, 通过指针取出的数据后,转换为CHAR进行显示字符 printf("data:%s\n",(char*)dat); //字符串时(char*), 要求指针,以CHAR的数据宽度取数据,直到取到\0后结束!
所以呢?TNeo的queue很强大,也很简单!爽歪歪呢。。。