2013年11月15日金曜日

フリスクケースで電圧計

こんばんは、kohtaです。

フリスクのケースに回路を載せる工作を載せた工作は、割と見かける気がします。
経験のある人は多いと思います(?)
ケースを使うためにフリスクを買う人も多いのではないでしょうか。

今回は(と言っても作ったのは今年の7月ごろだが)フリスクのケースを用いて電圧計を制作しました。面倒なのでこれ以降、フリスクのケースをフリスクと呼びます。

このプロジェクトwは、2つの実験的な要素を含んでいます。その要素は次の2つです。

  1. 大きな7セグをフリスクに収める
  2. ADCのついていないマイコンATTiny2313でAD変換をする
……などと言ってみましたが、単に部品が余っていたので作りました。

~ハードウェアの制作~

フリスクのケースの内寸法は、小部屋と突起を切り取ると67.2*27.7*8.5 mmです。
このケースに入る7セグLEDを探したところ、10mmくらいの小さな物しか見つかりませんでした。
LEDはなるべくケースから飛び出させたくありません。
しかし、小さなLEDでは見にくいです。なるべく大きな7セグLEDを使いたいと思いました。
そこで、文字高さ14mmの7セグLEDを少し加工して使うことにしました。
ちなみにこれとか、 これとか、 これ です。
また基板はt=0.8mmで片面基板とすることで、フリスクの蓋とLEDの面を面一にできました。


 LEDを表面実装するのです。
また、マイコンも同じようにピンを曲げて表面実装型にします。(表面実装パッケージのものも売っていますがあるものだけで作りたいという趣旨があります)


プリント基板は、(不)安定の熱転写方式で自作


部品を実装するとこのようになりました。

フリスクケースのほうも加工します。小部屋をカッターで切り取り、蓋をドリルとヤスリで穴を開けます。バリ取りはカッターを使うと綺麗にできます。

~回路の設計~
 主に自動車で使うことを想定したものにしてみました。測定範囲は6~30Vで、電源と測定端子は共通にします。共通にすると内部抵抗が下がり、精度が悪くなりますが、妥協しましょう。
回路図を下図に示します。 
 
 まず電源の6~30Vを5Vに降圧します。7セグLEDはマイコンATTiny2313に直結しました。ダイナミック・ドライブします。アノードコモンのLEDを使いましたが、プログラミングを変えればカソードコモンも使えるはずです。
ATTiny2313にはAD変換器が付いていませんが、ATTiny2313にはアナログコンパレータが付いているので100uAの定電流ダイオードとコンデンサを外付しAD変換器を作りました。測定電圧は、ツェナーダイオードで降圧し、分圧したのちAVR ATTiny2313に入力しています。


~プログラムの制作~
 AVRのプログラムをCで書きます。
タイマ割り込みでLEDをドライブして、mainで測定の処理をしました。

AD変換の原理について
 コンデンサを定電流で充電すると、コンデンサの端子電圧は、直線的に増加します。
式で表すと、
 Vc = (i/C) * t
 (Vc…コンデンサの電圧、i…電流、C…コンデンサの容量、t…時間)
となります。

そして、ATtiny2313にはアナログコンパレータがついています。
コンパレータとは、2つの電圧の大小を比較するものです。

コンデンサの電圧と測定したい電圧を比較し、コンデンサの電圧が測定電圧より上回るまでの時間を計測すればAD変換の値を得ることができます。



より具体的に表すと、
  1. コンデンサを0Vまで放電させる
  2. コンデンサを充電開始 & 時間をカウント開始
  3. コンパレータの出力が変わったところでカウントストップ
  4. カウントの値が測定電圧(に比例した数)
となります。

ここで重要なのは、コンデンサや分圧抵抗、ツェナーダイオードの精度、クロック源の精度です。
これらを測定していって真面目に計算するのは結構大変なので、最初に適当なプログラムを作り、入力した電圧と、出てきたAD変換の値から逆算しました。
また、AD変換器のコンデンサは特性の良いフィルム系の物を使います。セラミックコンデンサは向きません。


