雑記/2008-2

<< 2008-2 >>
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

2008-2-29

[公開:any]

[放電器,AVR,ATmega168,2SK2232,PWM]

header

雑記/2008-2-14に続いてバッテリー放電器の基礎実験をやっています。前回は定電流回路をPWMでオン・オフさせて電流可変しましたが、今回は直接、PWMで電流可変を試してみます。

body

今回も負荷としてMOS FET 2SK2232をAVRでPWM制御するところは同じですが、負荷に接続した電流検出抵抗0.1Ωに発生した電圧をAVRのAD変換で取り込んで電流値に換算し、あらかじめ設定した放流電流値(0〜1000mA)になるようにPWMのDuty比をフィードバック制御するようにしました。

また、電池の電圧が放電休止電圧(0.9V)に達すると放電を終了するようにしてあります。

実験に使用した回路です。とりあえず実験ということで電池1本分の回路です。

dischager_test.PNG

回路図一部修正:電池電圧測定用AD変換へローパスフィルタ追加(2008-03-03)

LCDのRSとR/Wのピン配置が間違っています。(2008-03-06)

放電電流300mAに設定したときの動作状態です。実際に単3のニッケル水素電池1本を放電させて見ました。アップ・ダウンスイッチで放電電流を100mA単位で可変することができます。

DSC01475.jpg

この放電回路では、電池の電圧や内部抵抗にかかわらず、常に一定の電流で放電するように制御されています。ためしに、電池に替わりに実験用可変電源をつないで電圧を1.5V〜12Vまで変化させて見ましたが、常に電流値は設定した一定の値となります。
この状態なら、放電電流と放電時間から正確に放電容量を求めることが出来ると思います。

実機は電池4本を同時に処理する予定ですので、PWM出力4ポート、電流検出4ポート、電圧検出4ポートとLCDやスイッチのポートが必要となり、28ピンのATmega168ではIOポートが不足します。特にAD変換が8ポート必要となるので、どうやりくりしても足りません。

・・ということで、最近、秋月電子で取り扱いを始めた40ピンDIPのAVR ATmega644Pを購入しました。

DSC01479.jpg

余談ですが・・・ATMEL AVRは、同じ機能でフラッシュメモリサイズ違いを数種類ラインナップしたものが多いようです。当然、フラッシュの容量が大きいほうが値段も高くなります。製品として何十台、何百台と作れば、そのコストは大きな差になりますが、われわれシロートが趣味で数台程度を製作する場合は、たいしたコストにはならないので(僅か数百円程度)、フラッシュ容量が一番大きなものを購入したほうが良いと思います。


参考までに実験で使用したソースです。AVRStudio4とWinAVR(GCC)で作ってあります。LCD関連のソースは省略してあります。実験では、放電電流値を放電中も可変(100mA単位でアップダウン)できるようにしてあります。

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <math.h>

#include "lcd.h"

#define cbi(addr, bit)     addr &= ~(1<<bit)
#define sbi(addr, bit)     addr |=  (1<<bit)
#define ADC_ENABLE (_BV(ADEN)|_BV(ADATE)|_BV(ADIF)|0b110)
#define ADC_START  (ADC_ENABLE|_BV(ADSC))

void delay_ms(unsigned int t) {    while(t--)  _delay_ms(1); }

FILE *fp;                    // for fdevopen()

unsigned int get_adc(char ch)
{
    ADMUX = ch;
   ADCSRA = ADC_START;
    loop_until_bit_is_set(ADCSRA, ADIF);

    return ADCW;
}        

