ATTINY2313で商用電源周波数監視

ATmega328で商用電源周波数の監視ができるようになりましたが、グラフを見てないと変動に気づきません。そこで、スタンドアローンで動くものを余っているATTINY2313で作ってみました。

基本的な構成はATmega328の時と同じです。100均のニッケル水素充電器のマイナス端子から内部のトランスの2次側電圧を引き出して、半波整流してLP2950L-3.3でATTINY2313の3.3V電源を生成します。一方でフォトカプラで商用電源の周期に同期した信号を生成して、ATTINY2313のTIMER1のICP信号に入力します。ATTINY2313の動作クロックは8MHzのクリスタルとして、適当に作っても最悪100ppm程度の精度は得られるようにします。スタンドアローンで動作するように、OC0B信号を圧電ブザーに接続して、TIMER0でブザーを鳴らせるようにします。

完成したものはこんな感じになります。

基板上のLEDはUARTのTXに接続してあるので、そこにトランジスタをつけたフォトダイオードをかざしてやると、非接触でシリアル通信がができます。

これをArduinoのシリアルプロッタに食わせると以下のような感じです。周波数は実際の周波数を1000倍したものです。

シリアルライブラリなどのArduinoのライブラリは使えないのでその部分は簡単なものを作っていますが、ソフトウェアはATmega328の時と大きくは変わりません。(下記の中で&が化けています・・・)

1#include <avr/io.h>   // /usr/lib/avr/include/
2#include <util/delay.h>
3#include <util/atomic.h>
4#include <string.h>
5 
6// FUSEは外部クリスタル8MHz、システムクロックを分周なしに設定(E:FF, H:DF, L:EF)
7 
8/////////////////////////////////////////////////
9// 端子定義
10#define BUZ 5    // PORT D5 に圧電ブザー接続
11#define ICPPIN 6 // PORT D6 = ICP
12#define UARTTX 1 // PORT D1 = TX
13 
14/////////////////////////////////////////////////
15// タイマ0関連
16void Buzzer(uint8_t period){
17    if(period>0){
18        // 高速PWM設定によるブザー駆動
19        TCCR0A = 0x23;     // COM0B[1-0]=10,WGM0[1-0]=11  高速PWM動作
20        TCCR0B = 0x0C;     // WGM02=1,CS[2-0]=4  分周=256分周=8MHz/256=31.25kHz
21        OCR0A = period;    // FREQ 31.25kHz / 31 ≒ 1008Hz / 63 ≒ 496Hz
22        OCR0B = period>>1; // DUTYを設定
23    } else {
24        TCCR0A = 0x00;  // 出力停止
25    }
26}
27 
28/////////////////////////////////////////////////
29// タイマ1関連
30// 周期測定ののための変数
31volatile uint16_t NumV;
32volatile uint32_t SumV;
33volatile uint16_t CapV;
34volatile uint16_t PreCap,NowCap;
35 
36// 1秒間の最大最小平均を格納するための変数
37uint16_t tNumV;
38uint32_t tAveV;
39uint32_t tSumV;
40 
41// 割り込みハンドラ
42ISR(TIMER1_CAPT_vect){
43  TIFR |= (1<<ICF1);
44  NowCap = ICR1;
45  CapV = NowCap - PreCap;       // 差分を求めて周期を算出
46  PreCap = NowCap;
47  SumV += CapV;
48  NumV++;
49}
50 
51// タイマ1設定
52void TIMER1_Init(void){
53    // TCC1でICP信号(PD6端子)の周期を計測する
54    TCCR1A = 0; //initialize Timer1
55    TCCR1B = 0;
56    TCNT1 = 0;
57 
58    TCCR1B =  0x02;   // 8MHzを8分周
59    TIMSK  |= (1 << ICIE1); // キャプチャ割り込み許可
60}
61 
62uint32_t Period(void){
63    // 割り込みで更新している変数をコピー&初期化する
64    cli(); //割り込み停止
65    tSumV = SumV; tNumV = NumV;
66    SumV = 0; NumV = 0;
67    sei();   //割り込み再開
68    tAveV = tSumV / tNumV;
69    return(tAveV);
70}
71 
72/////////////////////////////////////////////////
73// UART関連
74#define FOSC 8000000
75#define BAUD 38400
76#define MYUBRR FOSC/16/BAUD-1
77 
78uint8_t txbuf[16];
79uint8_t txp=0,txn=0;
80 
81ISR(USART_UDRE_vect){
82  if(txp<txn){
83    while ( !(UCSRA & (1<<UDRE)) );
84    UDR = txbuf[txp];
85    txp++;
86  } else {
87    UCSRB &= ~_BV(UDRIE);
88  }
89}
90 
91void USART_Init(unsigned int baud){
92    UBRRH = (unsigned char)(baud>>8);
93    UBRRL = (unsigned char)baud;
94    UCSRC = (1<<USBS)|(3<<UCSZ0);
95    txp = 0;
96    UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<UDRIE);
97}
98 
99void USART_txt(uint8_t *txt,uint8_t len){
100    while(txp<txn);
101    cli();
102    memcpy(txbuf,txt,len);
103    txp=0;
104    txn=len;
105    UCSRB |= _BV(UDRIE);
106    sei();
107}
108 
109void USART_num(uint16_t num){
110    uint16_t d=10000;
111    uint16_t n=num;
112    uint8_t  c,p=0,b[8];
113    while(d>0){
114        c=n/d; n=n%d;
115        d=d/10;
116        b[p++]=c+0x30;
117    }
118    b[p++]='\r'; b[p++]='\n';
119    USART_txt(b,p);
120}
121 
122void USART_znum(uint16_t num){
123    uint8_t s=1;    // ゼロサプレス中
124    uint16_t d=10000;
125    uint16_t n=num;
126    uint8_t  c,p=0,b[8];
127    while(d>0){
128        c=n/d; n=n%d;
129        d=d/10;
130        if(d==0) s=0;
131        if(s==0 || c!=0){
132            b[p++]=c+0x30;
133            s=0;
134        }
135    }
136    b[p++]='\r'; b[p++]='\n';
137    USART_txt(b,p);
138}
139 
140/////////////////////////////////////////////////
141// メイン
142int main(void)
143{
144    uint32_t f,p,d;
145 
146    PORTB  = 0xFF; // 入力設定時のプルアップ有効
147    PORTD  = 0xFF; // 入力設定時のプルアップ有効
148    DDRD   = _BV(BUZ);     // PORT D5を出力に
149    DDRD  &= ~_BV(ICPPIN); // ICPピンを入力に
150    PORTD &= ~_BV(ICPPIN); // ICPピンのプルアップ無効化
151    PORTD  = _BV(UARTTX);  // PORT D1を出力に
152 
153    TIMER1_Init();
154 
155    USART_Init(MYUBRR);
156 
157    for(;;){
158        p = Period();
159        f = 1000000000UL/p;  // 周波数の1000倍を求める
160        if(f > 50000){
161            d = f - 50000;
162        } else {
163            d = 50000 - f;
164        }
165        if(d > 200){      // 0.20Hz以上ずれた場合
166            Buzzer(31);  // 高速PWM設定によるブザー駆動 31=1kHz
167        }else if(d > 150){ // 0.15Hz以上ずれた場合
168            Buzzer( 78);  // 高速PWM設定によるブザー駆動 78=400Hz
169        }else if(d > 100){ // 0.10Hz以上ずれた場合
170            Buzzer(250);  // 高速PWM設定によるブザー駆動 250=125Hz
171        }else {
172            Buzzer(0);
173        }
174        USART_znum(f);
175        _delay_ms(1000);
176    }
177}

