「PIC AVR 工作室」サイトの日記的なブログです。
サイトに挙げなかった他愛ないことを日記的に書き残してます。
PIC AVR 工作室 ブログ



マイコンで何かやろうと思ったら、やっぱり
どうしても使いたくなるのは正確な時間制御。
timer機能ですね。

MEGA168にはtimerが0~2の計3つ登載されてます。
0と2が8ビットタイマー。1が16ビットタイマー。

使い方も機能もそれぞれ大体同じなんですが、
timer1にはキャプチャー機能が、timer2には
外部パルスクロック入力機能があるという違い
はあります。
まぁ、MEGA168ならどのtimerでもノーマルモード、
CTCモードもあるし、タイマーカウントの結果を
ピン出力するいわゆるPWMも各timerで使用する
ことが出来ます。

とはいえ、arduinoなのでハードウェアの隅から
隅まで使い尽くすということより、簡単な
スケッチで動くということが重要なので、
それらの機能を全部使える必要はないでしょう。

標準の組み込みライブラリにはtimer割り込み関係の
モノはありませんでした。(PWMだけみたい)

というわけで、まずは先人のスケッチを
探してみます。ありました。↓これ。
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1167000525

Q&Aの途中のモノのようです。思ったように
動いていないようです。
ソースが古いのかarduinoIDEがバージョンアップ
してしまったのかわかりませんが、コンパイルすると
内部レジスターファイルの名称などが未定義と
出ちゃうので、山根さんの本を参考に動作する
ように修正してみました。
(後日訂正:コンパイルが通らなかったのは、多分
 mega8用のスケッチだからだと思われます)

↓こんな感じです。

#include <avr/interrupt.h>
#include <avr/io.h>

#define INIT_TIMER_COUNT 6
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT

int ledPin = 3; //digital3 (PD3)
int swPin = 9; //digital9 (PB1)
int int_counter = 0;
volatile int second = 0;
int oldSecond = 0;
long starttime = 0;

// Aruino runs at 16 Mhz, so we have 1000 Overflows per second...
// 1/ ((16000000 / 64) / 256) = 1 / 1000
ISR(TIMER2_OVF_vect) {
RESET_TIMER2;
int_counter += 1;
if (int_counter == 1000) {
second+=1;
int_counter = 0;
}
};

void setup() {
pinMode(ledPin, OUTPUT); // set the digital pin as output
pinMode(swPin, INPUT); // set the digital pin as input
digitalWrite(swPin, HIGH); //set swPin internal pull-up
Serial.begin(9600);
Serial.println("Initializing timerinterrupt");
//Timer2 Settings: Timer Prescaler /64,
TCCR2B |= (1<<CS22); // turn on CS22 bit
TCCR2B &= ~((1<<CS21) | (1<<CS20)); // turn off CS21 and CS20 bits
// Use normal mode
TCCR2A &= ~((1<<WGM21) | (1<<WGM20)); // turn off WGM21 and WGM20 bits
// Use internal clock - external clock not used in Arduino
ASSR |= (0<<AS2);
TIMSK2 |= (1<<TOIE2) | (0<<OCIE2A); //Timer2 Overflow Interrupt Enable
RESET_TIMER2;
sei();
starttime = millis();
}

void loop() {
if (oldSecond != second) {
Serial.print(second);
Serial.print(". ->");
Serial.print(millis() - starttime);
Serial.println(".");
digitalWrite(ledPin, LOW);
delay(100);
digitalWrite(ledPin, HIGH);
oldSecond = second;
}

if (digitalRead(swPin) == LOW){
second = 0;
}
}

(後日訂正:#include文やビットシフト演算子の
 不等号記号は本来半角なのですが、半角不等号は
 htmlタグに認識されるのか、削除されてしまう
 ようなので、全角に置き換えてます。半角に
 読み直してください)

1秒ごとにLEDが光って、シリアル経由で
PCに秒数を表示します。

うーん、arduinoっぽく無いなぁ。
殆どgccのプログラムそのままですわ。
内部レジスタファイルをビット単位で操作
しているので、gccのプログラムと
変わりありません…
(それに、元からの間違えが数箇所残ったまま
 です。ゼロと論理和をとっても何も変わらない
 はずだよなぁ…ASSR |= (0<<AS2);とか。
 普通なら、AS2のビットを0にするなら
 論理積取らなきゃでしょう。まぁ、ひとまず
 放って置きます)

ちなみに、出力用LEDはreduino-nano用に
合わせてデジタル3番にしています。適宜
13番に修正して使ってください。
あと、sw3(PB1ピン)のボタンを有効に
してあり、押すと秒数が0にクリアされます。
PB1の内部プルアップを有効にしています。
ボタン押下でLOW入力です。
なおreduino-nanoをお使いの方へ。sw3は
↓この写真でいう緑のボタンです。


