jl7gmnのblog

yahooブログから移行してきました。アマチュア無線を中心としたブログです。

2013年06月

PICその26

タイマー0の確認でサンプルプログラムを動かし本当に計算どおりに動いているかを確かめた。
なんとタイマー0の計算と全く異なる時間で動いていた。サンプルプログラムは以下(PICはPIC12F683です。)
********************************************************************************************
#include <xc.h>
static void pic_init();

// XC8 CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator
//: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
//#pragma config WDTE = ON        // Watchdog Timer Enable bit (WDT enabled)
#pragma config WDTE = OFF        // Watchdog Timer Enable bit (WDT enabled)
//#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config PWRTE = ON      // Power-up Timer Enable bit (PWRT disabled)
//#pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
#pragma config MCLRE = OFF       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit
                                //(Internal External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit
                                //(Fail-Safe Clock Monitor is enabled)

unsigned int cnt;

void interrupt timing(){
    if(INTCONbits.T0IF == 1){
        INTCONbits.T0IF = 0;
        cnt++;
        if(cnt == 50){  //50:20mSECx50=1000mSec=1Sec
            cnt = 0;
            GPIObits.GP5 = ~GPIObits.GP5;
            GPIObits.GP4 = ~GPIObits.GP4;
        }
    }
}
int main(void) {
    pic_init();//PICの初期化

    cnt = 0;
    TMR0 = 100;
    INTCONbits.T0IE = 1;//Timer0 interrupt enable
    INTCONbits.GIE = 1;//Genaral interrupt enable
    while(1){
    }
}

//PICの初期化
static void pic_init(){
    OSCCON     = 0b01110000;//8MHz internal clock
    TRISIO     = 0b00000000;//ALL output
    ANSEL      = 0b00000000;//ALL Digital output
    GPIO       = 0b00000000;//GPIO 0 clear
    CMCON0     = 0b00000111;//Comparator not use
    OPTION_REG = 0b00000111;//Pull-up Enable and prs 111:1/256
}
********************************************************************************************
青色がタイマー0の主要設定にかかわる部分だが、ロジアナでの時間は1.6secである。本来なら1secでないといけない。ためしにTMR0の設定値をいろいろと変えてみたが、全く時間の変化がない状態でした。
理論計算上の待ち時間は(256-TMR0)*256*(4*(1/8MHz))なので(256-100)*256*0.5E-6=0.019968sec(≒20msec)で カウント数が50で トータル 20msec*50=1000msec(1秒)なはずなのだ。(実際の計算値は0.9984sec)
TMR0の値が書き込まれていない。つまりTMR0のカウントは初期値の256カウントをしているのか?計算してみると256と想定して 待ち時間は(256-0)*256*0.5E-6=0.032768sec  50カウントで 50*0.032768=1.6384sec なんとTMR0がやはり設定されていないようだ。サンプルプログラムではタイマー0がうまく動作していない。設定がされていない状態が分ったので、mainルーチン上のTMR0=100;を削除して、間違いなく設定されるプログラムの割り込みルーチンに書き加えることにした。
********************************************************************************************
void interrupt timing(){
    TMR0=100;
    if(INTCONbits.T0IF == 1){
        INTCONbits.T0IF = 0;
        cnt++;
        if(cnt == 50){  //50:20mSECx50=1000mSec=1Sec
            cnt = 0;
            GPIObits.GP5 = ~GPIObits.GP5;
            GPIObits.GP4 = ~GPIObits.GP4;
        }
    }
}
********************************************************************************************
上記でコンパイルしてタイマー0の動作時間を確認したところ計算どおりに動くようになりました。
XC8の場合TMR0設定はグローバル変数のようなわけにはいかないようです。?
もう少し調べてみる必要がありそうな感じだ。

PICその25

PICの回路図を記録したくて前に使っていたEAGLE CADのfreeの最新版をインストールしてみた。
CADなので100x80mmの基板まで2層パターンで作成できるものだ。前のバージョンはEAGLE ver5.4.0だったが、いまはver6.4.0になっている。しばらく使っていなかったので、回路図の描き方をわすれていたが、あちらこちら触っているうちに思い出してきた。3Dでのパーツ立体表示なぞもあったと思うが、どうやるんだっけ??状態だ。が何とかPICの回路図はかけました。フレームつけるのわすれた!これもまたどうするんだっけ状態だ。忘備録がいるな~!!
イメージ 1
EAGLE Ver6.4.0を実行したフォーム

実際の回路図作成Schematicフォーム
イメージ 2

Boardで自動パターン作成実行画面
イメージ 3

