ページ移動

エントリー

タグ「ATtiny13a」の検索結果は以下のとおりです。

導通チェッカーの作製

導通を確認するのにテスタを使用しているが「電源ON]「ダイヤル回す」「導通ボタンを押す」を行うのが面倒(だと思っていた)

この際なので導通チェッカを作製することにし参考は沢山あるだろうとネットを検索

多くは電源電圧をそのまま印加するような仕組みで電子回路には怖くて使えそうにないが,まともな導通チェッカーの1つとして見つけた,ELM ChaN氏が2008年に製作された「回路内導通チェッカ」を使わせていただくことにした(air variable 氏の「LMC555使用導通チェッカー」も魅力ではあった)

開発環境もあるし簡単に作製できるだろうと思っていたらいろんな問題(課題でもある)が発生し時間を費やしてしまう

材料

廃却したマザーボードの圧電ブザーと水銀電池ボックス部分を置いてあったので取り外して使う

IMG_20230611_135020.jpg

ATTiny13aは¥50の時に購入したのがある

開発環境

最新の「arduino-2.1.0」,前バージョンの「arduino-1.8.13」でもArdinoISPによるATTiny13aのスケッチ書き込みが不可になっている

書込装置がメニュに出てこないことが問題でこちらを参考に対応してみたがArdinoISPでは不可であった(ATtiny85は対応されているので調査すれば何とかなりそうには思えるが後回し)

更に前のバージョンである「arduino-1.8.10」を使用

デバッグには使えるソフトシリアルポートが無い(pinの空きが無い) ためBlink()で判定

タイマー使用できず

CPUクロック異なるためソフトdelayを使っていたのをタイマーにしようとしたらPWMピンを使用していたので不可

delay()で良いのに気づかずCPU速度でWAIT調整しソフトdelay_msを作製(後に必要ないので移行して削除)

尚,CPUクロックは9.6MHzで開発して最後に消費電力削減のため1.2MHzに落とした

ブザー音

ブザーの仕様が不明だったのでアナログ発信器を作り1kHz前後で発音することを調査

IMG_20230613_090427.jpg

ADC

delayを使った待ち動作では正常に読めないのでフラグ待ちに修正

ADCSRA = _BV(ADEN)|_BV(ADSC)|(0b100);
loop_until_bit_is_set(ADCSRA, ADIF);
uint16_t ad = ADC;
消費電力

CPUクロック9.6MHzで,スリープ時48mA,通常時で20~50mAもありこれでは電源SWなしでは使えない

IMG_20230613_091030.jpg

調査したところブザーピン(PB1)がスリープ時もHIGHになっていて消費していることが判明

PWM使用にてタイミングによってHIGHになってしまうことがあるようで強制的にPB1をLOW(0)に設定してもLOWにはならない

そこでブザーを鳴らす時つまりPWM出力時にPB1を出力ピンにして,ブザーを止める時に出力ピンをOFFにすることで対処してみたらOKとなる

void beep(uint8_t t)
{
if(t) {
DDRB = _BV(PIN_BZR);
OCR0A = t;
OCR0B = t / 2;
TCCR0A = _BV(COM0B1)|_BV(WGM01)|_BV(WGM00); //PWMの動作を指定(PB1出力,8ビット高速PWM動作)
TCCR0B = _BV(WGM02)|0b011; //WGM02|WGM01|WGM00で高速PWM動作
//CS2|CS1|CS0 = 0b011 clkI/O/64 (64分周)
} else {
TCCR0B = _BV(WGM02); //停止
DDRB &= ~_BV(PIN_BZR);
}
}

スリープ前に出力ピンをOFFでも良い(オリジナルはスリープ前に初期化しているようだ)

クロックも下げて再度消費電力を測定しようとしたが手持ちのテスター(60μAレンジのテスターでも)では測定できなくなってしまった(突入電流が僅かなのか起動しない)

PWM

