PIC16F1454のタイマー処理を作ってみた。きりの悪いシステムクロックのおかげで一般的によく使う1ms割り込みが正確にできなくて少し悩んでしまったが、それはどう考えてもしょうがないので妥協。違うアプローチをとることにした。
まず、多くの方が結構やってるっぽい感じがあるタイマー割り込みの中でタイマー値を変更するような荒業はタイミング的に他の割り込みに影響されることがあるので却下。タイマーを止めたりするのも同じことなのでタイマーはフリーランさせる方法とする。
PIC16F1454の3つあるタイマーのうち一番汎用的に使えそうな8bitのタイマー0割り込みにより32bitカウンター変数をカウントアップする単純な方法であるが前述のようにmsやusなどの時間を正確に表現できないのでtick単位(カウンター値)で扱う仕様とする。時間とtick値との変換はマクロで行う。定数指定であればコンパイル時に変換されるので実行時の変換時間は気にしなくて良い。検算してみるとわかるが1秒指定での誤差はない。
2018-05-12
不必要なレジスタ設定の削除とタイマー値が時々不正な値になる不具合を修正。
【1秒間隔でLEDを点滅する例】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <xc.h> #include "tmr0.h" void interrupt sys_interrupts(void) { TMR0_ISR(); } void main(void) { uint32_t timestamp; INTCONbits.GIE = 1; TRISAbits.TRISA5 = 0; // OUTPUT tmr0_init(); timestamp = tmr0_read(); while(1) { if (tmr0_read() - timestamp >= TMR0_MS2TICK(1000)) { timestamp += TMR0_MS2TICK(1000); LATAbits.LATA5 ^= 1; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
/* * File: tmr0.h * Author: Sasapea's Lab * * Created on 2018/03/14 */ #ifndef _TMR0_H #define _TMR0_H #include <stdint.h> #ifndef SYS_FOSC #define SYS_FOSC 48000000 #endif ///////////////////////////////////////////// // Prescaler Setting's (SYS_FOSC=48MHz) // // max time(s) period(us) irq-cycle(us)// ///////////////////////////////////////////// // 0: 357.913, 0.083, 21.333 // // 1: 715.827, 0.166, 42.666 // // 2: 431.655, 0.333, 85.333 // // 3: 2863.311, 0.666, 170.666 // // 4: 5726.623, 1.333, 341.333 // // 5: 11453.246, 2.666, 682.666 // // 6: 22906.492, 5.333, 1365.333 // // 7: 45812.984, 10.666, 2730.666 // // 8: 91625.968, 21.333, 5461.333 // ///////////////////////////////////////////// #ifndef TMR0_PS #define TMR0_PS 8 // 0=1/1, 1=1/2, 2=1/4,...8=1/256 #endif #define TMR0_MS2TICK(t) ((t) * (uint32_t)(SYS_FOSC / 4 / 1000) / (1 << TMR0_PS)) #define TMR0_US2TICK(t) ((t) * (uint32_t)(SYS_FOSC / 4 / 1000000) / (1 << TMR0_PS)) #define TMR0_ISR() do { \ if (INTCONbits.TMR0IF) \ { \ tmr0_isr(); \ INTCONbits.TMR0IF = 0; \ } \ } while (0) void tmr0_isr(); void tmr0_init(); uint32_t tmr0_read(); #endif // _TMR0_H |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* * File: tmr0.c * Author: Sasapea's Lab * * Created on 2018/03/14 */ #include <xc.h> #include "tmr0.h" static volatile uint32_t _counter; void tmr0_isr() { _counter += 0x0100; } void tmr0_init() { OPTION_REGbits.TMR0CS = 0; OPTION_REGbits.PSA = !TMR0_PS; OPTION_REGbits.PS = TMR0_PS - 1; TMR0 = 0; INTCONbits.TMR0IF = 0; INTCONbits.TMR0IE = 1; } uint32_t tmr0_read() { union { uint8_t b[4]; uint16_t w[2]; uint32_t d; } x; do { x.b[1] = ((uint8_t *)&_counter)[1]; x.w[1] = ((uint16_t *)&_counter)[1]; x.b[0] = TMR0; } while (x.b[1] != ((uint8_t *)&_counter)[1]); return x.d; } |