SSブログ

Arduino AVRでマルチタスクしてみる タスク2 [ATmarquino Arduino]

avrMultiTask_002.png


ファイル名を変えずに中身を書き換えちゃったのは、まずかったかなぁ、、、

マルチタスクのサンプルとして、PWMで50Hzのサイン波を出力するデモ。
別途用意したスイッチを押す度に別途用意したLPFを通してサイン波が出力される。ただし10秒間掛けて波形はフェードアウトする。

/**********************************************************/
/* マルチタスクやってみる                                 */
/* PWMで50hzのサイン波を出力する。10秒掛けてフェードアウト。 */
/**********************************************************/
#include <avr/io.h>
#include <FlexiTimer2.h>
#include "delivertive.h"

extern "C"
{
  #include "mul_tsk.h"
}

/**********************************************************/
/* prototypes                                             */
/**********************************************************/
void tsk_ini( void );
void stackMonitor( void );
void switchScanTask( void );
void pwmGenerateTask( void );

/**********************************************************/
/* valiables                                              */
/**********************************************************/
SYSTIM systim;  // 1msでインクリメントする変数
uint8_t tsk0_stk[ 128 * 1 ];
uint8_t tsk1_stk[ 128 * 1 ];
uint8_t tsk2_stk[ 128 * 1 ];

#define  PWM_PIN      10
#define  TRIGGER_PIN  2
#define  LED_PIN      13

#define  TIMER_COUNTER_CLOCK  (8 * 1000000UL)
#define  PWM_FREQUENCY        (10 * 1000)
#define  RESOLUTION           (40)  /* 50hz * 40 over sampling. */
#define  DELTA_SLOPE          (1.0f / 500)

int scale = TIMER_COUNTER_CLOCK / PWM_FREQUENCY / 2;  /* 1000000 is timer clock */
int offset = TIMER_COUNTER_CLOCK / PWM_FREQUENCY / 2;  /* center position */
int waveTableCounter;
float slope = 1.0f - DELTA_SLOPE;  /* 10s = 20ms * 500 */
int originalWaveTable[ RESOLUTION ];
unsigned int waveTable[ RESOLUTION ];
unsigned char switchScanUpdate;
unsigned long timer1CompbIsrCounter;
bool conversionStart = false;

/**********************************************************/
/* setup                                                  */
/**********************************************************/
void setup()
{
  Serial.begin( 115200UL );
  Serial.println( "AVR Multi Task Demo." );

  /* ststem and pwm update timer start. */
  FlexiTimer2::set( 5, 1.0f / 10000, pwmUpdateHandler );
  FlexiTimer2::start();

  tsk_ini();  //タスクの初期化
  sta_rdq( ID_monitor );  //ラウンドロビン開始。ここからタスクが開始される
}

/**********************************************************/
/* loop ※使われない                                      */
/**********************************************************/
void loop()
{
}

/**********************************************************/
/* タスク初期化                                           */
/**********************************************************/
void tsk_ini( void )
{
  reg_tsk( ID_monitor, (void *)stackMonitor, (void *)tsk0_stk, sizeof(tsk0_stk), 0,0,0,0 );
  reg_tsk( ID_switchScan, (void *)switchScanTask, (void *)tsk1_stk, sizeof(tsk1_stk), 0,0,0,0 );
  reg_tsk( ID_pwmGenerate, (void *)pwmGenerateTask, (void *)tsk2_stk, sizeof(tsk2_stk), 0,0,0,0 );

  sta_tsk( ID_monitor );
//  sta_tsk( ID_switchScan );
//  sta_tsk( ID_pwmGenerate );
}

/**********************************************************/
/* stack monitor task                                     */
/**********************************************************/
static unsigned int RemainStack( void *stk, unsigned int sz );
static void stackPrint( const char *msg, void *stk, unsigned int sz );

void stackMonitor( void )
{
  sta_tsk( ID_pwmGenerate );
  while( 1 )
  {
    dly_tsk( 10 * 1000UL );
    stackPrint( "task1 stack : ", tsk1_stk, sizeof(tsk1_stk) );
    stackPrint( "task2 stack : ", tsk2_stk, sizeof(tsk2_stk) );
    stackPrint( "monitor stack : ", tsk0_stk, sizeof(tsk0_stk) );
  }
}

