今回からPICをPIC16F84Aに変更しました。(PIC16F84とは最高クロックの違いだけです。)
例題4としてLCD1602に文字を表示するプログラムを試しました。
回路図です。クロックは10MHzとしました。
ブレッドボードに文字が表示された様子です。LCD1602が手持ちがなかったので、LCD2004を使っています。
プログラムです。
こちらのサイトのプログラムを使わせていただきました。(一部変更しています) ありがとうございます。
LCDのBUSY FLAGは、見ていません。
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
/* PICとLCD1602(2004)との接続
* PIC LCD
* RA0 RW
* RA1 E
* RA2 RS
* RB0 D4
* RB1 D5
* RB2 D6
* RB3 D7
*/
* PIC LCD
* RA0 RW
* RA1 E
* RA2 RS
* RB0 D4
* RB1 D5
* RB2 D6
* RB3 D7
*/
#define _XTAL_FREQ 10000000
#define RW RA0
#define EN RA1
#define RS RA2
#define LCD_DATA PORTB
#define RW RA0
#define EN RA1
#define RS RA2
#define LCD_DATA PORTB
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (Power-up Timer is enabled)
#pragma config CP = OFF // Code Protection bit (Code protection disabled)
/*STROBE信号*/
void LCD_STROBE(){
EN = 1;
EN = 0;
}
/* 4ビットモードでの8ビット分のデータ転送 */
void lcd_write(unsigned char c)
{
__delay_us(40);
LCD_DATA = (LCD_DATA & 0xf0) | ((c >> 4) & 0x0f);
LCD_STROBE();
LCD_DATA = (LCD_DATA & 0xf0) | (c & 0x0f);
LCD_STROBE();
}
/* 画面クリア */
void lcd_clear(void)
{
RS = 0;
lcd_write(0x01);
__delay_ms(2);
}
/* カーソル位置に文字列を出力 */
void lcd_puts(const char *s)
{
RS = 1; // write characters
while(*s)
lcd_write(*s++);
}
/* カーソル位置に1文字出力 */
void lcd_putch(char c)
{
RS = 1; // write characters
lcd_write( c );
}
/* カーソル位置の設定 y:行 x:桁*/
void lcd_locate(unsigned char y,unsigned char x){
RS = 0;
lcd_write(0x80 + (0x40 * y) +x);
}
void lcd_write(unsigned char c)
{
__delay_us(40);
LCD_DATA = (LCD_DATA & 0xf0) | ((c >> 4) & 0x0f);
LCD_STROBE();
LCD_DATA = (LCD_DATA & 0xf0) | (c & 0x0f);
LCD_STROBE();
}
/* 画面クリア */
void lcd_clear(void)
{
RS = 0;
lcd_write(0x01);
__delay_ms(2);
}
/* カーソル位置に文字列を出力 */
void lcd_puts(const char *s)
{
RS = 1; // write characters
while(*s)
lcd_write(*s++);
}
/* カーソル位置に1文字出力 */
void lcd_putch(char c)
{
RS = 1; // write characters
lcd_write( c );
}
/* カーソル位置の設定 y:行 x:桁*/
void lcd_locate(unsigned char y,unsigned char x){
RS = 0;
lcd_write(0x80 + (0x40 * y) +x);
}
void lcd_init(){
RS = 0;
EN = 0;
RW = 0;
__delay_ms(15); /* 15ms待つ */
LCD_DATA = 0b00000011; /* 一旦8bitモード設定(初期化) */
LCD_STROBE();
__delay_ms(5); /*5ms待つ */
LCD_STROBE();
__delay_us(200); /*200us待つ */
LCD_STROBE();
__delay_us(200); /*200us待つ */
LCD_DATA = 0b00000010; /* 4bitモード設定 */
LCD_STROBE();
lcd_write(0x28); /* 2行表示 7ドットモードに設定 */
lcd_write(0x0C); /* 表示ON,カーソルOFF,カーソル点滅OFF */
lcd_clear(); /* 画面クリア */
lcd_write(0x06); /* Entry Modeセット */
}
RS = 0;
EN = 0;
RW = 0;
__delay_ms(15); /* 15ms待つ */
LCD_DATA = 0b00000011; /* 一旦8bitモード設定(初期化) */
LCD_STROBE();
__delay_ms(5); /*5ms待つ */
LCD_STROBE();
__delay_us(200); /*200us待つ */
LCD_STROBE();
__delay_us(200); /*200us待つ */
LCD_DATA = 0b00000010; /* 4bitモード設定 */
LCD_STROBE();
lcd_write(0x28); /* 2行表示 7ドットモードに設定 */
lcd_write(0x0C); /* 表示ON,カーソルOFF,カーソル点滅OFF */
lcd_clear(); /* 画面クリア */
lcd_write(0x06); /* Entry Modeセット */
}
void main() {
// __delay_ms(1000);
TRISA = 0x00; //PORTA 全てOUTPUT
TRISB = 0x00; //PORTB 全てOUTPUT
// __delay_ms(1000);
TRISA = 0x00; //PORTA 全てOUTPUT
TRISB = 0x00; //PORTB 全てOUTPUT
lcd_init(); //LCD初期化
lcd_locate(0,0); //Cursor Home
lcd_puts("Hello World!");
lcd_locate(1,0);
lcd_puts("JH7UBC");
while(1){
}
}
lcd_locate(0,0); //Cursor Home
lcd_puts("Hello World!");
lcd_locate(1,0);
lcd_puts("JH7UBC");
while(1){
}
}
まず、分かっている方には、単純なことなのですが、関数を定義する前に関数を使うとエラーになります。
Aeduino言語のプログラミングに慣れていたため、関数(サブルーチン)はどこにおいてもコンパイルしてくれると思い込んでいましたが、XC8では、上の行からコンパイルしていき、定義されていない関数がでてくるとエラーを出すようです。
つまり、
void main(){
Test1();
}
void Test1(){
}
と書くと、エラーになります。
これを
void Test1(){
}
void main(){
Test1();
}
と書けば、エラーはでません。
単純なことですが、やってみないと分からないものですね。
今回のようなプログラムは、細かい関数は、ヘッダプログラムやライブラリを使えばもっとスマートに使えるようになると思いますが、それらの作り方や使い方がまだよく分かりません。
これから勉強していきたいと思います。