サイトアイコン 臨床工学技士の為の電子工作

PIC16F88でLCD表示に挑戦!!

前回はひさびさのマイコン工作の開始という事でPIC16F88で割り込みを学びました。

ACモーターのフィードバック制御まであとはLCD表示とA/D変換を学ぶのみです。

 

んで今回は難易度がグッと上がるLCDを表示させるという挑戦をします。

ちなみにこんな感じでLCD表示させる事に成功〜!!!!

今みたらLCD デ ユミ ムゲンダイってなってますね。 本当はユミ→ユメです。

 

使ったものはLCDパネルのSC1602です。ちなみにバックライトがついてるのもを秋月で500円でゲット

じつは今は値上がりしてます。今は700円なーり

 

ピンの配置

 

まず最初の感想は、こんなたいそうな物本当に表示させれるようになるんかいな?と正直思いました。

ネットでは結構情報もあるのですが、いまいち良くわかりませんでした。

しかし根気よく他サイトを読み込んでいくと・・・

なんとなーくやりかたがわかってきたのです。

PICでLCD表示させるということ

さてどのようにPICでLCDを表示させるかですが、もちろんのことPICのI/Oポートからの出力の切り替えによって文字データや数字データを出力します。

その取り決めはすでに決まっていて、私たちが自由に決める事はほぼありません。

そうです、表示させる取り決めや手順などは、あらかじめ決められていてその通りにプログラミングすればいいだけなんです。

難しいのは開発環境やプログラミング言語の違いで若干迷うというだけで基本的な方法は一緒です。

私の場合は王道のMPLAB X IDEの開発環境でC言語でプログラムしています。

大いに参考になったサイトはディスプレイ表示の基本を解説している ここ

PIC16F84Aを用いていますが、参考になるプログラムソースを公開している ここ 実際私はここのプログラムを少しいじらせてもらい、使っています。

PICでLCD表示する時に難渋する事

間違いなくムズイのはLCDパネルの初期化です。

まずLCDパネルを使うようにするにはPICのプログム上でPICを表示させる為に”初期化”させないと使えません。

その初期化がややこしくて、電源立ち上げ後数msecまってLCDのDB4−DB8にこのビットを送ってそのあと数ミリsec待って・・・めんどくさいんです。

でもこの世の中便利でそのような手順のソースコードをまとめてくれて、そのソースをインクルード(読み込む)するだけで簡単に使えるように公開してくれる先人達がいます。

ありがたーく使わせてもらいます。

ちなみにそのソースはこちらです。このソースはC言語でPIC16F84A用です。

試しにこのプログラムでPIC16F88でLCD表示させようと試みましたができませんでした。残念。最初にはまって嫌になりました・・・

しかしちょこっとプログラムを改造するだけでPIC16F88でも文字を表示させる事に成功しました!!!

 

回路図

LCD表示の方法は4ビットモードで。

クロックは便利な内部クロック1MHz

LCDは秋月で買った500円のSC1602を使用しました。

 

ソースの使い方

LCDの表示はなんだか難しそうですが、そうでもありません。

難しいプログラムは先人たちがソース化してくれており、私の様の相乗り精神満載の人が簡単に使えるようにしてくれています。

私の使命はその使い方を皆様に教授いたします。

とりあえずでしがMPLABXを使います。 知らないあいだにバージョンが3.4に上がっとります。

 

まず新規作成でプロジェクトをつくります。もちろんデバイスはPIC16F88を選んで、コンパイラーはXC8を選んでおきます。

MPLABXのざっくりした使い方はこちら

 

そして後のプログラムの解説の最後でダウンロードできるファイルをプロジェクトの中のヘッダーファイルとソースファイル下にドラッグ&ドロップさせます。赤線のところね。

 

そんでもってコンパイルするだけで、最初の映像のようにLCDを表示させる事が可能です。

 

メインプログラムを書き換えれば自由自在にLCDを使ったPIC電子工作の完成という手筈になります。

下記にプログラムの解説とLCD表示のワンポイントアドバイスを書いてます。

 

プログラムの解説

#include “lcd.h”をインクルードしているのでlcd.cの関数が使えます。

ちなみに

// LCD初期化
lcd_init();

で初期化を行い

// LCD画面クリア
lcd_cls();

画面のクリアは上記関数で行います。

 

文字を入力したい時は

