第27回 ブザーを制御するプログラムを追加する

プログラムにブザーを制御する部分を追加して、基礎編の回路とプログラムを完成させます!

目次

今回の説明

回路を完成させるために以下の順序で説明しています。このエントリの説明は(6)「ベース回路にブザーを追加する」のプログラム作成の部分になります。

  1. LEDを電池と抵抗のみで光らせる回路を組み立てる
    PICマイコンの回路を組み立てる前に、まずはブレッドボードに慣れておくことにします。電池、抵抗、LEDのみを使って、ブレッドポード上に回路を組んでLEDを光らせてみます。ここでは電池、抵抗、LEDの回路記号と回路図の説明をして、回路図からブレッドボードに組む方法を説明します。まずはブレッドボードに慣れましょう!
  2. PICマイコンのベース回路を組む
    はじめの一歩の回路は、LEDを1秒に1回光らせるだけの回路です。この回路をブレッドボードに組み立てます。
  3. プログラムを作る
    LEDを1秒に1回光らせるプログラムを作成します。
  4. PICマイコンに書き込んで動作させる
    作成したプログラムをPICマイコンに書き込んで動作させてみます。
  5. ベース回路にスイッチを追加する
    LEDの点滅をスイッチで開始させるために、ベース回路にスイッチを追加します。これまではLEDを光らせる、という出力制御をしましたが、今度はPICマイコンで外部から信号を入力する方法を確認します。
  6. ベース回路にブザーを追加する
    スタートスイッチ付きの、1秒に1回光らせる回路を作りましたので、ブザーを追加してタイマーとして完成させます。

動作処理の方針

今までに作成したプログラムは以下のような動作処理をしています。

  1. 初期状態の設定として、2番ピン(RA5ピン)をONにして、LEDを点灯させる(電源が入ってPICマイコンが動いたことを示すため)
  2. スイッチの4番ピン(RA3ピン)を監視し続けて、スイッチがONになるまで待つ
  3. スイッチが押されたら、LEDを1秒に1回、点滅させる。これを永遠繰り返す

今度は、一定時間経過したらブザーを鳴らすようにします。これをどのように制御すればよいか、上の処理をベースに差分を考えてみます。差分を赤文字にしてあります。

  1. 初期状態の設定として、2番ピン(RA5ピン)をONにして、LEDを点灯させる(電源が入ってPICマイコンが動いたことを示すため)。また3番ピン(RA4ピン)をOFFにしてブザーをOFFにする
  2. スイッチピンの4番ピン(RA3ピン)を監視し続けて、スイッチがONになるまで待つ
  3. スイッチが押されたら、LEDを1秒に1回、点滅させる。この点滅は指定秒数繰り返す
  4. 指定秒数経過したら、3番ピン(RA4ピン)をONにしてブザーを鳴らす。また2番ピン(RA5ピン)をONにして発光ダイオードを点灯させる。
  5. (4)の状態を続ける

今まで作成したプログラムに、赤文字の部分を追加、あるいは変更すればプログラムが作れそうです。それではひとつひとつ、どのようにすればよいか検討しましょう。

まず(1)のブザーをOFFにする制御ですが、RA4ピンをOFFにすればよいので、

LATA4 = 0;

でよさそうです。

(2)は変更がありませんのでそのままです。

(3)の指定秒数繰り返すのはどうしたらよいでしょうか。予め決めた回数を繰り返すのは、for文を使えばよさそうですよね。ということで、現在、点滅の繰り返しはwhile文を使用していますので、これをfor文に変えて一定回数繰り返すことにします。

また(4)ですが、(3)で一定時間点滅を繰り返してfor文を抜けたら、ブザーを鳴らします。また、LEDも同時に点灯させようと思います。ブザーを鳴らすのは、

LATA4 = 1;

でOKですよね。またLEDを点灯させるのは

LATA5 = 1;

で問題なしです。あとは(5)でこの状態をずっと保持するので、

while(1){
}

とすることにします。

プログラム作成

動作処理部分は上のように変更すればよさそうですが、他の部分についても検討します。何度もしつこくてすみませんが、プログラムの構成を再度確認しましょう。

Program structure

今回もコメント部分は変更履歴をメモしておくことにします。

次のヘッダファイルインクルード部分ですが、ブザーの制御はピンの制御だけで済みますので、今までどおりのヘッダファイルで問題ありません。PICマイコンコンフィグレーション設定部分とその他設定部分も、特に変更はありません。

それではメイン関数内を確認します。

main関数基本構造

まず内部クロック設定は特に変更ありません。

ピンの設定ですが、現在はすべてのピンがデジタル設定ですのでANSELAについては変更なしです。

入出力設定(TRISA)については、RA3ピンが入力の設定で、他のピンは出力の設定です。今回は新規にRA4ピンを出力ピンとしてブザーを制御しますが、すでに出力ピンになっていますので、この部分も変更なしです。

