PIC勉強メモ3-6(新居浜高専PICマイコン学習キットVer.2) 7segLED点灯及び、EEPROMの使い方(3)
今回は、カウントアップと、EEPROMについて、勉強します。作成したプログラムの動作動画まず、前回のプログラムの問題点として、ボタンを押したときに変な動作をしてしまったと思います。これは、 if(RB0==0) seg_1 +=1; // SW1:ON の時、1桁目を+1する。このプログラムだと、ボタンを押したら、押し続けている間ずっと高速でカウントされてしまい、正常に動作しないためです。なので、ここを、ボタンを押して、一度離さないと、カウントしないように変更します。変更後のプログラムーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー //ボタンの連続タッチの防止 b = 0x0F & PORTB; // read SW 0x0F & PORTB = 0b00001111 if(b == 0x0F) key_st = 0; // no SW is pressed if(key_st == 0){ if(RB0 == 0){ // if SW1 is pressed seg_1 +=1; // SW1:ON の時、1桁目を+1する。 if(seg_1 == 10) seg_1 = 0; //seg_1 が10になったら、0に戻す。 key_st = 1; //連続タッチ __delay_ms (10); //チャタリング防止 } }ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーこの書き方については、PICキットVer2のサンプルプログラムの中に入っていたものを参考しています。 b = 0x0F & PORTB; // read SW 0x0F = 0b00001111この「&」は、ネットで検索すると、4ビットを抽出する 演算子と紹介されています。参考:ビット計算実際、どう考えるかというと。&演算子は、掛け算だと考えるとわかりやすいと思います。どういうことかといえば、1×1=11×0=0になると考えます。今回の例で考えると。0x0F を2進数で表すと 0x0F = 0b00001111 PORTB は、0,1,2,3ビット目が入力になっています。何もないそのままの状態の時は、上位4bitは不定になっていますので、0か1のどっちかになっています。よって、PORTB = xx1x1111 となります。 (参考:スイッチの使い方)この状態で、 0x0F & PORTB を2進数で表すと。0x0F & PORTB = 00001111 となります。それが、SW1がONになった時、PORTB = xx1x1110 となります。SW1がONになった時の0x0F & PORTB を2進数で表すと。0x0F & PORTB = 00001110 となります。以上によって、0x0F & PORTBの説明が終わりです。&演算子などについては、デジタル回路で勉強することができます。下記本で私は勉強しまして、とても分かりやすかったので、おすすめです。【中古】 ディジタル回路 電気・電子系教科書シリーズ13/伊原充博(著者),若海弘夫(著者),吉沢昌純(著者) 【中古】afb価格:1042円(税込、送料別) (2018/8/26時点)以上により、SWが押されない時は b = 00001111SW1が押された時は b = 00001110となるので、 b = 0x0F & PORTB; // read SW 0x0F & PORTB = 0b00001111 if(b == 0x0F) key_st = 0; // no SW is pressedとすることで、 SWがOFFになるたびに、key_st = 0とすることができます。後は、簡単ですね。key_stが 0の時のみ、スイッチが押されるようにしてやり、key_stを SWが押された時に、 1にしてやれば、連続して、カウントされることがなくなります。以上によって、カウントをするためのプログラムの完成です。この前のプログラムに、このプログラムを変更すれば、ちゃんとカウントするようになります。これで、7segLEDのカウントアップが出来るようになりました。後は、EEPROMを使えるようになればいいのですが。これは簡単で、ツール・ラボの通り、書けばできます。参考資料:ツール・ラボEEPROMのメモリ 256byte(1) EEPROMからのデータの読み出し アドレス0から読み出した値を変数 read_data (unsigned char)に格納する。 read_data = eeprom_read(0);(2) EEPROMへのデータの書き込み write_data (unsigned char)の値をアドレス0に書き込みたい場合は、 eeprom_write(0, write_data);(3) 初期値を設定したい場合は、main関数の外に以下のフォーマットで書く。 __EEPROM_DATA (アドレス0のデータ, アドレス1のデータ, アドレス2のデータ,アドレス3のデータ,アドレス4のデータ,アドレス5のデータ, アドレス6のデータ, アドレス7のデータ);初期値設定例: タイマー設定値をEEPROMのアドレス0に保存するとする場合。 以下の文をmain関数の前に書く。 __EEPROM_DATA (0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); (必要が無い場合でも、8byteずつ、書き込まなければならない)電源投入後の処理 EEPROMからタイマー設定値を読み込む。 unsigned char timerValue = eeprom_read(0); これでアドレス0に保存されている5を読み出すことが出来る。スタートボタンが押されたら、タイマー設定値を保存 Eeprom_write(0,timerValue);下記が、EEPROMを含めた完成プログラムになります。ただ、実はチャタリングの所の待ちの設定が難しく、これだとまだダブルカウントしてしまうことがあるという欠陥プログラムです・・・ーーーー完成プログラムーーーーーーーーーーーーーーーーーーーーー/* * File: 7segled_1.c * Author: awret仕様:電源ON7segLED:点灯 (0000)前回の終了したカウントの読み込みsw1 :ONcount up :点灯+1 (0000 → 0001)sw2 : ONcount リセット :0000 カウントの保存 */#include <xc.h>#include <pic16f886.h>//マイコン初期設定 #pragma config FOSC=HS, WDTE=OFF, PWRTE = ON, MCLRE = ON, IESO=OFF, FCMEN=OFF, LVP=OFF#define _XTAL_FREQ 20000000 //外部発振周波数設定 (delayの設定に必要// グローバル変数の定義unsigned char segdata[16] = {// 0--F ==> セグメントデータ変換用の配列 0b11000000, 0b11111001, 0b10100100, 0b10110000, // 0, 1, 2, 3, 0b10011001, 0b10010010, 0b10000010, 0b11011000, // 4, 5, 6, 7, 0b10000000, 0b10010000 // 8, 9};void INITIALIZE(void) { //REGISTERS INITIALIZE ANSEL = 0x00; //ALL PORT IS DIGITAL I/O :AN0-AN4ピンをアナログピンとして使用 ANSELH = 0x00; //ALL PORT IS DIGITAL I/O :AN8-AN13ピンをアナログピンとして使用 TRISA = 0b00000111; //RA0,1,2 = INPUT RA3,4,5 = OUTPUT TRISB = 0b00101111; //RB0,1,2,3,5 = INPUT RB4,6,7 = OUTPUT TRISC = 0b00000000; //RC = OUTPUT PORTC = 0b11111110; //LED OFF :RC0-RC7を設定 PORTA = 0b00001000; //SELECT 8bit LED(0x30) :RA0-RA7を設定 1:HIGH 0:LO}void main(void) { INITIALIZE(); //ローカル宣言 char seg[4] = {0, 0, 0, 0}; //7segLED (seg[0]:1,seg[1]:2,seg[2]:3,seg[3]:4) char i; //カウント用変数 char d = 0; //7segダイナミック点灯用変数 char b = 0, key_st = 0; for (i = 0; i < 4; i++) seg[i] = eeprom_read(i); // TRISB = 0x0F; // RB5を出力に変更 while (1) { //ボタンの連続タッチの防止 b = 0x0F & PORTB; // read SW 0x0F = 0b00001111 if (b == 0x0F) key_st = 0; // no SW is pressed if (key_st == 0) { if (RB0 == 0) { // if SW1 is pressed seg[0] += 1; // SW1:ON の時、1桁目を+1する。 key_st = 1; //連続タッチ防止 __delay_ms(10); //チャタリング防止 for (i = 0; i < 4; i++)eeprom_write(i, seg[i]); //eeprom に書き込み }else if(RB1 == 0){ for (i = 0; i < 4; i++) seg[i] = 0; for (i = 0; i < 4; i++)eeprom_write(i, seg[i]); //eeprom に書き込み key_st = 1; //連続タッチ防止 } } if (seg[0] == 10) { seg[0] = 0; //seg_1 が10になったら、0に戻す。 seg[1] += 1; } if (seg[1] == 10) { seg[1] = 0; seg[2] += 1; if (seg[2] == 10) { seg[2] = 0; seg[3] += 1; if (seg[3] == 10) seg[3] = 0; } } //7segLED ダイナミック点灯 if (d == 0) { //7seg_4点灯 RA3 = 0; RA4 = 0; RA5 = 0; PORTC = segdata[seg[3]]; d++; __delay_us(100); } else if (d == 1) { PORTA = 0b00000000; //SELECT 8bit LED(0x30) :RA0-RA7を設定 1:HIGH 0:LO //7seg_3点灯 RA3 = 1; RA4 = 0; RA5 = 0; PORTC = segdata[seg[2]]; d++; __delay_us(100); } else if (d == 2) { //7seg_2点灯 RA3 = 0; RA4 = 1; RA5 = 0; PORTC = segdata[seg[1]]; d++; __delay_us(100); } else if (d == 3) { //7seg_1点灯 RA3 = 1; RA4 = 1; RA5 = 0; PORTC = segdata[seg[0]]; d = 0; __delay_us(100); } }}//ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー・目次(リンク一覧)1.初心者のPIC勉強メモ(新居浜高専PICマイコン学習キットVer.2)2.初心者のPIC勉強メモ2(新居浜高専PICマイコン学習キットVer.2) (コンフィグレーション設定)3.初心者のPIC勉強メモ3(新居浜高専PICマイコン学習キットVer.2)(メイン、関数部)4.初心者のPIC勉強メモ4(新居浜高専PICマイコン学習キットVer.2 :データシートの見方)5.初心者のPIC勉強メモ5(新居浜高専PICマイコン学習キットVer.2 :データシートの見方)6.初心者のPIC勉強メモ6(新居浜高専PICマイコン学習キットVer.2:サンプルプログラム終了 )7.PIC勉強メモ2-1(新居浜高専PICマイコン学習キットVer.2)スイッチの使う8.PIC勉強メモ2-2(新居浜高専PICマイコン学習キットVer.2)圧電スピーカを使う9.PIC勉強メモ2-3(新居浜高専PICマイコン学習キットVer.2) タイマーの作成10.PIC勉強メモ3-1(新居浜高専PICマイコン学習キットVer.2) PWMでLED制御(1)11.PIC勉強メモ3-2(新居浜高専PICマイコン学習キットVer.2) PWMでLED制御(2)12.PIC勉強メモ3-3(新居浜高専PICマイコン学習キットVer.2) AD変換13.PIC勉強メモ3-4(新居浜高専PICマイコン学習キットVer.2) 7segLED点灯及び、EEPROMの使い方14.PIC勉強メモ3-5(新居浜高専PICマイコン学習キットVer.2) 7segLED点灯及び、EEPROMの使い方(2)15.PIC勉強メモ3-6(新居浜高専PICマイコン学習キットVer.2) 7segLED点灯及び、EEPROMの使い方(3) 16.PIC勉強メモ3-7 (割り込み処理)17.PIC勉強メモ3-8 (割り込み処理2)