ラベル PIC16F88 の投稿を表示しています。 すべての投稿を表示
ラベル PIC16F88 の投稿を表示しています。 すべての投稿を表示

2010年11月18日木曜日

PWM機能でLEDの明るさ制御


RB0ポートかRB3ポートのどちらかを選択して利用出来ます。
Device Flags:で指定します。


/*
概要:PWM機能でLEDの明るさ制御

使用マイコン:16F886

使用ポート:RB0/INT/CCP1

発振器: Clock: 8.0MHz 内蔵発振

Device Flags:
 _CP_OFF    _CCP1_BR0   _DEBUG_OFF  _WRT_ENABLE_OFF
_CPD_OFF _LVP_OFF    _BODEN_OFF _MCLRE_OFF
_PWRTE_ON _WDT_OFF    _INTRC_IO
IESO_ON__CFG2   _FCMEN_ON__CFG2

MikroC v8.2.0.0
*/


void main() {

 unsigned short int i;

 OSCCON = 0b01110000; //内蔵発振器 8MHz使用に設定

 // A/D Pref // ANALOG=1, DIGITAL=0 
 ANSEL = 0b00000000;

 TRISA = 0b11111111;  //すべてインプット
 TRISB = 0b00000000;  //すべてアウトプット

 //ポートの初期化
 PORTA = 0b00000000;
 PORTB = 0b00000000;

 //PWM mode//
 PWM_Init(5000);   //Initialize PWM module at 5KHz:
 PWM_Start();   // start PWM

 while (1) {
  for (i = 0; i < 256; i++){
  PWM_Change_Duty(i);
  Delay_ms(50);
 }

 }
}

PWM_Change_Duty(i); iが0の時0% 127の時50% 255の時100%とマニュアルには書いてありました。

2010年11月17日水曜日

A/D変換+RS232C通信




RA3ポートは基準電圧です。本来なら電源電圧に接続しないで、正確に出力された電源に接続するべきでしょう。
電源電圧を基準電圧に使うならRA3ポートを使って電源電圧に接続しないで、
プログラムで基準電圧に電源電圧を利用する設定をすればいいでしょう。
ADCON1.VCFG1 = 0; //基準電圧は電源電圧
ADCON1.VCFG0 = 0;

/*
概要:A/D変換した値をRS-232c通信でパソコンに送信

PIC16F88

A/D: RA1 (10KΩ半固定抵抗で分圧しアナログ値を生成)
基準電圧入力ポート:RA3
RS-232通信用:RB2/RX RB5:TX

Clock: 8.0MHz 内蔵発振器使用

Device Flags:
_CP_OFF  _CCP1_RB3  _DEBUG_OFF  _WRT_ENABLE_OFF
_CPD_OFF  _LVP_OFF  _BODEN_OFF  _MCLR_OFF  _PWRTE_ON
_WDT_OFF  _INTRC_IO  _IESO_ON__CFG2  _FCMEN_ON__CFG2

MikroC v8.2.0.0
*/
 void main() {
 //使用変数の定義
 float volt,press,calc,adc_value;
 char inter, deci;

 PORTA = 0b00000000; //PORTAの初期化
 PORTB = 0b00000000; //PORTBの初期化

 OSCCON = 0b01110000; //内臓クロック8MHzに設定

 //A/D変換clock設定 0.125us*16倍=2.0us at 8MHz > 1.6us
 //Fosc=8MHz 8/2/8
 ADCON0.ADCS1=0;  //01 Fosc/8
 ADCON0.ADCS0=1;
 ADCON1.ADCS2=1;     //1:Foscを1/2にする

 ADCON1.VCFG1 = 1; //基準電圧入力ポートをRA3に設定
 ADCON1.VCFG0 = 0;   //Vref+  Vss

 // A/D利用PORTの設定 // ANALOG=1, DIGITAL=0 //
 ANSEL = 0b00000010; //RA3のみアナログ使用

 TRISA = 0b00001010; //RA1,RA3のみ1:入力に設定、他は0:出力
 //マイコンの初期化終わり

 usart_init(9600);

 do {
  //アナログデータの取得 10bit(0~1023)
  adc_value = ADC_Read(1); //RA1値をアナログデジタル変換(0~1023)
  press = adc_value*0.005; //AD変換した値を電圧に 0.005=基準電圧(5v)/1023 pressは小数点未満二桁
  inter = (int) press;        //小数点未満の切り捨て
  deci= (int) (press*10.0) - inter*10;//小数点未満の一桁目を取得
  usart_write('V');
  usart_write('O');
  usart_write('L');
  usart_write('T');
  usart_write('=');
  usart_write(inter | 0x30);
  usart_write('.');
  usart_write(deci | 0x30);
  usart_write('V');
  usart_write(13);        //1310改行コード
  usart_write(10);
  delay_ms(1000);
 } while(1);
}

