搜索
bottom↓
回复: 15

非常简单的菜鸟级任务切换,任务1实现LCD显示的,每个任务运行时对应的LED灯闪烁

[复制链接]

出0入0汤圆

发表于 2007-6-22 12:20:15 | 显示全部楼层 |阅读模式
前段时间刚刚看完small RTOS,想移植到AVR上,但对WINGCC的中断管理不熟悉。然后自己写了这个简单的任务切换练习。对于我们这些刚刚接触嵌入式操作系统的菜鸟来说会有一点帮助。高手看了千万别xiao我,程序中有几个疑点希望指点一下。

    采用时间片轮转法,总共定义了8个任务,每个任务对应一个LED灯,当前任务运行时,对应的LED灯闪烁,其他任务的LED灯熄灭。任务1还加了LCD1602显示功能,这个时我后来加上去的,可以删除。初始化时堆栈指针SP指向RAM的末端RAMEND,在定时器0的溢出中断函数中作任务切换,不保存当前任务的运行环境,所以在任务切换时SP都被重新赋值为RAMEND。

    程序如下:

#include <avr/io.h>

#include <util/delay.h>

#include <avr/interrupt.h>



//LED灯控制端口定义

#define LED_PORT PORTD

#define LED_DDR  DDRD

#define LED_PIN  PIND



//====================1602液晶模块================================

//1602控制端口和控制信号定义

#define LCD_CTRL_DDR  DDRB

#define LCD_CTRL_PORT PORTB

#define LCD_CTRL_PIN  PINB

#define LCD_RS   0X01

#define LCD_RW   0X02

#define LCD_EN   0X04



//读取类型:命令或数据

#define read_comm   0

#define read_data   1



//1602数据端口

#define LCD_DATA_DDR  DDRA

#define LCD_DATA_PORT PORTA

#define LCD_DATA_PIN  PINA



//1602功能函数声明

void lcd_init(void);                       //LCD初始化

void lcd_write_comm(unsigned char comm);  //写命令

void lcd_write_data(unsigned char data);  //写数据

void lcd_write_str(unsigned char x,unsigned char y,unsigned char *p);//写字符串

unsigned char lcd_read_char(unsigned char read_type);  //读取

void lcd_posion(unsigned char x,unsigned char y);     //位置设定

void lcd_busy_chek(void);

void lcd_en_signal(void);



//1602初始化函数

void lcd_init(void)

{   

   LCD_CTRL_PORT=0x00;

   LCD_CTRL_DDR= 0xff;   

   LCD_DATA_PORT=0X00;

   LCD_DATA_DDR=0XFF;   

   lcd_write_comm(0x3f); //功能设置,8位数据,两行显示,5X10  

   lcd_write_comm(0x06); //输入方式设置   

   lcd_write_comm(0x0f); //显示开关设置   

   lcd_write_comm(0x01); //清屏  

}



//写命令函数

void lcd_write_comm(unsigned char comm)

{  

   lcd_busy_chek();

   

   LCD_CTRL_PORT&=~LCD_RW; //WRITE

   LCD_CTRL_PORT&=~LCD_RS; //RS=0

   

   LCD_DATA_PORT=comm;

   lcd_en_signal();

   

   LCD_CTRL_PORT^=LCD_RS; //CONVERSE RS

   LCD_CTRL_PORT^=LCD_RW; //WRITE

}



//1602定位函数

void lcd_posion(unsigned char x,unsigned char y)

{

    unsigned char address;

    if(y == 0)

           address = 0x80 + x;

    else   

           address = 0xc0 + x;

    lcd_write_comm(address);

}



//写数据函数

void lcd_write_data(unsigned char data)

{

   lcd_busy_chek();

   

   LCD_CTRL_PORT&=~LCD_RW; //WRITE

   LCD_CTRL_PORT|=LCD_RS; //RS=0

   

   LCD_DATA_PORT = data;

   lcd_en_signal();

   

   LCD_CTRL_PORT^=LCD_RS; //CONVERSE RS

   LCD_CTRL_PORT^=LCD_RW; //WRITE

}



//写字符串函数

void lcd_write_str(unsigned char x,unsigned char y,unsigned char *p)  //写数据

{

   lcd_posion(x,y);

   

   while(*p)

   {

      lcd_write_data(*p);

      p++;

   }



}



//读数据函数

unsigned char lcd_read_char(unsigned char read_type)

