連休などは家を空けるが防犯が心配である。そこで、ちょっとしたものを考えてみようと思う。長時間の時間計測が必要なのでマイコンを使う。
やることは簡単。
その1
・暗くなったらライトON(SSRつかう)
・一定時間経ったらライトOFF
その2
・暗くなったら一定時間待機
・ライトオン
・一定時間待機
・ライトオフ
【メモ】
連休などは家を空けるが防犯が心配である。そこで、ちょっとしたものを考えてみようと思う。長時間の時間計測が必要なのでマイコンを使う。
やることは簡単。
その1
・暗くなったらライトON(SSRつかう)
・一定時間経ったらライトOFF
その2
・暗くなったら一定時間待機
・ライトオン
・一定時間待機
・ライトオフ
【メモ】
なかなかこれは面白い装置ですね。
適当に周波数を変えながら見ていると・・・周波数ホッピングっぽいものが見える。しかし、25MHzくらいで何をやっているのだろうか?
オフセット調節回路がどのように効果的か検証してみた。振動を検出するセンサーに対してのバイアス安定化回路を目指しています。
オフセットが小さいとあまり効果が見られないので、LM358のオフセット電圧を10mVにしてシミュレーション
オフセット×増幅率程度(10mV×51倍=510mV)のオフセットが出力に表れている。
DCサーボの回路をつけて(上の回路ではDCサーボの出力をつないでいない)見ると、まあ、安定しますね。
また、実機で検討してみようかと思う。
お盆休みが暇だったので、prosessingというお絵かきが出来るというプログラミング言語で時計を造ってみた。デザインはスイス鉄道時計。
ちなみに、processingはグラフィックにこだわったものが作れそう。
float R_dot=220; float R_hour=150; float R_minute=240; float R_second=180; void setup(){ size(500,500); background(255); smooth(); frameRate(1); } void draw(){ translate(250,250); colorMode(RGB,256); draw_back(); dots_around_clock(); hourhand(); minutehand(); secondhand(); } void draw_back(){ noStroke(); background(0); //fill black fill(255); //while circle ellipse(0,0,480,480); //white circle } void dots_around_clock(){ pushMatrix(); stroke(0,255); strokeWeight(2); rectMode(CENTER); fill(0); for(int i=0;i<60;i++){ rotate(radians(6)); line(R_dot-5,0,R_dot+14,0); } strokeWeight(0); for(int i = 0;i<360;i+=30){ rotate(radians(30)); rect(R_dot,0,35,15); } popMatrix(); } void hourhand(){ pushMatrix(); float hand_angle; hand_angle = radians(30*hour()+minute()/2-90) ; stroke(0,255); strokeWeight(0); fill(0); rectMode(CENTER); rotate(hand_angle); rect(R_hour/2-40,0,R_hour+40,20); popMatrix(); } void minutehand(){ pushMatrix(); float hand_angle; hand_angle = radians(6*minute()+0.1*second()-90); stroke(0,255); strokeWeight(0); fill(0); rectMode(CENTER); rotate(hand_angle); rect(R_minute/2-40,0,R_minute+40,15); popMatrix(); } void secondhand(){ float hand_angle; stroke(255,0,0,255); strokeWeight(5); hand_angle = radians(6*second()-90); line(-40*cos(hand_angle),-40*sin(hand_angle),R_second*cos(hand_angle),R_second*sin(hand_angle)); fill(255,0,0,255); ellipse(R_second*cos(hand_angle),R_second*sin(hand_angle),20,20); ellipse(0,0,10,10); }
時間延長できるタイマー作ってみた。
実験室で使う顕微鏡の照明をきり忘れるので、スイッチオフしなくても自動で切れるようにしたかった。7セグディスプレイは74LS247があったので、なんとなく付けてみた。
百均にいって延長コード買ってきたので、AC100Vの制御もしてみた。裸配線とヒューズなし以外は問題なかろう。
危なげながらも100Vの制御してみた。後できちんとした箱と、安全のためヒューズを付けよう。。
使ったSSRはゼロクロスのタイプ。オムロンのG3MB-202P。
ライト消灯時、16mAも消費している。1mAはマイコン。15mAが74LS247。ロジックICをFETでオフできるようにしておけばよかった。マイコンはスリープで0.5mAくらいまで電力削減できる。マイコンシャットダウンしたら割り込みで起きてくれなくてとりあえずスリープにしておく。シャットダウンすると内蔵プルアップなんかも無効になっちゃうのかな。
ほぼ初めてロジックICを使っている。74LS247。4ビットの信号を7セグLEDのコードに変換してくれるICだ。最近売ってないのね。74HC595みたいなシリアルからパラレルに変換してくれるICはまだ手に入るけど。
ブレッドボード使わずにユニバーサル基板に配置していって、途中でテストしてみようという運びになった。
光らない(・。・)
テスターでいろんな箇所の電圧を測定し、配線間違いがないか探し、悩むこと30分。
ふと、ロジックICの入力は特にプルアップもプルダウンもなしで裸でゲートが出てるんじゃないかと思った。正解だった。
なぜか知らんが、プルダウンされてるんじゃないかと思ってたよ。そんな馬鹿なだよね。馬鹿は俺だよと。
ふう、とりあえずマイコンに接続して大丈夫そうなところまではきた。ATTiny2313というマイコンがあまっているはずだから、使おうとおもったのだが、いざ使おうとするとどこに行ったのかわからない。
フラッシュ2kBで20ピンくらいなので、キッチンタイマー的なものを作るには足の数やらちょうどよいのだが。。。
なかったら注文だな。うん。
ちなみにキッチンタイマーを作るわけではない。ボタンをおしたら1分間通電し(カウントダウン表示あり)、その後電源オフするものを作りたい。実験室でついつい切り忘れてしまう照明装置があって、消し忘れ防止のデバイスを作りたい。
電源ON/OFFはSSRで制御。
私の暴走ではない、マイコンだ。
今日、車にいったら太陽電池MPPT充電器が動いていなかった。
MPPT動作のとき、開放電圧測定が終わった後にLEDを光らせているのだが、光っていなくておかしいなと思ってしばらくして思いついた。
夏の車内は暑い
しかし、データシートを確認する限り、125℃まで動作するとのことで問題ない。
起動失敗か?
外部電源で動くわけではなく、太陽電池から電源を供給されて動くので、起動のときにトラブル発生するとそのまま暴走する可能性がある。
電源電圧が一定以下でリセットがかかるようにはしてあるのだが、時として失敗するのだろうか?
問題は、現象を再現できないことにある。
光が当たっている間、何分かに一回リセットをするような外部回路があってもいいかもしれない。ウォッチドッグタイマー(WDT)っていうものがあるから、それを使ってみようか。
WDTってのはマイコンのCPUとは別にタイマーがまわっていて、タイマー溢れしないようにWDTをリセットしながら使う。WDTがカウントしきってしまうとシステムリセットなどをかけられる。CPUからのリセット命令こない→CPU暴走してるんじゃない?という発想の回路。
新月っぽいので撮影してみたが、いまいちだった。もう少しカメラを上に向けるべきだったか。
あと、星がつながらず、ブツブツ切れてしまってもいる。
暗い場所に住みたい。
やりたいこと:微速度撮影の制御。ロータリースイッチでシャッター間隔の時間を決める。
機材:ニコンのデジタル一眼レフカメラ(持ってるのはD40,D90)
以前、ニコンの一眼レフリモコンのプログラムを作ったのだが、ブレッドボード上で回路を作っただけで長時間野外で使うにはお粗末なものであった。
また、カメラの電池の容量が稼働時間を制限するため、夜通しの撮影などは無理だった。
で、ヤフオク。Nikonの一眼レフのACアダプタを落札@3800円。決して安くないカメラなので、純正部品にした。最近めっきり出番のないD40を一晩屋外放置などしようと思ったので、D40用のアダプタも落札@1000円。こちらも純正部品。
回路は簡単なもので、さくっと出来上がる。当初は赤外線LEDだけだったが、途中で動いているのか不安になったので、赤色LEDを追加した。リモコンコード送信のときに赤LEDも光るので電池切れで動かないなどがわかる。暗闇の中で使うのを前提にしたので赤色のあまり明るくないLEDを採用。電源はNiMH×4で最大5.2Vほど。5.5Vまでは使っていいみたいなので、ぎりぎりセーフ。電池の過放電が気になるが、無視しよう。一晩程度なら問題ない。
まず赤外線のフォーマットだが、キャリア周波数38kHz程度で、Duty 1/3のパルスである。
ニコンのレリーズ信号はこんな漢字らしい。
turn_on(); _delay_us( 2000); //2ms発光
turn_off(); _delay_us(27850); //27.85ms消灯
turn_on(); _delay_us( 390); //0.39ms発光
turn_off(); _delay_us( 1580); //1.58m消灯
turn_on(); _delay_us( 410); //0.41ms発光
turn_off(); _delay_us( 3580); //3.58ms消灯
turn_on(); _delay_us( 400); //0.4ms発光
turn_off(); _delay_us(63200); //63.2ms消灯
合計99.4msだが、実際は100msだと思う。誰かが測定した結果上記のようになったんだと思う。
では、マイコンのプログラム要素を考える。
38kHz Duty 1/3を8ビットタイマで実現する。出力をピンに接続するかどうかで上記のturn_on()とturn_off()を作ることにする。
マイコンは内臓9.6MHzのDIV8で1.2MHzで動かす(出荷状態どおり)→38kHzの1サイクルは1200/38≒31.5カウントで到達する。カウンタは31までカウントしたらリセットかかるようにして、0カウントでHigh, 10カウントでLowとなるように設定する。DIV8なしで9.6MHz駆動の場合はこれの8倍の値になって、たぶん普通のPWMモード(255カウントでリセットかかる)が使える。
カウンタのトップ値を設定するPWMモードの場合、OCR0Aレジスタで上限決定、OCR0BでDuty決定といったことをやるため、PWM出力がOC0B(PB1)になってしまいます。なので外付けDIPスイッチはPB0,PB2,PB3,PB4という飛び地になってしまいます。
8ビットカウンタの設定
カウンタでは何をするかというと、こんな設定
TCCR0A=0b00000011; //0b00100011と切り替えることでLEDオンオフをやる。
TCCR0B=0b00001001;
CS02-CS00はカウンタへのクロック供給である。1.2MHzをそのまま入れるのでCS02-CS00は001になる。
WGM02-00はレジスタを跨いでいるので注意が必要だが、111の設定(最終行)にする。TOPが0CR0Aになる高速PWMモード。
最後にCOM0Bxの設定だが、非反転の動作を使う。カウンタ0で出力high、カウンタがOCR0Bと一致でlowの出力になる。
ちなみに、このPWMの設定にたどり着くのに一週間以上かかった。
ここまでくれば後は簡単、LEDのON/OFFは関数作るか、そのまま書くかで出来上がり。
void turn_on(void){
TCCR0A=0b00100011;
}
void turn_off(void){
TCCR0A=0b00000011;
}
ポートの設定とピン状態の読み込み
PB1を出力にして、ほかを入力端子かつ内部で抵抗プルアップを施す。外に抵抗つけるの面倒くさいじゃない。そして、ロータリースイッチがコンプリメンタリである必要はここからくる。ツマミがオレンジというか朱色のを使うとよい。
DDRB = 0b00000010;
PORTB = 0b00011101; //入力なのにPORTレジスタに1を書き込むと内部プルアップ!!なるほど!
さて、PB0,PB2,PB3,PB4という4端子を使うのですが、飛び地なので、そのままでは面倒があります。一番右のビットをひとつ左にシフトして全体を右にビットシフトできればいいなー、いいなー、いいなー・・・こういうときは風呂だな。
で、風呂で思いつく。(PINB++)>>1だ!
(0b00011100++)>>1=(0b00011101)>>1=0b00001110
(0b00011101++)>>1=(0b00011110)>>1=0b00001111
きっと世の中じゃ常識なんだろうけど、思い通り程度の計算量で出来上がって便利。
ソースコード
/*ハジマリ*/
#define F_CPU 1200000
#include <avr/io.h>
#include <util/delay.h>
#include
#define SignalTime 99
int main(void)
{
DDRB = 0b00000010; // 出力方向にする
PORTB = 0b00011101; //抵抗プルアップ
TCCR0A = 0b00000011;
TCCR0B = 0b00001001;
OCR0A = 31; // (( 1.2MHz / 38kHz ) / 1(分周) ) - 1 = 30.6
OCR0B = 10; // duty比を1/3にする ( 1.2MHz / 38kHz ) / 3 = 10.5
while(1)
{
TCCR0A = 0b00100011; _delay_us( 2000); //サブルーチン使わず、コピペでやったれ!
TCCR0A = 0b00000011; _delay_us(27850);
TCCR0A = 0b00100011; _delay_us( 390);
TCCR0A = 0b00000011; _delay_us( 1580);
TCCR0A = 0b00100011; _delay_us( 410);
TCCR0A = 0b00000011; _delay_us( 3580);
TCCR0A = 0b00100011; _delay_us( 400);
TCCR0A = 0b00000011; _delay_us(63200);
uint8_t IntervalStatus = ((PINB & 0b11101) + 1) >> 1; //ふっ、おいらC育ちじゃないから++演算子わすれてたよ。
if(IntervalStatus == 0) {_delay_ms( 1000-SignalTime);} //1秒ごとのシャッター
if(IntervalStatus == 1) {_delay_ms( 2000-SignalTime);}
if(IntervalStatus == 2) {_delay_ms( 5000-SignalTime);}
if(IntervalStatus == 3) {_delay_ms( 10000-SignalTime);}
if(IntervalStatus == 4) {_delay_ms( 20000-SignalTime);}
if(IntervalStatus == 5) {_delay_ms( 30000-SignalTime);}
if(IntervalStatus == 6) {_delay_ms( 40000-SignalTime);} //星の撮影だと露光30sほどやるのでたぶんこの辺をよく使う
if(IntervalStatus == 7) {_delay_ms( 60000-SignalTime);}
if(IntervalStatus == 8) {_delay_ms(120000-SignalTime);}
if(IntervalStatus == 9) {_delay_ms(240000-SignalTime);}
}
}
/*オワリ*/
待機時間はカウンタが止まっていても問題ないが、一連の信号を送信する間、2ms発光から最後の0.4ms発光まではコヒーレントな38kHzがいいかとおもってタイマはとめていない。もっとも面倒くさくなったので、上記のプログラムではずっとタイマは動いている。タイマとめても大して節電にならない気がするから。
スリープに入って、など節電できる工夫はまだできるが、充電電池使うし、いつ飽きるかわからないので、今回はこれでよし。
そんなブログを書いている間に月は昇った。送電線が邪魔なので、引っ越したいくらい。ACアダプタがないと長時間の露光ができないので事実上部屋のまどから外を撮影、というのが今の限界である。
組みあがった回路はこちら。配線がほとんどない。赤外線LEDはデジカメのところまで引っ張っていってる。
撮影の様子
送電線が邪魔だ!これさえなければ!これさえなければ!
備忘録
シャッター速度、長いほうから
Bulb, 30s, 25s, 20s, 15s, 10s, 8sというような感じなので、後で比較明コンポジットなどを行いたい場合はこれらの時間よりやや長い程度のものにしておくとよいかも。
35s, 30s, 25s, 20s,というような時間がいいだろうかと。
失敗は成功の元といいましょうか、一発目での成功はなかなかありませんね。
マイコンPI制御のいろいろをデータログとって見ると気がついたことが。目標値と現在地の差分、ヒーター出力が直線にのってるんじゃないかと。それってただのP制御じゃ・・・・
係数をあまりにも適当に決めたのが原因だったようだ。ちょっと考えて、係数を決めてみたらある程度ヒステリがでるので、積分項が動いているのだろうということがわかった。
今は積分項の時定数が大きすぎて収束が遅い→また変更。
ヒーターの上に布をかけたり、はずしたり、また布をかけて夜の間放置してみたり。とりあえず温度は一定値になっているようです。ちっとオーバーシュートおおきい。
制御初期の状態を見てみると・・・
先の比較とは違うが、温度とヒーター出力のグラフをとってみると、直線ではないので、ちゃんとI制御が入っていることがわかる。
赤い線は大体この辺に落ち着くだろうという温度。30度を目標にしたのだが、ArduinoのADCがずれているのかオペアンプがずれているのか、まあ、多少誤差はあるだろう。
温度がノイジーな箇所があるが、P制御が0か1かばたついたとき、制御に対しては差分の3倍の制御量を入れているので、PWMが3/255(=1%)変動するの原因だろうかと思ってPの制御が0になる範囲をある程度広げてもいいのかなって。
横軸入力で縦軸出力だとこんな感じで。
りんごは人工授粉をしてやらないといけないが、葯から花粉を取り出すのに25℃一定で一日おいてやる必要がある。
4月下旬だと愛知はもう暖かいが、地元長野北部はまだ寒いのでヒーターが必要。今までは白熱電球なんかで暖めていたようだが、せっかくならと温度調節機能があったほうがいいだろうと。
回路図載せても、結局はマイコンのプログラムがキモなので意味がないかもしれないが・・・
P0は温度のモニター箇所、P1はヒーター出力の状態モニター。
温度センサーはLM35DZを使います。25℃で250mV出力なので、マイコンのADCでも十分に拾えそうだが、なんとなく10倍にしてみた。こっちのほうがP制御の分解能が高そうだから。
ところが、実験しようとおもったら、室温が25℃にきわどい所でしたので目標値を35℃にして実験してみた。データロガーはArduinoマイコンボードで作った。ひたすらデータをPCに送り続けるようにしてデータロギング。
まあ、悪くはないでしょう。今回の系ではオーバーシュートは1℃未満の様子。ヒーターの出力はチラチラ変動があるようです。
20分弱の所、ヒーターに息を吹きかけてみました。ちょっと温度が下がって、出力が増大しています。ヒーターの出力変動は室内の微妙な風などの影響かもしれません。
次に気になるのは長時間放置での様子。上記のデータ、寝ている間も記録を続けました。朝方にかけてやや気温が低下傾向ですが、その分ヒーター出力が増大し、ヒーター部分の温度はある程度安定しているようです。ちょっと温度下がっているけど、目的が花粉の開葯なので問題ないでしょう。
実家に帰れば気温15℃程度、保温目標値25℃程度でしょうから、こんな制御でよさそうです。
プログラムのコードは色付けるのが面倒くさいので画面キャプチャ。
先の太陽電池MPPT回路、昇圧回路でかつ出力からのフィードバックなしなので出力が解放されるとたぶんトランジスタがパンクするかコンデンサがバンクするまで電圧が上がると思う。
とりあず、ツェナーダイオード使ってマイコンにリセットかけるような回路がどうかと思ってみた。マイコン起動の時に数秒間のディレイを設けたら端子開放の際に間欠発振になってツェナーダイオードが食う電気も小さくなるんじゃないかと思って。