あとはピンの初期設定でブザー制御の追加となります。

ということで、ほぼピンの初期設定部分と動作処理部分の追加・変更で済みそうですね。

特に難しいところはないと思いますので、これ以上の解説はせずに、プログラムを載せておきます。なお、タイマーの時間は10秒にしています。コメントを入れましたので、プログラム上での処理内容を確認してみてください。わからないことがありましたらお問い合わせページからご連絡いただくかコメントいただければと思います。

/*
 * File:   main.c
 * 変更履歴
 *    2016.11.20: スイッチ制御部分を追加
 *    2016.12.05: 時間計測とブザー制御部分を追加
 */

#include <xc.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_ms()関数が使用する
#define _XTAL_FREQ 1000000

void main(void) {

    // PICマイコン設定
    OSCCON = 0b01011010;  // 内部クロック周波数を1MHzに設定
    ANSELA = 0b00000000;  // すべてのピンをデジタルモードに設定
    TRISA  = 0b00001000;  // すべてのピンを出力モードに設定(ただしRA3ピンは常に入力モード)
    
    // 時間計測の変数
    unsigned char timer;

    // LEDを点灯する
    LATA5 = 1;
    
    // ブザーをOFFにする
    LATA4 = 0;

    // スイッチが押されるまで待つ
    while(RA3){
    }
        
    // LED点滅処理(10秒間繰り返す)
    for(timer=0; timer<10; timer++){
        // LEDを950ms消灯する
        LATA5 = 0;
        __delay_ms(950);
        // LEDを50ms点灯する
        LATA5 = 1;
        __delay_ms(50);            
    }
    
    // LEDを点灯する
    LATA5 = 1;
    
    // ブザーをONにする
    LATA4 = 1;
    
    // 何もしないで待つ
    while(1){
    }

    // 以下の命令は実行されない
    return;

}

動作確認

プログラムが理解できたら、ビルドしてPICマイコンに書き込み、動作確認してみてください。10秒間点滅を繰り返したら、ブザーが鳴ってLEDが点灯した状態になるはずです。動きましたか? これでついに入門回路の完成です!

ただ、残念ながら時間が経つとブザーは鳴りっぱなしですので、ブザーを止めるには電池ボックスのスイッチをOFFにするしかありません。この改善については、チャレンジ課題にしたいと思います。

動作確認についても、うまく動かなかったり、わからないところがありましたらご連絡いただければサポートできる範囲でお手伝いします。

タイマー時間の変更

さて、これでようやく完成したわけですが、上のプログラムではあとあと問題が出てしまうような、よくありがちな実装をしています。もしかしたら、プログラムを読んでいる時に気づかれた方もいらっしゃるかもしれませんね。

動作確認するときの時間を短くするために、タイマーとしては短い10秒、という時間で動作確認しました。でも実用的なタイマーでしたらもうちょっと時間をのばしてみたいですよね。ということで早速プログラムを変更して5分タイマーを作ってみたいと思います。

今の10秒タイマーを5分タイマーにするには、for文のところが現在は10回ループするようになっているので、ここを5分=300秒、つまり300回ループするように変更すれば、簡単じゃん、っていう感じですよね。

それでは実際にfor文のところを