2010年11月15日月曜日

RS232C通信-PCソフトを作成してLED点灯

PIC18F4550 USBマイコンボード(秋月電子通商製)で遊ぶ
のコーナーのCDC - Basic Demo の 
ボタンでLEDの点灯・消灯 で作ったソフトを流用して作成しました。


パソコン側ソフト:pic-pc.zip
ダウンロード

PIC側ソフト:rs232c-pic-pc.zip
ダウンロード

RS232C通信-コマンドでLED点滅

とりあえずRS232C通信 で作成したプログラムを修正して、
コマンドを送ってLEDを点滅させるプログラムに変更したいと思います。

/*
概要:RS232C通信-コマンドでLED点滅

対象PIC  :PIC16F88
クロック :内蔵8MHz
コンパイラ:mikroC Version: 8.2.0.0

電源:5V

コンフィグレーションフラグ:
_CP_OFF  _CCP1_RB3  _DEBUG_OFF  _WRT_ENABLE_OFF
_CPD_OFF  _LVP_OFF  _BODEN_OFF  _MCLR_OFF  _PWRTE_ON
_WDT_OFF  _INTRC_IO  _IESO_ON__CFG2  _FCMEN_ON__CFG2


*/

void main() {

    unsigned short int com;


 PORTA = 0b00000000;  //PortBの中初期化
 PORTB = 0b00000000;  //PortBの中初期化

 OSCCON = 0b01110000; //8MHzを指定

 ANSEL = 0b00000000;  //すべてデジタルポート

 TRISA = 0b00000000;
 TRISB = 0b00000100;    //B2/RXを入力に,B5/TXを出力

 Usart_Init(9600);      //通信速度の設定

 do {

        if (Usart_Data_Ready()) {
            com = Usart_Read(); //受信データの読込
        }

        switch(com) {
            case 'a':
                PORTA.F0 = 1; //RB5 ON
                break;
            case 'b':
                PORTA.F0 = 0; //RB5 OFF
                break;
        }
    } while(1);

}

とりあえずRS232C通信

使うのは2,3,5,7,8番ピン
7番ピンと8番ピンは直結します。
パソコンからの送信要求(7番ピン)に対し、
無条件に送信可(8番ピン)を返すようにするためです。
5番ピンはグランドに接続します。
2番ピンと3番ピンだけが、PICから制御する信号線になります。


aを永遠に送り続けるだけのプログラム
/*
概要:取り合えすRS232C通信

対象PIC  :PIC16F88
クロック :内蔵8MHz
コンパイラ:mikroC Version: 8.2.0.0

電源:5V

コンフィグレーションフラグ:
_CP_OFF  _CCP1_RB3  _DEBUG_OFF  _WRT_ENABLE_OFF
_CPD_OFF  _LVP_OFF  _BODEN_OFF  _MCLR_OFF  _PWRTE_ON
_WDT_OFF  _INTRC_IO  _IESO_ON__CFG2  _FCMEN_ON__CFG2


*/

