FC2カウンター

現在の訪問者数

現在の閲覧者数:

カレンダー

07 | 2017/08 | 09
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 - -

プロフィール

剣菱P

Author:剣菱P
剣菱Pと申します。
性別:男
年齢:27
二兎を追って一兎も得られないタイプ

マイコンやプログラミング、ニコニコ動画、雑記等
方向性は見えずとも、ちょっとずつ更新していく予定です!

リンクフリーです。
こんなブログでよかったらよろしくお願いしま~す。

公開メール kenbishiP@gmail.com

検索フォーム

最新記事

最新コメント

カテゴリ

メールフォーム

名前:
メール:
件名:
本文:

月別アーカイブ

最新トラックバック

リンク

ブロとも一覧

ブロとも申請フォーム

ランキング

ランキング参加中です。気が向いたらクリックしてあげてください。


にほんブログ村 その他趣味ブログへ
にほんブログ村 その他趣味ブログ 趣味の工作へ

スポンサーサイト


上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PIC 液晶制御関数ちょっと追加 PIC LCD»

コメント

コメントの投稿













管理者にだけ表示を許可する

PIC LCD2


さて液晶(LCD)の続きです。

今回は実際にLCDを使うところです。

このLCDは起動する再に所定の手順を踏まないと動いてくれません。
正直言って初めて見たときは「何故こんなめんどくさいことを・・・」と思いましたね。

その手順とは
1.電源ON
   ↓
2.15ms以上待つ
   ↓
3.8ビットモード設定
   ↓
4.4.1ms以上待つ
   ↓
5.再度8ビットモードに設定
   ↓
6.100μs以上待つ
   ↓
7.またまた8ビットモードに設定
   ↓
8.4ビットモードに設定
   ↓
9.ファンクション設定
   ↓
10.ディスプレイOFF
   ↓
11.ディスプレイON
   ↓
12.エントリーモード


8ビットモードの設定などなぜか3回も出てきます。なぞです

何はともあれ、順を追って見てみましょう。
15ms待つのは、問題ないですね。DelayMs関数でも使って適当に時間を稼ぎましょう。

次の8ビットモード設定。
今回は4ビットモードで使うといいましたが、初期化のステップでは一度8ビットモードで起動しなければならないとなっているので、8ビットモードに設定します。
「でも、4ビットモードで使うっていうから、線4本しかつなげてないけど・・・ いけるのか?」
そこらへんはうまく出来ていて、8ビットモードでいる間の作業は下位の4ビットが全て0で問題なく、上位4ビットしか実質意味がないので、大丈夫なのです。

コマンド表を見てもらうとわかりますが、8ビットモード選択のコマンドは

0 0 1 DL N F * *
DL:1で8ビットモード 0で4ビットモード
N:1で1/6Duty 0で1/8Duty
F:1で5*10 0で5*7ドットの文字
*:意味なし(どっちでもよい)

ですので、とりあえず8ビットモードにするためにDLを1にする以外はどうでも良い感じです。
具体的には
0 0 1 1 0 0 0 0 でよいわけです。 ほら下位4ビットは0なんでGNDにつながってる状態でも問題なさそうですね。 上位4ビットは0011なのでこれを出力してやります。液晶君はこれで00110000の8ビットが送られてきたと勘違いするわけですね。

これをあと二回繰り返します。

その後4ビットモードに設定します。これより後は4ビットモードなので4ビットの信号を二回送らなければなりません。
とりあえず4ビットモードにすることだけを意識すれば、コマンドは
0 0 1 0 0 0 0 0 ですね。
ここまでは8ビットモードで動いてるのでコマンドは一度送信するだけで大丈夫です。

次にファンクション設定
結局さっきの4ビット、8ビットを選択したコマンドがこのファンクション設定です。
ここで改めて文字の大きさなどを設定します。
先ほど4ビットモードにしたのでここからは2度に分けてコマンドを送ります。

4ビットモードで 1/6Duty 5×10ドットの文字を使いたいとすれば
0 0 1 0 1 1 0 0 になるので
0 0 1 0 を送った後 1 1 0 0を送ります。

次にディスプレイON/OFFのコマンドは
0 0 0 0 1 D C B
D:1で表示ON 0でOFF
C:1でカーソルON、0でOFF
B:1でブリンクON,0でOFF