【2021年2月21日追記】
回路図のリクエストをいただきましたので、現物から書き起こしました。
(注:ATtiny2313への書き込み回路は描いてありません。別途ICクリップで挟んで書き込んでいます。)
追記2: 下記回路図ではRESETのプルアップがないですが、プルアップしておいたほうがいいと思います。何かの拍子にリセットがかかるようです。(データシートの読み込み不足だと思います)

左側の入力には、100均ニッケル水素充電器の2つある電池マイナス端子をそれぞれつなぎます。
入力をショットキーダイオードで半端整流して3端子レギュレータで3.3V電源を作ります。入力はフォトカプラに通して入力をデジタル信号化して、ATTINYのICP端子へ接続、インプットキャプチャ機能でエッジからエッジまでの時間を1us単位で測定します。整流時にショットキーダイオードを使ったのは、電圧降下を小さくしたいためです。
大したことはしていないので、インプットキャプチャ機能のあるマイコンであれば、(ソフトウェアは当然作り直しになりますが)大抵のものが使えるものと思います。

“ATTINY2313で商用電源周波数監視” への6件の返信

    1. 投稿に気づくのが遅れてすみません。実は、回路図描いてないんです^^;
      いま現物から起こす形で描いてますので、少々お時間ください。
      描いたら、この記事に追加しますね。

      1. わざわざありがとございます!
        328Pで周波数測定したデータを7セグに表示したいのですが、どのようにしたら出来ますか….??

        1. やり方はいろいろな方法がありますし、空いているポートや電源などの制限事項や優先したい事項などにもよってベストな方法は変わると思います。
          一品物でしたら、
          https://akizukidenshi.com/catalog/g/gM-06681/

          https://akizukidenshi.com/catalog/g/gM-09162/
          のようなシリアル制御のモジュールを接続するのが比較的配線の手間や難易度が低そうに見えます。(自分は使ったことがないのでわかりませんが)

          1. 分かりました。ありがとうございます!
            プログラムの方が全く分からなくて、
            どうしたらよろしいですか….??

        2. 返信の階層が深いと返信できなくなるようです。
          ソフトウェアをどう作るかですが、まずは秋月のページ内の「メーカー製品情報」「参考資料」のリンクをたどったりすると、サンプルプログラムにたどり着いたりすることが少なくないですよ。
          その他には、製品名の「SPI(3線式) LED Module 8 Digital」「Grove-4桁7セグメント赤色LEDモジュール」でググったり、そこから得られるコントローラICの「TM1637」でググったりして探すなどして情報を集めるしかないのではないでしょうか。
          最後の最後はデバイスのデータシートと回路図を突き合わせて自力でスクラッチ開発ですね。(本業で売り物としてやる場合には普通の話ですが)
          頑張ってください。

tomono へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)