(黄色はリセットなので、実験中は押し間違え
 しないように…)


arduinoなのに、こんなにゴチャゴチャした
プログラムってねぇ…スケッチじゃないよ…。

と思っていたら、arduinoのサイトのlibraryの
ページ↓
http://www.arduino.cc/en/Reference/Libraries
に「MsTimer2」というライブラリが公開されて
いました。

このライブラリはOfficial Librariesではなく
Contributed Librariesなんですが、簡単に
使えるので便利、便利。

このライブラリを使ってみた結果と、そもそも
なぜみなさんtimer2を好んで使っているのかに
ついても調べてみました。

調べたら、それなりに理由があってtimer2のようです。
ある程度納得の行く理由が見つかりました。

この辺のことについてはまた後で書きます。



コメント ( 0 )




arduino(ほぼ)互換機reduino-nano。IDE環境の
簡単さに味をしめてしまったので、さらに実験を。

今度はアナログセンサーICを繋いで見ます。
温度センサーICのS8100Bです。秋月に行けば
100円でたくさん並んでます。死蔵してたのを
引っ張り出してきました。
(本当は、三軸加速度センサーを繋ごうと思った
 んですが、サーボモーターと一緒にどこかへ
 行ったまま。(TへT) )

温度センサーICS8100BにICに与える電源は5V
だそうなので、例によってreduino-nanoのVccとGNDの
両端子から電源を拝借。
電池もACアダプターも必要ないのがラクチンで
good。

このS8100B。3ピンのICですが、データシートの
PDFファイルを拾ってきても、足の順番がよくわかり
ません。っていうか、普通と反対向きに表裏が定義
されているので、PDFファイルどおりに配置すると
逆差しになっちゃいます。ご注意。
正しくはこれ↓


①がVDD、②がVSS、③がVoutとなっています。
VDDを5Vに、VSSをGNDに、VoutをADコン
の入力に繋げば温度センサーとしての機能を始めます。

さて、プログラムはこんな感じ。

int ledPin = 3; // select the pin for the LED
int analogpin0 = 0; // select the pin for analog0 input

double max = 80.0 + (1085.0/8.14); // temperature at ADC=0

int data = 0; // input data from ADC
int summary = 0; // summary of input data
int i;

double t_value; //temperature value


void setup() {
pinMode(ledPin, OUTPUT); // declare the ledPin as an OUTPUT
Serial.begin(9600);

Serial.println("start");
Serial.println((int)max);
}


void loop() {

digitalWrite(ledPin, HIGH);
delay(1800);

summary = 0;
for(i=0;i

お初のブレッドボードですが、おニューではありません。
買ったは良いけど、ちっと小さすぎて死蔵していた
モノです。reduino-nano専用にしました。

さて、動かしてみると…

それっぽい温度がPC側に転送されるんですが、
温度が激しくバタバタと動きまくってます。
…電源ノイズかな?

というわけで、ノイズ対策に50回サンプリングした
平均値を取ってみたんですが…それでもバタついちゃい
ます。

そもそも、微細なアナログ電圧を弄るのに、
デジタル用電源とアナログ用電源を共用
しちゃったら電源からノイズ乗り放題だろうな
と思って、GNDとVoutの間(2番ピンと
3番ピンの間)に0.1uFのパスコンを
入れてみました。

写真では一番手前にセンサーIC。その後ろに
黄色いフィルムコンデンサーがあります。
これがその0.1uFのパスコン。

これ入れたら、一応ぴたりと止まりました。

さて、気を取り直して温度はというと…

部屋は28度なのに表示される温度は23度。
手でICを触って暖めると、それなりに
じわーっと温度が上がっていくのが判ります。
が、なんで5度も差があるの???

昔の秋月の温度計キットの説明書とか読み返して
いたら、どうやら温度センサーって大なり小なり
校正が必要みたいですね。

それにしても5度も狂うの?
何か配線間違っているのかな?
そういえば、redino-nanoの電源ピンから出力されてる
電圧をテスターで測ったら、ACアダプターより少し
低かったなぁ。PCのUSB端子から供給される
電源電圧がちょっと低かったのかな?
うーん、低かったら逆に温度は高く表示されそうだし、
いや、逆にMEGA168内部のAREF電圧が低くなってて
ADコンの値が大きな数字になっちゃってるのか???

と謎は深まるばかり。厳密なアナログにはやっぱり
ちゃんとした電源回路を用意しましょう!

まぁいいや。温度計作るんじゃなく、単なる実験
なので。まぁいつか機会があったらまたやってみます。

本当は、温度センサーICといえばLM35DZの方が
計算簡単なんだよなぁ。(氷点下計れないけど)



コメント ( 0 )