void main() {
 PORTA = 0b00000000;  //PortBの中初期化
 PORTB = 0b00000000;  //PortBの中初期化

 OSCCON = 0b01110000; //8MHzを指定

 ANSEL = 0b00000000;  //すべてデジタルポート

 TRISA = 0b00000000;
 TRISB = 0b00000100;    //B2/RXを入力に,B5/TXを出力

 Usart_Init(9600);      //通信速度の設定

 do {
    Usart_Write('a'); //RS232C通信でPCへ送信
 } while(1);

} 





mikroC のメニューバーのTools から USART Terminal を開いて接続してたところ


ハイパーターミナルで表示した場合

電源を入れた直後の接続しか正常に常時出来ません。
接続と切断を繰り返すと別な文字が表示されたりします。

2010年11月12日金曜日

赤外線リモコンの受信

概要:赤外線リモコンの信号受信
使用PIC:PIC16F88
赤外線リモコン受信モジュール:PL-IRM-2161-C438(秋月電子通商で購入)
使用リモコン:NECのテレビリモコン

参考サイト
PICとMikroCのTVリモコン信号の受信機 のコーナーは非常に参考になりました。
リモコンのフォーマットは 秋月電子通商のダウンロードコーナーの資料も大いに役立ちます。
手元にNECのテレビリモコンがあってラッキーでした。



タイマTMR0を使用しての時間の計測
内部クロックの周期は(1/4MHz)*4=1usとなる。
TMR0は8bitのカウンタであるため,
TMR0は,256us(1us * 256)までの時間を計測することができる。
これではリーダー部の9msを計測できないのでプリスケーラを設定する。

プリスケーラ1/64に設定
(1/4MHz)*4*64=64us=0.0664ms
TMR0は,16.384ms(64us * 256)までの時間を計測することができるようになる.
0.064msから16.384ms の間の時間を計測できる。

リーダ部の9ms を計測したい場合に必要なタイマーカウント、
9ms = 0.064ms * x
x = 9ms/0.064ms
x = 140.625 = 141回
/**
概要:TVリモコン信号(赤外線)受信器
(ボタンと押している間だけLED点灯、ボタンをはなすとLED消灯)

Device Flags: _BODEN_OFF _BOREN_OFF _CP_OFF _PWRTE_ON _WDT_OFF
       _LVP_OFF _MCLRE_OFF _INTRC_OSC_NOCLKOUT

PICとMikroCさん(http://kuri6005.sakura.ne.jp/pic/)のソースを
PIC16F88  内蔵4MHzに変更
RB0:赤外線リモコン受信モジュール PL-TRM2161-C438 二個で100円
LED: RB2, RB3, RB4, RB5 動作確認用
電源:乾電池2本(3V)
コンパイラ:MikroC 8.2.0.0
*/
unsigned short int flag = 0;
unsigned short int custom_a = 0;
unsigned short int custom_b = 0;
unsigned short int data_a = 0;
unsigned short int data_b = 0;
unsigned short int old_F2 = 0;
unsigned short int old_F3 = 0;
unsigned short int old_F4 = 0;
unsigned short int old_F5 = 0;