ATTiny13aのPWM関係のレジスタ制御が思うようにいかない

例えばPB1に出力する場合で,

//OCR0A = (値);
OCR0B = (値);

出力されない(発音しない)

OCR0A = (値);
//OCR0B = (値);

出力する(発音)

OCR0A = 255;
OCR0B = 0;

出力する(255の発音)

OCR0A =(値);
OCR0B = 255;

出力されない(発音しない)

他のレジスタとの設定順もないようだ

前にPB0では発音できないこともあり拙者が持っているATTiny13aの不具合なのか(?)

回路図

オリジナルではPIN7(PB2)でスイッチを利用しているがこれをリセットスイッチに変更

(オリジナル)起動後,スリープ状態へ移行し,SW割り込みでウエイクアップし導通チェック開始,SWかタイムアウトでスリープへを繰り返す

(変更)起動後,導通チェック開始,タイムアウトでスリープ,リセットで再起動の繰り返し(更にリセットを電源SWにすればバッテリー持ちが向上する)

他の変更点(PSWはタクトスイッチ使用→タクトスイッチの図が大きいので代わり)

  • LEDの極性
  • 圧電ブザーの抵抗(チップ保護)
  • タイムアウトは1分間

導通チェッカーV2_回路図.png

スケッチ)(UTF-8N,TAB4,LF)

オリジナルのリメイク版(ブレッドボードで試作)

導通チェッカー_回路図.png

オリジナルのリメイク版スケッチ)(UTF-8N,TAB4,LF)

消費電力を含め動作的には完成

IMG_20230614_193859.jpgIMG_20230614_193940.jpg

操作ボタンとLEDは高さを合わせ,一番高さのある圧電ブザーの逆サイドに実装

ケースに重量が欲しいのでコイン電池ではなく1.2V×3本バッテリーを使用予定

ケース

いつものとおり3Dプリンタでケースを作製

IMG_20230616_103046.jpgIMG_20230616_102534.jpg

(←)表,(→)裏,(↓)中身

IMG_20230616_102518.jpg

ATtiny開発ボードの改版

新しい開発ボードを作成

IMG_20191006_214828697.jpg

改版した理由は

  • ATtiny85対応
  • チップの差し替えをZIFソケットにしたかった
  • スケッチ書込みと動作試験時のピン切替を楽にしたい(ZIFの装着位置を変えることで切替)

ATtiny85には既存版でも対応されてはいるが新規一転の意味もある

ZIFソケットを採用するのは付け替えを簡単にするため

問題はピンの切り替えで,当初は短絡ピンでの切替だったをDIP-SWにする案を考えていたが16ピンのZIFソケットを観て位置を変えることで切り替えられることに気付いた

スケッチ書込み時は(写真で)左に挿入,動作させる時は(写真で)右に挿入する

電源は共通の5VでON/OFF SWを緑LED付きにした

既存版の3.3Vでの動作確認は5Vでの確認でも問題ないので削除した

リセットSWは動作試験用のみ(書込み時は1番ピンを使うため必要なし)

2番ピンは赤LEDを動作確認プログラム用(blink)に設置

3番ピンをデバック用シリアル出力にする予定

(ボードの確認)

ATtiny13aとATtiny85で書込みと試験位置動作を確認した

書込み時

IMG_20191012_194105738.jpg

試験時

IMG_20191012_194134306.jpg

DSO138に付けたロータリエンコーダ

DSO138に付けたロータリエンコーダ・・・使えない訳でではないのだが早く回すと今一つの動作なのは感じていた

そこでロータリエンコーダ制御プログラムの修正を行うことにした

//DSO138改造
//ロータリエンコーダを取り付け V1.40
//
// ロータリエンコーダの回転を割込みで処理
// A・B軸割込みを全て受けて前回と今回でインデックス処理し回転カウントを蓄積
// メインループでは蓄積された量によってボタンをエミュレートする回数を決める
// 蓄積が少ない多いでロータリエンコーダの回転速度を判定し
// 初回をある程度の回数をボタン1回とし残りはボタン1回とする数を変動する
// 現在は2段階にしている
//
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

