建立一個(gè)AVR的RTOS(2)—人工堆棧
在單片機(jī)的指令集中,一類指令是專門與堆棧和PC指針打道的,它們是
本文引用地址:http://butianyuan.cn/article/201612/325273.htmrcall相對(duì)調(diào)用子程序指令
icall間接調(diào)用子程序指令
ret子程序返回指令
reti中斷返回指令
對(duì)于ret和reti,它們都可以將堆棧棧頂?shù)膬蓚€(gè)字節(jié)被彈出來送入程序計(jì)數(shù)器PC中,一般用來從子程序或中斷中退出。其中reti還可以在退出中斷時(shí),重開全局中斷使能。
有了這個(gè)基礎(chǔ),就可以建立我們的人工堆棧了。
例:
#include <avr/io.h>
void fun1(void)
{
unsigned char i=0;
while(1)
{
PORTB=i++;
PORTC=0x01<<(i%8);
}
}
unsigned char Stack[100]; //建立一個(gè)100字節(jié)的人工堆棧
void RunFunInNewStack(void (*pfun)(),unsigned char *pStack)
{
*pStack--=(unsigned int)pfun>>8; //將函數(shù)的地址高位壓入堆棧,
*pStack--=(unsigned int)pfun; //將函數(shù)的地址低位壓入堆棧,
SP=pStack; //將堆棧指針指向人工堆棧的棧頂
__asm__ __volatile__("RET nt"); //返回并開中斷,開始運(yùn)行fun1()
}
int main(void)
{
RunFunInNewStack(fun1,&Stack[99]);
}
RunFunInNewStack(),將指向函數(shù)的指針的值保存到一個(gè)unsigned char的數(shù)組Stack中,作為人工堆棧。并且將棧頂?shù)臄?shù)值傳遞組堆棧指針SP,因此當(dāng)用"ret"返回時(shí),從SP中恢復(fù)到PC中的值,就變?yōu)榱酥赶騠un1()的地址,開始運(yùn)行fun1().
上面例子中在RunFunInNewStack()的最后一句嵌入了匯編代碼"ret",實(shí)際上是可以去除的。因?yàn)樵赗unFunInNewStack()返回時(shí),編譯器已經(jīng)會(huì)加上"ret"。我特意寫出來,是為了讓大家看到用"ret"作為返回后運(yùn)行fun1()的過程。
評(píng)論