/*
LY RTOS a lightweight micro RTOS for WinAVR - GCC for ATMEL AVR micro controller
build 2008.5.28 copyrights by LYSoft(C) Liu Yang
http://G4Soft.net
*/
// you cannot remove this for your project which use LY RTOS
// 不得LYSoft之移除版权信息
unsigned char CopyRights[] ={"LY RTOS for AVR by LYSoft Liu Yang"};
#include <io.h>
#include <iom32.h>
#include <interrupt.h>
#define F_CPU
11059200
#define BAUDRATE
9600
// avoid compiler to use the following register
/*
register unsigned char tempR16 asm("r16");
register unsigned char tempR17 asm("r17");
// only about R15 can be used with IMD data LDI R16,0x01
*/
#define OSMaxTask
3
#define OSInfinite
0xFFFF
#define OSInvalid
0xFF
#define OSTaskEmpty
0
#define OSTaskReady
1
#define OSTaskWait
2
#define OSTaskSuspend
3
// Time(Sec) = CCR * (MAX - TCNT0 + 1) / F_CPU
#define OSTimerValue
120 // about 100ns
#define MCURegCount
32
static unsigned char OSCurrentTaskID = 0;
static unsigned char OSAtomFlag = 0;
static unsigned long OSIdleCount = 0, OSTickCount = 0;
struct tagTaskControlBlock
{
unsigned char Status;
unsigned int Stack;
unsigned int WaitTick;
unsigned char * Semaphore;
} TCB[OSMaxTask + 1];
unsigned char OSCreateTask(void (*Task)(void), unsigned char *TaskStack)
{
unsigned char i = 1, TaskID;
for (TaskID = 0; TaskID < OSMaxTask + 1; TaskID ++)
if (TCB[TaskID].Status == OSTaskEmpty)
{
i = 0;
break;
}
if (i) return OSInvalid;
TCB[TaskID].Status = OSTaskReady;
// PUSH = SP --; POP = SP ++
*TaskStack --= (unsigned int)Task;
// save low address of SP
*TaskStack --= (unsigned int)Task >> 8; // save high address of SP
*TaskStack --= 0x00;
// R0 __tmp_reg__
*TaskStack --= 0x80;
// SREG: SEI = 1
for (i = 0; i < MCURegCount - 1; i ++) *TaskStack --= 0x00;
TCB[TaskID].Stack = (unsigned int)TaskStack;
// save SP
}
unsigned char OSTerminateTask(unsigned char TaskID)
{
if (TaskID > OSMaxTask) return 0;
if (TCB[TaskID].Status == OSTaskEmpty) return 0;
TCB[TaskID].Status = OSTaskEmpty;
return 1;
}
void OSSwitchTask()
{
unsigned char i = OSMaxTask;
while (i)
{
i --;
OSCurrentTaskID ++;
if (OSCurrentTaskID > OSMaxTask) OSCurrentTaskID = 1;
if (TCB[OSCurrentTaskID].Status == OSTaskReady) return;
// check semaphore
if (TCB[OSCurrentTaskID].Semaphore > 0)
if (* TCB[OSCurrentTaskID].Semaphore > 0)
{ // deattach semaphore from task and then resume task
TCB[OSCurrentTaskID].Semaphore = 0;
// task ready for dispatch
TCB[OSCurrentTaskID].Status = OSTaskReady;
return;
}
}
// OS idle
OSCurrentTaskID = 0;
return;
}
// Macro for saving the context during an interrupt service.
#define SaveContext(void) /
__asm__ __volatile__ ( /
"push r0" "/n/t" /
"in r0, __SREG__" "/n/t" /
"cli" "/n/t" /
"push r0" "/n/t" /
"push r1" "/n/t" /
"clr __zero_reg__" "/n/t" /
"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 r18" "/n/t" /
"push r19" "/n/t" /
"push r20" "/n/t" /
"push r21" "/n/t" /
"push r22" "/n/t" /
"push r23" "/n/t" /
"push r24" "/n/t" /
"push r25" "/n/t" /
"push r26" "/n/t" /
"push r27" "/n/t" /
"push r28" "/n/t" /
"push r29" "/n/t" /
"push r30" "/n/t" /
"push r31" "/n/t" /
:: /
)
// Macro for restoring the context during an interrupt service.
#define RestoreContext(void) /
__asm__ __volatile__ ( /
"pop r31" "/n/t" /
"pop r30" "/n/t" /
"pop r29" "/n/t" /
"pop r28" "/n/t" /
"pop r27" "/n/t" /
"pop r26" "/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 r19" "/n/t" /
"pop r18" "/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" /
"pop r1" "/n/t" /
"pop r0" "/n/t" /
"out __SREG__, r0" "/n/t" /
"pop r0" "/n/t" /
:: /
)
void OSDispatch(void) __attribute__ ((naked));
void OSDispatch(void)
{
SaveContext();
__asm__ __volatile__("INT_OSDispatch: /t");
// dispatch from interrupt
if (OSAtomFlag == 0)
{
TCB[OSCurrentTaskID].Stack = SP;
OSSwitchTask();
SP = TCB[OSCurrentTaskID].Stack;
}
RestoreContext();
__asm__ __volatile__("RETI /t");
}
ISR(TIMER0_OVF_vect) __attribute__ ((naked));
ISR(TIMER0_OVF_vect)
{
SaveContext();
static unsigned char TaskID; // move variable out of register
for (TaskID = 1; TaskID < OSMaxTask + 1; TaskID ++)
{
if (TCB[TaskID].WaitTick && TCB[TaskID].WaitTick != OSInfinite && TCB[TaskID].Status == OSTaskWait)
{
TCB[TaskID].WaitTick --;
if (TCB[TaskID].WaitTick == 0) TCB[TaskID].Status = OSTaskReady;
}
}
OSTickCount ++;
TCNT0 = OSTimerValue;
__asm__ __volatile__("JMP INT_OSDispatch /t");
}
void OSSuspendTask(unsigned char TaskID)
{
if (TaskID > OSMaxTask) return;
TCB[TaskID].Status = OSTaskSuspend;
if (OSCurrentTaskID == TaskID) OSDispatch();
}
void OSResumeTask(unsigned char TaskID)
{
if (OSCurrentTaskID == TaskID || TaskID > OSMaxTask) return;
TCB[TaskID].Status = OSTaskReady;
OSDispatch();
}
void OSDelay(unsigned int Ticks)
{
if (Ticks)
{
TCB[OSCurrentTaskID].WaitTick = Ticks;
TCB[OSCurrentTaskID].Status = OSTaskWait;
OSDispatch();
}
}
void OSIdleTask()
{
while(1)
{
OSDispatch();
OSIdleCount ++;
}
}
#define OSIdleTaskStackSize 64
unsigned char OSIdleTaskStack[OSIdleTaskStackSize];
void OSInit()
{
unsigned char i;
for (i = 0; i < OSMaxTask + 1; i ++)
{
TCB[i].Status = OSTaskEmpty;
TCB[i].Stack = 0;
TCB[i].WaitTick = 0;
TCB[i].Semaphore = 0;
}
OSCreateTask(OSIdleTask, OSIdleTaskStack + OSIdleTaskStackSize - 1);
OSAtomFlag = 0;
}
void OSExecute()
{
TCCR0 = 0;
TCCR0 |= (1 << CS01);
TIMSK |= (1 << TOIE0);
TCNT0 = OSTimerValue;
SP = TCB[0].Stack + MCURegCount + 1;
sei();
__asm__ __volatile__("RETI /t" );
}
void OSEnterAtom(unsigned char IsAllowINT)
{
if (IsAllowINT == 0) cli();
OSAtomFlag = 1;
}
void OSLeaveAtom()
{
OSAtomFlag = 0;
sei();
}
unsigned char OSGetCurrentTaskID()
{
return OSCurrentTaskID;
}
unsigned long OSGetTickCount()
{
return OSTickCount;
}
unsigned long OSGetIdleCount()
{
return OSIdleCount;
}
// Semaphore
void OSPostSemaphore(unsigned char * Semaphore)
{
if (Semaphore == 0) return;
if (* Semaphore < 0xFF) * Semaphore += 1;
}
unsigned char OSWaitSemaphore(unsigned char * Semaphore, unsigned int Ticks)
{
if (Semaphore == 0) return;
if (* Semaphore > 0)
{
* Semaphore -= 1;
return 1;
}
// Semaphore = 0, suspend current task
if (Ticks)
{
TCB[OSCurrentTaskID].WaitTick = Ticks;
TCB[OSCurrentTaskID].Semaphore = Semaphore;
TCB[OSCurrentTaskID].Status = OSTaskWait;
OSDispatch();
}
if (* Semaphore > 0)
{
* Semaphore -= 1;
return 1;
}
return 0;
}
//*************************************************************************
#define uchar unsigned char
#define uint
unsigned int
#define ulong unsigned long
#define MaxReadSize 100
uchar ReadSize = 0, Sem = 0, ReadBuffer[MaxReadSize];
ISR(USART_RXC_vect)
{
uchar Data,Status;
Status = UCSRA;
Data = UDR;
if ((Status & ((1<<FE) | (1<<DOR) | (1<<PE))) != 0) return;
if (Data == 13)
{
UCSRB &= ~(1 << RXCIE);
OSPostSemaphore(&Sem);
return;
} else if (Data == 10) return;
if (ReadSize >= MaxReadSize) return;
ReadBuffer[ReadSize] = Data;
ReadSize++;
}
void UARTSend(unsigned char *pASCII, unsigned char Length)
{
uchar i;
if (Length == 0) Length = 0xFF;
for (i=0; i < Length; i++)
{
if ((Length == 0xFF) && (pASCII[i] == 0)) return;
while ( !(UCSRA & (1<<UDRE)) ) ;
UDR = pASCII[i];
}
}
void UARTEnableReceive()
{
ReadSize = 0;
UCSRB |= (1 << RXCIE);
}
#define sbi(port, bit) (port) |= (1 << (bit))
#define cbi(port, bit) (port) &= ~(1 << (bit))
#define nob(port, bit) (port) ^= (1 << (bit))
#define KBPort PORTB
#define KBDDR DDRB
#define KBPIN PINB
#define KBLine 7
uchar ScanKey()
{
uchar i, j, k;
for (i = 0; i < KBLine; i++)
{
KBDDR = 0x80; //use PB7 as LCD light output, but original is KBDDR = 0;
sbi(KBDDR, i);
KBPort = KBPort | 0x7F; //use PB7 as LCD light output, but original is KBPort = 0xFF;
cbi(KBPort, i);
j = ~(1<<i);
k = ~KBPIN;
k &= 0x7F; //added for use PB7 as LCD light output
if ((k & j) != 0)
{
OSDelay(1000);
if ((k & j) != 0) return ((k & j) | (1<<i));
}
}
return 0;
}
void UARTInit()
//初始化串口
{
UCSRC = (1<<URSEL) | 0x06;
//异步,8位数据,无奇偶校验,一个停止位,无倍速
UBRRL= (F_CPU/BAUDRATE/16-1)%256;
UBRRH= (F_CPU/BAUDRATE/16-1)/256;
UCSRA = 0x00;
UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN); //|(1<<TXCIE);
UDR=0;
}
void Task1()
{
unsigned char i, Text[16];
while (1)
{
i = ScanKey();
if (i)
{
sprintf(Text, "Key: %u/r/n", i);
OSEnterAtom(0);
UARTSend(Text, 0);
OSLeaveAtom();
}
}
}
void Task2()
{
unsigned char i, Text[32];
while (1)
{
i = OSWaitSemaphore(&Sem, OSInfinite);
OSEnterAtom(0);
if (i)
{
sprintf(Text, "CMD > [%u]/r/n", ReadSize);
UARTSend(Text, 0);
} else // these code never runs when Ticks = OSInfinite
UARTSend("Read Timeout/r/n", 0);
OSLeaveAtom();
UARTEnableReceive();
}
}
void Task3()
{
unsigned int i = 0;
unsigned char Text[48];
while (1)
{
i ++;
sprintf(Text, "TCC: %u, IC: %lu, OSTC: %lu/r/n", i, OSIdleCount, OSTickCount);
OSEnterAtom(0);
UARTSend(Text, 0);
OSLeaveAtom();
OSDelay(5000);
}
}
void InitMCU()
{
// init port
DDRA = 0x37;
DDRC = 0xFF;
DDRD = 0xFF;
PORTA = 0;
PORTC = 0;
PORTD = 0;
}
// global task stack
static unsigned char Stack[600];
int main (void)
{
InitMCU();
UARTInit();
OSInit();
OSCreateTask(Task1, Stack + 199);
OSCreateTask(Task2, Stack + 399);
OSCreateTask(Task3, Stack + 599);
OSExecute();
}