じゅんのなんでもD.I.Y.

インターネットラジオVer.2を製作中・・・

└電子工作入門

[ リスト | 詳細 ]

記事検索
検索

全1ページ

[1]

イメージ 1

#include <pic.h>

__CONFIG(UNPROTECT & DEBUGDIS & LVPDIS & BORDIS & PWRTEN & WDTDIS & INTIO & MCLRDIS);
__CONFIG(FCMDIS & IESODIS);

void main()
{
	int		ADRes;
	long	ADResSUM;
	int		i;

	OSCCON	= 0b01100000;	// 4MHz,INTIO

	TRISA	= 0b00000001;	// RA0:Analog Input
	TRISB	= 0b00000000;	// PORTB:Output

	ANSEL	= 0b00000001;	// Selet AN0
	ADCON0	= 0b01000001;	// FOSC/8,AN0,ADON
	ADCON1	= 0b10000000;	// Right Justified,VREF+:AVDD,VREF-:AVSS

	while(1)	 {
		ADResSUM = 0;
		for(i=0;i<1024;i++) {
			ADGO	= 1;
			while(ADGO) {
			}
			ADRes = ADRESH*256+ADRESL;
			ADResSUM = ADResSUM + ADRes;
		}
		ADRes = ADResSUM >> 10;
		if(ADRes>819) {
			PORTB = 0b00000001;
		} else {
			if(ADRes>683) {
				PORTB = 0b00000010;
			} else {
				PORTB = 0b00000011;
			}
		}		
	}
}


その3は、今日やるつもりなかったんだけど(笑)、ノートPCにワンセグ機能を内蔵しようと思って改造していたら、部品が足りないことに気がついて、今日の改造は諦めました。

では、その3

まず、ソースリストの頭から

イメージ 1

DispDataをcharが4文字入るタイプに変更しました。「char[3]」ってなっているけど、1文字目は「char[0]」、2文字目は「char[1]」なので、「char[3]」だと4文字入ります。なぜ4文字にしたかは後ほど…

あとはこのページは前回と変わらないですね。(←ウソ。DIG0〜2の並びをちょこっと修正しています。)

では次のページ

イメージ 2

サブルーチン名が「interrupt」というのが増えていますね。これは特殊なサブルーチンで、メインルーチンに呼び出されることはありません。いつ呼び出されるかというと、割り込みが発生した時に呼び出されます。

今回はタイマー割り込みというのを使っていて、ある一定間隔のタイマーを作って自分自身で割り込みを発生しています。

タイマーにもいろいろ種類がありますが、今回はTMR0を使っています。

TMR0タイマーはTMR0というレジスタがあって、クロックがすすむごとにひとつずつカウントアップしていって、レジスタがオーバーフローしたら割り込みが掛かります。

TMR0レジスタは8ビット長のタイマーなので0〜255までカウントアップしていき、その次はオーバーフローするので割り込みが発生して、TMR0レジスタは0にリセットされます。

256回では長い!!という時は、0からスタートではなく、例えばソフトでTMR0に200とかセットすればもっと短い間隔で割り込みが発生します。

さて、その辺の割り込みの設定方法は後回しにして、この割り込みが発生した時になにをやっているか、ソースリストを追っていくと…

割り込みサブルーチンに入って、しょっぱなでINTCONのT0IFをクリア(0をセット)しています。T0IFとはタイマー0割り込みフラグの事です。

割り込みはタイマー0以外にもたくさんあって、それらを1個だけでなく同時に設定することができるので、割り込みサブルーチンの頭で、どの種類の割り込みが発生したかをこのフラグで判別することができますが、今回はタイマー0割り込みしか使っていないので特にチェックする必要はありません。

ただ、このフラグをクリアしておかないと次の割り込みが発生しなくなっちゃいます。そこで割り込みサブルーチンの先頭でクリアしているというわけです。

次はDigitをSelect文で評価していますが、割り込みが掛かるたびにDigitが0だったら100の桁を、Digitが1だったら10の桁を、Digitが2だったら1の桁を7SegLEDに表示するようにしています。

最初に、Digitが0(100の桁を処理したい)だった場合…
 ・前回の割り込みはDigit2(1の桁)の処理だったのでDigit2の7SegLEDを消灯。
 ・PORTBへ7SegLED表示データをセット
 ・Digit0(100の桁)の7SegLEDを点灯
 ・次はDigit1の処理にしたいのでDigitに1を足す

これを残りのDigit1(10の桁)とDigit2(1の桁)のケースも記述して、これで割り込み処理はおしまいです。

では次にメインルーチン

CMCONの設定の後に割り込み関係の設定をしています。

TMR0関係の設定はほとんどがOPTIONレジスタとINTCONレジスタです。

OPTIONレジスタのT0CSはタイマー0クロックソースを選ぶビットで、1だと外部のクロックを使用し、0だと内部クロックを使用します。

PSAはプリスケーラーの割り当てです。タイマー0で使うプリスケーラーはウオッチドッグタイマーとしても使えるので、今回はタイマー0で使うと宣言しています。