{

    unsigned char temp;

       

    lcd_busy_chek();

       

    if(read_type==read_comm)   //read comm

    {

       LCD_CTRL_PORT&=~LCD_RS;

    }

    else                      //read data

    {

       LCD_CTRL_PORT|=LCD_RS;

    }

    LCD_CTRL_PORT|=LCD_RW; //read

       

    lcd_en_signal();

    temp=LCD_DATA_PIN;

       

    LCD_CTRL_PORT^=LCD_RW; //CONVERSE RW

    LCD_CTRL_PORT^=LCD_RS; //CONVERSE RS

       

    return temp;

}



//1602忙检测函数

void lcd_busy_chek(void)

{

   LCD_DATA_DDR  = 0X00;

   LCD_DATA_PORT = 0XFF;

   

   LCD_CTRL_PORT&=~LCD_RS;

   LCD_CTRL_PORT|=LCD_RW; //read

   

   //为什么这里换成函数lcd_en_signal()却不行???

   LCD_CTRL_PORT&=~LCD_EN;

   _delay_us(1);

   LCD_CTRL_PORT|=LCD_EN;

   _delay_us(1);

   LCD_CTRL_PORT&=~LCD_EN;

   while( LCD_DATA_PIN&0X80 )

   {

      LCD_CTRL_PORT&=~LCD_EN;

      _delay_us(1);

      LCD_CTRL_PORT|=LCD_EN;

      _delay_us(1);

      LCD_CTRL_PORT&=~LCD_EN;

   }      

   LCD_CTRL_PORT^=LCD_RW; //CONVERSE RW

   LCD_CTRL_PORT^=LCD_RS; //CONVERSE RS

   

   LCD_DATA_PORT = 0X00;

   LCD_DATA_DDR  = 0XFF;

}



//1602使能信号

void lcd_en_signal(void)

{   

   LCD_CTRL_PORT&=~LCD_EN;

   _delay_us(1);

   LCD_CTRL_PORT|=LCD_EN;

   _delay_us(1);

   LCD_CTRL_PORT&=~LCD_EN;   

}

//====================================1602功能模块结束============================================================



//全局变量定义

volatile unsigned char static tick=0;

volatile unsigned char static i=0;

volatile unsigned char static swich=0x00;



//任务1

void task1(void)

{   

    if(swich<0xf0)

    {

      lcd_write_comm(0x01); //清屏

      lcd_write_str(0,0,"www.ouravr.com");

      lcd_write_str(0,1,"nicholasldf");

      swich=0xff;          

    }   

    else

    {  

      lcd_write_comm(0x01); //清屏

      lcd_write_str(0,0,"remember mydream");

      lcd_write_str(0,1,"I will be winner");

      swich=0x00;

    }

       

    while(1)

    {

      LED_PORT^=0X01;

      _delay_ms(200);

      _delay_ms(200);

      _delay_ms(200);

    }   

}



//任务2

void task2(void)

{

  LED_PORT=0;

  while(1)

  {

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    LED_PORT^=0X02;

  }

}



//任务3

void task3(void)

{

  LED_PORT=0;

  while(1)

  {

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    LED_PORT^=0X04;

  }

}



//任务4

void task4(void)

{

  LED_PORT=0;

  while(1)

  {

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    LED_PORT^=0X08;

  }

}



//任务5

void task5(void)

{

  LED_PORT=0;

  while(1)

  {

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    LED_PORT^=0X10;

  }

}



//任务6

void task6(void)

{

  LED_PORT=0;

  while(1)

  {

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    LED_PORT^=0X20;

  }

}



//任务7

void task7(void)

{

  LED_PORT=0;

  while(1)

  {

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    LED_PORT^=0X40;

  }

}



//任务8

void task8(void)

{

  LED_PORT=0;

  while(1)

  {

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    _delay_ms(200);

    LED_PORT^=0X80;

  }

}



//任务数组

void  (*const TaskFuction[8])(void)={task1,task2,task3,task4,task5,task6,task7,task8};



//启动函数

void start(void)

{  

   //将SP设置指向存储器末端

   SP=RAMEND;

   

   //将第一个任务的入口入栽  

   *(unsigned char *)SP-- = ((unsigned int)(TaskFuction[0])) % 256;

   *(unsigned char *)SP-- = ((unsigned int)(TaskFuction[0])) / 256;

   

   //开中断

   sei();

   

   //用中断返回指令将入口地址弹出到PC指针,运行第一个任务

   asm("RETI");     

}



//定时器0溢出中断函数,作任务切换