#define EN_A PB0
#define EN_B PB1
#define OUT1 PB2
#define OUT2 PB3

#define BTNON_TIME_US   (20000)   //ボタンON時間
#define BTNOFF_TIME_US  (10000)   //ボタンOFF時間
#define RT_FIRST_COUNT  (3)       //初回回転カウント数(クリック付きでは1クリック4なので4以下が望ましい)
#define RT_NEXT_COUNT   (2)       //初回以降の回転カウント数

//回転方向テーブル
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
// 0 + - 0 - 0 0 + + 0 0 - 0 - + 0
// 0: 静止,無効,+: 右,-: 左
static const int dir[] = { 0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0 };
static int count = 0;
static int prev = 0;

//ロータリー動作割込み:前回値と今回値でインデックスを作り回転方向を蓄積
ISR(PCINT0_vect) {
int current = (PINB&0x03);
if(prev != current) { //チャタリング対応
int index = ((prev<<2) + current) & 0x0f;
count += dir[index];
prev = current;
}
}

void setup() {
//内蔵のプルアップ抵抗を有効にする場合は、DDRxで該当のピンを入力にした後
//そのピンをHIGHに設定する(有効にしない場合はLOWに設定する)
DDRB = (_BV(OUT1)|_BV(OUT2)); //pinMode(OUT1, OUTPUT); pinMode(OUT2, OUTPUT);
PORTB |= _BV(EN_A); //pinMode(EN_A, INPUT_PULLUP);
PORTB |= _BV(EN_B); //pinMode(EN_B, INPUT_PULLUP);
PORTB |= _BV(OUT1); //digitalWrite(OUT1, HIGH);
PORTB |= _BV(OUT2); //digitalWrite(OUT2, HIGH);

GIMSK |= (1<<PCIE); //PCINT割込みを有効
PCMSK = _BV(EN_A) | _BV(EN_B); //割込み許可ポートの設定
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}

void loop() {
int dt;
boolean cont_flg = false; //連続中フラグ
int cont_cnt = 0; //連続中の前回残りカウント

for(;;) {
cli(); //割り込み禁止
dt = count;
count = 0;
sei(); //割り込み許可

if(dt == 0) {
//今回カウントが0なら回転を止めたと判断
//残りもリセットしてスリープ,残りカウントはクリアしないほうが良さそう
cont_flg = false;
// cont_cnt = 0;
sleep_mode();
} else {
dt += cont_cnt;
if(cont_flg) {
//継続
if(dt > 0) {
//右回転(+)
while(dt >= RT_NEXT_COUNT) {
PORTB &= ~_BV(OUT1); //digitalWrite(OUT1, LOW);
_delay_us(BTNON_TIME_US);
PORTB |= _BV(OUT1); //digitalWrite(OUT1, HIGH);
_delay_us(BTNOFF_TIME_US);
dt -= RT_NEXT_COUNT;
}
} else {
//左回転(-)
while(dt + RT_NEXT_COUNT <= 0) {
PORTB &= ~_BV(OUT2); //digitalWrite(OUT2, LOW);
_delay_us(BTNON_TIME_US);
PORTB |= _BV(OUT2); //digitalWrite(OUT2, HIGH);
_delay_us(BTNOFF_TIME_US);
dt += RT_NEXT_COUNT;
}
}
cont_cnt = dt;
} else {
//初回
//クリック1回分のカウントがあれば実行
if(dt >= RT_FIRST_COUNT) {
//右回転(+)
PORTB &= ~_BV(OUT1); //digitalWrite(OUT1, LOW);
_delay_us(BTNON_TIME_US);
PORTB |= _BV(OUT1); //digitalWrite(OUT1, HIGH);
_delay_us(BTNOFF_TIME_US);
cont_cnt = dt - RT_FIRST_COUNT;
cont_flg = true;
} else if(dt + RT_FIRST_COUNT <= 0) {
//左回転(-)
PORTB &= ~_BV(OUT2); //digitalWrite(OUT2, LOW);
_delay_us(BTNON_TIME_US);
PORTB |= _BV(OUT2); //digitalWrite(OUT2, HIGH);
_delay_us(BTNOFF_TIME_US);
cont_cnt = dt + RT_FIRST_COUNT;
cont_flg = true;
} else {
cont_cnt = dt;
}
}
}
}
}