for(timer=0; timer<300; timer++) {

と変更して動作させてみてください。点滅を300回数えるのはしんどいので、時計で時間を計測してみましょう。電源をつないで、スイッチを押してタイマーを開始して、、5分待って、、、そろそろ6分すぎるんだけど、、、、あれ? 鳴らない、、、、、なかなかブザーが鳴りませんよね。このプログラムではいつまで待ってもブザーは鳴りません。

結論を言ってしまうと、変数の「timer」に問題があります。このtimerは

unsigned char timer;

で型宣言しています。この “unsigned char” は符号なし8ビット、ということで10進数でいうと、0〜255までしか数字を保持できません。for文では “timer++” としてtimerをカウントアップしていますが、timerが255の状態で timer++ をすると0に戻ります。つまり、いつまで待っても300(正確には299)までカウントできないわけです。

timerを型宣言するときは実用的な時間が計測できるようにします。符号なしの変数型としては、

  • unsigned char (8ビット)
  • unsigned short (16ビット)
  • unsigned short long (24ビット)
  • unsigned long (32ビット)

があります。8ビットは255までのカウント、つまり4分強のタイマーしか作れません。16ビットあれば65535までのカウント、時間に直すと18時間強までのタイマーとなります。今回の回路はそこまでの時間を正確に測れなさそうですので、timerの型は unsigned shortで十分でしょう。ということで、このあたりにも注意してプログラムの最終版とします。タイマー時間は5分にしています。

/*
 * File:   main.c
 * 変更履歴
 *    2016.11.20: スイッチ制御部分を追加
 *    2016.12.05: 時間計測とブザー制御部分を追加
 */

#include <xc.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_ms()関数が使用する
#define _XTAL_FREQ 1000000

void main(void) {

    // PICマイコン設定
    OSCCON = 0b01011010;  // 内部クロック周波数を1MHzに設定
    ANSELA = 0b00000000;  // すべてのピンをデジタルモードに設定
    TRISA  = 0b00001000;  // すべてのピンを出力モードに設定(ただしRA3ピンは常に入力モード)
    
    // 時間計測の変数
    unsigned short timer;

    // LEDを点灯する
    LATA5 = 1;
    
    // ブザーをOFFにする
    LATA4 = 0;

    // スイッチが押されるまで待つ
    while(RA3){
    }
        
    // LED点滅処理(5分=300秒間繰り返す)
    for(timer=0; timer<300; timer++){
        // LEDを950ms消灯する
        LATA5 = 0;
        __delay_ms(950);
        // LEDを50ms点灯する
        LATA5 = 1;
        __delay_ms(50);            
    }
    
    // LEDを点灯する
    LATA5 = 1;
    
    // ブザーをONにする
    LATA4 = 1;
    
    // 何もしないで待つ
    while(1){
    }

    // 以下の命令は実行されない
    return;

}

プログラムの仕様を決めるときは、最小値や最大値に注意するようにしたほうがよいですね。今回はタイマーでしたのでどのくらいの時間まで計れればよいかを先に検討して、それに応じてプログラム内の変数を定義するように注意します。

他の例では、例えば温度計を作る場合、何度〜何度まで計れるようにするか、その値が扱える内部の変数をどう定義するか検討する必要があります。

なお、余裕を見て変数を用意するのはよくありません。long型を使えばかなりの値を扱うことができますが、必要バイト数が多い分、メモリを余計に消費しますし、処理時間もかかることになります。

WindowsやMacのアプリでしたら贅沢にメモリやCPUパワーを使ってもよいかもしれませんが、マイコンの場合はメモリやCPUパワーはかなり貧弱ですので、プログラムを作る際はこのような観点でも注意するようにしてください。

これで一通り終わりました。随分長い間いろいろと寄り道もしてしまいましたが、ようやく入門の回路とプログラムが完成しました。いろいろとわかりづらいところもあったかもしれませんが、長い間お疲れさまでした!

次回から、基礎編の締めくくりとしてチャレンジ課題に挑戦しましょう!

更新履歴

日付 内容
日付 内容
2016.12.5 新規投稿
2018.11.24 プログラムテンプレートをMPLABX IDE v5.10版に変更
通知の設定
通知タイミング
guest
9 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
ahjime wada
ahjime wada
7 年 前

ありがとうございます。一応動いたのでこの先もうすこし悪あがきしてみようと思います。お忙しいと思いますのでお返事はあわてません。こちらはもう集中してできない歳なのでゆっくりのほうがありがたいです。
 それにしてもたぶん初歩的なことがわかっていないので起こすミスが多いのでしょうね。今回は丁寧に教えていただいてありがたかったです。また、わからないところがあればよろしくお願いします。

管理者
管理者
7 年 前

早速エラーメッセージどうもありがとうございました。

メッセージを見る限り、マイコンの型番が正しく認識されていないようですが、2回目の書き込みで動作したとのことで、プログラム書き込みは成功しているようです。

こちらでももう少し調べてみますので、何か分かりましたらこのコメント欄に書き込みいたします。

時間が取れないため、週末の調査になりますことをご容赦ください。

hajime wada
hajime wada
7 年 前

お世話になっております。お忙しいのに無理なことを言っているのではないかと心配です。先ほど思い立って最初から新規のプロジェクトにして更のプログラムをコピーし、接続も確認し、pickitも慎重に押さえて書き込みましたところ、やっぱりエラーが出ましたが、2度目になんと最後のverifyがでて正常に作動しました!(verifyは昨日もなんかの拍子に出ていたのですが作動はしませんでした)これで成功ということでいいのでしょうか?

 念のためエラーメッセージをお送ります。

Connecting to MPLAB PICkit 3…

Currently loaded firmware on PICkit 3
Firmware Suite Version…..01.46.14
Firmware type…………..Enhanced Midrange

Programmer to target power is enabled – VDD = 5.000000 volts.
Target Device ID (0x0) is an Invalid Device ID. Please check your connections to the Target Device.

Device Erased…

Programming…

The following memory area(s) will be programmed:
program memory: start address = 0x0, end address = 0x7ff
configuration memory
program memory
Address: 0 Expected Value: 2801 Received Value: 0
Failed to program device

*****************************************************

Connecting to MPLAB PICkit 3…

Currently loaded firmware on PICkit 3
Firmware Suite Version…..01.46.14
Firmware type…………..Enhanced Midrange

Programmer to target power is enabled – VDD = 5.000000 volts.
Target Device ID (0x0) is an Invalid Device ID. Please check your connections to the Target Device.

Device Erased…

Programming…

The following memory area(s) will be programmed:
program memory: start address = 0x0, end address = 0x7ff
configuration memory
Programming/Verify complete
p.s.1 返信のところではDISQUS が邪魔をして送れません。
p.s.2 スクリーンショットの意味が分かりません(^^;)

管理者
管理者
7 年 前

早速ご確認いただき、どうもありがとうございました。
DeviceIDが0x2700ということはPICマイコンを正しく認識しているようですが、なぜエラーになるのか、もう少し調べる必要がありそうです。

お手数ですが、MPLABXで書き込みエラーが発生した際の、エラーメッセージを丸ごとコピペして教えていただけますでしょうか。(スクリーンショットでしたら本サイトの問い合わせページから一度ご連絡いただければと思います。こちらのメールアドレスをご連絡いたします)

hajime wada
hajime wada
7 年 前

すみません 投稿するのに2時間くらいかかりました(;_;)まあ、いつもこんな調子なので気長にお付き合いください。

hajime wada
hajime wada
7 年 前

早速回答していただいてありがとうございます。午前中外出していていま拝見しました。まず電圧の変更ですがFailed

がでました。

 次に、ブザーを外して書き込みするとやはりエラーが出るのですがDEVICE ID(0x2700)と数字が変わってました。そこで、振出しに戻ってスイッチ回路第25回のスイッチ回路のプログラムをコピーして書き込んだところまた同じエラーが出ました!ということで以前うまくいっていたところが、ダメになってしまい落ち込んでおります。

 ちょっと頭を冷やしてひと休み後もう一度挑戦したいと思いますが、なんか基本的なところでミスをしているのかもしれません。書き込みソフトの使い方がおかしいのかもしれません。このへんが初心者の悲しさですね。

 ちなみにブザーそのものは直接つなぐとなります。

しかし投稿がうまくいきません・・・

hajime wada
hajime wada
7 年 前

古希を迎えてから電子工作に取り組み、だいたいが挫折で終わっておりますが、このブログは何とかここまでついてこれました(といっても全部わかっているわけではありません)。
 ところがここにきてブザーが鳴りません。書き込むときに Target Device ID(0x0) is an Invalid DEvice ID. という警告が出て、続けると Failed to Program Device になります。
 プログラムはコピーしたし、ブザーは DB Products のHDB06LFPNを秋月で買いました。先に進めないのでどうしたらいいのか教えていただけるとありがたいです。
 ・・・とここまで書いて投稿の仕方がわからない・・・

管理者
管理者
返信  hajime wada
7 年 前

wadaさま、はじめまして。
古希を迎えられてから電子工作に取り組まれたとのことで、心より尊敬いたします。自分も何歳になっても色々なことに興味をもつ心を持ちたいと思っていますので、そのような姿勢をお持ちでとても羨ましいです。

ところで、ブザーをつけるとInvalid Device IDになる、とのことですが、すみません、すぐに時間が取れませんので少々お時間をいただければと思います。

また、お手間でなければ、以下の動作がどのようになるかお教えいただけませんでしょうか。

1) ブレッドボードからブサーを取り外して(ブザーだけで構いません)、ブザーを鳴らすプログラムを書き込むことができるか