次の工程はディスプレイOFFなので
とりあえず全部OFFにしちゃいましょう
0 0 0 0 1 0 0 0 ですね

そしてディスプレイON
表示をONにして カーソルをON カーソルの点滅はなしにしました。よって
0 0 0 0 1 1 1 0 になります。

いよいよ最後、エントリーモードセット
コマンドは
0 0 0 0 0 1 I/D S
I/D:メモリ書き込み後のアドレスを1で+1 0でー1
   アドレスを+1するということはどういうことかというと、前回最後に画面の文字表示部には全て番号がふってあると書きましたが、その番号はを+1するということです。
   右隣のアドレスは自分より1つ大きくなってるので+1すれば右隣に移動します。
S:1なら表示もシフトする
  0なら表示はシフトしない

ここでは +1で、表示はシフトしないとします。よって
0 0 0 0 0 1 1 0

これで初期化終了です。
ではプログラムで実際にこの行程を実現して見ます。
lcd_v1.txt

↑ちなみにLCD制御用の関数をまとめたものです。これをlcd.hとして保存してCの本体がある場所に保存して、プロジェクトに組み込めば、つかえるようになる、はず、です。
最低限の関数だけ作ったので、まだまだ物足りないものですが、よろしければどうぞ。
↓がテキストファイルの中身です。


//========================================================//
// 2009.5.12
// LCD表示用関数
// Ver 1.0
//========================================================//


#include "delay.h"            //関数ないでDelayMs()を使用しているため必要
#define LCD_RS RB2            //RS端子をポートBの2番ピンに
#define LCD_E  RB3            // E端子をポートBの3番ピンに
#define PORTX PORTB            //任意のポートで使用できるように(今はポートB)

//********** LCDにデータを送信する関数 *************//
//この関数が送信機能を持つ基本の部分です。
//********************************************//
void lcd_out(char code, int flag){                                //codeは送信するデータが入った変数 flagはコマンドかデータの選択をする変数
   
    PORTX = ((code & 0xf0) | (PORTX & 0x0f));                    //codeの上位4ビットと 今現在のポートの下位4ビットの状態を合わせて、出力
    if(flag == 0)                                                //flagが0ならデータ 1ならコマンド
        LCD_RS = 1;
    else
        LCD_RS = 0;

    NOP();                                                        //時間稼ぎ
    LCD_E = 1;                                                    //LCDのE端子に5Vを出力
    NOP();
    NOP();
    NOP();
    LCD_E = 0;                                                    //LCDのE端子を0Vに
}

//********** LCDに文字データを送信する関数 ************//
void lcd_data(char asci){                                        //asciは文字データが入った変数
   
    lcd_out(asci,0);                                            //LCDにデータを送信する関数に文字データを渡す
    lcd_out(asci<<4,0);                                            //データを4ビットシフトして送信用関数に渡す
    DelayUs(50);

}

//********** LCDにコマンドを送信する関数 **************//
void lcd_cmd(char cmd){                                            //cmdにはコマンドデータが入ってます
   
    lcd_out(cmd,1);                                                //コマンドデータを送信用関数に渡す
    lcd_out(cmd<<4,1);                                            //コマンドデータを4ビットシフトして送信用関数に渡す
    DelayMs(2);
}

//********** LCDの画面をリセットするコマンドを送る関数 *******//
void lcd_clear(){

    lcd_cmd(0x01);                                                //画面リセットコマンドを送信
    DelayMs(15);
}

//********** LCDを初期化する関数 *********************//
void lcd_init(){                                                //液晶を使うために必要な初期化の手順

    DelayMs(15);                                                //始めに15ms以上待つ
    lcd_out(0x30,1);                                            //8bitモード設定
    DelayMs(5);                                                    //4.1ms以上待つ
    lcd_out(0x30,1);                                            //再度8bitモードに設定
    DelayMs(1);                                                    //100μs以上待つ
    lcd_out(0x30,1);                                            //またまた8bitモードに設定
    DelayMs(1);                                                    //
    lcd_out(0x20,1);                                            //4bitモードに設定
    DelayMs(1);                                                    //
    lcd_cmd(0x2C);                                                //ファンクション設定
    lcd_cmd(0x08);                                                //ディスプレイOFF
    lcd_cmd(0x0E);                                                //ディスプレイON
    lcd_cmd(0x06);                                                //エントリーモードセット
    lcd_cmd(0x02);                                                //カーソルをホームに移動
}




