【
MPC17-02-C
】
PIC12F1822
マイコンタイマのハードとファームウェア製作
1
<MISSION> 次の仕様を満たすマイコン・タイマのハードウェアとファームウェアを完成せよ
(1) 作成したいマイコンライトの仕様
(a)ハードウェアの仕様
回路図に示したように、マイコ ン(PIC12F1822P)にLEDと圧 電ブザーを接続したものである
(b)ファームウェアの仕様
①電源投入時には、音が鳴った後LEDが数回点滅し、待機状態に入る。
②待機状態では、圧電ブザーの振動を監視し続ける無限ループにする。
③圧電ブザーが振動を検出した場合、指定した秒数だけLEDを規則的に点滅する。
④指定した秒数が経過すると、LEDは消灯する。
⑤②に戻る。
2
ハードウェアの製作
(1) 回路図
(2) 部品
[1]マイコン
PIC12F1822P
PIC12F1822
A
A
150Ω
茶緑茶金
[2]LED
[3]抵抗器
[4]圧電ブザー
10kΩ
(3) 実体配線図
(4) PICkit3の接続
図のように、PICkit3を接続する。
A
+
-PIC 12F1822
A
+
-PIC 12F1822
A
+
-PIC 12F1822
A
+
-PIC 12F1822
+・−端子には、
電池ボックスを接続する。
単三電池2本または3本
PICkit3
MCLR/VPP
+2.4〜
5V
-PIC 12F1822
VDD VSS Ground ICSPDAT
3
プログラミングの前の準備
(1) プログラムの開発環境の準備とプロジェクトの作成
別添資料「PICマイコンにプログラムを書き込む方法」を参
照のこと。
ここでは、学習用プロジェクトファイルmpc17-02を作成す
る方法を説明する。
(2) 統合開発環境MPLAB XIDEでプロジェクトを開く。
(a) MPLAB XIDEを起動する。
(b)新しいプロジェクトを作成
[File]-[New Project ...]をクリック
(c) [Choose Project]
初期のプロジェクト[Microchip embedded]-[Standard project]のま
ま、[Next]をクリック。
(d) [Select Device]
マイコンの種類を選択する。
[Family] は[Mid-Range-8-bit-MCUs]を選択、 [Device]は[PIC12F1822]を選択、
[Next]をクリック。
(e) [Select Header]
デバッグ用のヘッダを選択する。
今回は、簡単なプログラムなのでヘッダをつけない。[None]のま
ま、[Next]をクリック。
(f) [Selet Tool]
プログラムの書き込み用のツールを選択する。
[PICkit3]をクリックして、[Next]をクリック。
(g) [Select Compiler]
ソースプログラムをマイコンの機械語に変換するためのコンパイ ラを選択。[XC8...]の最新のものをクリックして、[Next]をクリッ
ク。
(h) [Select Project Name and Folder] プロジェクト名とフォルダ名の設定。
[Project Name]を[mpc17-02]と入力
[Encoding]は、[UTF-8]とする。これは、ソースプログラム中に日 本語を使うために設定する。
[Finish]をクリック。 (i) Main Project確認
MPLAB XIDEでは、複数のプロジェクトを開 いているとき
4
ファームウェア製作のための関数の用意とプログラムの動作確認
関数は、複雑なプログラムを作成するための部品のようなもの。次の関数を使うために、プログ ラムをコピーする。
(1) 関数の一覧
関数名 機能 戻り値 引数
initIo() I/Oポートの初期化 なし なし
initAdc() A/Dコンバータの初期化 なし なし
ledOn() LEDを点灯する なし なし
ledOff() LEDを消去する なし なし
ledBlink() LEDが点灯していたら
消灯、消灯していたら点 灯する。
なし なし
isShock() 衝撃センサの反応の有無
を検出する
衝撃あり -1,
衝撃なし 0
なし
startTimer(uint32_t time) Timer0を初期化して計 時を開始する
なし time タイマを設定する
時間(秒数) beepBuz(uint32_t length,
uint32_t height) ブザを鳴らす なし length
:
音の長さheight : 音の高さ(小さ いほど高い音)
beepAlarm() 警報音を鳴らす なし なし
(2) コピー&ペーストするプログラム /*
* LED1 : PIN 2 (RA4) : 1-OFF, 0-ON * Buzzer : PIN 6 (RA1)
* ANALOG PORT : PIN 6 (AN1) *
*/
#include <xc.h> // XC8コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む)
#include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル
// PICマイコンの動作設定その1
// PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。
#pragma config WDTE = OFF // ウォッチドッグタイマなし。 #pragma config PWRTE = ON // 64ms後にプログラム開始。
#pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。 #pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。 #pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。 #pragma config FCMEN = OFF // FCMなし。
// 動作設定その2 // Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。 #pragma config PLLEN = OFF // PLLなし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。 #pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
// I/Oポートの初期化 void initIo(void) {
OSCCON = 0b01110010 ; // Internal clock 8MHz OPTION_REG = 0b00000000 ; // Weak Pull up ON ANSELA = 0b00000000 ; // ALL Digital PORT
TRISA = 0b00001000 ; // Input : RA3, Output: others WPUA = 0b00001000 ; // Weak pull-up : RA3
PORTA = 0b00000000 ; // Initialize PORTA }
// I/Oポートの定義 (LED を接続するポートが変わった時はここを変更する)
#define PORT_LED RA4 #define TRISA_LED TRISA4 #define PORT_ADC ANSA1 #define PORT_BUZ RA1 #define TRISA_BUZ TRISA1 #define TRISA_ADC TRISA1 #define PORT_NO_ADC 1
// LED制御用関数
inline static void ledOn(void) { PORT_LED = 0; } inline static void ledOff(void) { PORT_LED = 1; } inline static void ledBlink(void) { PORT_LED ^= 1; }
// ちょっと待つ処理を簡単に書くための関数 void wait(volatile uint32_t i)
{
while (i-- > 0); }
void initAdc(void)
// A/D変換システムの初期化
{
PORT_ADC = 1; // PORT_ADC で定義されたポートをアナログポートにする。Analog port (see PORT_ADC def.) setting
TRISA_ADC = 1; // A/D 変換端子を入力モードにする。RA1 as input
ADCON0 = 0b00000001 | (PORT_NO_ADC << 2); //AD 変換を有効化。0:unimp, xxxxx:analog ch, 0:GOnDone, 1:ADC enable
ADCON1 = 0b01000000; //0:(ADFM=0)Left justified (10bit res.), 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
CM1CON0 = 0x00; //コンパレータを無効化。Comparator disable }
uint16_t getAdc(void)
// A/D変換した値を得る。
// 戻り値:
// A/D 変換されたアナログ信号の大きさ(0〜1023) {
uint16_t adcvalue; //ADC
wait(10); GO_nDONE = 1; while (GO_nDONE);
adcvalue = ADRESH<<2 | ADRESL>>6 ; return adcvalue;
int8_t isShock(void)
// 衝撃センサの反応の有無を検出する // 戻り値: 衝撃あり -1, 衝撃なし 0 {
uint8_t shock; // 衝撃の有無 uint16_t adcvalue;
uint16_t shock_threshold = 20; // 衝撃の閾値 (0 ~ 1023)
TRISA_ADC = 1; // Buzzer Port INPUT mode PORT_ADC = 1; // ADC port as Analog port adcvalue = getAdc();
if ( adcvalue > shock_threshold ) { // 閾値を超えたら shock = -1; // 衝撃あり
} else {
shock = 0; // 衝撃なし }
return shock; }
void initTimer0(void) // Timer0
{
TMR0 = 0x00; // Initialize TIMER0
TMR0CS = 0; //Internal instruction cycle clock (FOSC/4) PSA = 0; //Prescaler is assigned to the Timer0 module
PS2 = 1; PS1=1; PS0 = 1; // Prescaler Rate Select bits set 1:256 TMR0IE = 1; // Timer0 Intterupt Enable
PEIE = 1; GIE =1; }
volatile uint32_t T0Counter; // Timer0 overflow Counter
void interrupt isr(void)
// 割り込みが発生するごとに、この関数が呼ばれる。 {
if (TMR0IF) {
// Timer0 Interruption
TMR0IF = 0; // Clear Timer0 Interrupt Flag TMR0 = 0; // Clear Timer1 counter
if (T0Counter > 0) T0Counter--; // T0Counter が 0 より大きいときは1ずつ減る }
}
void startTimer(uint32_t time)
// Timerを初期化して計時を開始する
// 引数: time タイマを設定する時間(秒数) {
uint32_t T0UNIT = 31; // Timer0Counter about 1sec ( 1 / (1 / ((Clock 8MHz / 4) / prescaler 256) * 256) initTimer0(); // TIMER0 の初期化
// ブザー制御用関数
inline static void buzToggle(void) { PORT_BUZ ^= 1; }
void beepBuz(uint32_t length, uint32_t height) // ブザを鳴らす
// 引数:
// length : 音の長さ
// height : 音の高さ(小さいほど高い音) {
uint16_t i;
TRISA_BUZ = 0; // Buzzer Port OUTPUT mode PORT_ADC = 0; // ADC port as Digital port
for (i = 0; i < length; i++) { buzToggle();
wait(height); }
}
void beepAlarm(void)
// 決められた時間が経過したときの警報音を鳴らす
{
uint8_t i;
for (i = 0; i < 3; i++) { beepBuz(4000, 8); beepBuz(2000, 16); wait(2000);
} }
void main(void)
// メイン関数。この関数から動作開始
{
initIo(); // I/O ポートの初期化
ledOn(); // LED を点灯する while(1) {
5
MISSION
のファームウェアの作成手順
(1) ファームウェアの仕様の確認
①電源投入時には、音が鳴った後LEDが数回点滅し、待機状態に入る。
②待機状態では、圧電ブザーの振動を監視し続ける無限ループにする。
③圧電ブザーが振動を検出した場合、指定した秒数だけLEDを規則的に点滅する。
④指定した秒数が経過すると、LEDは消灯する。
⑤②に戻る。
(2) 設計書の記入
項目 数値
電源投入時のLEDの点滅回数[回]
衝撃が検出されたときのLED点灯時間[秒]
(3) main-mpc17-02.cファイルに仕様をコメントで記入する
main()関数の中に、仕様の順序でコメント(//で始まる文)を記入していく。
void main(void) {
// 繰り返し用カウンタの宣言
// 制限時間を変数 time_limit に設定 // I/O ポートの初期化
// A/D 変換ポートの初期化 // 音が鳴る
// 起動時に LED を 3回点滅する // 無限ループ
…以下略…
※表 コメントとプログラム(関数)の対応
コメント プログラム(関数)
// 制限時間を変数 time_limit に設定 uint32_t time_limit = 3;
// 繰り返し用カウンタの宣言 uint32_t i;
// …の処理を3回繰り返す for (i = 0; i < 3; i++) {
…
}
// I/Oポートの初期化 initIo();
// A/D変換ポートの初期化 initAdc();
// ブザーを鳴らす beepBuz(1000, 5);
// 警報音を鳴らす。 beepAlarm();
// LEDを消灯する。 ledOff();
// LEDを点灯する。 ledOn();
// LEDを点滅する。(点灯時は消灯、消灯時は点灯) ledBlink(); // 衝撃を検出したら
//そうでなければ
if ( isShock() ) {
} else {
} //タイマを time_limit 秒(変数の値で変わる)に設定し て計時開始
startTimer( time_limit );
// タイマの設定時間が経過するまで…する while ( T0Counter > 0 ) {
…
}
// 無限ループ While (1) {
…
}
(4) C言語でコーディング
上記対応表を参考にして、コメントの内容を実行するための処理を書く。 よくわからない場合は、次ページ以降のヒントを実行してから考えるとよい。
void main(void)
// メイン関数。この関数から動作開始
{
uint32_t i;// 繰り返し用カウンタの宣言 initIo();// I/O ポートの初期化
…以下略…
6
(ファームウェアのヒント)LED
が点灯・消灯するプログラム
(1) main-mpc17-02.c を開くMPLAB XIDEの画面で、”MPC17-02”-”Source Files”-”main-mpc17-02.c”を開く。
(2) main-mpc17-02.c の編集
次のmain関数をコピー&ペーストして、前のものと置き換え、ビルド、書き込み。動作を
確認する。
void main(void)
// メイン関数。この関数から動作開始
{
initIo(); // I/O ポートの初期化
ledOn(); // LED点灯
wait(10000);
ledOff(); // LED消灯
wait(10000);
while(1) { } return; }
(3) ビルドと書き込み、動作確認
[Make and Program Device Main Project]のアイコンをクリック
[CAUTION]警告のダイアログボックスが表示されたら、
電源が正しく接続されていることを確認して、[OK]をクリック。
(標準では、PICkit3から電源供給をしないので、問題はない)
※書き込みの段階で、赤い字でエラーメッセージが出る場合、電源が接続 されていなかったり、電線の接続に不具合があったりすることが多い。
X IDEの下側の[Output]に[Programming/Verify complete]と表示されたら、書き込み完了。
7
(ファームウェアのヒント)LED
が決まった回数だけ点滅するプログラム
(1) main-mpc17-02.c を開くMPLAB XIDEの画面で、”MPC17-02”-”Source Files”-”main-mpc17-02.c”を開く。
(2) 関連知識:for文
決められた条件を満たしている間、{}で囲まれた処理を繰り返すには、for文が使える。
決まった回数だけ繰り返す処理を書くときの基本的な書式は以下のとおり。 uint32_t i; // カウンタ変数 i の宣言
for ( i = 0; i < (繰り返し回数); i++ ) { (繰り返す処理);
}
uint32_tは、符号なし(unsigned)32ビットの整数(integer)型変数を表す。
i++は、変数iが繰り返しのたびに1ずつ増加することを表す。
(3) main-mpc17-02.c の編集
次のmain関数をコピー&ペーストして、動作を確認する。
void main(void)
// メイン関数。この関数から動作開始
{
uint32_t i; // LED点灯回数のカウンタ
initIo(); // I/O ポートの初期化
for (i = 0; i < 3; i++) { // {}の中を 3回繰り返す ledOn(); // LED点灯
wait(20000);
ledOff(); // LED消灯
wait(20000); }
while(1) { } return;
}
(4) ビルドと書き込み、動作確認
[Make and Program Device Main Project]のアイコンをクリック
[CAUTION]警告のダイアログ ボックスが表示されたら、 電源が正しく接続されている ことを確認して、[OK]をク リック。
(標準では、PICkit3から電源供給をしないので、
8
(ファームウェアのヒント)LED
が決まった時間で点滅するプログラム
(1) main-mpc17-02.c を開くMPLAB XIDEの画面で、”MPC17-02”-”Source Files”-”main-mpc17-02.c”を開く。
(2) タイマに設定した時間だけ、LEDを点灯するサンプルコード
設定した秒数の間だけ何もしないで待つには、次のコードを使う。
while( T0Counter );
また、設定した秒数の間、LEDを点滅させるには、次のように書ける。
while ( T0Counter ) { blinkLed(); wait(5000) } ;
(3) main-mpc17-02.c の編集
次のmain関数をコピー&ペーストして、動作を確認する。
void main(void)
// メイン関数。この関数から動作開始
{
uint32_t time_limit = 3; // タイマの設定時間(秒数)
initIo(); // I/O ポート初期化
while (1) { // 無限ループ
ledBlink(); // LED の点滅を切り替える(点灯→消灯、消灯→点灯) startTimer(time_limit); // タイマの開始
while ( T0Counter ); // 設定時間になるまで待つ }
return; }
(4) ビルドと書き込み、動作確認
[Make and Program Device Main Project]のアイコンをクリック
[CAUTION]警告のダイアログ ボックスが表示されたら、 電源が正しく接続されている ことを確認して、[OK]をク リック。
(標準では、PICkit3から電源供給をしないので、
問題はない)
※書き込みの段階で、赤い字でエラーメッセージが 出る場合、電源が接続されていなかったり、電線の 接続に不具合があったりすることが多い。
X IDEの下側の[Output]に[Programming/Verify complete]と表示されたら、書き込み完了。
9
(ファームウェアのヒント)衝撃を検出すると
LED
が点灯するプログラム
(1) main-mpc17-02.c を開くMPLAB XIDEの画面で、”MPC17-02”-”Source Files”-”main-mpc17-02.c”を開く。
(2) 関連知識:if文
条件を満たしているときだけ実行する処理を選択できるのがif文である。
衝撃センサが衝撃を検出したとき(isShock() == -1)だけLEDを点灯するコードは、以下のとお
り。
if ( isShock() == -1 ) { // 衝撃を検出したとき if ( isShock() ) と書いてもよい ledOn(); // LED点灯
} else { // そうでないとき ledOff(); // LED消灯
}
(3) main-mpc17-02.c の編集
次のmain関数をコピー&ペーストして、動作を確認する。
void main(void)
// メイン関数。この関数から動作開始
{
initIo(); // I/O ポート初期化
initAdc(); // A/D 変換ポートの初期化
while (1) {
if (isShock() == -1) { // 衝撃を検出したとき if ( isShock() ) と書いてもよい ledOn(); // LED点灯
} else { // そうでないとき ledOff(); // LED消灯
} } return; }
(4) ビルドと書き込み、動作確認
[Make and Program Device Main Project]のアイコンをクリック
[CAUTION]警告のダイアログ ボックスが表示されたら、 電源が正しく接続されている ことを確認して、[OK]をク リック。
(標準では、PICkit3から電源供給をしないので、
問題はない)
10
(ファームウェアのヒント)警報音を鳴らすプログラム
(1) main-mpc17-02.c を開くMPLAB XIDEの画面で、”MPC17-02”-”Source Files”-”main-mpc17-02.c”を開く。
(2) main-mpc17-02.c の編集
次のmain関数をコピー&ペーストして、動作を確認する。
void main(void)
// メイン関数。この関数から動作開始
{
initIo(); // I/O ポート初期化
beepAlarm(); // 警報音を鳴らす while (1) {
} return; }
(3) ビルドと書き込み、動作確認
[Make and Program Device Main Project]のアイコンをクリック
[CAUTION]警告のダイアログ ボックスが表示されたら、 電源が正しく接続されている ことを確認して、[OK]をク リック。
(標準では、PICkit3から電源供給をしないので、 問題はない)
※書き込みの段階で、赤い字でエラーメッセージが 出る場合、電源が接続されていなかったり、電線の 接続に不具合があったりすることが多い。
X IDEの下側の[Output]に[Programming/Verify complete]と表示されたら、書き込み完了。
11
(ファームウェアのヒント)決まった長さと高さの音を鳴らすプログラム
(1) main-mpc17-02.c を開くMPLAB XIDEの画面で、”MPC17-02”-”Source Files”-”main-mpc17-02.c”を開く。
(2) beepBuz()関数
音は、圧電ブザーを繰り返しON/OFFすることで振動させることで発生する。
ブザーをON/OFFする間隔を短くすると高い音になり、ブザーのON/OFFの処理を繰り返す回数
を増やすと、長さが長くなる。 (3) main-mpc17-02.c の編集
次のmain関数をコピー&ペーストして、動作を確認する。
void main(void)
// メイン関数。この関数から動作開始
{
initIo(); // I/O ポート初期化
initAdc(); // A/D 変換ポートの初期化
beepBuz(10000, 8); //音を鳴らす(長さ 10000, 高さ 8) while (1) {
} return; }
(4) ビルドと書き込み、動作確認
[Make and Program Device Main Project]のアイコンをクリック
[CAUTION]警告のダイアログ ボックスが表示されたら、 電源が正しく接続されている ことを確認して、[OK]をク リック。
(標準では、PICkit3から電源供給をしないので、
問題はない)
※書き込みの段階で、赤い字でエラーメッセージが 出る場合、電源が接続されていなかったり、電線の 接続に不具合があったりすることが多い。
X IDEの下側の[Output]に[Programming/Verify complete]と表示されたら、書き込み完了。
12
(付録)プロジェクトの作成
学習用プロジェクトファイルmpc17-02-bの作成方法を説明する。
(1) プログラムの開発環境の準備
別添資料「PICマイコンにプログラムを書き込む方法」を参
照のこと。
(2) 統合開発環境MPLAB XIDEでプロジェクトを作成
(a) MPLAB XIDEを起動する。
(b)新しいプロジェクトを作成
[File]-[New Project ...]をクリック
(c) [Choose Project]
初期のプロジェクト[Microchip embedded]-[Standard project]のま ま、[Next]をクリック。
(d) [Select Device]
マイコンの種類を選択する。
[Family] は[Mid-Range-8-bit-MCUs]を選択、 [Device]は[PIC12F1822]を選択、
[Next]をクリック。
(e) [Select Header]
デバッグ用のヘッダを選択する。
今回は、簡単なプログラムなのでヘッダをつけない。[None]のま
ま、[Next]をクリック。
(f) [Selet Tool]
プログラムの書き込み用のツールを選択する。
[PICkit3]をクリックして、[Next]をクリック。
(g) [Select Compiler]
ソースプログラムをマイコンの機械語に変換するためのコンパイ ラを選択。[XC8...]の最新のものをクリックして、[Next]をクリッ
ク。
(h) [Select Project Name and Folder] プロジェクト名とフォルダ名の設定。
[Project Name]を[mpc17-02-b]と入力
[Encoding]は、[UTF-8]とする。これは、ソースプログラム中に日
本語を使うために設定する。
[Finish]をクリック。
(i) Main Project確認
MPLAB XIDEでは、複数のプロジェクトを開 いているとき
は、”Main Project”に設定したプロジェクトだけをビルドするよ
うになっている。上記の操作では、プロジェクト”mpc17-02”は Main Projectになっている。他のプロジェクトを実行するなどし て、mpc17-02がMain Project ではない(太字でない)ときは、
MPLAB XIDEのProjectウインドウで、”mpc17-02-b “ を右ク
(3) ソースプログラムの作成
(a)プロジェクトの展開
画面左側のProjects ウィンドウにある[▶︎
mpc17-02-b]の︎をクリックし、展開する。
(b)ソースファイルの追加
[▶︎Source Files]を右クリック。
[New ▶︎]-[main.c…]
(c)ソースファイル名の入力
ファイル名として[main-mpc17-02-b]と入力。 [Finish]をクリック。
(d)作者名の変更
ソースファイルの先頭3行目にある、Author (作者)の欄に、作者名を記入。
/*
* File: main-mpc17-02.c * Author: *****
*
* Created on August 11, 2017, 3:12 PM */
(MISSION)の解答例
/*
* LED1 : PIN 2 (RA4) : 1-OFF, 0-ON * Buzzer : PIN 6 (RA1)
* ANALOG PORT : PIN 6 (AN1) *
*/
#include <xc.h> // XC8 コンパイラ用のヘッダ(レジスタ名などのキーワードの定義を含む) #include <stdint.h> // 整数型のビット数を明示して宣言するためのヘッダファイル // PIC マイコンの動作設定その1
// PIC micro controller Configuration 1
#pragma config FOSC = INTOSC // 内部クロック使用。 #pragma config WDTE = OFF // ウォッチドッグタイマなし。 #pragma config PWRTE = ON // 64ms 後にプログラム開始。 #pragma config MCLRE = OFF // 外部リセットなし。RA3 は入力ピン。 #pragma config CP = OFF // コード保護なし。
#pragma config CPD = OFF // データ保護なし。
#pragma config BOREN = ON // 電源電圧低下時のリセットあり。 #pragma config CLKOUTEN = OFF // クロック出力不可。
#pragma config IESO = OFF // 内部外部クロックなし。 #pragma config FCMEN = OFF // FCM なし。
// 動作設定その2 // Configuration 2
#pragma config WRT = OFF // 書き込み保護なし。 #pragma config PLLEN = OFF // PLL なし。
#pragma config STVREN = ON // スタックオーバー/アンダーフローでリセット。 #pragma config BORV = LO // 電源電圧低下監視閾値は Low モード
#pragma config LVP = OFF // 低電圧プログラムなし。 // I/O ポートの初期化
void initIo(void) {
OSCCON = 0b01110010 ; // Internal clock 8MHz OPTION_REG = 0b00000000 ; // Weak Pull up ON ANSELA = 0b00000000 ; // ALL Digital PORT
TRISA = 0b00001000 ; // Input : RA3, Output: others WPUA = 0b00001000 ; // Weak pull-up : RA3
PORTA = 0b00000000 ; // Initialize PORTA }
// I/O ポートの定義 (LED を接続するポートが変わった時はここを変更する) #define PORT_LED RA4
#define TRISA_LED TRISA4 #define PORT_ADC ANSA1 #define PORT_BUZ RA1 #define TRISA_BUZ TRISA1 #define TRISA_ADC TRISA1 #define PORT_NO_ADC 1 // LED 制御用関数
inline static void ledOn(void) { PORT_LED = 0; }
inline static void ledOff(void) { PORT_LED = 1; }
inline static void ledBlink(void) { PORT_LED ^= 1; }
// ちょっと待つ処理を簡単に書くための関数 void wait(volatile uint32_t i) {
while (i-- > 0); }
// A/D 変換関数
// A/D conversion functions void initAdc(void) {
PORT_ADC = 1; // PORT_ADC で定義されたポートをアナログポートにする。Analog port (see PORT_ADC def.) setting TRISA_ADC = 1; // A/D 変換端子を入力モードにする。RA1 as input
ADCON0 = 0b00000001 | (PORT_NO_ADC << 2); //AD 変換を有効化。0:unimp, xxxxx:analog ch, 0:GOnDone, 1:ADC enable ADCON1 = 0b01000000; //0:(ADFM=0)Left justified (10bit res.), 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF CM1CON0 = 0x00; //コンパレータを無効化。Comparator disable
}
uint16_t getAdc(void) // A/D 変換した値を得る。 // 戻り値:
// A/D 変換されたアナログ信号の大きさ(0〜1023) {
uint16_t adcvalue; //ADC
wait(10); GO_nDONE = 1; while (GO_nDONE);
adcvalue = ADRESH<<2 | ADRESL>>6 ; return adcvalue;
}
int8_t isShock(void)
// 衝撃センサの反応の有無を検出する // 戻り値: 衝撃あり -1, 衝撃なし 0 {
uint8_t shock; // 衝撃の有無 uint16_t adcvalue;
uint16_t shock_threshold = 20; // 衝撃の閾値 (0 ~ 1023) TRISA_ADC = 1; // Buzzer Port INPUT mode
PORT_ADC = 1; // ADC port as Analog port adcvalue = getAdc();
if ( adcvalue > shock_threshold ) { // 閾値を超えたら shock = -1; // 衝撃あり
} else {
shock = 0; // 衝撃なし }
{
TMR0 = 0x00; // Initialize TIMER0
TMR0CS = 0; //Internal instruction cycle clock (FOSC/4) PSA = 0; //Prescaler is assigned to the Timer0 module PS2 = 1; PS1=1; PS0 = 1; // Prescaler Rate Select bits set 1:256 TMR0IE = 1; // Timer0 Intterupt Enable
PEIE = 1; GIE =1; }
volatile uint32_t T0Counter; // Timer0 overflow Counter void interrupt isr(void)
// 割り込みが発生するごとに、この関数が呼ばれる。 {
if (TMR0IF) {
// Timer0 Interruption
TMR0IF = 0; // Clear Timer0 Interrupt Flag TMR0 = 0; // Clear Timer1 counter
if (T0Counter > 0) T0Counter--; // T0Counter が 0 より大きいときは1ずつ減る }
}
void startTimer(uint32_t time) // Timer を初期化して計時を開始する // 引数: time タイマを設定する時間(秒数) {
uint32_t T0UNIT = 31; // Timer0Counter about 1sec ( 1 / (1 / ((Clock 8MHz / 4) / prescaler 256) * 256) initTimer0(); // TIMER0 の初期化
T0Counter = time * T0UNIT; // TIMER0 のカウンタを設定値にする }
// ブザー制御用関数
inline static void buzToggle(void) { PORT_BUZ ^= 1; }
void beepBuz(uint32_t length, uint32_t height)
// ブザを鳴らす
// 引数:
// length : 音の長さ
// height : 音の高さ(小さいほど高い音)
{
uint16_t i;
TRISA_BUZ = 0; // Buzzer Port OUTPUT mode PORT_ADC = 0; // ADC port as Digital port
for (i = 0; i < length; i++) {
buzToggle(); wait(height); } } void beepAlarm(void)
// 決められた時間が経過したときの警報音を鳴らす
{
uint8_t i;
for (i = 0; i < 3; i++) {
beepBuz(4000, 8); beepBuz(2000, 16); wait(2000); } } void main(void)
// メイン関数。この関数から動作開始
{
uint32_t time_limit = 3; // 時間の設定
uint32_t i; // LED点滅回数のカウンタ
initIo(); // I/O ポートの初期化 initAdc(); // A/D 変換ポートの初期化
for (i = 0; i < 3; i++) {
ledOn(); wait(10000); ledOff(); wait(10000); }
beepBuz(1000, 5); // 起動音を鳴らす
while (1) { // 無限ループ開始
if ( isShock() ) { // 衝撃を検出したら
ledOn(); // LED を点灯する。
beepBuz(2000, 2); // タイマが始まるときの音
startTimer( time_limit );
while ( T0Counter > 0 ) { //タイマが決まった時間になるまで待つ
ledBlink(); wait(10000); }
ledOff(); // LED を消灯する。
beepAlarm(); //警報音を鳴らす。
} else {//そうでなければ
ledOff(); // LED を消灯する。
}
} //無限ループ終わり