木子剑
生命不熄,学习不止!

使用队列功能, 令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很强大,也很简单!爽歪歪呢。。。

 

posted on 2022-03-13 12:55  木子剑  阅读(72)  评论(0编辑  收藏  举报