很久前的代码(初学代码较乱),希望对阅读本文的读者理解RTOS有所帮助。
main.c
#include<stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include"ARM7.h"
#define P3 *((volatile unsigned *)0x80000090)
#define P2 *((volatile unsigned *)0x80000088)
#define P1 *((volatile unsigned *)0x80000084)
#define P0 *((volatile unsigned *)0x80000080)
#define tasknumsize 4
#define semMaxNum 3
volatile unsigned char cnt=0,IntNestNum=0;
volatile unsigned int clk=0,wait[tasknumsize];
volatile unsigned long taskrdy=0,nxttask=0,curtask=0,pcurtask,phightask,taskstkptr[tasknumsize];
void delay(unsigned int z);
void putS(char *s);
void CNTinterrupt(void);
void USARTinterrupt(void);
extern void start(void);
extern void run(void);
void clkTick(void);
void Sched(void);
void EnterInt(void);
void IntExitSw(void);
void CNTinterrupt(void)
{
if(CNT>=0x3)
{
CNT=0x0;
// BUF='A';
clkTick();
}
CNTINT=0x0;//清零计数器中断
INTFLG=0x03;//清零中断标志位
}
void USARTinterrupt(void)
{
char tmp;
tmp=BUF; //通过读取BUF,清除LSR(0)位
INTFLG=0x02; //清零中断标志位,bit0->CNT,bit1->USART
INTMSK=0x03;
}
void DisInt(void)
{
INTMSK=0x00;
}
void EnInt(void)
{
INTMSK=0x01; //使能定时器中断
}
void delay(unsigned int z)
{
unsigned int x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void put_char(char ch)
{
BUF = ch;
while(!(LSR&0x40));
}
void putS(char *s)
{
while(*s!='\0')
{
BUF = *s;
while(!(LSR&0x40));
s++;
}
}
#define stksize 512
unsigned int task0stk[stksize];
unsigned int task1stk[stksize];
unsigned int task2stk[stksize];
unsigned int idlestk[stksize];
void task0(void);
void task1(void);
void task2(void);
void idle(void);
#define NOINT (0xC0)
#define Mode_SVC (0x13)
void create(void (*fun)(void),unsigned int *pstk,unsigned char num)
{
*(pstk)=(unsigned int)fun;
*(--pstk) = (unsigned int)13; /* lr */
*(--pstk) = (unsigned int)12; /* r12*/
*(--pstk) = (unsigned int)11; /* r11*/
*(--pstk) = (unsigned int)10; /* r10*/
*(--pstk) = (unsigned int)9; /* r9 */
*(--pstk) = (unsigned int)8; /* r8 */
*(--pstk) = (unsigned int)7; /* r7 */
*(--pstk) = (unsigned int)6; /* r6 */
*(--pstk) = (unsigned int)5; /* r5 */
*(--pstk) = (unsigned int)4; /* r4 */
*(--pstk) = (unsigned int)3; /* r3 */
*(--pstk) = (unsigned int)2; /* r2 */
*(--pstk) = (unsigned int)1; /* r1 */
*(--pstk) = (unsigned int)0; /* r0 */
*(--pstk) = (unsigned int)(Mode_SVC); /* spsr 保存在任务栈中*/
taskstkptr[num]=(unsigned int)pstk;
wait[num]=0;
taskrdy |= (0x1<<num); //是任务进入就绪态
}
struct sem{
unsigned int semCnt;
unsigned int semPend;
}sem_t[semMaxNum];
void semCreate(unsigned char idx,unsigned int semN)
{
if(idx < semMaxNum)
{
sem_t[idx].semCnt = semN;
sem_t[idx].semPend = 0;
}
}
void semPending(unsigned char idx)
{
if(idx < semMaxNum)
{
if(sem_t[idx].semCnt==0)
{
sem_t[idx].semPend |= (0x1<<curtask);
taskrdy &= ~(0x1<<curtask); //挂起任务
Sched();
}
if(sem_t[idx].semCnt>0)
{
sem_t[idx].semCnt--;
}
}
}
void semPost(unsigned char idx)
{
unsigned char i;
DisInt();
if(sem_t[idx].semCnt < 0xffff)
sem_t[idx].semCnt++;
for(i=0;((i<tasknumsize)&&!(sem_t[idx].semPend&(0x01<<i)));i++);
EnInt();
if(i<tasknumsize)
{
sem_t[idx].semPend &= ~(0x1<<i);
taskrdy |= (0x1<<i); //就绪任务
Sched();
}
}
void EnterInt(void)
{
if(IntNestNum<255)
IntNestNum++;
}
void IntExitSw(void)
{
if(IntNestNum>0)
IntNestNum--;
if(IntNestNum==0)
Sched();
}
void Sched(void)
{
DisInt();
for(nxttask=0;nxttask<tasknumsize;nxttask++)
{
if((taskrdy&(0x1<<nxttask))!=0)//只要寻找到更高优先级的任务就退出
{
if(nxttask!=curtask)
{
phightask=taskstkptr[nxttask];
run();
}
goto exit; //当任务切换回自己的任务时,Sched中for循环还没有结束,导致还没执行自己的任务又跳到其他的任务。
}
}
exit:
EnInt();
}
void waitdly(unsigned int dly)
{
DisInt();
if(dly!=0)
{
taskrdy &= ~(0x1<<curtask); //挂起任务
wait[curtask]=dly;
Sched();
}
EnInt();
}
void clkTick(void)
{
unsigned char t;
for(t=0;t<tasknumsize;t++)
{
if(wait[t]>0)
{
wait[t]--;
if(wait[t]==0)
taskrdy |= (0x1<<t); //是任务进入就绪态
}
}
}
void idle(void)
{
unsigned char i;
while(1)
{
i++;
delay(100);
P0 = i;
}
}
void initBD(void)
{
LCR=0x83;
DLM=0x0;
DLL=0x01;
LCR=0x03;
IER=0x1; //使能接收中断
INTMSK=0x00; //失能中断,bit0->CNT,bit1->USART
}
void TimeOn(void)
{
INTMSK=0x01;
}
void startTask(void)
{
create(idle,&idlestk[stksize-1],3);
phightask=taskstkptr[nxttask];
start();
}
int main()
{
initBD();
pISR_CNT=(unsigned)CNTinterrupt;
pISR_USART=(unsigned)USARTinterrupt;
putS("\r\nMy rtos test!!!\n\r");
putS("Build...\n\rDate: " __DATE__ "\n\rTime:" __TIME__ "\n\r");
semCreate(0,1);
semCreate(1,1);
semCreate(2,1);
create(task0,&task0stk[stksize-1],0);
create(task1,&task1stk[stksize-1],1);
create(task2,&task2stk[stksize-1],2);
P0=0xaa;P1=0x0a;P2=0x0f;P3=0xf0;
TimeOn();
startTask();
return 0;
}
#define EnableSem 1
void task0(void)
{
unsigned char a = 0;
while(1)
{
#if EnableSem
semPending(0);
semPending(1);
semPending(2);
#endif
putS("task0........................................................\n\r");
delay(100);
putS("task0............................................................\n\r");
delay(100);
putS("task0................................................................\n\r\n\r");
#if EnableSem
semPost(1);
#endif
waitdly(8);
P1 = a++;
}
}
void task1(void)
{
unsigned char b = 0;
while(1)
{
#if EnableSem
semPending(1);
#endif
putS("task1........................................................\n\r");
delay(100);
putS("task1............................................................\n\r");
delay(100);
putS("task1................................................................\n\r\n\r");
#if EnableSem
semPost(2);
#endif
waitdly(28);
P2 = b++;
}
}
void task2(void)
{
unsigned char c = 0;
while(1)
{
#if EnableSem
semPending(2);
#endif
putS("task2........................................................\n\r");
delay(100);
putS("task2............................................................\n\r");
delay(100);
putS("task2................................................................\n\r\n\r");
#if EnableSem
semPost(0);
semPost(1);
semPost(2);
#endif
delay(800);
P3 = c++;
waitdly(10);
}
}
init.s
_ISR_STARTADDRESS EQU 0xc03ffff0
INTFLG EQU 0x80000008
INTMSK EQU 0x8000000c
CNTINT EQU 0x80000004
IRQMODE EQU 0x12
SVCMODE EQU 0x13
MODEMASK EQU 0x1f
NOINT EQU 0xc0
EXPORT run
EXPORT start
IMPORT phightask
IMPORT taskstkptr
IMPORT curtask
IMPORT nxttask
IMPORT IntNestNum
IMPORT IntExitSw
IMPORT EnterInt
IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
IMPORT |Image$$RW$$Base| ; Base of RAM to initialise
IMPORT |Image$$ZI$$Base| ; Base and limit of area
IMPORT |Image$$ZI$$Limit| ; to zero initialise
IMPORT main
EXPORT __ENTRY
AREA Example,CODE,READONLY ; 声明代码段Example
ENTRY ; 标识程序入口
CODE32 ; 声明32位ARM指令
__ENTRY
b ResetHandler ;for debug
b HandlerUndef ;handlerUndef
b HandlerSWI ;SWI interrupt handler
b HandlerPabort ;handlerPAbort
b HandlerDabort ;handlerDAbort
b . ;handlerReserved
ldr pc,=HandlerIRQ ;这段代码是不能在rom低地址的被执行的
b HandlerFIQ
HandlerIRQ
stmfd sp!,{r1-r3}
mov r1,sp
add sp,sp,#3*4
sub r2, lr, #4
mrs r3,spsr
msr cpsr_c, #SVCMODE|NOINT ;Change to SVC mode
stmfd sp!,{r2}
stmfd sp!,{r4-r12,lr}
ldmfd r1,{r4-r6}
stmfd sp!,{r4-r6}
stmfd sp!,{r0}
stmfd sp!,{r3}
bl EnterInt
ldr r0,=INTMSK
ldr r1,=0x00 ;//关闭中断,防止中断嵌套
str r1,[r0]
msr cpsr_c,#IRQMODE|NOINT
ldr r9,=INTFLG
ldr r9,[r9]
mov r8,#0x0
0
movs r9,r9,lsr #1
bcs %F1
add r8,r8,#4
b %B0
1
ldr r9,=HandleCNT
add r9,r9,r8
ldr r9,[r9]
cmp r9, #0
movne lr, pc
movne pc, r9
msr cpsr_c,#SVCMODE|NOINT
bl IntExitSw
2
ldr r0,=INTMSK
ldr r1,=0x01 ;cntr interrupt anable
str r1,[r0]
ldmfd sp!, {r0} ;从IRQ返回
msr spsr_cxsf, r0
ldmfd sp!, {r0-r12,lr,pc}^
ResetHandler
HandlerUndef
HandlerSWI
HandlerPabort
HandlerDabort
HandlerFIQ
ldr r0,=INTMSK
ldr r1,=0x00 ;all interrupt disable
str r1,[r0]
ldr r0,=INTFLG
ldr r1,=0x00 ;clean all interrupt Flag
str r1,[r0]
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 ;IRQMode
ldr sp,=IRQStack
bic r0,r0,#MODEMASK|NOINT
orr r1,r0,#SVCMODE
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack
LDR r0, =0xc0f00000 ;必须复制到ram中才能正常执行,不然就会使得RW段与ZI段不正常
LDR r1, =0x0
LDR r2, =|Image$$ZI$$Limit| ;注意,此时的Image$$ZI$$Limit为设置的ro_base后的地址值
sub r2,r2,r0
3
ldmia r1!,{r3-r7}
stmia r0!,{R3-R7}
cmp r1,r2
bcc %b3
ldr pc,=ram_code
ram_code
LDR r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
LDR r1, =|Image$$RW$$Base| ; and RAM copy
LDR r3, =|Image$$ZI$$Base|
;Zero init base => top of initialised data
CMP r0, r1 ; Check that they are different
BEQ %F5
4
CMP r1, r3 ; Copy init data
LDRCC r2, [r0], #4 ; --> LDRCC r2, [r0] + ADD r0, r0, #4
STRCC r2, [r1], #4 ; --> STRCC r2, [r1] + ADD r1, r1, #4
BCC %B4
5
LDR r1, =|Image$$ZI$$Limit| ; Top of zero init segment
MOV r2, #0
6
CMP r3, r1 ; Zero init
STRCC r2, [r3], #4
BCC %B6
bl main
b .
start
ldr r2,nxttask
ldr r1,=curtask
str r2,[r1]
ldr r0,=INTMSK
ldr r1,=0x01 ;cntr interrupt enable
str r1,[r0]
ldr sp,phightask
ldmfd sp!,{r1}
msr spsr_c,r1 ;SVCMode
ldmfd sp!, {r0-r12,lr,pc}^
run
stmfd sp!,{lr} ;pc
stmfd sp!,{r0-r12,lr}
mrs r0, spsr ;Push SPSR
stmfd sp!,{r0}
mov r0,sp
ldr r1,=taskstkptr
ldr r2,curtask
mov r2,r2,lsl #2 ;r2=curtask*4,taskstkptr一个成员变量占用4字节内存
add r1,r1,r2
str r0,[r1]
ldr r2,nxttask
ldr r1,=curtask
str r2,[r1]
ldr r0,=INTMSK
ldr r1,=0x01 ;cntr interrupt enable
str r1,[r0]
ldr sp,phightask ;把任务切换前的堆栈指针给sp,让该任务按切换前的函数返回进行原路返回。
ldmfd sp!,{r1}
msr spsr_c,r1 ;SVCMode
ldmfd sp!, {r0-r12,lr,pc}^
ALIGN
AREA RamData,DATA,READWRITE
^ (_ISR_STARTADDRESS-1024*4)
SVCStack # 1024*2
IRQStack # 1024*2
^ _ISR_STARTADDRESS
HandleCNT # 4
HandleUSART # 4
END
效果:
源码下载地址:点击打开链接