2) (1)がうまく行くようであれば、プログラム書き込み後、ブザーを取り付けて、ブザーを鳴らすことができるか

3) (1)がうまくいかない場合、ブザーとブザーを接続するためのワイヤを外して、ブザーを鳴らすプログラムを書き込むことができるか

試していたただく内容が不明確でしたらコメントいただければと思います。

お手数ですがよろしくお願いいたします。

管理者
管理者
返信  hajime wada
7 年 前

度々申し訳ございません。

取り急ぎ、このサイトで作成しているブレッドボードで確認したところ、現象は発生しませんでした。

ただ、確認していて思い出したのですが、以前、書き込みできていた回路で、急にInvalid Device IDのエラーが出ることがありました。

その時の対処方法は正確に思い出せないのですが、一度、以下の操作を試していただけませんでしょうか。書き込み時の電圧を5Vではなく3.375Vにしてみる、というものです。(特に根拠はないのでただ試していただくだけですが…)

MPLABX上で

1) プロジェクトフォルダを右クリック
2) メニューが表示されるので一番下のPropertiesメニューを選択
3) プロパティダイアログが開くので、左側のCategories領域のPicKit3を選択
4) 上のメニューのOption CategoriesのPowerを選択
5) 電圧メニューから3.375を選択

この設定で書き込みを行うとどうなるかご確認いただければと思います。

目次