void interrupt() {            //割込み関数
    unsigned short int i, b;

    if(INTCON.INTF) {         //割込み種がRB0/INT割込みの場合
        INTCON.INTE = 0;      //RB0/INT割込みの禁止

        //リーダ部の確認        時間の計測にはタイマー0を割込みなしで使用
        TMR0 = 0;            //timer0リセット、タイマーは常に動作
        
        while(PORTB.F0 == 0);   //0Vの状態をカウント、5Vになるまでループ
                                //カウンタの比較
        if(TMR0 < 120) {       // < 141 (=9.0ms * 4MHz/4 /64) 誤差を見越して120
            flag = 1;           //120より少なかったらヘッダではないので受信を終了し、
            return;             //メインルーチンに戻り、受信待ち状態にします
        }                       //120以上であれば次に進みます。

                   //リーダー部の残りの部分を判定
        TMR0 = 0;            //timer0リセット
        while(PORTB.F0 == 1);   //5Vの状態をカウント
        if(TMR0 < 27) {        // < 35 (=2.250ms * 4MHz/4 /64)
            flag = 1;
            return;
        }else if(TMR0 < 60) { // < 71 (=4.5ms * 4MHz/4 /64)
            //リピートリーダを受信した時
            PORTB.F2 = old_F2;
            PORTB.F3 = old_F3;
            PORTB.F4 = old_F4;
            PORTB.F5 = old_F5;
            Delay_ms(96);
            flag = 1;
            return;
        }
        //リーダー部の確認終了

        //custom codeの取得
        custom_a = 0;
        for (i = 0; i < 8; i++) {   //繰返し0-7になるまで
            TMR0 = 0;         //timer0リセット
            while(PORTB.F0 == 0);     //0Vの期間をカウント
            while(PORTB.F0 == 1);     //5Vの期間をカウント
            if(TMR0 < 27)       // < 18 (=1.125ms * 4MHz/4 /64) 誤差を見越して27(35より小さい値)
                b = 0;
            else                // < 35 (=2.250ms * 4MHz/4 /64)
                b = 1;
            custom_a |= (b << i);     //custom_aと(b << i)の論理和をcustom_aに代入する
                     //bを左にiビットずらす
        }
        custom_b = 0;
        for (i = 0; i < 8; i++) {
            TMR0 = 0; //timer0リセット
            while(PORTB.F0 == 0);
            while(PORTB.F0 == 1);
            if(TMR0 < 27) // < 18 (=1.125ms * 4MHz/4 /64)
                b = 0;
            else          // < 35 (=2.250ms * 4MHz/4 /64)
                b = 1;
            custom_b |= (b << i);
        }
        //custom codeの取得終了

        //data codeの取得
        data_a = 0;
        for (i = 0; i < 8; i++) {
            TMR0 = 0; //timer0リセット
            while(PORTB.F0 == 0);
            while(PORTB.F0 == 1);
            if(TMR0 < 27) // < 18 (=1.125ms * 4MHz/4 /64)
                b = 0;
            else          // < 35 (=2.250ms * 4MHz/4 /64)
                b = 1;
            data_a |= (b << i);
        }

    data_b = 0;
        for (i = 0; i < 8; i++) {
            TMR0 = 0; //timer0リセット
            while(PORTB.F0 == 0);
            while(PORTB.F0 == 1);
            if(TMR0 < 27) // < 18 (=1.125ms * 4MHz/4 /64)
                b = 0;
            else          // < 35 (=2.250ms * 4MHz/4 /64)
                b = 1;
            data_b |= (b << i);
        }
        //while(PORTB.F0 == 0); //ストップビット受信

        //data_aとdata_bの各ビットを反転しその結果が同じか比較
        if (data_a == ~data_b) {  //data誤りのチェックOKの場合
            switch (data_a) {
                case 0x11:     //2チャンネルのボタンが押されている場合
                    PORTB.F2 = 1;   //RB2ポートのLEDを点灯する。
                    PORTB.F3 = 0;
                    PORTB.F4 = 0;
                    PORTB.F5 = 0;
                    break;

                case 0x13:      //4チャンネルのボタンが押されている場合
                    PORTB.F2 = 0;
                    PORTB.F3 = 1;
                    PORTB.F4 = 0;
                    PORTB.F5 = 0;
                    break;

                case 0x15:      //6チャンネルのボタンが押されている場合
                    PORTB.F2 = 0;
                    PORTB.F3 = 0;
                    PORTB.F4 = 1;
                    PORTB.F5 = 0;
                    break;

                case 0x17:      //8チャンネルのボタンが押されている場合
                    PORTB.F2 = 0;
                    PORTB.F3 = 0;
                    PORTB.F4 = 0;
                    PORTB.F5 = 1;
                    break;

                default:
                    PORTB.F2 = 0;
                    PORTB.F3 = 0;
                    PORTB.F4 = 0;
                    PORTB.F5 = 0;
                    break;
            }
            old_F2 = PORTB.F2;
            old_F3 = PORTB.F3;
            old_F4 = PORTB.F4;
            old_F5 = PORTB.F5;
        }
    }
    Delay_ms(40);
    flag = 1;
}