SIGNAL(SIG_OVERFLOW0)

{

  tick++;

  

  //200次时钟中断作一次任务切换

  if(tick==200)

  {   

     tick=0;

       

     //用静态变量i来实现任务加1

     i=(i++)%8;

       

     //SP重新定位到RAMEND,不保存任务现场

     SP=RAMEND;

       

     //将下一个任务的入口地址入栽       

     //而不能表示为:*SP-- = ((unsigned int)(TaskFuction)) % 256;

     //              *SP-- = ((unsigned int)(TaskFuction)) / 256;

     //并且还不能表示为:*(unsigned int *)SP-- = ((unsigned int)(TaskFuction)) % 256;

     //                  *(unsigned int *)SP-- = ((unsigned int)(TaskFuction)) / 256;

     *(unsigned char *)SP-- = ((unsigned int)(TaskFuction)) % 256;

     *(unsigned char *)SP-- = ((unsigned int)(TaskFuction)) / 256;

       

    //用中断返回指令将入口地址弹出到PC指针,作任务切换

    asm("RETI");  

  }

  

}





int main(void)

{  

   //LED灯控制端口设置

   LED_PORT=0X00;

   LED_DDR =0XFF;   

   

   //定时器0初始化

   TCCR0=0X05;

   TIMSK=0X01;

   

   lcd_init();

   

   //开始运行任务

   start();

   

   while(1);   

}



   最后请教大家:SP指针为16位的,为何不能如下面那样使用,编译会出错

   *SP-- = ((unsigned int)(TaskFuction)) % 256;

   *SP-- = ((unsigned int)(TaskFuction)) / 256;

   或者:

   *(unsigned int *)SP-- = ((unsigned int)(TaskFuction)) % 256;

   *(unsigned int *)SP-- = ((unsigned int)(TaskFuction)) / 256;

出0入0汤圆

发表于 2007-9-29 13:23:19 | 显示全部楼层
不错

出0入0汤圆

发表于 2007-9-29 13:24:58 | 显示全部楼层
兄弟我顶你!

出0入0汤圆

发表于 2007-9-29 13:35:48 | 显示全部楼层
small rtos在AVR上不太适合。实时性很差,切换任务占用大量时间。
程明计关于非系统管理中断(程明计书中称软非屏蔽中断)存在严重问题,任务在出临界段的时候,打开了所有系统管理中断,而不论在进临界段之前这个中断是否是打开的。使得系统管理中断完全不能控制。

出0入0汤圆

发表于 2007-9-29 13:37:54 | 显示全部楼层
呵呵,avr适合裸奔

出0入0汤圆

发表于 2007-9-29 13:40:19 | 显示全部楼层
我一直使用操作系统。
个人认为usmartx最适合AVR了,其次是avrx.
而small rtos和ucos2都不太适合。

出0入42汤圆

发表于 2007-9-29 14:19:40 | 显示全部楼层
直接用:SP = TaskFuction;

出0入0汤圆

发表于 2007-9-29 19:39:20 | 显示全部楼层
占个位 以后有时间看看 呵呵

出0入0汤圆

发表于 2007-10-1 22:15:23 | 显示全部楼层
不错,顶

出0入0汤圆

发表于 2007-10-4 15:37:06 | 显示全部楼层
usmartx是什么?收费的还是免费的?

出0入0汤圆

发表于 2007-10-7 15:40:01 | 显示全部楼层
不错!看上去思路很清晰!很适合入门!

出0入0汤圆

 楼主| 发表于 2007-10-8 10:34:48 | 显示全部楼层
呵呵!谢谢大家!这是6月份好老的帖子了,前段时间在同usbfish的交流过程中,重新写了个调度程序,在21IC上张贴过请教存在的问题,在这里也贴一下,大家指点一下:

    基于AVR单片机(Meag16)、编译器WINAVR20070122的调度程序,基于时间片轮转法,定时器0计时,轮流让8个任务运行,切换任务时保存全部寄存器R0-R31、SREG到当前任务的堆栽,然后恢复下一个任务的现场,用中断返回指令作任务切换。设置让编译器在中断程序不保存任何寄存器,由自己保存寄存器。
    8个任务可以轮流运行,之前任务内部定义的局部变量在任务每次重新执行时都变为0,后来发现是没有保存栽顶指针!程序代码如下:

(1)头文件:任务控制块TCB定义、保存任务环境的入栽宏、恢复任务现场的出栽宏。
typedef struct
{
    unsigned char* task_stk_top;  //保存任务的栽顶
    unsigned char task_stack[100];//任务堆栽
     
}OS_TASK_TCB;

//保存所有寄存器的宏
#define pushall() \
__asm__ __volatile__ ("push r1"   "\n\t");\
__asm__ __volatile__ ("push r0"   "\n\t");\
__asm__ __volatile__ ("in  r0, 0x3f"   "\n\t");\保存CPU状态寄存器
__asm__ __volatile__ ("push r0"   "\n\t");\
__asm__ __volatile__ ("eor r1, r1"   "\n\t");\WINAVR要求R1等于0
__asm__ __volatile__ ("push r2"   "\n\t");\
__asm__ __volatile__ ("push r3"   "\n\t");\
__asm__ __volatile__ ("push r4"   "\n\t");\
__asm__ __volatile__ ("push r5"   "\n\t");\
__asm__ __volatile__ ("push r6"   "\n\t");\
__asm__ __volatile__ ("push r7"   "\n\t");\
__asm__ __volatile__ ("push r8"   "\n\t");\
__asm__ __volatile__ ("push r9"   "\n\t");\
__asm__ __volatile__ ("push r10"   "\n\t");\
__asm__ __volatile__ ("push r11"   "\n\t");\
__asm__ __volatile__ ("push r12"   "\n\t");\
__asm__ __volatile__ ("push r13"   "\n\t");\
__asm__ __volatile__ ("push r14"   "\n\t");\
__asm__ __volatile__ ("push r15"   "\n\t");\
__asm__ __volatile__ ("push r16"   "\n\t");\
__asm__ __volatile__ ("push r17"   "\n\t");\
__asm__ __volatile__ ("push r18"   "\n\t");\
__asm__ __volatile__ ("push r19"   "\n\t");\
__asm__ __volatile__ ("push r20"   "\n\t");\
__asm__ __volatile__ ("push r21"   "\n\t");\
__asm__ __volatile__ ("push r22"   "\n\t");\
__asm__ __volatile__ ("push r23"   "\n\t");\
__asm__ __volatile__ ("push r24"   "\n\t");\
__asm__ __volatile__ ("push r25"   "\n\t");\
__asm__ __volatile__ ("push r26"   "\n\t");\
__asm__ __volatile__ ("push r27"   "\n\t");\
__asm__ __volatile__ ("push r28"   "\n\t");\
__asm__ __volatile__ ("push r29"   "\n\t");\
__asm__ __volatile__ ("push r30"   "\n\t");\
__asm__ __volatile__ ("push r31"   "\n\t");\

//恢复任务现场时弹出所有寄存器的宏
#define popall() \
__asm__ __volatile__ ("pop r31"   "\n\t");\
__asm__ __volatile__ ("pop r30"   "\n\t");\
__asm__ __volatile__ ("pop r29"   "\n\t");\
__asm__ __volatile__ ("pop r28"   "\n\t");\
__asm__ __volatile__ ("pop r27"   "\n\t");\
__asm__ __volatile__ ("pop r26"   "\n\t");\
__asm__ __volatile__ ("pop r25"   "\n\t");\
__asm__ __volatile__ ("pop r24"   "\n\t");\
__asm__ __volatile__ ("pop r23"   "\n\t");\
__asm__ __volatile__ ("pop r22"   "\n\t");\
__asm__ __volatile__ ("pop r21"   "\n\t");\
__asm__ __volatile__ ("pop r20"   "\n\t");\
__asm__ __volatile__ ("pop r19"   "\n\t");\
__asm__ __volatile__ ("pop r18"   "\n\t");\
__asm__ __volatile__ ("pop r17"   "\n\t");\
__asm__ __volatile__ ("pop r16"   "\n\t");\
__asm__ __volatile__ ("pop r15"   "\n\t");\
__asm__ __volatile__ ("pop r14"   "\n\t");\
__asm__ __volatile__ ("pop r13"   "\n\t");\
__asm__ __volatile__ ("pop r12"   "\n\t");\
__asm__ __volatile__ ("pop r11"   "\n\t");\
__asm__ __volatile__ ("pop r10"   "\n\t");\
__asm__ __volatile__ ("pop r9"   "\n\t");\
__asm__ __volatile__ ("pop r8"   "\n\t");\
__asm__ __volatile__ ("pop r7"   "\n\t");\
__asm__ __volatile__ ("pop r6"   "\n\t");\
__asm__ __volatile__ ("pop r5"   "\n\t");\
__asm__ __volatile__ ("pop r4"   "\n\t");\
__asm__ __volatile__ ("pop r3"   "\n\t");\
__asm__ __volatile__ ("pop r2"   "\n\t");\
__asm__ __volatile__ ("pop r0"   "\n\t");\
__asm__ __volatile__ ("out 0x3f, r0"   "\n\t");\恢复CPU状态寄存器
__asm__ __volatile__ ("pop r0"   "\n\t");\
__asm__ __volatile__ ("pop r1"   "\n\t");\
__asm__ __volatile__ ("RETI"   "\n\t");\
//******************************************************************

