DSO138の操作性改善に挑戦
今年の1月くらいにJYE Techから新しくDSO150なるオシロスコープキットが出て,スペック的にはDSO138とあまり変わらないが,ケースを追加しロータリエンコーダで操作するようになったようだ
ケース付きになって良さそう・・・最近Amazonでも取り扱い開始・・・しかも安いが,いわくつきだけどサインスマートのDSO138があるのでどうしようか・・・
そこで,DSO150を真似てDSO138を改造(改良かな?)してしまおうと考えた
サインスマートDSO138のメイン基板,キット制作時にコンデンサの変更やボタンを交換してある
ロータリーエンコーダ―を付ける
DSO150にはDSO138(DSO062も同じ)では操作性の悪い(+)(-)ボタンをロータリーエンコーダ―に変更してあり,ロータリーエンコーダ―の扱いも慣れてきたことだし(+)(-)ボタンを制御するようにすればいけそうなので付けてみる
ここでATMegaを使うのもオーバースペックでサイズ的にも組み込みしにくいのでATtiny13aでドライブすることにした
まずは実験・・・しようとしたが・・・嵌りまくった
開発環境で嵌る
昔構築したIDE1.6環境が怪しげなのでIDE1.8.1で新たに環境構築したが(全てにおいて)ボードへの書込みができない問題が発生
すったもんだして動くようになったがはっきりした原因は不明(つまり何をやったら動くようになったか特定できなかった)
おそらくとなるがhardwareフォルダに昔の情報データがあったため動作不良となっていたのではないか(hardwareフォルダ内で不必要なのは削除した)
開発支援ボードで嵌る
今回UNO互換ボードで(自己開発の)開発支援ボードを使ったがUNOに未対応だった
3.3Vピンがショートしていたり余計なピンが絶縁されていなかった設計不良が発覚(これまで3.3Vピンが出力されていないボードで動作させていたため)
シリアル出力で嵌る
シリアル出力されない場合があり原因不明(ノイズか?)
プログラム開発
コード1KBの世界なので苦労するかと思ったが1KBはやっぱ広い・・・と思うのはTK80やLKIT世代のせいか^^
ただしデータ64Bytesは辛い(PROGMEMもあるけど利用は要注意)
もっとハードウェアレジスタの直接操作でサイズを減らせるけど余裕あったので判りやすいコードで済ませた(とは思っている)
ATtiny13aのPB0とPB1をロータリーエンコーダ入力とし,PB2とPB3をそれぞれ+-ボタンとして出力する
//DSO138改造
//ロータリエンコーダを取り付け
//
#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 40000
//割込みはsleepから抜けるだけで処理は無い
ISR(PCINT0_vect) {}
void setup() {
pinMode(EN_A, INPUT_PULLUP);
pinMode(EN_B, INPUT_PULLUP);
pinMode(OUT1, OUTPUT);
pinMode(OUT2, OUTPUT);
digitalWrite(OUT1, HIGH);
digitalWrite(OUT2, HIGH);
GIMSK |= (1<<PCIE); //PCINT割込みを有効
PCMSK = _BV(EN_A) | _BV(EN_B); //割込み許可
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}
void loop() {
unsigned char dt = 0;
for(;;) {
//前回値と今回値でインデックスを作る
dt = ((dt<<2) + (PINB&0x03))&0x0f;
if(dt == 0x07) { //right
digitalWrite(OUT1, LOW);
_delay_us(BTNON_TIME_US);
digitalWrite(OUT1, HIGH);
} else if(dt == 0x0d) { //left
digitalWrite(OUT2, LOW);
_delay_us(BTNON_TIME_US);
digitalWrite(OUT2, HIGH);
} else {
sleep_mode();
}
}
}
制御プログラムは難なく完成したがボタンONーOFF間隔の設定調整に時間を費やした
ボタンONーOFF間隔はロータリーエンコーダの回転速度に(そこそこは)合わせないとスムーズにならない(早くても遅くても駄目)
尚,変化なし時のウエイトは無くても良いことを実働では確認
既にロータリーエンコーダ―化している方もいたので参考にはさせてもらっている
追加パーツは秋月D基板の取付穴が本体に整合したので右側に置いた
設定ボタンの複数化
DSO062では各設定項目の専用ボタンがあったがDSO138では6つの設定項目を1ボタンで順列選択する操作になった
DSO150ではグループ化して複数ボタンにしたようだ
同じようにするのはしゃくなのでボタンを3つにして選択できる設定項目をまとめた
DSO138の選択(select)ボタンで選択できる設定項目
- Horizonal Position
- Vertical Position Indicator
- Timebase(s/div)
- Trigger Mode
- Trigger Slope
- Trigger Level Indicator
3つのボタンを配置し以下のように割り当てた
- 1,2 :H/V.Pos
- 3 :S/Div
- 4,5,6:Trigger
PB1,PB2,PB3をグループ化したボタン入力とし,本体の設定項目選択ボタンに接続したPB4へ出力する
//DSO138改造
//機能ボタンを追加
//
#include <avr/io.h>
//#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
//接続PIN
#define HVPOS PB3 //PB0では動作しない(不明)
#define SECDIV PB1
#define TRIGGER PB2
#define BTNOUT PB4
#define BTNON_TIME_MS 40 //ボタンON時間
#define BTNOFF_TIME_MS 20 //ボタンOFF時間
static int btint = 0;
//外部ピン変化割込み
ISR(PCINT0_vect) {
//チャタリング10ms待ち
_delay_ms(10);
//ボタンの状態チェック(押下時のみ)
if(!bit_is_set(PINB, HVPOS)) {
btint = HVPOS;
}
else if(!bit_is_set(PINB, SECDIV)) {
btint = SECDIV;
}
else if(!bit_is_set(PINB, TRIGGER)) {
btint = TRIGGER;
}
}
void setup() {
//機能ボタン(入力)
pinMode(HVPOS, INPUT_PULLUP);
pinMode(SECDIV, INPUT_PULLUP);
pinMode(TRIGGER, INPUT_PULLUP);
//ハンドルボタン(出力)
pinMode(BTNOUT, OUTPUT);
digitalWrite(BTNOUT, HIGH);
//ピン変化割込み許可
GIMSK |= (1<<PCIE); //PCINT割込みを有効
//PCMSK = (1<<PCINT1)|(1<<PCINT2)|(1<<PCINT3);//PB1,2,3の割込み許可
PCMSK = (1<<HVPOS)|(1<<SECDIV)|(1<<TRIGGER);//割込み許可
sei();
}
// 0.Horizonal Position
// 1.Vertical Position Indicator
// 2.Timebase(s/div)
// 3.Trigger Mode
// 4.Trigger Slope
// 5.Trigger Level Indicator
void loop() {
int nowpos, movpos, btncnt;
//nowposを復旧
//(本体は電源OFFで記憶してなかったので処理を外す)
//eeprom_busy_wait();
//nowpos = (int)eeprom_read_byte((uint8_t *)0);
nowpos = 2;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
for(;;) {
//_delay_ms(1);
sleep_mode();
cli();
if(btint) {
switch(btint) {
case HVPOS:
if(nowpos == 0) {
movpos = 1;
//} else if(nowpos == 1) {
// movpos = 0;
} else {
movpos = 0;
}
break;
case SECDIV:
movpos = 2;
break;
case TRIGGER:
if(nowpos == 3) {
movpos = 4;
} else if(nowpos == 4) {
movpos = 5;
//} else if(nowpos == 5) {
// movpos = 3;
} else {
movpos = 3;
}
break;
}
if(movpos < nowpos) {
btncnt = movpos + 6 - nowpos;
} else {
btncnt = movpos - nowpos;
}
while(btncnt--) {
_delay_ms(BTNOFF_TIME_MS);
digitalWrite(BTNOUT, LOW);
_delay_ms(BTNON_TIME_MS);
digitalWrite(BTNOUT, HIGH);
_delay_ms(BTNOFF_TIME_MS);
}
nowpos = movpos;
//nowposを退避(本体は電源OFFで記憶してなかったので処理を外す)
//eeprom_busy_wait();
//eeprom_write_byte((uint8_t *)0, (uint8_t)nowpos);
btint = 0;
}
sei();
}
}
操作性はそこそこで(雰囲気がイメージでは判らないので上記画像選択でビデオが観えるようにした)劇的に良くなったとは言えない
スクロールする操作はボタンを押すよりロータリーエンコーダで良くなったとは思う
ボタン
赤:HOLDボタン,回路は本体のボタンと並列で付けている(ATtiny13aは感知しない)
黄:H/V.Posの切替
青:S/Div専用
黒:Trigger関係3箇所の選択
電源と電源SW
本オシロは家の中でもコンパクトなため扱いやすく見易い場所で利用することができるのがメリットである
しかしACアダプタではコンセントまでのケーブル取り回しが厄介なこともあり006Pの充電池(8.4V)を使用することが多い
だが電力消費が9V120mAあるため,連続使用時間が約1時間(持たないことも)程度となる
そこでコンパクトな電源の構想を延々と考えている
・・・小容量のバッテリの昇圧では厳しそう
・・・コンパクトで大容量なら2000mAh+クラスのリポで昇圧・・・だけど高価かな(スマホ充電用の5Vの旧品が安く出回ってはいる)
・・・電子ライターのリポを取り出し3個直列という方法は・・・もともと取扱に気を遣うリポを直列は面倒なので極力パス
・・・やはり単4ニッケル水素×7個か8個かな
電源は電源SWを含み検討中
その他(まとめ)
- ピンの余裕がないので機能別にATtiny13aを2個使用
- ケースは横幅が増えたため凝らない程度で作り直しする予定
- ATtiny13aの使い方を改めて検証できたのと,その開発ボードの欠点(欠陥かな)が判明したので満足
- こつこつと調整したので記事の公開が遅くなった(最終編集が4/2(日)となる)