void main() {
    //使用変数の定義
    unsigned short int i;

    PORTB  = 0b00000000;  //PORTBの中身をきれいにする
  OSCCON = 0b01100000;  //内臓クロック4MHzに設定
    TRISB  = 0b00000001;  //RB0を1:入力、他は0:出力に設定

    //PIC稼働確認(LED点滅)
    for (i=0; i < 5; i++) {
        PORTB = 0b11111110;
        Delay_ms(50);
        PORTB = 0b00000000;;
        Delay_ms(50);
    }

    //timer0プリスケーラ64回に設定
    OPTION_REG = 0b10000101;

    INTCON.INTE = 1;    //RB0/INT割込みの許可
    INTCON.GIE = 1;    //全体割込み許可

    do {
        if(flag == 1) {
            flag = 0;
            PORTB.F2 = 0;
            PORTB.F3 = 0;
            PORTB.F4 = 0;
            PORTB.F5 = 0;
            INTCON.INTE = 1; //RB0/INT割込みの許可
        }
    }while(1);
}

参考:5Vになるまでと表現していますが、実際には、受信センサーからの出力される電圧です。

クロック設定

設定例:
OSCCON = 0b01110000;        // クロックを8Mhzに設定する。


2010年11月10日水曜日

LEDの点滅

/*
概要:A/D変換値を液晶ディスプレイ(LCD)に表示 データ4bit接続

対象PIC  :PIC16F88
クロック :内蔵8MHz
コンパイラ:mikroC Version: 8.2.0.0

Led  :RA0

電源:5V

コンフィグレーションフラグ:
* _CP_OFF  _CCP1_RB3  _DEBUG_OFF  _WRT_ENABLE_OFF
* _CPD_OFF  _LVP_OFF  _BODEN_OFF  _MCLR_OFF  _PWRTE_ON
* _WDT_OFF  _INTRC_IO  _IESO_ON__CFG2  _FCMEN_ON__CFG2


*/
void main() {

     PORTA = 0b00000000; //PORTAの初期化
     PORTB = 0b00000000; //PORTBの初期化
     OSCCON = 0b01110000; //内臓クロック8MHzに設定

    // A/D利用PORTの設定 // ANALOG=1, DIGITAL=0
    ANSEL = 0b00000000; //全てデジタル使用

    TRISA = 0b00000000; //PORTA 全て出力に設定

    do {
        //RA0 のLDEを点滅させる
        PORTA.F0 = 1;
        Delay_ms(1000);
        PORTA.F0 = 0;
        Delay_ms(1000);
    } while(1);
}

2010年11月9日火曜日

LCDに文字を表示


mikroC で用意されているライブラリを使用しています。
可変抵抗器VRは10KΩの炭素被膜抵抗器に置き換える事も可能です。

/*
概要:A/D変換値を液晶ディスプレイ(LCD)に表示 データ4bit接続

対象PIC  :PIC16F88
クロック :内蔵8MHz
コンパイラ:mikroC Version: 8.2.0.0

LCD制御 :R/W:RB0  RS:RB2  E:RB3
LCDデータ:DB4:RB4 DB5:RB5 DB6:RB6 DB7:RB7 

電源:5V

コンフィグレーションフラグ:
 _CP_OFF  _CCP1_RB3  _DEBUG_OFF  _WRT_ENABLE_OFF
 _CPD_OFF  _LVP_OFF  _BODEN_OFF  _MCLR_OFF  _PWRTE_ON
 _WDT_OFF  _INTRC_IO  _IESO_ON__CFG2  _FCMEN_ON__CFG2
*/
void main()
{

    PORTA = 0b00000000; //PORTAの初期化
    PORTB = 0b00000000; //PORTBの初期化
    OSCCON = 0b01110000; //内臓クロック8MHzに設定

    // A/D利用PORTの設定 // ANALOG=1, DIGITAL=0 //
    ANSEL = 0b00000000; //全てデジタル使用

    //PORTの設定 0:出力 1:入力
    TRISA = 0b00000000; //PORTA 全て出力に設定
    TRISB = 0b00000000; //PORTB 全て出力に設定
    //マイコンの初期化終わり

    Lcd_Config(&PORTB,2,3,0,7,6,5,4); //LCDのピン接続設定
    Lcd_Init(&PORTB); //LCD初期化

    Lcd_Cmd(LCD_CURSOR_OFF); //カーソル非表示

    Lcd_Out(1, 1, "hello sc1602bslb");//LCD上段文字列表示
    Lcd_Out(2, 1, "pic16f88"); //LCD下段文字列表示

}