// LCDに文字列出力
lcd_locate( 0, 0 );//これは文字の表示位置の設定です。(0,0)最初の0のところで1行目か2行目を設定1なら2行目です。
そんで次の0のところで何文字目から文字を表示させるかを決めます。SC1602は16文字表示なので0−15を入れる事になります。
lcd_puts( “Hello world” );

文字は上記で表示させます。半角英数と半角カタカナが表示させる事ができます。

また

#include<stdio.h>
#include<stdlib.h>
#pragma jis

の3つをインクルードした上で、メインプログム上で

////////////printf関数の出力先のスタブ関数を定義する////////////
void putch(unsigned char ch){
lcd_putc(ch);
}

を定義しておくと、なんとC言語でおなじみのpringf関数が使えます。かなり便利です。

 

 

結局のところ
lcd_locate( 0, 0 );
で文字位置を決めて
printf(“モジヲニュウリョク”);
で文字をLCDに表示させれるようになります。

メインプログラムでLCDに表示させる為に使う関数は上記2つで事足ります。
すごくないですか?
本当ならもっと面倒なんですよ。

 

 

 

あとPICのどのピンをLCDに割り当てるかなどの細かい設定は実際のプログラム中に書いています。

 

今回作成したプログラムですがダウンロードできるようにしておきまますね。以外とPIC16F88を利用したLCD表示を解説しているサイトがないので・・・

ダウンロードは右クリックで”名前をつけてダウンロード”でゲットしてね。

2017年2月20日 なんと外部発振でLCDを動かすと挙動がおかしくなることが判明しました。原因はlcd.cの中でstrobe(E)の信号を送る前と送ったあとの待ち時間が短い事に原因がある事が判明しました。なので修正する事でHSの外部発振でも使用可能になりました。千九!!

 

まずメインプログラムのソースです pic16f88deLCD

そしてLCDの初期化や書き込みなどのソースコード lcdkaizou

そんでそのソースの関数を使えるようにするヘッダーファイル lcd

この3つのファイルをダウンロードしてMPLAB X IEDでコンパイルするだけで使えます。

メインファイルを書き換えるだけで他の用途にも改造できるでしょう。

ファイトん!!

 

下記に全てのプログラムを載せておきまーす。

pic16f88delcd.c

/*

* Author: kazurock
*
* Created on september 21, 2016, 8:44 PM
*/

#include <xc.h>
#include “lcd.h”
#include<stdio.h>
#include<stdlib.h>
#pragma jis
//————————————–
// コンフィグレーションビットの指定
//————————————–
// CONFIG1
#pragma config FOSC = INTOSCIO //
#pragma config WDTE = OFF //
#pragma config PWRTE = OFF //
#pragma config MCLRE = OFF //
#pragma config BOREN = OFF //
#pragma config LVP = OFF //
#pragma config CPD = OFF //
#pragma config WRT = OFF //
#pragma config CCPMX = RB3 //
#pragma config CP = OFF //

// CONFIG2
#pragma config FCMEN = OFF //
#pragma config IESO = OFF //

/*

ピン配列はこんな感じにしました。LCDを使うには4ビットモードで4つのピンを使います。ですのでRB4-RB7をLCDのDB4-DB7へ、RA6をLCD RS RA7をLCD Enableに設定しました。
LCD RSとLCD Enableは設定次第でどこでも設定できます。
 4ビットモード使う4つのピンはRB0-RB3の下位4ビットかRB4-RB7の上位4ビットかを、LCDの初期化や書き込みなどのソースコード lcd.cで簡単に設定できます。詳しくはlcd.cの説明で。
* RA0—
* RA1—
* RA2—
* RA3—
* RA4—
* RA5—
* RA6—LCD RS
* RA7—LCD Enable
*
* RB0—
* RB1—
* RB2—
* RB3—
* RB4—DB4
* RB5—DB5
* RB6—DB6
* RB7—DB7
*/
///////////delay関数を使うために発振周波数を定義 1Mhz////////////
#define _XTAL_FREQ 1000000

////////////printf関数の出力先のスタブ関数を定義する printfを利用するならこの記述がいります。////////////
void putch(unsigned char ch){
lcd_putc(ch);
}