(2)主函数main()代码,包括8个任务,调度程序,定义8个任务,每个任务对应一个LED灯的闪烁:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "RTOS.h"

#define LED_PORT PORTA //LED端口定义
#define LED_DDR  DDRA
#define LED_PIN  PINA

//第1个任务定义
void task1( void )
{   
    unsigned char temp ;//任务1的局部变量
        
    TCCR0 = 0X05;//定时器0初始化
    TIMSK = 0X01;         
         
    TCNT0 = 0x00;
    sei();       //打开全局中断
     
    while(1)
    {        
         temp++;

         LED_PORT ^=0X01;
         for( unsigned char i=0; i<250; i++)
           _delay_ms(10);
    }   
}

//第2个任务定义
void task2(void)
{   
    while(1)
    {        
       LED_PORT ^=0X02;
       for( unsigned char i=0; i<250; i++)
         _delay_ms(10);
    }
}

//第3个任务定义
void task3(void)
{
    while(1)
    {      
       LED_PORT ^=0X04;
       for( unsigned char i=0; i<250; i++)
         _delay_ms(10);
    }
}

//第4个任务定义
void task4(void)
{
    while(1)
    {        
       LED_PORT ^=0X08;
       for( unsigned char i=0; i<250; i++)
         _delay_ms(10);
    }
}

//第5个任务定义
void task5(void)
{
    while(1)
    {      
       LED_PORT ^=0X10;
       for( unsigned char i=0; i<250; i++)
         _delay_ms(10);
    }
}

//第6个任务定义
void task6(void)
{
    while(1)
    {        
       LED_PORT ^=0X20;
       for( unsigned char i=0; i<250; i++)
         _delay_ms(10);
    }
}

//第7个任务定义
void task7(void)
{
    while(1)
    {        
      LED_PORT ^=0X40;
      for( unsigned char i=0; i<250; i++)
        _delay_ms(10);
    }
}

//第8个任务定义
void task8(void)
{
    while(1)
    {        
      LED_PORT ^=0X80;
      for( unsigned char i=0; i<250; i++)
         _delay_ms(10);
    }
}
//*******************************************************************

volatile unsigned char next_task = 0;//用来计算下一个运行的任务

//计数变量,在定时器0中断函数里加1,用来控制任务切换频率
volatile unsigned char count = 0;

volatile OS_TASK_TCB task_tcb[ 8 ];//定义8个任务的任务控制块TCB数组

//任务堆栽初始化函数,参数为:任务入口地址、任务序号(1-8)
unsigned char* stackinit( void (*task)( void ), unsigned char task_id )
{
    unsigned char* stk;
    unsigned int temp;     
     
    temp = (unsigned int)task;//任务入口地址   
     
    stk = &( task_tcb[task_id].task_stack[99] );//取得任务栽顶指针
    *stk-- = (unsigned char)(temp&0xff);//将任务入口地址入栽
    *stk-- = (unsigned char)(temp>>8);

    //以下是CPU所有寄存器初始化,为0值,
    *stk-- = (unsigned char)0x00;        /* R0  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R1  = 0x00 */
    *stk-- = (unsigned char)0x80;        /* R2  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R3  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R4  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R5  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R6  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R7  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R8  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R9  = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R10 =      */
    *stk-- = (unsigned char)0x00;        /* R11 =      */
    *stk-- = (unsigned char)0x00;        /* R12 =      */
    *stk-- = (unsigned char)0x00;        /* R13 =      */
    *stk-- = (unsigned char)0x00;        /* R14 =      */
    *stk-- = (unsigned char)0x00;        /* R15 =      */
    *stk-- = (unsigned char)0x00;        /* R16 =      */
    *stk-- = (unsigned char)0x00;        /* R17 =      */
    *stk-- = (unsigned char)0x00;        /* R18 =      */
    *stk-- = (unsigned char)0x00;        /* R19 =      */
    *stk-- = (unsigned char)0x00;        /* R20 =      */
    *stk-- = (unsigned char)0x00;        /* R21 =      */
    *stk-- = (unsigned char)0x00;        /* R22 =      */
    *stk-- = (unsigned char)0x00;        /* R23 =      */
    *stk-- = (unsigned char)0x00;        /* R24 = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R25 = 0x00 */
    *stk-- = (unsigned char)0x00;        /* R26 =      */
    *stk-- = (unsigned char)0x00;        /* R27 =      */
    *stk-- = (unsigned char)0x00;        /* R28 =      */
    *stk-- = (unsigned char)0x00;        /* R29 =      */
    *stk-- = (unsigned char)0x00;        /* R30 =      */
    *stk-- = (unsigned char)0x00;        /* R31 =      */
    *stk-- = (unsigned char)0x00;        /* SREG =    */
    return ( (unsigned char*)stk );//返回当前堆栈指针
}

