「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 )
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする




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 )
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする




メインPCの調子が今ひとつです。

電源入れたら、ハイバネから復旧できませんの
メッセージが!リセットしても電源off-on
しても同じ症状。

HDDは交換してからまだ数ヶ月だし、ハイバネ中
にエラーが出た記憶も無いし…。

それに、bios画面がなんだか少し遅い気が…
熱暴走かなぁ?

ちなみに、エアコン入れてから電源入れなおしたら
前回ハイバネにした状態からちゃんと立ち上がった…

うーん。

ちなみに、1ヶ月くらい前も変な動きしたので、
一旦箱を開けてみたんですが、中の電解コンは
全部無事みたいでした。

といっても、もう4年前後使ってるマザボだから
そろそろ寿命なのかな?

だからと言って、速度的にはまだ新しいマシンに
したいという要望は全然ないしなぁ。
それ以上に、PCの再インストールが大嫌い
なんだよなぁ…
ゼロからソフト類をインストールしなおすと、
それだけで丸一日以上は掛かるはず。

そういえば最近HDDのバックアップとって
なかったなぁ。ちゃんとバックアップとって
置かないと危険だな。

熱暴走といえば、さっき近所を自転車で走って
いたら、ネコがマンホールの真中でゴロンと
寝っ転がってました。道の真中のマンホールで!
…危ないってば!

しかも、暑すぎて判断力もクソもないのか、
近くを通り過ぎても片目を開けてこっち
ちょっとだけ眺めただけ。
野生感ゼロですよー。こっちが気を使ってしまった…

マンホールの上って、涼しいのかなぁ?
金属製じゃなくて、セメント製のマンホール
だったんだけどな。

植え込みの土の上とかのほうが涼しそうな
気がするんだけども…。



コメント ( 0 )
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする




もひとつオマケに、アナログ”入力”の実験も
してみました。

アナログ出力はPWMでしたが、アナログ入力は
内蔵ADコンバーターにアサインされてます。

1個ではさみしいし、死蔵してある三軸加速度
センサーモジュールを繋ぎたいので、
アナログ入力の0~2の3本をそれぞれ可変抵抗
で分圧した電圧を入力することにします。

こんな感じ。

USBケーブルや電源ケーブルなど、邪魔に
なるものが全然無いので、ブレッドボードの
真中に「えい、やっ」とぶっ差すことができて
good! レイアウトが良くできてます。

プログラムはarduinoのサイトを参考にして
こんな感じ↓

int ledPin = 3;   // select the pin for the LED
int analogpin0 = 0;  // select the pin for analog0 input
int analogpin1 = 1;  // select the pin for analog1 input
int analogpin2 = 2;  // select the pin for analog2 input
int data = 0;  // input data from ADC


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

  Serial.println("start");

}

void loop() {

  data = analogRead(analogpin0);  //read data from analog0 pin
  Serial.print(data);
  Serial.print(",");

  data = analogRead(analogpin1);  //read data from analog1 pin
  Serial.print(data);
  Serial.print(",");

  data = analogRead(analogpin2);  //read data from analog2 pin
  Serial.println(data);

  analogWrite(ledPin, data/4);  //(works on pins 3, 5, 6, 9, 10, and 11)

  delay(100);
}

(さっきと違って、ちゃんと<pre>タグを使って
 整形してみました)

ご覧のとおり、アナログ入力0、1、2の3つの
アナログ入力端子を使ってます。入力した3つの値は
シリアルの9600bpsで出力してます。

アナログ2から入力した10ビット値(0~1023)
は、4で割って0~255の閾値に変換後、3番ピン
(LED)にPWMでアナログ出力してます。
可変抵抗をグルグルするとLEDの明るさが変わります。

注意点としては、アナログADの参照電圧は常に5V
固定ということです。つまり、外部リファレンス電圧などは
使えないようです。
(↑標準機能の場合。もしかしたら内部レジスタを直接
 操作すれば外部リファレンスが使えるかも)
 

それにしても簡単にできますね。ホント。プログラム
じゃなくてまさにスケッチという表現が的確。

大きいものをガチガチに組み上げるにはちょっと…
という感じではありますが、買ってきたばかりの
センサーIC等をチョイチョイっと繋いで試す時には
便利便利。


そういえば、アナログ出力は大体490Hzだそうですが、
逆数を取ると約2m秒。
http://www5b.biglobe.ne.jp/~YASUSI/gallery/electronics/050820/050820.htm
一方↑こちらのサイトによると、サーボモーターのPWM
周期は16ms。うーん、一桁違うなぁ。

このままではサーボモーター使うにはちょっと不便か?

なぜこんな周波数で固定されてるんだろう?
LEDの点滅が人間の目でわからない程度の周波数
にしました、という事なのだろうという気がするけど、
サーボモーターを使うには不便すぎるなぁ。

サーボモーター用には何か別のアナログ出力方法が
あるのかなぁ?



コメント ( 0 )
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする




reduino-nanoのテストプログラムです。

せっかくLEDもついてることだし、完全互換品と
違ってLEDが13番ではなく3番についているので、
PWMでLEDを光らせることができます。

ということで、LEDで蛍のようなボワーとした
点滅をさせてみました。簡単です。


int ledPin = 3; // select the pin for the LED
int i;

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

void loop() {
for(i=0;i<255;i++){
analogWrite(ledPin, i); //(works on pins 3, 5, 6, 9, 10, and 11)
delay(5);
}

for(i=255;i>0;i--){
analogWrite(ledPin, i); //(works on pins 3, 5, 6, 9, 10, and 11)
delay(5);
}
}

こんな感じ。
(タブがずれちゃうみたいなので、arduino-IDEの
 「tool」の「auto format」で整形してください)

まぁ、こういうフィジカルコンピューティングで
PWMを使うとしたら、普通はLEDじゃなくて
サーボモーターだよなぁ。

サーボモーター、秋月で買っておいた死蔵品があった
はずなんですが、どこに隠しておいたかな?
(ハムスター並みの記憶力なので、どこにしまったか
忘れちゃう…)

見つけたら繋いで遊んでみよう。



コメント ( 0 )
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする



« 前ページ