PIC16F88に書き込む

PIC16F88に書き込むには、ちょと細工をしないと書き込めないようです。
書き込みソフトのPICkit 2 v2.61で書き込む場合、
連続して、書き込み出来ない時などは、
一旦他のディバイスを選択してから、
PIC16F88のディバイスを選択し直せば、書き込みが成功したりします。

ディバイスの読み込み(Read)は出来るが、書き込みが出来なかったりする時は、
http://www.microchip.com/forums/tm.aspx?m=242087 にあるように、
VDD PICkit 2 をOn にして3.0にしてReadボタンを押して、
アドレス0番に2800と入力して、Write ボタンを押す。
VDDを5.0にして、 Eraseボタンを押して完了。(この部分は飛ばしても良かったです。)
書き込むファイルを読み込んで書き込むと成功したりします。

2010年11月8日月曜日

コンフィグレーション一覧

コンフィグレーション指定サンプル
__CONFIG _CONFIG1, _HS_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF & _BODEN_ON & _LVP_OFF & _CPD_OFF & _DEBUG_OFF


_CONFIG1             備考
_CP_ALL コードプロテクション。読み込み禁止。
プロテクト オン

_CP_OFF
プロテクト オフ

_CCP1_BR0 CCP1ピンの選択 RB0
_CCP1_RB3 CCP1ピンの選択 RB3
_DEBUG_OFF デバッグ機能を使うかどうか
_DEBUG_ON ONにするとRB6とRB7はデバッガ用になってIOに使えない。
_WRT_ENABLE_OFF Writeプロテクション。書き込み禁止。
_WRT_ENABLE_512

_WRT_ENABLE_1052

_CPD_ON Data EE Memoryのコードプロテクション。読み込み禁止。
_CPD_OFF

_LVP_ON Low-Voltage Programming の設定。
_LVP_OFF ONにするとRB3はPGMピンになる。
_BODEN_ON ブラウンアウトリセットの設定。
_BODEN_OFF

_MCLR_ON MCLRを使うかどうか。ONにするとRA5はMCLR。
_MCLR_OFF OFFにするとRA5として使えて、内部的にMCLRはVddと直結する。
_PWRTE_OFF パワーアップタイマー。
_PWRTE_ON

_WDT_ON ウォッチドッグタイマー。
_WDT_OFF

_EXTRC_CLKOUT
外部RC発振モード OSC2ピンはクロック出力

_EXTRC_IO
外部RC発振モード OSC2ピンはRA6として汎用入出力

_INTRC_CLKOUT RA6(15番ピン)に(内部周波数)/4 Hz が出力される
_INTRC_IO 内臓クロックを使って、クロック用の足をIOに使う。
_EXTCLK
外部発振器モード OSC2ピンはRA6として汎用

_HS_OSC 4MHz~20MHz(水晶振動子orセラミック振動子)
_XT_OSC 4MHz以下(水晶振動子orセラミック振動子)
_LP_OSC 100KHz以下(水晶振動子,省電力モード)

_CONFIG_2
備考
_IESO_ON__CFG2 外部クロックが安定するまでは内蔵クロックを使う。
_IESO_OFF__CFG2

_FCMEN_ON__CFG2 外部クロックが途切れたときは内蔵クロックを使う。
_FCMEN_OFF__CFG2

PIC16F88のピン配置