搜索
bottom↓
回复: 10

求救:尝试RTOS,但RET返回时返回地址不是从STACK中弹出而变为0,(AVRStudio+WinAVR200604

[复制链接]

出0入70汤圆

发表于 2008-1-25 19:48:56 | 显示全部楼层 |阅读模式
照着http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=574348&bbs_page_no=1&search_mode=4&search_text=PaulDE&bbs_id=9999里的教程走的。
但是错的有点莫名其妙。
1
2
3
4

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入70汤圆

 楼主| 发表于 2008-1-25 20:02:05 | 显示全部楼层
晕,尝试把低地址先入栈,结果通过了


void RunFunInNewStack(void (*pfun)(),unsigned char *pStack)
{
        *pStack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,
        *pStack-- = (unsigned int)pfun>>8;    //将函数的地址高位压入堆栈,
//        *pStack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,
        SP = pStack;                         //将堆栈指针指向人工堆栈的栈顶
        __asm__ __volatile__("RET \n\t");    //返回并开中断,开始运行fun1()
}

出0入70汤圆

 楼主| 发表于 2008-1-25 21:13:17 | 显示全部楼层
4个LED可以有节奏的点亮了


#include <avr/io.h>
#include <avr/Interrupt.h>
#include <avr/signal.h>

//LED引脚定义                              
#define LED_PORT        PORTD   
#define LED_MASK        0xF0

#define LED1            0x10
#define LED2            0x20
#define LED3            0x40
#define LED4              0x80


#define LED1On()        LED_PORT |= LED1  // 点亮提示灯1
#define LED2On()        LED_PORT |= LED2  // 点亮提示灯2
#define LED3On()        LED_PORT |= LED3  // 点亮提示灯3
#define LED4On()        LED_PORT |= LED4  // 点亮提示灯4

#define LED1Reverse()   LED_PORT = LED_PORT ^ LED1                  // 关闭提示灯1
#define LED2Reverse()   LED_PORT = LED_PORT ^ LED2                  // 关闭提示灯2
#define LED3Reverse()   LED_PORT = LED_PORT ^ LED3                  // 关闭提示灯3
#define LED4Reverse()   LED_PORT = LED_PORT ^ LED4                  // 关闭提示灯4

#define LEDOn()         LED_PORT |= LED_MASK;                     // 所有灯点亮
#define LEDOff()        LED_PORT &= (~LED_MASK)

unsigned char Stack[250];
register unsigned char OSRdyTbl           asm("r2");      //任务运行就绪表
register unsigned char OSTaskRunningPrio  asm("r3");      //正在运行的任务

#define  OS_TASKS 4           //设定运行任务的数量

struct TaskCtrBlock           //任务控制块
{
        unsigned int OSTaskStackTop;  //保存任务的堆栈顶
        unsigned int OSWaitTick;      //任务延时时钟
}TCB[OS_TASKS+1];


//防止被编译器占用
register unsigned char tempR4  asm("r4");
register unsigned char tempR5  asm("r5");
register unsigned char tempR6  asm("r6");
register unsigned char tempR7  asm("r7");
register unsigned char tempR8  asm("r8");
register unsigned char tempR9  asm("r9");
register unsigned char tempR10 asm("r10");
register unsigned char tempR11 asm("r11");
register unsigned char tempR12 asm("r12");
register unsigned char tempR13 asm("r13");
register unsigned char tempR14 asm("r14");
register unsigned char tempR15 asm("r15");
register unsigned char tempR16 asm("r16");
register unsigned char tempR16 asm("r17");


//建立任务
void OSTaskCreate(void (*Task)(void),unsigned char *Stack,unsigned char TaskID)
{
        unsigned char i;
        *Stack--=(unsigned int)Task;         //将任务的地址低位压入堆栈,
        *Stack--=(unsigned int)Task>>8;    //将任务的地址高位压入堆栈,
        //*Stack--=(unsigned int)Task;         //将任务的地址低位压入堆栈,
        *Stack-- = 0x00;                     //R1 __zero_reg__
        *Stack-- = 0x00;                     //R0 __tmp_reg__
        *Stack-- = 0x80;                     //SREG 在任务中,开启全局中断
        for(i=0;i<14;i++)     //在avr-libc中的FAQ中What registers are used by the C compiler?
        *Stack-- = i;        //描述了寄存器的作用

        TCB[TaskID].OSTaskStackTop=(unsigned int)Stack;//将人工堆栈的栈顶,保存到堆栈的数组中
        OSRdyTbl|= 0x01<<TaskID;      //任务就绪表已经准备好
}



//开始任务调度,从最低优先级的任务的开始
void OSStartTask()
{
        OSTaskRunningPrio = OS_TASKS;
        SP = TCB[OS_TASKS].OSTaskStackTop+17;
        __asm__ __volatile__("reti \n\t");
}



//进行任务调度
void OSSched(void)
{
        //  根据中断时保存寄存器的次序入栈,模拟一次中断后,入栈的情况
        __asm__ __volatile__("PUSH __zero_reg__    \n\t");  //R1
        __asm__ __volatile__("PUSH __tmp_reg__     \n\t");  //R0
        __asm__ __volatile__("IN   __tmp_reg__, __SREG__ \n\t");  //保存状态寄存器SREG
        __asm__ __volatile__("PUSH __tmp_reg__     \n\t");
        __asm__ __volatile__("CLR  __zero_reg__     \n\t");  //R0重新清零
        __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 R30    \n\t");
        __asm__ __volatile__("PUSH R31    \n\t");
        __asm__ __volatile__("PUSH R28    \n\t");  //R28与R29用于建立在堆栈上的指针
        __asm__ __volatile__("PUSH R29    \n\t");  //入栈完成

        TCB[OSTaskRunningPrio].OSTaskStackTop = SP;   //将正在运行的任务的堆栈底保存

        unsigned char OSNextTaskID;                   //在现有堆栈上开设新的空间进行任务调度
        for(OSNextTaskID = 0;OSNextTaskID < OS_TASKS && !(OSRdyTbl & (0x01<<OSNextTaskID));OSNextTaskID++);
        OSTaskRunningPrio = OSNextTaskID;
        cli();  //保护堆栈转换
        SP = TCB[OSTaskRunningPrio].OSTaskStackTop;
        sei();


        //根据中断时的出栈次序
        __asm__ __volatile__("POP  R29    \n\t");
        __asm__ __volatile__("POP  R28    \n\t");
        __asm__ __volatile__("POP  R31    \n\t");
        __asm__ __volatile__("POP  R30    \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  __tmp_reg__ \n\t");       //SERG 出栈并恢复
        __asm__ __volatile__("OUT  __SREG__, __tmp_reg__ \n\t");   //
        __asm__ __volatile__("POP  __tmp_reg__     \n\t");       //R0 出栈
        __asm__ __volatile__("POP  __zero_reg__    \n\t");      //R1 出栈
        //中断时出栈完成
}



void OSTimeDly(unsigned int ticks)
{
        if(ticks)            //当延时有效
        {
                OSRdyTbl &= ~(0x01<<OSTaskRunningPrio);
                TCB[OSTaskRunningPrio].OSWaitTick = ticks;
                OSSched();        //从新调度
        }
}

void TCN0Init(void)    // 计时器0
{
        TCCR0 = 0;
        TCCR0 |= (1<<CS02);  // 256预分频
        TIMSK |= (1<<TOIE0); // T0溢出中断允许
        TCNT0 = 100;         // 置计数起始值
}


SIGNAL(SIG_OVERFLOW0)
{
        unsigned char i;
        for(i=0;i<OS_TASKS;i++)       //任务时钟
        {
                if(TCB.OSWaitTick)
                {
                        TCB.OSWaitTick--;
                        if(TCB.OSWaitTick==0)     //当任务时钟到时,必须是由定时器减时的才行
                        {
                                OSRdyTbl |= (0x01<<i);     //使任务在就绪表中置位
                        }
                }
        }
        TCNT0=100;
}



void Task0()
{
        while(1)
        {
                LED1On();
                OSTimeDly(10);
                LED1Reverse();
                OSTimeDly(10);
        }
}



void Task1()
{
        while(1)
        {
                LED2On();
                OSTimeDly(20);
                LED2Reverse();
                OSTimeDly(20);
        }
}



void Task2()
{
        while(1)
        {
                LED3On();
                OSTimeDly(40);
                LED3Reverse();
                OSTimeDly(40);
        }
}

void Task3()
{
        while(1)
        {
                LED4On();
                OSTimeDly(80);
                LED4Reverse();
                OSTimeDly(80);
        }
}

void TaskScheduler()
{
        while(1)
        {
                OSSched();      //反复进行调度
        }
}

int main(void)
{
        DDRD = 0xff;
        LEDOn();
       
        TCN0Init();
        OSRdyTbl = 0;
        OSTaskRunningPrio = 0;
        OSTaskCreate(Task0, &Stack[49], 0);
        OSTaskCreate(Task1, &Stack[99], 1);
        OSTaskCreate(Task2, &Stack[149], 2);
        OSTaskCreate(Task3, &Stack[199], 3);
        OSTaskCreate(TaskScheduler, &Stack[249], OS_TASKS);
        OSStartTask();
       
        LEDOff();

        return 0;
}

出0入0汤圆

发表于 2008-2-28 13:41:46 | 显示全部楼层
晕,尝试把低地址先入栈,结果通过了


void RunFunInNewStack(void (*pfun)(),unsigned char *pStack)
{
        *pStack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,
        *pStack-- = (unsigned int)pfun>>8;    //将函数的地址高位压入堆栈,
//        *pStack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,
        SP = pStack;                         //将堆栈指针指向人工堆栈的栈顶
        __asm__ __volatile__("RET \n\t");    //返回并开中断,开始运行fun1()
}



-------------------------------------------------------------------------------------
偶也遇到同样问题,那位DX解释一下?   谢了先

出0入70汤圆

 楼主| 发表于 2008-2-28 14:56:07 | 显示全部楼层
我估计是写这个os的DX用的编译器版本跟咱们不同的缘故。
可是我的os+usart还是没有通啊,郁闷!
哪位dx解救一下!!

出0入0汤圆

发表于 2008-4-9 17:05:37 | 显示全部楼层
就是要把任务堆栈地址换一下,低位先入,高位迟入。具体你可以用GCC写一个空的中断函数,你看该中断函的汇编代码的出入栈顺序就比较明白需要保存那些堆栈,和出入栈顺序了。还是就是GCC的优化最好用0S,不要不优化,不优化就会出问题,这个问题没搞懂

出0入0汤圆

发表于 2010-7-21 15:37:15 | 显示全部楼层
回复【2楼】PaulDE
-----------------------------------------------------------------------

4个LED可以有节奏的点亮了 ,的程序是否通过,你在调试时到OSStartTask(); 函数之后到了那里呢

出0入0汤圆

发表于 2011-1-15 21:11:26 | 显示全部楼层
__("RET \n\t");   
RET 指令后跟了\n\t是什么意思,一头雾水,

出0入0汤圆

发表于 2011-1-15 22:28:47 | 显示全部楼层
\n,\t什么意思
是跟printf类似的吗?

出0入0汤圆

发表于 2011-1-16 19:34:10 | 显示全部楼层
回复【3楼】sunxflower 大风起兮云飞扬
晕,尝试把低地址先入栈,结果通过了  
void runfuninnewstack(void (*pfun)(),unsigned char *pstack)  
{  
        *pstack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,  
        *pstack-- = (unsigned int)pfun&gt;&gt;8;    //将函数的地址高位压入堆栈,  
//        *pstack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,  
        sp = pstack;                         //将堆栈指针指向人工堆栈的栈顶  
        __asm__ __volatile__("ret \n\t");    //返......
-----------------------------------------------------------------------

其实,AVR地址是2字节16位,帮直接定义成short就不要分是高位还是低们先存的问题了,
unsigned int Stack[100]; //建立一个100字节的人工堆栈

void RunFunInNewStack(void (*pfun)(),unsigned int *pStack)
{
*pStack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,
//*pStack-- = (unsigned int)pfun>>8;    //将函数的地址高位压入堆栈,
// *pStack-- = (unsigned int)pfun;        //将函数的地址低位压入堆栈,
SP = (int) pStack;                         //将堆栈指针指向人工堆栈的栈顶
__asm__ __volatile__("RET \n\t");    //返回并开中断,开始运行fun1()
}
不明白作者为什么非要用char做人工堆栈

出0入0汤圆

发表于 2011-1-16 19:53:12 | 显示全部楼层
早知道有这个小错误了,但也不明白为什么这样
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-23 15:32

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

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