進化した8bitAVRマイコン"AVR Dx"をArduinoにしてみる。Atmega328PのArduinoでリソースが足りない場合の選択肢としていんじゃないかなって。タイマーを使ってみる。さて、正確なタイミングで動作させたいことが多い業界にいるのでタイマーで割り込み起こして処理をするってのをやってみる。とはいえ割り込みハンドラ内で条件分岐とかしてしまうと結局条件によってタイミングが変わってしまうので、回避する工夫も考える。個人的に好きなのは関数ポインタの配列を作っておいて、処理を開始する前に全条件分岐の結果による処理内容を配列にぶっこんでおくってやつ。まぁタイマー設定時間に対して余裕がある場合は処理した後に次の条件分岐をやっておくって手もよく使う。
で、UNO R3ではArduinoっぽくない書き方でタイマーを使うことが多かったけど、AVR128DB28はAtmega328Pと比較してタイマーの構成がまぁまぁ大きく変わっていて、調べるのがめんどくさいのでまずはライブラリがないかどうか探してみると、Dx_TimerInterruptってのがあるらしいので、これでチャレンジする。
Arduinoのライブラリマネジャでdx_で検索すると、
って感じで見つかるので、Installする。で、本家サイトはこちら(https://github.com/khoih-prog/Dx_TimerInterrupt/tree/main)
で、使い方がびみょーに変わっていて、ヘッダをインクルードする前にいくつかの条件を#defineするってかんじらしい。本家サイト見ただけではわからんくてカルくはまったけど、Arduino IDEからexampleを開いてみたら、あーそういうことかいってかんじです。
で、こんな感じで
-
#define USING_FULL_CLOCK true
-
#define USING_HALF_CLOCK false
-
#define USING_250KHZ false // Not supported now
-
#define USE_TIMER_0 false
-
#define USE_TIMER_1 true
-
#define USE_TIMER_2 false // Normally used by millis(). Don't use
-
#define USE_TIMER_3 false
-
#define USE_TIMER_4 false
-
#if USE_TIMER_0
-
#define CurrentTimer ITimer0
-
#elif USE_TIMER_1
-
#define CurrentTimer ITimer1
-
#elif USE_TIMER_2
-
#define CurrentTimer ITimer2
-
#elif USE_TIMER_3
-
#define CurrentTimer ITimer3
-
#elif USE_TIMER_4
-
#define CurrentTimer ITimer4
-
#else
-
#error You must select one Timer
-
#endif
-
#include "Dx_TimerInterrupt.h"
-
#define LED_PIN (19)
-
#define TIMER1_INTERVAL_MS 500
-
volatile bool PIN_STATE;
-
void TimerHandler1(void){
-
digitalWrite(LED_PIN,PIN_STATE);
-
PIN_STATE=!PIN_STATE;
-
}
-
void setup(){
-
pinMode(LED_PIN, OUTPUT);
-
-
Serial.begin(115200);
-
while (!Serial && millis() < 5000);
-
Serial.println(F("\r\nDx_TimerInterrupt test"));
-
CurrentTimer.init();
-
CurrentTimer.attachInterruptInterval(TIMER1_INTERVAL_MS, TimerHandler1);
-
}
-
void loop()
-
{
-
}
残メモリーがめちゃ多いってのに超感激するのは、ちょっと前にAtmega328PでSRAM使用率90%を超えるようなソフトを作ったからである。で、 なにか変なキャラクターをおもらししているみたいだけど、とりあえずUARTも動いている。で、 、、、あれ、1msもずれている。まぁ気にせずに攻めていく。attachInterruptIntervalだとmsオーダーでしか設定できないけど、attachInterruptにすれば周波数で設定できるので、usオーダーもいけるはず、で、
-
#define USING_FULL_CLOCK true
-
#define USING_HALF_CLOCK false
-
#define USING_250KHZ false // Not supported now
-
#define USE_TIMER_0 false
-
#define USE_TIMER_1 true
-
#define USE_TIMER_2 false // Normally used by millis(). Don't use
-
#define USE_TIMER_3 false
-
#define USE_TIMER_4 false
-
#if USE_TIMER_0
-
#define CurrentTimer ITimer0
-
#elif USE_TIMER_1
-
#define CurrentTimer ITimer1
-
#elif USE_TIMER_2
-
#define CurrentTimer ITimer2
-
#elif USE_TIMER_3
-
#define CurrentTimer ITimer3
-
#elif USE_TIMER_4
-
#define CurrentTimer ITimer4
-
#else
-
#error You must select one Timer
-
#endif
-
#include "Dx_TimerInterrupt.h"
-
#define LED_PIN (19)
-
//#define TIMER1_INTERVAL_MS 500
-
#define TIMER1_INTERVAL_HZ 20000.0
-
volatile bool PIN_STATE;
-
void TimerHandler1(void){
-
digitalWrite(LED_PIN,PIN_STATE);
-
PIN_STATE=!PIN_STATE;
-
}
-
void setup(){
-
pinMode(LED_PIN, OUTPUT);
-
-
Serial.begin(115200);
-
while (!Serial && millis() < 5000);
-
Serial.println(F("\r\nDx_TimerInterrupt test"));
-
CurrentTimer.init();
-
//CurrentTimer.attachInterruptInterval(TIMER1_INTERVAL_MS, TimerHandler1);
-
CurrentTimer.attachInterrupt(TIMER1_INTERVAL_HZ, TimerHandler1);
-
}
-
void loop()
-
{
-
}
まぁちゃんとできているようです。では任意のデータ(いわゆるNRZデータ)を送ってみます。タイマー割込ハンドラで都度判定すると、タイミングがおかしくなっちゃうので、タイマー開始前に動きを関数配列にぶっこんでおく。
-
#define USING_FULL_CLOCK true
-
#define USING_HALF_CLOCK false
-
#define USING_250KHZ false // Not supported now
-
#define USE_TIMER_0 false
-
#define USE_TIMER_1 true
-
#define USE_TIMER_2 false // Normally used by millis(). Don't use
-
#define USE_TIMER_3 false
-
#define USE_TIMER_4 false
-
#if USE_TIMER_0
-
#define CurrentTimer ITimer0
-
#elif USE_TIMER_1
-
#define CurrentTimer ITimer1
-
#elif USE_TIMER_2
-
#define CurrentTimer ITimer2
-
#elif USE_TIMER_3
-
#define CurrentTimer ITimer3
-
#elif USE_TIMER_4
-
#define CurrentTimer ITimer4
-
#else
-
#error You must select one Timer
-
#endif
-
#include "Dx_TimerInterrupt.h"
-
#define LED_PIN (19)
-
#define TIMER1_INTERVAL_HZ 20000.0
-
volatile uint8_t send_pos;
-
uint8_t send_pattern[]={0xAA,0xAA,0xCC,0x33,0x6A,0x0F,0x9C,0x51,0x55,0x55};
-
uint8_t send_pattern_len=77;
-
void (*funcarray[256])(void);
-
void func0(void){
-
digitalWrite(LED_PIN,LOW);
-
}
-
void func1(void){
-
digitalWrite(LED_PIN,HIGH);
-
}
-
void Generate_funcarray(){
-
uint8_t i,j,k,sdat;
-
uint8_t nbyte,nbit;
-
nbyte=send_pattern_len>>3;
-
nbit=send_pattern_len-nbyte*8;
-
k=0;
-
for(i=0;i<nbyte;i++){
-
sdat=send_pattern[i];
-
for(j=0;j<8;j++){
-
if(sdat&0x80){
-
funcarray[k]=func1;
-
}else{
-
funcarray[k]=func0;
-
}
-
sdat=sdat<<1;
-
k=k+1;
-
}
-
}
-
if(nbit>0){
-
sdat=send_pattern[i];
-
for(j=0;j<nbit;j++){
-
if(sdat&0x80){
-
funcarray[k]=func1;
-
}else{
-
funcarray[k]=func0;
-
}
-
sdat=sdat<<1;
-
k=k+1;
-
}
-
}
-
}
-
void TimerHandler1(void){
-
funcarray[send_pos]();
-
send_pos=send_pos+1;
-
}
-
void setup(){
-
pinMode(LED_PIN, OUTPUT);
-
-
Serial.begin(115200);
-
while (!Serial && millis() < 5000);
-
Serial.println(F("\r\nDx_TimerInterrupt test"));
-
Generate_funcarray();
-
send_pos=0;
-
CurrentTimer.init();
-
CurrentTimer.attachInterrupt(TIMER1_INTERVAL_HZ, TimerHandler1);
-
}
-
void loop()
-
{
-
if(send_pos>=send_pattern_len){
-
CurrentTimer.pauseTimer();
-
delay(100);
-
send_pos=0;
-
CurrentTimer.setCount(0);
-
CurrentTimer.resumeTimer();
-
}
-
}
FusionPCBはこんな状況。
いつもよりちょっと遅いような。かつて一度だけあるけど、データ不備とかあるとメンドクサイよな。まぁ、すすまんなーと思いながら見ていると、突然、発送しましたメールが来ることもあるのでゆるーく待つ。そもそもこの値段で輸送込みで2週間弱で届くんだから、すごいことよ。
コメントをお書きください