で、さらにプログラム本体です。


#include<pic.h>
#include<stdio.h>
#include"lcd.h"
#include"delay.h"
__CONFIG(HS & WDTDIS & PWRTDIS & UNPROTECT);


void main(){
    char i,c;
    TRISA = 0x00;
    TRISB = 0x00;
    PORTA = 0x00;
    PORTB = 0x00;


    lcd_init();

    while(1){
        lcd_clear();
        DelayMs(2);
        for(i=0;i<16;i++){
            lcd_data(i+'0');
            DelayMs(250);
        }       
    }
}




さて、ではlcd.hの中身を見てみませう
まず#include "delay.h"があります、このヘッダ内でDelayMs()関数を使用しているため書いておきました。
次に#define LCD_RS RB2 これはポートBの2番ピンにLCD_RSというつけたと言う事です。
同様に#define LCD_E RB3 としました。
また今回はポートBを使いましたが、他のPICで他のポートを使えるようにPORTXとしておきました、PORTBの部分をPORTCとかに変えれば他のところで使えます。

さて、ここからが本番
PORTX = ((code & 0xf0 | (PORTX & 0x0f));
まずcodeですがこの中身はコマンドもしくは文字データです。ここでは例えば10101010が入ってると仮定しましょう。
code & 0xf0となっていますがこれが何をしているかというと、マスク処理ということをしています。
&は論理積と呼ばれる演算子で二つのビットを比べて両方1だった場合に1になりどちらかが0だったら0になる性質があります。具体的に書けば
code  10101010
 &
0xf0   11110000
 
     10100000
同じ桁のビット同士を掛け合わせたものが結果になります。つまり元のデータのうちほしいところだけを残して後は全部0にすることが出来るわけです。
なんでこんなことが必要かというと、4ビットモードだからです。文字データもコマンドも8ビットですが、
実際に送るデータは4ビットを二回に分割して送るわけです。ですかLCDにつながっていない下位4ビットは必要ないのです。
「別に消さなくても、物理的に送信できないんだから、わざわざ0にしないでもいいんじゃない?」
と、思うかもしれませんが、ここである問題が発生します。コマンドと文字データを切り替えるためのRS,タイミングを知らせるためのE端子もポートBの2,3番につながってるのです、つまりこいつらに影響が出てしまうのです。
「ちょっとまった、じゃあ、これじゃRSもEも強制的に0になっちゃうけど」
実は今回の場合はそれでも問題ないのですが、一応対応策を講じます。
それが PORTX & 0x0fです。
これもマスク処理ですね。今度は下位4ビットを残して上位4ビットを0にします。
何の下位4ビットを残すかといえばポートB自体の現在の状態の下位4ビットを残します。
そして、((code & 0xf0) | (PORTX & 0x0f))とします。
|は論理和というものでビット同士を足し合わせます。
code  10101010
 |
0x07  00000111

     10101111
といった具合です。ちなみに1+1も1です
つまり、codeの中身の上位4ビットとPORTXの下位4ビットの現在の状態を合わせて送ることで。
RSとEに影響を与えずに信号を送信できるのです。
「ところでcodeの下位ビットは消されちゃったままだけど、それだと文字データとして使えなくね?」
そこらへんは大丈夫です。この関数はあくまで文字コードの上位4ビットのみを送信するための関数で、下位の4ビットは他の関数の処理で解決します。

この関数はcodeの他にflagという引数も受けとります。
文字データを送る時はこのflagが0 コマンドの時は1とします。
それぞれに合わせてRS端子を1か0にします。
さらに少し時間を稼いだ後E端子を立ち上げ450ns以上経過した後さげます。
今回はこのPICで使える最速の20MHzを使用しいるのでこのNOPという関数の実行に200nsかかるはずです。NOPは何もせず1命令分待機せよという命令です。これが3つで450nsを超えられます。
周波数が遅くなればNOPの実行時間はさらに遅くなるので、450nsの時間稼ぎはこれでよしとしました。

ちなみにこの関数がLCD制御の要になる関数で以降の関数はこれにだいたい依存します。

次の関数はLCDに文字データを送信するための関数です。
asciという変数に文字データが入っています。
そのデータを先ほどのデータ送信関数に渡します。flagには文字データを示す0を入れて
lcd_out(asci,0);

ここで先ほどの問題を思い出してください、データ送信関数は上位4ビットしか送ってくれません。
そこで次は下位の4ビットを送ってもらわねばなりません。
lcd_out(asci<<4,0);
これで解決です。<<はビットシフトというもので、指定された数だけ<の方向にビットをシフトします。仮にasciの中身が00001110とすると
00001110
   1ビット左シフト
00011100
   1ビット左シフト
00111000
   1ビット左シフト
01110000
   1ビット左シフト
11100000
となります。4ビット左シフトすると、下位の4ビットにいたはずのものが上位の4ビットの位置まで移動してきましたね。これをデータ送信関数に渡せば下位のデータを送信できます。

コマンド送信関数も原理は同じでflagに1を入れてコマンドであることを示していることが大きな違いです。

次のリセット関数はリセット用のコマンドにわかりやすく名前をつけただけす。
リセット処理は時間がかかるので長めに時間稼ぎをします。

そして初期化関数の登場です。

今回の初めに出てきた初期化の行程を一つ一つプログラムに置き換えたものです。

まず、15ms待機
そして8ビットモードにセットするコマンドを送信します。
これは当然コマンドを送信するわけですが、コマンド送信用関数は使用不可です。
なぜなら、コマンド送信用関数は4ビット動作を前提に作られているからです。
この段階では8ビットモードで液晶が動作しているので、コマンドは8ビットを一度だけ送信することで
受け付けられます。00110000を一度送ればいいのです。
ここでコマンド送信関数を使えば00110000を送信した後に00000000を送ってしまいます。

ですので、データ送信関数に直接コマンドデータを渡します。
lcd_out(0x30,1) ですね
これを三回繰り返し、間に所定の時間稼ぎをいれます。

次に4ビットモードにセットするため
lcd_out(0x20);

同様にして、以前説明したコマンドを次々に送信します。
ここからは4ビットモードですので、コマンド送信関数が使用可能になります。

最後に一応カーソルをホームポジションにもどすコマンドを送信しました。


以上が基本的な液晶制御用関数です。

ではプログラムのメインルーチンを見てみましょう。
#includeが入っていますが、これは実験中に書いたものを消し忘れただけです。今回は使ってません。(ノ_-;)

そして、先ほどの関数が入ったヘッダファイル lcd.hを読み込んでいます。プログラム本体と同じ場所にヘッダファイルがあるときは
ファイル名を””で囲みます。

LCD初期化関数 lcd_init()を呼び出し初期化します。
次にwhile(1)のループの中身ですが、
lcd_clear()関数で液晶の表示をクリアします。

forループ内で文字データ送信関数に文字データを渡しています。
i+'0'というのが文字データなのですが、何故こんな形をしているかというと、
iの中には数字が入っています。液晶にも数字を表示させようと思っているのですが、ただ単にiと書いてしまったら
中に入ってる数字が文字データ送信関数に渡ってしまいます。たとえば3が入っているとします。
3は二進数でいうと00000011となり、これは3のキャラクターコードではありません。液晶ないにこのコードに該当する文字は存在しません。
3のキャラクターコードは00110011なのです。でもこれ数字の3と文字の3のコード下位4桁は同じですよね。
なぜなら、0のキャラクターコードが00110000なのです。つまりこの文字0に3たしてあげれば文字の3になるのです。
文字をあらわすには’’をつかって’0’とあらわします。’0’が00110000と等価なのです。

これをループしていけば0~の数字をどんどん表示していきます。
文字データを一文字送信した場合、今の設定ではアドレスを+1するとなっているので自動的にカーソルが右にずれて、
数字が次々に現れるようになります。

では実際に実行してみます。
PIC 液晶

[広告] VPS

9の次の文字コードは:;<=と続くのでこうなってます。


ちなみにこの関数たちは原始的すぎてこのままでは実用的ではありません。いつかは実用的なものを作ろうと思います。 本当はprintf関数を利用してやろうと思ったのですが、なぜかPIC C Liteはprintfが使えないみたいなので、あきらめました。
ぐはぁ、長文失礼しました。


クリックもらえるととっても喜びます。
スポンサーサイト

PIC 液晶制御関数ちょっと追加 PIC LCD»

コメント

コメントの投稿













管理者にだけ表示を許可する


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。