static void stackPrint( const char *msg, void *stk, unsigned int sz )
{
  Serial.print( msg );
  Serial.print( RemainStack( stk, sz ), DEC );
  Serial.print( "/" );
  Serial.println( sz, DEC );
}

static unsigned int RemainStack( void *stk, unsigned int sz )
{
  unsigned int i;
  char *ptr = (char *)stk;

  for( i = 0; i < sz; i++ )
  {
    if( *ptr++ != 0 ) break;
  }

  return sz - i;
//  return i;
}

/**********************************************************/
/* switchScanTask                                         */
/**********************************************************/
void switchScanTask( void )
{
  pinMode( TRIGGER_PIN, INPUT_PULLUP );
  unsigned char sw = 0x00;
  while( 1 )
  {
    sw <<= 1;
    if( digitalRead( TRIGGER_PIN ) == LOW ) sw |= 1;
    if( (sw & 0x0f) == 0x07 )
    {
      switchScanUpdate++;
    }

    dly_tsk( 50UL );
  }
}

/**********************************************************/
/* PWM Generate Task                                      */
/**********************************************************/
void pwmGenerateTask( void )
{
  pinMode( PWM_PIN, OUTPUT );
  digitalWrite( LED_PIN, LOW );
  pinMode( LED_PIN, OUTPUT );

  /* wave table generate. */
  for( int i = 0; i < RESOLUTION; i++ )
  {
    int tempI = (int)(sin( 2 * M_PI * i / RESOLUTION) * scale);
    originalWaveTable[ i ] = tempI;
    waveTable[ i ] = (unsigned int)tempI + offset;
    Serial.print( waveTable[ i ], DEC );
    Serial.print( "," );
    if( (i % 10) == 9 ) Serial.println();
  }

  /* start switch scan task. */
  sta_tsk( ID_switchScan );

  while( 1 )
  {
    /* wait for switch pushed. */
    unsigned char switchScanUpdateBase = switchScanUpdate;
    while( switchScanUpdateBase == switchScanUpdate ) dly_tsk( 50UL );
    switchScanUpdateBase = switchScanUpdate;
    Serial.println( "pwmGenerateTask PWM start." );

    /* timer counter initialize. */
    TCCR1B = 0x00;  //  timer1 stop
    TCNT1 = 0x0000;  // 16bit counter clear
    TIMSK1 = 0x00;  // interrupt disable
    TCCR1A = 0b00100011;  //  0b00 10 00 11
      // OC1A : normal port and not connected OC1A.
      // OC1B : compare match goes OC1B to clear and top goes OC1B to set.
      // fast PWM and top is OCR1A.
    TCCR1B = 0b00011001;  //  0b0 0 0 11 001
      // fast PWM and top is OCR1A.
      // clkIO / 1 priscaller.
    OCR1A = (unsigned int)(TIMER_COUNTER_CLOCK / PWM_FREQUENCY);
    OCR1B = waveTable[ 0 ];
    TIMSK1 = 0x00;

    /* interrupt timer start. */
    slope = 1.0f - DELTA_SLOPE;
    waveTableCounter = 1;
    conversionStart = true;
    digitalWrite( LED_PIN, HIGH );

    /* wait 10s. */
    dly_tsk( 11 * 1000UL );
    conversionStart = false;
    for( int i = 0; i < RESOLUTION; i++ )
    {
      int tempI = originalWaveTable[ i ];
      waveTable[ i ] = (unsigned int)tempI + offset;
    }
    Serial.println( "pwmGenerateTask PWM stop." );
    digitalWrite( LED_PIN, LOW );
  }
}

/**********************************************************/
/* pwm update handler                                     */
/**********************************************************/
void pwmUpdateHandler()
{
  static int count = 0;

  /* system timer update */
  if( count & 1 ) systim += 1UL;
  count++;

  if( conversionStart == true && slope >= 0.0f )
  {
    OCR1B = waveTable[ waveTableCounter ];
    float tempF = (float)originalWaveTable[ waveTableCounter ] * slope;
    waveTable[ waveTableCounter ] = (unsigned int)tempF + offset;
    if( ++waveTableCounter >= RESOLUTION )
    {
      waveTableCounter = 0;
      slope -= DELTA_SLOPE;
    }
  }
}


nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。