2012年4月30日月曜日

ARMで時間待ち関数

PICで時間待ちをしたい場合
delay_ms(n);やdelay_us(n);といった関数で(ほぼ)正確な時間待ちができますが
ARMにはそう言った関数が用意されていません
(たぶん)

正確な1秒であればRTCでも作れるので
1日に1回 というレベルの時間待ちならそれで十分ですが
マイクロ秒単位での時間待ちだと使えません
と言うことで
タイマ2を使用して(ほぼ)正確なウエイト処理を書いてみました
検証環境はSTBeeに例のごとくストリナの開発環境です




本体

void wait(int time) {
    TIM_SetCounter(TIM2, 0);
    IntrrCnt = time;
    while (IntrrFlag == RESET);
    IntrrFlag = RESET;
}


割り込みハンドラ

void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        if (IntrrCnt != 0) {
            IntrrCnt--;
            if (IntrrCnt == 0) {
                IntrrFlag = SET;
            }
        }
    }
}


初期化

void TIM2_init(void) {
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = 7200 - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = 10 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

    TIM_Cmd(TIM2, ENABLE);
}


こんな感じです
ハンドラの中身がカオスですが まぁそこら辺は各自改良してください
なお int型でカウト用の変数"IntrrCnt"とフラグ"IntrrFlag"が必要になります
カウンタはlong longでwait関数の引数もlong longにすればかなり長時間のウエイトができますが
intでもおそらく20日くらいは待てるので
それ以上待つならRTCを使ったほうが賢明だと思います
つーか 1時間以上なら1秒程度は誤差のうちなのでRTCでカウントしてください


なお「(ほぼ)正確な」というのは
wait関数を呼び出したり値を設定したりで微妙に待ち時間が発生するからです
最大で千分の1~5くらいだと思います


とりあえず こんな感じです
時間待ちのためにタイマ2を専用に割り当てるのは
なんかイヤですが...
あえて例えるなら仲の良い女の子が知らない男と談笑していた みたいな

誤差が大きくても(1~2ms)いいなら もうちょっと色々できますが
誤差が少ないほうが使いやすいという判断でこうなりました


ところで STBeeのRTC これ500mS毎に割り込みってできないのかな…

0 件のコメント:

コメントを投稿