zouzhichao 发表于 2013-6-9 14:58:38

Mega16的简单多线程OS

本帖最后由 zouzhichao 于 2013-6-9 15:01 编辑

代码如下,4个线程

#include <avr\io.h>
#include <avr\interrupt.h>
#include <util\delay.h>

#define int8_ char
#define uint8_ unsigned char
#define int16_ short
#define uint16_ unsigned short
#define int32_ long
#define uint32_ unsigned long

#define PUSH()\
{\
        asm volatile(\
        "push r2\n\t"\
        "push r3\n\t"\
        "push r4\n\t"\
        "push r5\n\t"\
        "push r6\n\t"\
        "push r7\n\t"\
        "push r8\n\t"\
        "push r9\n\t"\
        "push r10\n\t"\
        "push r11\n\t"\
        "push r12\n\t"\
        "push r13\n\t"\
        "push r14\n\t"\
        "push r15\n\t"\
        "push r16\n\t"\
        "push r17\n\t"\
        "push r19\n\t"\
        "push r26\n\t"\
        "push r27\n\t"\
        "push r28\n\t"\
        "push r29\n\t"\
       : : );\
}

#define POP()\
{\
        asm volatile(\
        "pop r29\n\t"\
        "pop r28\n\t"\
        "pop r27\n\t"\
        "pop r26\n\t"\
        "pop r19\n\t"\
        "pop r17\n\t"\
        "pop r16\n\t"\
        "pop r15\n\t"\
        "pop r14\n\t"\
        "pop r13\n\t"\
        "pop r12\n\t"\
        "pop r11\n\t"\
        "pop r10\n\t"\
        "pop r9\n\t"\
        "pop r8\n\t"\
        "pop r7\n\t"\
        "pop r6\n\t"\
        "pop r5\n\t"\
        "pop r4\n\t"\
        "pop r3\n\t"\
        "pop r2\n\t"\
       : : );\
}

#define OsTaskStateSave(pTask)\
{\
        PUSH();\
        (pTask)->StackPoint = (uint8_*)SP;\
}

#define OsTaskStateLoad(pTask)\
{\
        SP = (uint16_)((pTask)->StackPoint);\
        POP();\
}

#define OsTaskRun(pTask)\
{\
        SP = (uint16_)((pTask)->StackPoint);\
        POP();\
        asm volatile(\
        "pop r31\n\t"\
        "pop r30\n\t"\
        "pop r25\n\t"\
        "pop r24\n\t"\
        "pop r23\n\t"\
        "pop r22\n\t"\
        "pop r21\n\t"\
        "pop r20\n\t"\
        "pop r18\n\t"\
        "pop r0\n\t"\
        "out __SREG__, r0\n\t"\
        "pop r0\n\t"\
        "pop r1\n\t"\
        : : );\
        return;\
}

typedef struct tagTASK
{
        int8_ (*TaskFunction)(int16_ Para);
        uint8_* StackPoint;
        uint8_ Stack;
        uint8_ Flag;
}TASK;

int8_ OsTaskInit(int8_ (*TaskFun)(int16_ Para), int16_ TaskFunPara, TASK *Task)
{
        Task->TaskFunction = TaskFun;
        Task->StackPoint = (uint8_*)Task->Stack + sizeof(Task->Stack) - 1;
        *(Task->StackPoint--) = (uint8_)((uint16_)(Task->TaskFunction)); /* Put task start address on top of stack */
    *(Task->StackPoint--) = (uint8_)(((uint16_)(Task->TaskFunction)) >> 8);
        *(Task->StackPoint--) = 0x00; /* R1 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R0 = 0x00 */
        *(Task->StackPoint--) = 0x80; /* SREG = Interrupts enabled */
        *(Task->StackPoint--) = 0x00; /* R18 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R20 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R21 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R22 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R23 = 0x00 */
    *(Task->StackPoint--) = (uint8_)TaskFunPara; /* Simulate call to function with argument */
    *(Task->StackPoint--) = (uint8_)(TaskFunPara >> 8);        /* R24, R25 contains argument pointer pdata */
        *(Task->StackPoint--) = 0x00; /* R30 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R31 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R2 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R3 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R4 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R5 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R6 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R7 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R8 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R9 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R10 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R11 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R12 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R13 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R14 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R15 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R16 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R17 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R19 = 0x00 */
        *(Task->StackPoint--) = 0x00; /* R26 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R27 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R28 = 0x00 */
    *(Task->StackPoint--) = 0x00; /* R29 = 0x00 */
        return 0;
}