void main( void )
{
OSCCON = 0b01000000;//内部周波数1mhzに
ANSEL = 0b00000000;//すべてデジタルに設定
TRISA = 0x00; // RA0-7をOutputにする
TRISB = 0x00; // RB0-7をOutputにする

PORTA = 0b00000000;//
PORTB = 0b00000000;

// LCD初期化
lcd_init();

// LCD画面クリア
lcd_cls();

// LCDに文字列出力
lcd_locate( 0, 0 );
lcd_puts( “Hello world” );

lcd_locate( 1, 0 );
lcd_puts( “コンニチワ” );

__delay_ms(1000);
__delay_ms(1000);

//メインループ突入
while( 1 ) {

//printfでLCDに文字列出力
lcd_locate( 0, 0 );
printf(“printf デモ OK”);

lcd_locate( 1, 0 );
printf(“LCD デ ユミ ムゲンダイ”);

__delay_ms(1000);
__delay_ms(1000);
__delay_ms(1000);

// LCD画面クリア
lcd_cls();

 

 

//カウントダウンを表示 本当はfor分などを使うとスッキリするのですが、勉強の為、たくさん書いてます。
// LCDに文字列出力
lcd_locate( 0, 0 );
lcd_puts( “count down” );
lcd_locate( 1, 7 );
lcd_puts( “10” );
__delay_ms(1000);
lcd_cls();

// LCDに文字列出力
lcd_locate( 0, 0 );
lcd_puts( “count down” );
lcd_locate( 1, 7 );
lcd_puts( “9” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “8” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “7” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “6” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “5” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “4” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “3” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “2” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “1” );
__delay_ms(1000);

// LCDに文字列出力
lcd_locate( 1, 7 );
lcd_puts( “0” );
__delay_ms(1000);

}
}

 

 

 

LCDのヘッダーファイル

lcd.h

このヘッダーファイルで定義された関数を使って文字を表示させます。

lcd_locate( 1, 7 );で2行目の8文字目から文字を入力指定
lcd_puts( “0” );で0を入力

#ifndef LCD_H
#define LCD_H#ifdef __cplusplus
extern “C” {
#endif
void lcd_init( void );void lcd_cls( void );
void lcd_locate( unsigned char x, unsigned char y );
void lcd_putc( char c );
void lcd_puts( const char *p );#ifdef __cplusplus
}
#endif#endif /* LCD_H */

 

 

 

 

 

LCDの初期化や書き込みなどをまとめたソースコード

lcd.c

もともとがPIC16F84A用のソースコードなのでそのままではLCD表示できません。

なので少し手を加えて書き直しました。っと言ってもほぼそのまま使っています。

手を加えたところだけで書き直しております。

PIC16F88では初期化に時間がかかるみたいで、だいたいwait時間を決められた時間より5倍程度伸ばすとうまくいきます。

あと4ビットモードで使う為#define LCD_DATA_IS_HIGH //で partB上位を使うか下位を使うか決めます。HIGHのところをLOWなど他の言葉に入れ替えるとPORTB の下位から出力するようになります。

