[Embedded Software] 경희대 임베디드 소프트웨어 과제6 - Semaphore in uC/OS-II
on Study
개발 환경
- 개발보드 : JKIT-128-1
- MUC : ATmega128
- OS : uC/OS-II
- Editor : WinAVR Progrmmers Notepad
- Compiler : WinAVR
uC/OS-II
C 언어 기반으로 작성된 마이크로프로세서를 위한 저비용 우선순위 기반 선점형 실시간 운영체제 커널 위키백과
uC/OS-II File Structure
Task state Diagram in uC/OS-II
실습 내용
FND task를 분초 시계로 변경하고, LED task에서 1초마다 수행시키도록 semaphore를 사용하여 동기화 (이 방법은 FND가 1의 자리만 출력되는 문제점이 존재한다.)
// lab7.c 코드
#include "includes.h"
#define F_CPU 16000000UL // CPU frequency = 16 Mhz
#include <avr/io.h>
#include <util/delay.h>
// 사용할 태스크의 수는 2이며 이 테스크의 스택 사이즈는 os_cfg.h에 선언한 값으로 정한다.
#define TASK_STK_SIZE OS_TASK_DEF_STK_SIZE
#define N_TASKS 2
OS_STK TaskStk[N_TASKS][TASK_STK_SIZE];
// 세마포 변수
OS_EVENT *Sem;
void LedTask(void *data);
void FndTask(void *data);
int main (void)
{
OSInit();
OS_ENTER_CRITICAL();
TCCR0=0x07;
TIMSK=_BV(TOIE0);
TCNT0=256-(CPU_CLOCK_HZ/OS_TICKS_PER_SEC/ 1024 );
OS_EXIT_CRITICAL();
OSTaskCreate(LedTask, (void *)0, (void *)&TaskStk[0][TASK_STK_SIZE - 1], 0);
OSTaskCreate(FndTask, (void *)0, (void *)&TaskStk[1][TASK_STK_SIZE - 1], 1);
OSStart();
return 0;
}
void LedTask (void *data)
{
data = data;
// 크리티컬 섹션 앞에서 세마포 생성
Sem = OSSemCreate(0);
DDRA = 0xff;
while (1) {
PORTA = 0xaa;
OSTimeDlyHMSM(0, 0, 0, 500);
PORTA = 0x55;
OSTimeDlyHMSM(0, 0, 0, 500);
// 세마포 반환
OSSemPost(Sem);
}
}
void FndTask (void *data)
{
unsigned char FND_DATA[ ]= {
0x3f, // 0
0x06, // 1
0x5b, // 2
0x4f, // 3
0x66, // 4
0x6d, // 5
0x7d, // 6
0x27, // 7
0x7f, // 8
0x6f, // 9
0x77, // A
0x7c, // B
0x39, // C
0x5e, // D
0x79, // E
0x71, // F
0x80, // .
0x40, // -
0x08 // _
};
unsigned int num=0, num0, num1, num2, num3;
INT8U err;
data = data;
DDRC = 0xff;
DDRG = 0x0f;
PORTC = FND_DATA[0];
PORTG = 0x01;
while(1) {
// 세마포 사용
OSSemPend(Sem, 0, &err);
num++;
num3 = (num / 1000) % 10;
num2 = (num / 100) % 10;
num1 = (num / 10) % 10;
num0 = num % 10;
PORTC = FND_DATA[num3];
PORTG = 0x08;
_delay_ms(2);
PORTC = FND_DATA[num2];
PORTG = 0x04;
_delay_ms(3);
PORTC = FND_DATA[num1];
PORTG = 0x02;
_delay_ms(2);
PORTC = FND_DATA[num0];
PORTG = 0x01;
_delay_ms(3);
}
}
실습 응용
FndDisplayTask를 추가하여 실습 내용의 문제점을 수정(Mutex를 사용하여 FndTask와 FndDisplayTask 사이의 공유변수 보호)
// lab7.c
#include "includes.h"
#define F_CPU 16000000UL // CPU frequency = 16 Mhz
#include <avr/io.h>
#include <util/delay.h>
// FndDisplayTask의 추가로 태스크 수 변경
#define TASK_STK_SIZE OS_TASK_DEF_STK_SIZE
#define N_TASKS 3
OS_STK TaskStk[N_TASKS][TASK_STK_SIZE];
// 세마포 변수와 뮤텍스 변수 선언
OS_EVENT *Sem;
OS_EVENT *Mutex;
volatile unsigned int num=0, num0, num1, num2, num3;
void LedTask(void *data);
void FndTask(void *data);
void FndDisplayTask(void *data);
int main (void)
{
OSInit();
OS_ENTER_CRITICAL();
TCCR0=0x07;
TIMSK=_BV(TOIE0);
TCNT0=256-(CPU_CLOCK_HZ/OS_TICKS_PER_SEC/ 1024 );
OS_EXIT_CRITICAL();
// 멀티 태스크
OSTaskCreate(LedTask, (void *)0, (void *)&TaskStk[0][TASK_STK_SIZE - 1], 1);
OSTaskCreate(FndTask, (void *)0, (void *)&TaskStk[1][TASK_STK_SIZE - 1], 2);
OSTaskCreate(FndDisplayTask, (void *)0, (void *)&TaskStk[2][TASK_STK_SIZE - 1], 3);
OSStart();
return 0;
}
void LedTask (void *data)
{
data = data;
// 세마포 변수 생성
Sem = OSSemCreate(0);
DDRA = 0xff;
while (1) {
PORTA = 0xaa;
OSTimeDlyHMSM(0, 0, 0, 500);
PORTA = 0x55;
OSTimeDlyHMSM(0, 0, 0, 500);
// 세마포 반환
OSSemPost(Sem);
}
}
void FndTask (void *data)
{
// 뮤텍스 변수 생성
Mutex = OSMutexCreate(0, OS_ERR_CREATE_ISR);
while(1) {
// 세마포 사용
OSSemPend(Sem, 0, OS_ERR_CREATE_ISR);
num++;
num3 = (num / 1000) % 10;
num2 = (num / 100) % 10;
num1 = (num / 10) % 10;
num0 = num % 10;
}
}
void FndDisplayTask(void *data) {
unsigned char FND_DATA[ ]= {
0x3f, // 0
0x06, // 1
0x5b, // 2
0x4f, // 3
0x66, // 4
0x6d, // 5
0x7d, // 6
0x27, // 7
0x7f, // 8
0x6f, // 9
0x77, // A
0x7c, // B
0x39, // C
0x5e, // D
0x79, // E
0x71, // F
0x80, // .
0x40, // -
0x08 // _
};
INT8U err;
data = data;
DDRC = 0xff;
DDRG = 0x0f;
PORTC = FND_DATA[0];
PORTG = 0x01;
while(1) {
// 뮤텍스 사용
OSMutexPend(Mutex, 0, OS_ERR_CREATE_ISR);
PORTC = FND_DATA[num3];
PORTG = 0x08;
_delay_ms(2);
PORTC = FND_DATA[num2];
PORTG = 0x04;
_delay_ms(3);
PORTC = FND_DATA[num1];
PORTG = 0x02;
_delay_ms(2);
PORTC = FND_DATA[num0];
PORTG = 0x01;
_delay_ms(3);
// 뮤텍스 반환
OSMutexPost(Mutex);
}
}