[Embedded Software] 경희대 임베디드 소프트웨어 과제6 - Semaphore in uC/OS-II

경희대학교 컴퓨터공학과 조진성 교수님의 ‘임베디드 소프트웨어’ 강의의 과제입니다.


개발 환경



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);
    }
}