今回は、MCCと比較のための手書きプログラム(?)を作成します。
目次
手書きの場合のプロジェクト構成
次回以降の記事で、MCCを使用したプログラムを作成しますが、比較のために同じ内容のプログラムを自分で書いた場合どうなるか、確認しておきます。
前回の記事で作成した「MCCTest」プロジェクトとは別に、新規プロジェクトを作成します(「Test」プロジェクトなど適当な名前で構いません)。次に、プロジェクトフォルダの中の「Source Files」フォルダ内に「main.c」ファイルを作成します。
簡単な内容のプログラムであれば、このmain.cファイル内に全てのコードを書きますので、プロジェクトとしてはこのmain.cファイルのみという構成になります。
MCCでプログラムを自動生成した場合、main.cファイル以外にいろいろなファイルが作成されますので、この基本構造と比較する形で説明を読み進めていただければと思います。
手書きの場合のプログラム
例題としては、RA2ピンに接続されている2個のスイッチの片方を押すとLED点灯、もう片方を押すとLED消灯、という動作にします。
具体的な動作としては、RA2ピンの電圧値をADコンバータで読み取り、その値に応じてLEDを点灯、消灯どちらかの動作をする、というものです。
手書きでプログラムを作成する場合、例えば以下のようになります。
/*
* File: main.c
* 内容:
* MPLAB Code Configuratorのプログラムと比較するための手書きプログラム
* RA2ピンに接続しているスイッチ状態をADコンバータで読み取り
* 片方のスイッチはLEDオン、もう片方のスイッチはLEDオフの動作
*/
#include <xc.h>
#include <stdbool.h>
// PIC12F1822 Configuration Bit Settings
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
// クロック周波数指定
// __delay関数が使用する
#define _XTAL_FREQ 1000000
void main(void) {
// PICマイコン設定
OSCCON = 0b01011010; // 内部クロックを使用、周波数を1MHzに設定
ANSELA = 0b00000100; // RA2ピンをアナログ、それ以外のピンはデジタルに設定
TRISA = 0b00001100; // RA2とRA3を入力、それ以外は出力に設定
// ADコンバータ設定
ADCON0 = 0b00001001; // RA2(AN2)をADコンバータピンに設定し、ADコンバータ機能をEbableにする
ADCON1 = 0b10000000; // 結果数値は右寄せ、ADコンバータクロックはFOSC/2、基準電圧はVDD
// LEDを点灯する
LATA5 = 1;
// ブザーをOFFにする
LATA4 = 0;
// スイッチ状態に応じたLED点滅制御を行う
while(true){
// ADコンバータ読み取り開始
GO = 1;
// 読み取り完了待ち
while(GO);
// 読み取りが終わると結果の数値はADRESレジスタに入っている
// ADRESの数値に応じてLEDのON/OFF制御を行う
//
// LEDオンの処理
// (ADコンバート値が250未満の場合)
if( ADRES < 250 ) {
LATA5 = 0;
} else {
// LEDオフの処理
// (ADコンバート値が250以上750未満)
if( 250 <= ADRES && ADRES < 750 ) {
LATA5 = 1;
}
}
}
return;
}
手書きプログラムのポイント
この手書きプログラムのポイントを以下に説明します。
- ヘッダファイルのインクルード
ヘッダファイルは、デフォルトで「xc.h」、その他必要なヘッダファイルをインクルードします。 - コンフィグレーション設定
PICマイコンの場合、マイコンの基本的な動作仕様を指定するために必ずコンフィグレーション設定が必要になります。この例では、main.cに書いていますが、別途ヘッダファイルに書いてそれをインクルードすることもあります。 - 動作設定
マイコンの周波数設定やピンの属性設定などは、それぞれの設定を行うレジスタに数値を代入することにより行なっています。このような設定を行う場合、データシートでどのレジスタにどのような値を設定すればよいか、調べながらプログラムを作成していきますが、結構面倒なんですよね。 - 機能の実装
今回の例題はADコンバータを使用しますが、ADコンバータを使用する場合、先ほどと同様に該当するレジスタに数値を代入することにより行います。複雑な機能の場合、設定レジスタが多く、また難解な場合もあり、心が折れそうになることがしばしばです。
というわけで手書きの場合、簡単なプログラムはそれほど負担ではありませんが、複雑な機能を使用する場合、レジスタの設定やら各種機能の使い方やら、いろいろとデータシートを調べることが多く、心が折れそうになる、という結論です。
次回以降の記事でMCCを使ってプログラムを作成していきます。
更新履歴
日付 | 内容 |
---|---|
2017.12.7 | 新規投稿 |
2017.12.2 | プログラムテンプレートをMPLABX IDE v5.10のものに変更 |
毎回丁寧に説明していただき、納得して読ませて頂いています。
タッチセンサーの下位で出来た、boolについていまいち納得できません。
第26回で使われているのは、”while(true){” となっており、以前の回の
while文では、数字が使われています。
数字のゼロと1ではまずいのでしょうか。 どうもすっきり致しません。
ご質問どうもありがとうございます。
結論としては数字(0と1)で記述しても問題ありません。
文章でうまくご説明できるかわかりませんが、bool型と数値について比較してみます。
while文はwhileの括弧の中が「真」か「偽」かを判定して処理をします。
PICマイコンに限らず、コンピュータの世界では「真」と「偽」は以下のように定義されています。
真: 数字のゼロ以外
偽: 数字のゼロ
そのため、たとえばwhile文を以下のように記述すると、
while(0) {処理;} → 処理は実行されない
while(1) {処理;} → 処理が繰り返し実行される
ここで、「while(1)」について考えてみます。
このwhile(1)はwhile分を繰り返し実行する意図でこのようなコードを書いているわけですが、そもそも「真」はゼロ以外の数値であれば良いので、
while(2) {処理;}
や
while(50) {処理;}
と書いても全く問題ありません。つまり「while(1)」の「1」はこのように記述する必然性がありません。「1」は真を意味するたくさんの数字の中の単に一つの数字になります。(「1」が唯一の「真」を意味する数字ではない、つまり1にする根拠はそれほど強くない)
そこで処理の意味をより明確にするために「真」と「偽」を意味するbool型の「true」「false」の登場です。bool型は「true」が「真」、「false」が「偽」の意味で、bool型はtrueとfalseの2つの値しかありません。そこでwhile文を以下のように記述するとより意味が明確になるわけです。
while(false) {処理;} → 処理は実行されない
while(true) {処理;} → 処理が繰り返し実行される
なお、stdbool.hヘッダファイルでは、true、falseは以下のように定義されています。
#define true 1
#define false 0
というわけで、while(true)と書いたところで、ビルド時にtrueは1に置き換えられていますので、ここをwhile(1)と書いても全く問題ありません。
実際にネットでコードを調べているとwhile(1)と書く人も多いですし、テンプレでwhile(1)と書かれていることもあります。
うまく説明できているかわかりませんが、何か疑問点ありましたらまたご質問いただければと思います。
日曜日なのに早速回答頂き有り難う御座います。
改めて、bool型について再確認しました。
第22回のタッチセンサーのプログラムでこの講座で初めてbool型が出て来ましたので、それを全部、0と1に置き換えで試してみました。全く同じように作動しました。
このあたりの感じがどうもすっきりしません。
「0」と「1」だと,何処の数値か解らなくなるので、「true」、「false」と表してすっきりさせると言うことで有れば成るほどと思います。
プログラミング言語として、このように書いた方が,すっきりすると言うのであれば,はい、そうですかと納得するしか有りません。
プログラムの書き方、読みやすさの問題ですので、ご自身の理解しやすい方で書かれていただければ問題ないと思います。
了解です。これですっきりしました。有り難う御座いました。