次のPS2〜PS0(次ページにまたがり)はプリスケーラーの設定です。

プリスケーラーとは分周する装置の事で、タイマー0で使用するクロックだと早すぎる場合、そのクロックをTMR0レジスタに適用するときに2倍の遅さ、4倍の遅さ… とクロックを分周してTMR0へ適用(カウントアップ)してくれます。

PS2:0が「000」だとプリスケーラーは2分周、「001」だと4分周、「010」だと8分周… っで、「111」だと256分周してくれます。とりあえず最大の「111」を設定してあとで調整しましょう。

イメージ 3

次にINTCON全体をゼロクリアしてから、まずGIEをセットして割り込みを許可しています。割り込みは色んな割り込みがあり、個別に割り込みの許可・拒否(デフォルト)の設定の必要がありますが、この「GIE」でさらに一括して割り込みを許可あるいはマスクすることができます。GIEで一括許可しても、個別の割り込みを許可しなければ、それらの割り込みは発生しません。

次のT0IEはタイマー0割り込みを許可しています。TMR0を使うということですね。

その次のT0IFは先ほども説明しました。タイマー0割り込みフラグをクリアしてタイマー0割り込みが走るようにしています。

最後にTMR0レジスタを0クリアして、割り込み関係の設定は終わりです。

あとはメインルーチンのWhileループを見てみましょう。中を見るとixという変数を1個ずつ足していっているみたいですね。

その前にByteToStr(ix, DispData)というのがありますが、これはバイトタイプをストリング(文字)タイプに変換する関数です。

ixはバイト宣言していますので数字ですが、Disp7SegLEDサブルーチンの中では文字を判定していますので数字を文字に変換する必要がありますが、このByteToStr関数一発でできます。

ixはバイトタイプですから0〜255までですので、文字に変換しても3文字で済んじゃいそうですが、DispDataは4文字で宣言しましたよね? 実は3文字目の後ろに「これで終わりですよ」っていう文字が1文字付加されているので、必要長+1文字の長さの変数が必要になるんです。

なぜわざわざ数字から文字に変換したかというと10の割り算、100の割り算がめんどくさかったということと、あとは「000」の時に「0」とゼロサプレスさせて表示させたかったので、文字タイプにしたということです。

メインルーチンはこれだけ。ダイナミック点灯のめんどくさい処理は割り込みルーチンで勝手にやってくれますから、メインルーチンではひたすら「DispData」に表示したいデータをセットすることだけを考えていればいいわけです。

らくちんですね〜 (^_^)v (ここまでの仕組みを作るのが大変なんですが…)

プリスケーラーが256の時の動き↓


あちゃー、プリスケーラーが256では遅すぎたようですね。

じゃあPS2:0を「011」にセットしてプリスケーラーを一気に16まで減らしてみましょう


うん、ちょうどいいみたいですd(^-^)ネ!

↓は実際のこのプログラムを入れてみて0〜255を繰り返し表示している動きです。

じゃあ、とにかく、前回の記事で掲載したビデオのような表示をするプログラムを組んでみましょう。

イメージ 1
イメージ 2

2枚目のイメージから解説します。「main:」の後のメインルーチンからです。

CMCONやTRISなどのレジスタの設定はいつもの通り。

次にPORTAやPORTBへオールゼロを出力し、7SegLEDの表示を抑止します。

whileの無限ループを使って、その中で以下の事をやっています。

最初のSetBitですが、これは例えば「SetBit(PORTB,0)」と書くとするとそれは「PORTB.0 = 1」と同じことです。あるビットを1にセットするのがSetBit、反対に0にするのはClearBitです。

SetBitの最初のパラメータはポート名ですが、「CtrlPort」としていますが、これはなんでしょう?

1枚目の画像イメージの最初の方を見て下さい。「symbol」というのがありますが、ここで「CtrlPort」は「PORTA」だといっています。こうしておけば、回路が変わってPORTAからPORTBへソフトを変更したい時でも、symbol文を修正するだけで済みます。

同様にDIG1(100の桁)は「6」だとしています。

このことから「SetBit(CtrlPort,DIG1)」はRA6を1にする事を表しています。次とその次の文を見ると、10の桁、1の桁を0にセットしていますので、これで100の桁の7SegLEDだけトランジスタのスイッチが入ってオンの状態になったことにないます。

次の「DataPort = Decode7SegLED("3")」という文がありますが、symbol文からDataPortはPORTBであることがわかります。ビデオを見ると、100の桁は「3」が表示されていましたよね。だから、「Decode7SegLED("3")」で3を表示するようなデータが作られればいいわけです。

じゃあそのDecode7SegLEDサブルーチンを見てみましょう。1枚目のイメージを見て下さい。

Select文の中の評価する値はDecode7SegLEDへ渡されたデータをそのまま使っていますね。ちなみにこういう渡すデータの事を「引数」などと言ったりします。