自動作成だといろいろとパターンの不満がでるが、回路図どおりに自動結線してくれるのは、見ていて楽しいですよ。実際にパターンは作成する必要はまだないが、回路図を作っているとパターはどうしても作成したくなります。ベタアースなんかもできるし、基板サイズは小さいとはいえ本格的CADだ。今回も回路図を作った後に結構な時間パターン修正で遊んで時間をとられています。ということで今回は回路図を記録しておく為のEAGLE CADでした。


PICその24

PIC16F88での7SEGx4LEDの時計をLCDに表示するためのプログラムが一応できた。7SEGで使用したプログラムは基準タイマー以外はほとんど使わないで、結局別プログラムにて作ることとなりました。応用的な作成は可能ですが、新たに作り直したほうが、プログラム量的にもスマートで面倒が無いと思われたからです。作るとはいえ、あちらこちらからの良いとこ取りの手法です。時計とRS-232Cシリアル通信もマージ的に組み込んだ為かなりプログラム量が増えています。ちょっとした事をやると4Kはメモリでは不足した為、シリアル通信も簡単な動作でしか組めていません。IOポートの使い方の練習であれば十分だということで、まずは納得しています。なお動作は,時計とシリアル通信は別モードとして動作させています。切り替えは3つあるSWの内の一つを割り当てました。時計用のSWは、時間のHH時間調整用SWと、MM分調整用SWの2つです。モード切り替えは通常時(OFF)で時計モードです。SW3はプッシュSWでなく,ON/OFF型のSWで行います。ONではシリアル通信モードに表示が変わり、時計モードは表示されません。SWをOFFに戻すとまたもとの時計モードになります。時計はキチンと止まらずに動きます。通常時(電源オン)は時計モードです。
イメージ 1
いままで、小型のブレッドボードにあった通信インターフェースをメインのブレッドボードに移し変えました。空いたブレッドボードは別のPIC12F683での割り込み、タイマーの動作確認練習用で使用しています。
イメージ 2
実際にボード上のPIC16F88でのCLOCKのボード上の状態です。7SEGは表示のみのせてあり、本体のPICは小型のブレッドボードにあります。なお表示はシャッタースピードの関係で1桁しか写っていませんが、人の目では全部表示が見えています。
イメージ 3
時計はLCDのカーソル表示を止めて、モード切替(RS-232C)との表示前の初期化が一番大切です。データ表示は単純に場所を決めてデータ表示するだけです。表示前に表示部をクリアしてから表示です。尚ちらつきはほとんど感じられません。
 手持ちにロジックアナライザがあったので、7SEGX4LEDのクロックの各LEDを順次表示するタイミングを見てみた。ちゃんと1つ1つ別々に表示されているのがわかる。高速に行われているので、点いたり消えたりしているのが全く目には分らないということです。
イメージ 4
ロジックアナライザーでは一目瞭然で各7SEGx4LEDの1目盛りが1msのアクティブローで動作しているのが分ります。1回全LED表示するのに4msで、1秒間に250回も表示動作が行われています。このロジックの表示を見ていて思い出しましたが、ステッピングモータの回転のロジックに似ています。応用ができますね。今回は割り込みとタイマーの使い方の理解に時間をかけました。時計の基準時間作成が基本であることが良く分りました。

PICその23

ふとネットでLCDのサンプルプログラムを見ていたら、簡単な定義だけでLCDとPICのポートの任意設定ができるものがあった。対応する箇所は同じだが、シンプルですばらしい。ビットシフトとかで頭を使ったのに、こんなに良い方法があるとは、といった感じだ。内容は次の通りでした。
main.c上の変更対応箇所はPORTA用のTRISAの設定で全く同じ方法です。
TRISA = 0b00111000; //ポートAの方向を設定 RA3,RA4,RA5 INPUT RA6用

lcd.cでは以下の定義部追加と先の2関数の差し替えで対応します。
--------------------------------------------------------
#define lcd_d7 RA6
#define lcd_d6 RA2
#define lcd_d5 RA1
#define lcd_d4 RA0
--------------------------------------------------------
void lcd_data_byteset(unsigned char c){
        lcd_d4 = (( c ) & 0x01);
        lcd_d5 = (( c >> 1 ) & 0x01);
        lcd_d6 = (( c >> 2 ) & 0x01);
        lcd_d7 = (( c >> 3 ) & 0x01);
        LCD_STROBE;
}
void lcd_data_set(unsigned char c){
    lcd_d4 = (( c >> 4 ) & 0x01);
    lcd_d5 = (( c >> 5 ) & 0x01);
    lcd_d6 = (( c >> 6 ) & 0x01);
    lcd_d7 = (( c >> 7 ) & 0x01);
    LCD_STROBE;
    lcd_d4 = (( c ) & 0x01);
    lcd_d5 = (( c >> 1 ) & 0x01);
    lcd_d6 = (( c >> 2 ) & 0x01);
    lcd_d7 = (( c >> 3 ) & 0x01);
    LCD_STROBE;
}
---------------------------------------------------------
 #defineで定義したポートビット単体に引数cの対応するビットシフト時の値をいちいち読み込んでいるので、ポートに対して1対1に設定できている。