int8_ OsTickInit(void)
{
        cli(); //disable all interrupts
        TCCR0 = 0x00; //stop
        TCNT0 = 0x00; //set count
        OCR0= 0x0E;//set compare
        TCCR0 = 0x05; //start timer
        MCUCR = 0x00;
        GICR= 0x00;
        TIMSK = 0x01; //timer interrupt sources
        sei(); //re-enable interrupts
        return 0;
}

int8_ TaskFun0(int16_ Para)
{
        for ( ; ; )
        {
                _delay_us(20);
                PORTA ^= 0x01;
        }
        return 0;
}

int8_ TaskFun1(int16_ Para)
{
        for ( ; ; )
        {
                _delay_us(20);
                PORTA ^= 0x02;
        }
        return 0;
}

int8_ TaskFun2(int16_ Para)
{
        for ( ; ; )
        {
                _delay_us(20);
                PORTA ^= 0x04;
        }
        return 0;
}

int8_ TaskFun3(int16_ Para)
{
        for ( ; ; )
        {
                _delay_us(20);
                PORTA ^= 0x08;
        }
        return 0;
}

static TASK Task;
static uint8_t ID = 0;
int main()
{
        DDRA |= 0xff;
        PORTA ^= 0xff;
        OsTaskInit(TaskFun0, 10, &Task);
        OsTaskInit(TaskFun1, 1, &Task);
        OsTaskInit(TaskFun2, 2, &Task);
        OsTaskInit(TaskFun3, 3, &Task);
        OsTickInit();
        OsTaskRun(&Task);
        for ( ; ; )
                ;
        return 0;
}

ISR(TIMER0_OVF_vect)
{
        OsTaskStateSave(&Task);
        if (4 == ++ID)
                ID = 0;
        OsTaskStateLoad(&Task);
}

mitchell 发表于 2013-6-9 15:12:02

SREG也需要保存的。
SP指针因为是双字节的,切换时必须屏蔽中断。

zouzhichao 发表于 2013-6-9 15:14:06

本帖最后由 zouzhichao 于 2013-6-9 15:17 编辑

mitchell 发表于 2013-6-9 15:12 static/image/common/back.gif
SREG也需要保存的。
SP指针因为是双字节的,切换时必须屏蔽中断。

后面那句是对的,我考虑不周
前一句你说的是对的,但是我也已经保护了SREG了,只是你没看到

zouzhichao 发表于 2013-6-9 15:23:29

mitchell 发表于 2013-6-9 15:12 static/image/common/back.gif
SREG也需要保存的。
SP指针因为是双字节的,切换时必须屏蔽中断。

R0,R1,SREG,R18,R20,R21,R22,R23,R24,R25,R30,R31的保护是中断时编译器生成的代码实现的,PUSH()源代码里不是直接可见

mitchell 发表于 2013-6-9 15:24:46

zouzhichao 发表于 2013-6-9 15:14
后面那句是对的,我考虑不周
前一句你说的是对的,但是我也已经保护了SREG了,只是你没看到
...

嗯,进入中断时自动保存的。
如果只在中断里进行调度,sp切换也不要关中断,因为reti之前中断本来就关着的,哈哈。

zouzhichao 发表于 2013-6-9 15:29:18

mitchell 发表于 2013-6-9 15:24 static/image/common/back.gif
嗯,进入中断时自动保存的。
如果只在中断里进行调度,sp切换也不要关中断,因为reti之前中断本来就关着 ...

这个有点投机取巧了,十分依赖编译器编译出来的代码,我是一边写,一边看编译出来的汇编代码写的,换了别的环境或者开优化,很可能就是错的了,并且中断里面的东西不能随便乱加
如果完全用汇编写中断处理代码就不会有这问题了,我这是取的对C语言动刀尽可能小的方式去实现

zouzhichao 发表于 2013-6-9 15:32:56

除了几个PUSH,POP之外,没有动用别的汇编代码,尽可能地用C实现
页: [1]
查看完整版本: Mega16的简单多线程OS