#include <htc.h>
#include “lcd.h”
#define _XTAL_FREQ 1000000 // __delay_ms()用クロック定義 (1MHz駆動)
//—————————–
// PIC-LCDのピンアサイン
//—————————–
#define LCD_RS PORTAbits.RA6//define関数でLCD_RSにRA6を指定
//#define LCD_RW PORTAbits.RA1 // 未使用 ちなみにLCDパネルのLCD_RWはグランドに落としておかいとLCDがうまく表示してくれません。
#define LCD_ENABLE PORTAbits.RA7//define関数でLCD_RSにRA7を指定
#define LCD_DATA PORTB
#define LCD_DATA_IS_HIGH // PortBの上位4bitをLCDのDB4-7に接続// 内部関数のプロトタイプ宣言
static void lcd_write_cmd( unsigned char data );
static void lcd_write_databus( unsigned char data );//****************************************************************************************
// Function : lcd_init
// Description: LCD初期化処理(4bitモード)
//****************************************************************************************void lcd_init( void )
{//——————-
// 制御ピンの初期化
//——————-
LCD_RS = 0;
LCD_ENABLE = 0;
#ifdef LCD_DATA_IS_HIGH
LCD_DATA = (LCD_DATA & 0x0f);
#else
LCD_DATA = (LCD_DATA & 0xf0);
#endif__delay_ms( 500 ); // ウェイト500msにしてみる 300ms以上じゃないとうまくいかないよ
//——————-
// LCD初期化処理
//——————-
lcd_write_databus( 0x03 );
__delay_ms( 20 ); // 4.1mSec以上ウェイトlcd_write_databus( 0x03 );
__delay_us( 500 ); // 100uSec以上ウェイトlcd_write_databus( 0x03 );// モードの指定
lcd_write_databus( 0x02 ); // 4bitモードに変更する
__delay_ms( 2 ); // 40uSec以上ウェイト//——————–
// 画面のクリア
//——————–
lcd_write_cmd( 0x28 ); // ファンクションセット(2行表示、5*7dot)
__delay_ms( 2 );// Display off
lcd_write_cmd( 0x08 ); // ディスプレイ・カーソルの設定(カーソル非表示)
__delay_ms( 2 );lcd_write_cmd( 0x01 ); // clear display
__delay_ms( 2 );lcd_write_cmd( 0x06 ); // エントリモード(1:右にスクロール、0:シフトなし)
__delay_ms( 2 );

// lcd_write_cmd( 0x0F ); // ディスプレイ・カーソルの設定(ディスプレイ:ON, カーソル:ON , カーソル点滅:ON)
// lcd_write_cmd( 0x0E ); // ディスプレイ・カーソルの設定(ディスプレイ:ON, カーソル:ON , カーソル点滅:OFF)
lcd_write_cmd( 0x0C ); // ディスプレイ・カーソルの設定(ディスプレイ:ON, カーソル:OFF, カーソル点滅:OFF)
}
//*****************************************************************************
// Function : lcd_locate
// Description : 印字位置の指定
//*****************************************************************************
void lcd_locate( unsigned char x, unsigned char y )
{
unsigned char writeData;

writeData = 0x40 * x + y; // 表示位置を決定(2行目に出すときは,3bit目を立てる)
writeData |= 0x80; // 最上位ビットを立てる
lcd_write_cmd( writeData );
}
//*****************************************************************************
// Function : lcd_cls
// Description : LCD画面クリア
//*****************************************************************************
void lcd_cls()
{
lcd_write_cmd( 0x01 ); // clear display
__delay_ms( 3 ); // 1.64mSec以上ウェイト
}
//*****************************************************************************
// Function : lcd_putc
// Description : LCDに1文字出力
//*****************************************************************************
void lcd_putc( char c )
{
LCD_RS = 1;
__delay_us( 1 ); // 40nSec以上

lcd_write_databus( (c & 0xf0) >> 4 );
lcd_write_databus( (c & 0x0f) );
}
//*****************************************************************************
// Function : lcd_puts
// Description : LCDに文字列出力
//*****************************************************************************
void lcd_puts( const char *p )
{
while( *p != ‘¥0’ ) {
lcd_putc( *p );
p++;
}
}
//*****************************************************************************
// Function : lcd_write_cmd
// Description : 4bitモードでの命令書き込み(RS=LOW)
// 命令は上位ビットから順に送る
//*****************************************************************************
static void lcd_write_cmd( unsigned char data )
{
LCD_RS = 0;
__delay_us( 1 ); // 40nSec以上

lcd_write_databus( (data & 0xf0) >> 4 );
lcd_write_databus( (data & 0x0f) );
}
//*****************************************************************************
// Function : lcd_write_databus
// Description : dataで指定された下位4bit分のデータをDB4-7に書き込む
//*****************************************************************************
static void lcd_write_databus( unsigned char data )
{

// 書き込むべきデータをセット
#ifdef LCD_DATA_IS_HIGH
LCD_DATA = (LCD_DATA & 0x0f) | ( (data<<4) & 0xf0);
#else
// 下位4bitにセットする
LCD_DATA = (LCD_DATA & 0xf0) | (data & 0x0f);
#endif
__delay_us( 40 ); // Enableを1にする前に80nSec以上→40μSec以上必要

// Enableをactiveする
LCD_ENABLE = 1;

 

__delay_us( 230 ); //Enableを0にするまでに 220nSec以上→230μSec以上必要

// Enableをinactiveにする
LCD_ENABLE = 0;

__delay_us(1);//10nsec以上必要

 

// データをALL0でクリアしておく
#ifdef LCD_DATA_IS_HIGH
LCD_DATA = (LCD_DATA & 0x0f); // 上位4bitをクリア
#else
LCD_DATA = (LCD_DATA & 0xf0); // 下位4bitをクリア
#endif

}

 

むちゃくちゃたくさん書きましたが、理解すると驚くほど簡単にLCD表示が可能になりPIC電子工作のリミッターをさらに上昇させる事になるでしょう。

あきらめずに頑張っていきましょう。

モバイルバージョンを終了