lcd_data_setについて確認してみると。
引数cのデータを(C7,C6,C5,C4,C3,C2,C1,C0)とすると最初の4行で上位の(C7,C6,C5,C4)が(RA6,RA2,RA1,RA0)に出力される
またLCD_STROBE;の後の4行では引数cの下位の(C3,C2,C1,C0)が(RA6,RA2,RA1,RA0)に出力される。きちんと引数cの上位データ値、下位データ値と設定できています。ということで、ポートの定義を変えることのみで対応ができる。早速今までのlcd.cの部分を上記に変更して確認してみた。こんなにシンプルに任意ポート対応ができてしまいました。やはり先人はすごいですね。THANKS!
なお、参考プログラムに関しての利用はホームページ上で以下の通り問題ないようです。
----------------------------------------------------------------------------------
当サイトのソフトウエアは特に記述が無い限りPDS(Public Domain Software)とします。
作権表示義務無し。商用利用、改造、自由。連絡不要とします。
役立ててやって下さい。
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
これだけ簡単にポート定義とTRISAの簡単な書き換えだけでLCDポートとPIC側の任意ポート対応できるならファンクション化は必要ないですね。

PICその22

以下、PIC21の続きです。
最終的な書き換え後の関数を下記します。
**********************************************************************************
void lcd_data_byteset(unsigned char c){
PORTA =((c & 0b00000111)|((c<<3) & 0b01000000));//for RA6,RA2,RA1,RA0 low DATA
        LCD_STROBE;
}

void lcd_data_set(unsigned char c){
    PORTA = (((c >>4 ) & 0b00000111)|(((c >>1 ) & 0b01000000)));//for RA6,RA2,RA1,RA0 Hi DATA
        LCD_STROBE;
        PORTA = ((c & 0b00000111)|((c<<3) & 0b01000000));//for RA6,RA2,RA1,RA0 low DATA
        LCD_STROBE;
}
**********************************************************************************
これで、ポートAのLCD対応の関数部の変更が完了です。

あとはmain.cのTRISAの設定をポート変更にあわせた書き換え対応が必要です。
LCDプログラムに対し、時計の回路のRA3は入力なので入力に、RA6は出力になります。
TRISA = 0b01110000; //ポートAの方向を設定 (RA4,RA5.RA6 INPUT)(RA0,RA1,RA2,RA3,RA7 OUTPUT)
         ↓
TRISA = 0b00111000; //ポートAの方向を設定 (RA3,RA4,RA5 INPUT)(RA0,RA1,RA2,RA6,RA7 OUTPUT)

上記の変更を行って、全て完了です。実際に液晶のポートD7のPICポートRA3の接続をPICポートRA6に接続変更し対応ポート(RA6,RA2,RA1,RA0)ということでLCDプログラムを走らせて見ます。前のポート対応(RA3,RA2,RA1,RA0)の時となんら違いなく動作しました。
 案外、このポート変更対応はLCD表示を扱うには欠かせない手法の一つと思います。
今回はプログラムの動作を解析確認し、プログラム作成でビットのシフトを駆使したため、とても為になったと思います。細かなハードのタイミング設定は、メーカーの資料が欠かせませんが、特に今回の様なポート仕様変更などは、ある程度頻繁にあることなので、比較的容易に対応できるようになればこれにこした事は無いと思います。なので今回のポート変更は、XC8でLCDを使うユーザーには役に立つかも。
時間がとれれば、LCDポート設定コンフィグとしてのファンクション化をしてみるのも面白いかもしれない。
誰かやってくれればありがたいです。Hi!(microCではLCDのPICポート設定専用関数が用意されているようです。Lcd_Custom_Config(&PORTB, 4, 6, 7, 1, &PORTA, 1, 0, 7);きゃりーぱみゅぱみゅじゃないが、それいいな!です。
 ここまでで、LCDの動作プログラム上で時計用の3つのSWがひとまず確保できたので、LCDに時間表示をする変更を考えてみようかなぁ~。セグメント出力は全部はずして...時間取り込みは変数に変えて....それから.....現在思案中です。

アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード
  • ライブドアブログ