使用しているロータリエンコーダはクリック付きの物であり1クリックで4回のカウントが出るので単純に4回を1回として数えるだけとかクリックを無視して全カウントを数えるとか試行してみたが操作性が良くならなかった

ロータリエンコーダの動作を得てもボタンのエミュレート処理の方で遅延が発生するためリアルタイムに処理できないためである

テストプラグラムでは右回転だけしていてもチャタリングや高速回転で処理が追い付かない場合もあるのか左回転と判断してしまう事もあることが判っている

そこで最終的に回転結果をQue化にすることにした

Queといっても1つずつ取り出して処理する必要はないので回転数をカウントしておくカウンタであり溜まったカウンタの数から回転速度を想定しボタンエミュレートする

今回は2段階速度の判定で操作性が十分になった

最後に

プログラムは難しいものでないので速攻で出来た・・・のだけど・・・実は思うように動作しないバグがあって情けないことに解決まで3時間位掛かった

デバッグコードが埋め込めないので動作予想できる範囲でコードをコメントアウトしながらデバッグした結果

以下が問題だったことがやっとこさ判る

static const byte dir[] = { 0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0 };

サイン付きデータなのにサイン無しのbyteになっていたのである

書き換え前はサイン無しデータ(元は-1は2)だったので変更するのを忘れてしまっていた

しかしこれはコンパイラでwarning出して欲しい(それともメッセージ設定があって設定するのをミスってるのかな?)

3.6Vの組充電池用充電器の試作

秋月電子のニッケル水素電池パックは安価で何かと使える3.6V充電池である

IMG_20170903_153320.jpg

これまで(リポを外した)ダイソーのUSB充電ライターの充電機能を利用して充電していた(真ん中のパーツ)

充電は問題なくできるのだがリポ用のため完全な満充電にはならないのが欠点

今後充電する事が増えそうなので専用の充電器を作製しようとしたら実は半年前に作製しようと設計していた(いろいろあって中止し忘れてしまっていたようだ)

diagram.png

ATTINY13aで充電制御する方式で設計,スケッチがまだなのでプログラミングしていたが,今のところ先日の充電器で十分なため記録だけにしておく(他に完了させないといけない物があるので落ち着いたら組み立てる予定)

上記の回路は問題があり正常に充電できません!(Nch FETにして,スケッチを修正,印加電圧も要調整)

暫定仕様
  • 全体の8~9割までは500mAの急速充電
  • 残りの1~2割は50%位で充電
  • 最終充電電圧を10秒間保持できていたら充電完了
  • LEDの点滅具合で充電状態が判るようにする
スケッチ
//
// ATMEL ATTINY13 / ARDUINO
//
//                 +-\/-+
// ADC0 (D 5) PB5 1|   |8 Vcc
// ADC3 (D 3) PB3 2|    |7 PB2 (D 2) ADC1
// ADC2 (D 4) PB4 3|    |6 PB1 (D 1) PWM1
// GND            4|   |5 PB0 (D 0) PWM0
//                 +----+
// 1: Reset
// 2: LED
// 3: Serial Out
// 4: GND
// 5: PWM(FET SW)
// 6:
// 7: ADC(充電池電圧確認)
// 8: Vcc 3.3V
//
#include <avr/io.h>

#define BAUD_RATE 38400
#include <BasicSerial3.h>