今回、引数に「"3"」が渡されると、サブルーチンから戻す時に返す値「result」に「%10111100」をセットしています。

その上の行にコメントで「afbdcgpe」と書いてありますが、これはPORTBのそれぞれのビットに対する7SegLEDのセグメント位置を表しています。3だとa,b,d,c,gだけがオンになっていますね。これを前回の記事の7SegLEDデータシートと見比べてみて下さい。この5つのセグメントを表示すると「3」と表示されるのがわかるかと思います。

同様に0〜9の表示パターンをこのサブルーチンで作り出してあげているわけです。ちなみに引数に" "を渡すと全消灯になります。

メインのルーチンに戻ってみると、1秒ごとに、100の桁に3、10の桁に2、1の桁に1を表示してそれを繰り返していることがわかるでしょうか。

ちなみに「Delay_ms(1000)」を1msに変えて実行したのが↓です。

イメージ 3

同時に3桁表示されていますネ。 あれ? でも1の桁がうっすら「2」と表示されているような…

よくよくソフトをみてみると、同時に2桁分のトランジスタがオンになっている時期が一瞬だけありますね。それでうっすら点いていたんですね。

それでは必ずひとつしかトランジスタがオンにならないようにソフトを修正して…

イメージ 4

イメージ 5

うん、今度は大丈夫そうですね。これがソフトでダイナミック点灯を実現する手段です。

ただ、これだと他に仕事ができないですよねー。スイッチをつけて監視したりとか… 工夫すればできるんですが、めんどくさそうです。

じゃあ、次はメインルーチンではダイナミック点灯を意識せずにプログラミングする方法を解説します。これはタイマー割り込みという手法を使います。

ちょっと込み入っているので来週か再来週くらいになっちゃうかも (^^;)
ちょっと予定していた時間が空いたので、7SegLEDのダイナミック点灯テスト回路を作ってみました。

7SegLEDとはこんなやつです。

イメージ 1

どんな構造になっているかというとLEDが8つ入っているだけです。

↓回路図

イメージ 2

数字を表示するためのLEDが7つなので7SegLEDと言います。それに小数点を現すLEDが1つあるので全部で8つですね。

これだったら例えばPICのRB0〜RB7へ8本配線すれば数字を表示するのは簡単そうですよね。

じゃあ、これが2桁だったら? 4桁だったら? 8桁だったら?

全部PICから配線していったらとてもじゃないけどPICの足が足りません。

そこで↓のように配線します。これは3桁の例です。

イメージ 3

数字を現すLEDのA〜Gと小数点をパラに配線して、電流制限抵抗を経由してRB0〜RB7へ配線しています。これなら桁が増えてもLEDへの配線は増えていきませんね。

でもどうやって、桁ごとに表示を分けるんでしょうか? これだと全部の桁に同じ数字が点灯されてしまいそうですよね。

LEDのカソードにあたるところはA〜G、小数点の8本あるんではなくて、それが1本の共通の線に7SegLEDの内部でまとめられています。カソードを共通にしているのでカソードコモンと言います。これとは逆にアノードコモンタイプの7SegLEDもあります。

カソードはダイレクトにGNDに接続されているんではなくて、トランジスタを経由していますよね。

このトランジスタはスイッチの役目をしています。

回路図を見ると100の桁がRA0、10の桁がRA7、1の桁がRA6につながっていますね。RA0・6・7をソフトでそれぞれ「1」に設定すると、トランジスタのスイッチが入って7SegLEDのカソードがGNDとつながり点灯するしくみになっています。

これを3桁とも同時にオン・オフしていたら、表示される数字は同じですが、オン・オフのタイミングをずらしたらどうでしょうか?


こんな感じですね。

これは1秒ごとにオン・オフして、それぞれ3・2・1を表示しています。

オン・オフするタイミングをもっと高速にしていけば? 例えば1/100秒ごとにオン・オフすれば、人間の目がもつ残像を利用して、あたかも「321」と同時に点灯しているように見えるようになるはずです。

ちなみに今回は3桁が内蔵されている特殊な7SegLEDを使用しました。ただメーカーサイトをみるとすでにもうラインナップされてないようです。わたしは秋月で買いました。

イメージ 4

イメージ 5

これなら7SegLED間のパラの配線を省略することができます。



次回はソフトをMikroBasicで作ってみましょう。

全1ページ

[1]


.
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

ブログバナー

じゅん
じゅん
男性 / O型
人気度
Yahoo!ブログヘルプ - ブログ人気度について

スマートフォンで見る

モバイル版Yahoo!ブログにアクセス!

スマートフォン版Yahoo!ブログにアクセス!

検索 検索

過去の記事一覧

よしもとブログランキング

もっと見る

プライバシー -  利用規約 -  メディアステートメント -  ガイドライン -  順守事項 -  ご意見・ご要望 -  ヘルプ・お問い合わせ

Copyright (C) 2019 Yahoo Japan Corporation. All Rights Reserved.

みんなの更新記事