int main()
{
    unsigned int duty;
    unsigned int load;
    unsigned int volt;
    unsigned int cur;
    unsigned char sw0_state, sw1_state;

    DDRC = 0b00000000;        //
    DDRB = 0b11111111;        // LCD
    DDRD = _BV(PD6);        // PD6 PWM output
    DIDR0 = _BV(ADC0D);        // ADC0 Digital Input Disable
    PORTD = 0b00000011;        // PD0,1 pull up

    lcd_init();
    lcd_cls();
    fp = fdevopen(lcd_putch, NULL);        // LCD出力ファイルディスクプリタ

    cur = 0;
    duty = 0;

    ADCSRA = ADC_ENABLE;

    OCR0A = 0;
    TCCR0A = _BV(WGM01)|_BV(WGM00)|_BV(COM0A1)|_BV(COM0B1);
    TCCR0B = 1;                    // Timer0 CLK/0

    while(1) {
        if(bit_is_clear(PIND, PD0)) {
            sw0_state = 1;            
            delay_ms(10);
        }
        if(sw0_state && bit_is_set(PIND, PD0)) {
            sw0_state = 0;
            if(cur < 1000) {        // Current Up 100mA
                cur += 100;
            }
        }
        if(bit_is_clear(PIND, PD1)) {
            sw1_state = 1;            
            delay_ms(10);
        }
        if(sw1_state && bit_is_set(PIND, PD1)) {
            sw1_state = 0;
            if(cur > 0) {            // Current Down 100mA
                cur -= 100;
            }
        }

        volt = get_adc(1);
        if(volt < 184) {            // 0.9 / (5/1024) = 184....
            cur = 0;                // Stop Discharge
        }

        load = (int)(get_adc(0) * 4.88);    // 5/1024 * level = Load
        if(load < cur) {
            duty++;
        }
        if(load > cur) {
            duty--;
        }
        if(duty > 120) {        // limiter
            duty = 120;
        }
        if(duty < 0) {
            duty = 0;
        }

        OCR0A = duty;

        lcd_goto(0, 0);
        fprintf(fp, "Set:%03dmA %03dmA", cur, load);
        lcd_goto(1, 0);
        fprintf(fp, "PWM:%03d %.1fV", duty, volt * 0.00488);
    }
}

2008-2-14

[公開:any]

[放電器,AVR,ATmega168,MOS FET,2SK2232,PWM]

header

単3や単4サイズの充電式電池(ニッカドやニッケル水素)の特性と見るためにMOS FETを使った放電器を作りたいと思っています。そのための基礎実験をやってみました。

body

ミニッツレーサなどのスモールサイズラジコンで使うニッカドやニッケル水素電池などの充電可能な乾電池(2次電池)を1セルごとに放電させる放電器を製作して性能の良い電池を選別したいと、以前から考えていました。放電器の基本的な仕様として

  • 単セル単位の定電流放電
  • 放電停止電圧設定(0.6V〜1.0Vまで0.1V単位)
  • 放電電流が設定可能(100mA〜1000mAまで100mA単位)
  • 放電時間表示
  • 単セル単位の放電容量表示
  • 4セル同時に処理

が実現できればいいと考えています。

ワンチップマイコンのAVRかPICを使えば簡単に出来そうですが、放電電流を可変式として電圧(電池の電圧)によらない定電流制御を行う方法がわからなくて困っていました。
MOS FETを使った電子負荷装置の製作」では、単純にMOS FETのゲート電圧を変化させて電流値を可変していましたが、エンハンストタイプのMOS FETの使い方としてはイレギュラーだと思います。今回のように正確な放電電流値を安定して得る用途には向かないと思います。

インターネットをあちこち検索していたら、定電流回路をPWMでON/OFFしてやれば電流値の可変と同等という記事を見つけました。つまり、1Aの定電流回路をPWMのデューティ比50%でオン・オフすれば0.5Aの放電回路と同等になると・・・・・・そうなのか?・・・

ということで、下の回路で早速実験してみました。

bat_disch_test.PNG

定電流回路は、トランジスタのベース・エミッタ電圧が、十分なベース電流を流したときにほぼ一定の値(約0.6V)となることを利用したものです。
MOS FET(2SK2232)のソースにつないだ1Ωの抵抗の両端電圧がトランジスタ(2SC1815)のVBEでクランプされます。この場合、この1Ωの抵抗に流れる電流は、オームの法則により電圧VBEを抵抗1Ωで割った値となります。
このトランジスタのVBEは実測で0.78Vとなっているので、0.78/1=0.78A・・・・780mAの定電流回路ということになります。

この定電流回路をAVRのATmega168でPWM制御します。実際に実用化するときは、1Ωの抵抗を電流検出抵抗として扱い、その両端電圧をAVRのAD変換で読み取ってPWMのduty比をフィードバック制御する必要がありますが、実験では単純にボリュウムでduty比を変化させてみます。

DSC01422.jpgDSC01419.jpg

上の画像は負荷電流100mA時のものです。理論的には、AD値が32なのでduty比が32/255*100=12.5%となり電流値が780mA*0.125 = 97.5mAとなります。

この状態で、負荷バッテリー(実験では電源装置)からの電流(テスターで測定)がduty比に比例した値かどうかを確認したところ、かなり正確に電流値を可変できることがわかりました。つまり、理論的には電流の値を255段階(8ビット)に変化させることが出来るようです。

放電器の基本実験はうまくいきました。なんとかなりそうです。あとは、時間が取れれば続けて製作していきたいと思います。でも、今回のパルス性の負荷と抵抗負荷などの連続負荷がバッテリーに対して同等かどうかがチョット気になります。


▲ページ Top へ...