//任务创建函数:
void taskcreat( void (*task)( void ), unsigned char task_id )
{
    unsigned char *temp;

    temp = stackinit( task, task_id );//堆栽初始化,并返回栽顶指针
   
    //初始化之后将堆栽栽顶指针保存在任务的TCB里,这个变量一直指向栽顶
    task_tcb[task_id].task_stk_top = temp;
}

void OS_Start( void )
{   
    SP = task_tcb[0].task_stk_top + 33;//堆栽指针指向第一个任务

    //用中断返回指令将入口地址弹出到PC指针,运行第一个任务
    asm("RETI");
}

//定时器0的中断函数:加上下面这句,WINAVR将不保存任何寄存器
void SIG_OVERFLOW0( void ) __attribute__ ( ( signal, naked ) );
SIGNAL( SIG_OVERFLOW0 )
{   
    pushall( );//自己人工保存所有寄存器

    count++;   //每次中断加1
    if(count>100)//100时任务切换,count值可以调整任务切换频率
    {
         count = 0;//重新清0
         
         task_tcb[ next_task % 8 ].task_stk_top =SP;//保存当前任务的栽顶SP指针到当前任务的控制块TCB
         
         next_task++;指向下一个任务
              
         //堆栽指针指向下一个任务栽顶
         SP = task_tcb[ next_task % 8 ].task_stk_top;
    }

    popall( );//人工恢复所有寄存器
}

//main()函数
int main( void )
{  
    //LED灯控制端口设置
    LED_PORT=0Xff;
    LED_DDR =0Xff;   
     
    //创建并初始化8个任务
    taskcreat( task1, 0 );
    taskcreat( task2, 1 );
    taskcreat( task3, 2 );
    taskcreat( task4, 3 );
    taskcreat( task5, 4 );
    taskcreat( task6, 5 );
    taskcreat( task7, 6 );
    taskcreat( task8, 7 );
     
    OS_Start( );//开始运行任务
     
    while( 1 );   
}//****************************************************************

出0入0汤圆

发表于 2007-10-8 11:04:47 | 显示全部楼层
LZ 辛苦了,
这是入门的好东东啊,
我顶!

出0入0汤圆

发表于 2007-10-9 02:40:14 | 显示全部楼层
一次压入所有寄存器,而且每个任务都得分一块,内存少的片子就完全没办法用了.

我一直都是用伪多任务,一个函数进入一次只执行一部分功能,利用全局变量来控制执行哪部分功能的代码片.写程很麻烦,但不占内存,实时性也好,不用在堆栈里倒来倒去的.

unsigned char step_test1=0;
void test1(void){
  if(step_test1 == 1){
    ....
  }
  if(step_test1 == 2){
    ....
  }
  if(step_test1 == 3){
    ....
  }
  step_test1 ++;
  if(step_test1 > 3)
     step_test1 = 0;
}

unsigned char step_test2=0;
void test2(){
  if(step_test2 == 1){
    ....
  }
  if(step_test2 == 2){
    ....
  }
  step_test2++;
  if(step_test2 > 2)
     step_test2 = 0;
}

main(){
  while(1){
    test1();
    test2();
  }
}

出0入0汤圆

发表于 2007-10-9 09:57:44 | 显示全部楼层
楼主,如果每个任务都有不同的入口参数,如何调度呢?

出0入0汤圆

发表于 2008-4-24 15:43:13 | 显示全部楼层
任务是不需要参数的,,
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-3 04:33

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表