#define PIN_ADC 1   //PB2(ADC1)
#define PIN_LED PB3 //LED
#define PIN_OUT PB4 //SerialOut(Debug)
#define PIN_FET PB0 //FET

#define MCHR_VOLT (1400*3) //最大充電終止電圧(mV)
#define LAST_VOLT (1420*3) //充電終止電圧(mV)

static void serOut(const char *str) {
while(*str) TxByte(*str++);
}

//確認用シリアル出力
static void voltOut(int v) {
char bf[8];

itoa(v, bf, 10); //10は十進数
serOut(bf);
serOut("mV\r\n");
}

//電圧(mV)
static int voltRead() {
    ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(0<<ADIF)|(0<<ADIE)|(0b100);
//ADC#3
    loop_until_bit_is_set(ADCSRA,ADIF); //ADC#4
    long v = (long)ADC; //long v = (long)analogRead(PIN_ADC);
    v *= 5000;                           //基準電圧5V
    v /= 1024;
    return((int)v);
}

void setup() {
    DIDR0 = _BV(PIN_ADC);                              //ADC#1: pinMode(PB2, INPUT);
    ADMUX = (0<<REFS0)|(0<<ADLAR)|PIN_ADC; //ADC#2: analogReference(DEFAULT);
    DDRB = (_BV(PIN_LED)|_BV(PIN_FET)|_BV(PIN_OUT));   //pinMode(PIN_LED, OUTPUT);
                                                       //pinMode(PIN_FET, OUTPUT);
                                                       //pinMode(PIN_OUT, OUTPUT);
    OSCCAL = 91;                           //87 - 96 (91, 92)
}

void loop() {
   int volt;

    serOut("Begin.\r\n");

    //MAX充電
   while((volt = voltRead()) < MCHR_VOLT) {
        voltOut(volt);
        PORTB |= _BV(PIN_LED);                         //digitalWrite(PIN_LED, HIGH);
        PORTB |= _BV(PIN_FET);                         //digitalWrite(PIN_FET, HIGH);
        delay(4000);
        PORTB &= ~_BV(PIN_LED);                        //digitalWrite(PIN_LED, LOW);
        delay(1000);
    }

    //残りを50%充電で完了させる
    int final = 5;
    do {
        voltOut(volt);
        PORTB |= _BV(PIN_LED);                         //digitalWrite(PIN_LED, HIGH);
        PORTB |= _BV(PIN_FET);                         //digitalWrite(PIN_FET, HIGH);
        delay(1000);
    PORTB &= ~_BV(PIN_FET);                        //digitalWrite(PIN_FET, LOW);
    PORTB &= ~_BV(PIN_LED);                        //digitalWrite(PIN_LED, LOW);
        delay(1000);
    if((volt = voltRead()) < LAST_VOLT) final = 5;
    } while(--final != 0);

//終了
serOut("End.\r\n");
PORTB &= ~_BV(PIN_LED);                            //digitalWrite(PIN_LED, LOW);
for(;;);
}
コードサイズ
  • arduinoのライブラリを利用すると1Kbytesを超えた
  • ADCを直接ハードウェア操作することで210bytes減る
  • その他も直接操作で最終的に780bytesになっている
  • 確認用のシリアル出力は削除できる
ADC関係
  • ADC#1: デジタル入力抵抗を無効(消費電流が減る)
  • ADC#2: REFS0=Reference: 0でVCC参照, 1で1.1V内部電圧源,ADLAR=0:右詰め,1:左詰め,下位2bitで00から11までADC0からADC3
  • ADC#3: ADEN=ADC有効,ADSC=ADC開始,ADIE=完了割込許可,下位3bitがクロック指定
  • ADC#4: ADIFビットが1の間はAD変換中

ページ移動

  • ページ
  • 1
  • 2

ユーティリティ

検索

エントリー検索フォーム
キーワード

過去ログ

Feed