実際に組んだプログラムです。(汚いのは勘弁w
/*********************************
  電圧計
  ○○○○○○○○○○○○○○○○
*********************************/
#define F_CPU 12000000UL //12.0MHz

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>

// グローバル変数
char keta = 0;
volatile int num = 0;
volatile unsigned long volt = 0;

void Set7seg( char number){
// セグ初期化
PORTB |= 0b00010100;
PORTD |= 0b01110111;
// セグメント割り当て
switch(number){
case 0:
PORTB &= ~0b00010100;
PORTD &= ~0b01010011;
break;
case 1:
PORTB &= ~0b00010000;
PORTD &= ~0b00010000;
break;
case 2:
PORTB &= ~0b00000100;
PORTD &= ~0b00110011;
break;
case 3:
PORTB &= ~0b00010100;
PORTD &= ~0b00110010;
break;
case 4:
PORTB &= ~0b00010000;
PORTD &= ~0b01110000;
break;
case 5:
PORTB &= ~0b00010100;
PORTD &= ~0b01100010;
break;
case 6:
PORTB &= ~0b00010100;
PORTD &= ~0b01100011;
break;
case 7:
PORTB &= ~0b00010100;
PORTD &= ~0b00010000;
break;
case 8:
PORTB &= ~0b00010100;
PORTD &= ~0b01110011;
break;
case 9:
PORTB &= ~0b00010100;
PORTD &= ~0b01110010;
break;
default:
break;
}
}

// タイマ0割り込み
ISR(TIMER0_OVF_vect){
// TCNT0 = 150;
PORTB &= 0x00; // 消灯
if(keta == 2){
Set7seg(num%1000/100);
PORTB |=  _BV(PB5); // 3桁目 点灯
keta = 1;

}else if(keta == 1){
Set7seg(num%100/10);
PORTB |=  _BV(PB6); // 2桁目 点灯
PORTD &= ~_BV(PD2);
keta = 0;

}else if(keta == 0){
Set7seg(num%10);
PORTB |=  _BV(PB7); // 1桁目 点灯
keta = 2;
}
}
// カウンタ1の捕獲発生
ISR(TIMER1_CAPT_vect){
TCNT1 = 0;
volt = ICR1;
}
int main(void) {
/*
a PB2
b PD4
c PB4
d PD1
e PD0
f PD6
g PD5
DP PD2
COM1 PB5
COM2 PB6
COM3 PB7

コンデンサは、500uSで満タン
*/
DDRD  = 0b01110111;
PORTD = 0b00001000;
DDRB  = 0b11111100;
PORTB = 0b00000000;

// タイマー0
TCCR0B = 0x03; // プリスケーラは  (dataseet p.66)
TCNT0 = 0; // タイマ0の初期値
TIMSK |= _BV(TOIE0);// タイマ0オーバーフローだけ割り込み許可

// タイマー1
TCCR1A = 0x00;
TCCR1B = 0b11000001;
TIMSK |= _BV(ICIE1);// 捕獲割り込み許可
TCNT1 = 0x0000;

// アナログコンパレータ
ACSR = _BV(ACIC); // アナログ比較器捕獲起動許可
//ACSR = _BV(ACIS1); // コンパレータ上昇で
//ACSR = _BV(ACIS0); //

DIDR = 0b11; // デジタル入力禁止

sei(); // 割り込み許可

char ave_cnt = 0;
long volt_ave = 0;

while(1){

volt_ave += (((volt*100)+69863)/1800);
volt_ave = volt_ave/2;
ave_cnt++;
if(ave_cnt >= 20){
num = volt_ave;
ave_cnt = 0;
}

_delay_ms(20);

DDRB &= ~_BV(PB0); // コンデンサのピンをオープン

cli(); // 割り込み禁止
// Cを充電開始
TCNT1 = 0x0000;
PORTB |= _BV(PB3); // 充電開始

// コンパレータが1を吐くまで待つ
while(!(ACSR & (1<<ACO))){
}
PORTB &= ~_BV(PB3); // 充電を止める
sei(); // 割り込み許可
// Cを放電
DDRB |= _BV(PB0); // コンデンサのピンを接地=放電



}




}

書き込みは平ピンICソケットを上から被せると便利です。




~まとめ~
フリスクケースでそこそこ見やすい電圧計を作ることができました。
また、定電流ダイオード+コンデンサの組み合わせで作ったAD変換器は、直線性も良く、安定した物ができました。
この基板を少し改造したら電圧計以外にもいろいろ応用ができそうです。ただし電源が別でいるのが厄介ですね。マイコンをSOPなどの表面実装部品に換えたら小さなバッテリーを置くことができそうですが、そうなるとLEDより消費電力の低い液晶のほうが有利になってしまいます。

7セグLEDはそのままでは見にくいので、グレースモークの下敷きを貼り付けようと思いました
が、力尽きました……

~参考文献~
簡易A/D変換(積分回路の応用)
ELM - シンプルなA-Dコンバータ

0 件のコメント:

コメントを投稿