PIC用のコンパイラであるXC8にも、標準文字出力関数である printf が標準で装備されています。標準文字出力関数のうち特に有益な関数は printf でしょう。整数値を自由に構成(フォーマット)して出力することが可能です。XC8の場合、この関数の初期設定は、UARTによる出力に指定されていますから、シリアルデータの出力にはそのまま使用することが可能です。 PIC回路で最も頻繁に使用するLCD表示で printf を利用可能にするには、今までのプログラムに以下を追加する必要があります。
これで、標準出力チャネルはユーザー出力(LCD)に変更されます。
printf で使用れることの多いフォーマット例は、「その他ーLCD表示にprintf」 に書いておきます。
*注意*
SCL SDAの2ピンで通信を行いますが、これらは、PPSでどのピンを使用するかを指定できます。これらは双方向で使うため、ピンはオープンドレイン回路にし、TRISレジスタは入力モードに設定する必要があります。
PI2Cを利用したLCD表示器(LCD-AQM0802A)を使用するプログラムです。通常 I2Cラインに取り付けるプルアップ抵抗は、PIC内の弱プルアップを利用しています。
main.c を短くするために、LCD関連は、LCDi2c.h,LCDi2c.c に分離してあります。また、LCD表示器は、RC4,RC5に接続しますが、LCDi2c.c の、LCD_int関数に書かれているPPS命令を変更すればどのpinにも変更できます。
<回路図>
<プログラム>
main.c
/*********************************************************************
* データをLCDに表示する。 1MHz (内部クロック)
* RC5 SCL
* RC4 SDA
*
* PIC16F18313 MPLAB X IDE with XC8
* Copyright (c) 2017 iwamoto All Rights Reserved
* *******************************************************************/
#define _XTAL_FREQ 1000000
#include <xc.h>
#include <stdio.h>
#include "LCDi2c.h"
//******************* コンフィグレーション ****************************
#pragma config FEXTOSC = OFF,RSTOSC = HFINT1 // HFINTOSC (1MHz)
#pragma config CLKOUTEN = OFF,CSWEN = ON,FCMEN = OFF
#pragma config MCLRE = OFF,PWRTE = OFF,WDTE = OFF,LPBOREN = OFF
#pragma config BOREN = OFF,BORV = LOW,PPS1WAY = OFF,STVREN = ON
#pragma config DEBUG = OFF
#pragma config WRT = OFF,LVP = OFF,CP = OFF,CPD = OFF
// ******************* main ******************************************
void main() {
LATA = 0x00;
TRISA = 0xFF; // Port すべて入力
ANSELA = 0x00; // すべてデジタル
WPUA = 0xFF; // 弱プルアップ ON
LATC = 0x00;
TRISC = 0xFF; // Port すべて入力
ANSELC = 0x00; // すべてデジタル
WPUC = 0xFF; // 弱プルアップ ON
// --------------------------------------------------------
i2c_int();
LCD_int(); // LCDを初期化
printf("LCD Test");
LCD_posyx(1,1); // 下段にカーソル移動
printf("%04X",0x12AB); // 数値をHEX表示する
while(1);
}
LCDi2c.h
/* * File: LCDi2c.h * データをLCDに表示する。 * 秋月(ACM1602NI)I2C LCD表示器を使用 * 1MHz (内部クロック) * RC5 SCL * RC4 SDA * * PIC16F18313 MPLAB X IDE with XC8 * Copyright (c) 2017 iwamoto All Rights Reserved ** Author: ki * Created on October 21, 2017, 11:53 AM */ #ifndef _XTAL_FREQ #define _XTAL_FREQ 1000000 #endif //************************************************* // 調整用定数 //************************************************* #define CONTRAST 0x28 // for 3.3V // #define CONTRAST 0x18 // for 5.0V // プロトタイプ ******************************* void i2c_int(void); void i2cByteWrite(char, char, char); void i2cTxData(char); void LCD_dat(char); void LCD_cmd(char); void LCD_clr(void); void LCD_posyx(char,char); void LCD_int(void); void LCD_str(char *); void LCD_ROMstr(const char *);
LCDi2c.c
/* ************************************
* File: LCDi2c.c
* プログラム例
* int a = 1234;
* printf("%d %o %x\n", a, a, a);
* printf("%s %c\n", "abc", 'x');
* 結果 -------------------------------
* 1234 2322 4d2
* abc x
* *************************************/
#include <xc.h>
#include <stdio.h>
#include "LCDi2c.h"
//******************************************************
// LCD で printf関数が使用できるようにするため putch を設定する
//******************************************************
void putch(char data) {
LCD_dat(data); // LCD への一文字表示関数
}
//******************************************************
// I2C 関連 RC5 SCL, RC4 SDA
//******************************************************
void i2c_int(void){
ODCC4 = 1; // RC4をオープンドレイン
ODCC5 = 1; // RC5をオープンドレイン
TRISC4 = 1; // RC4を入力にする
TRISC5 = 1; // RC5を入力にする
RC4PPS = 25; // RC4をDAT出力に指定
RC5PPS = 24; // RC5をCLK出力に指定
SSP1DATPPS = 0x14; // RC4をDATに入力指定
SSP1CLKPPS = 0x15; // RC5をCLK入力に指定
// SSP1設定 ------------------------------------------
SSP1STAT = 0b10000000; // スルーレート制御はOff
SSP1ADD = 1; // クロック設定 125k@1MHz
SSP1CON1 = 0b00101000; // I2C Master modeにする
}
//-------- ByteI2C送信
void i2cByteWrite(char addr, char cont, char data){
SSP1CON2bits.SEN = 1; // Start condition 開始
while(SSP1CON2bits.SEN); // Start condition 確認
i2cTxData(addr); // アドレス送信
i2cTxData(cont); // 制御コード送信
i2cTxData(data); // データ送信
SSP1CON2bits.PEN = 1; // Stop condition 開始
while(SSP1CON2bits.PEN); // Stop condition 確認
}
//-------- Data送信
void i2cTxData(char data){
PIR1bits.SSP1IF = 0; // 終了フラグクリア
SSP1BUF = data; // データセット
while(!PIR1bits.SSP1IF); // 送信終了待ち
}
//********************************************************
// LCD 関連
//********************************************************
//-------- 1文字表示
void LCD_dat(char chr){
i2cByteWrite(0x7C, 0x40, chr);
__delay_us(50); // 50μsec
}
//-------- コマンド出力
void LCD_cmd(char cmd){
i2cByteWrite(0x7C, 0x00, cmd);
if(cmd & 0xFC) // 上位6ビットに1がある命令
__delay_us(50); // 50usec
else
__delay_ms(2); // 2msec ClearおよびHomeコマンド
}
//-------- 全消去
void LCD_clr(void){
LCD_cmd(0x01); //Clearコマンド出力
}
//-------- カーソル位置指定
void LCD_posyx(char ypos, char xpos){
unsigned char pcode;
switch(ypos & 0x03){
case 0: pcode=0x80;break;
case 1: pcode=0xC0;break;
}
LCD_cmd(pcode += xpos);
}
//-------- 初期化
void LCD_int(void){
__delay_ms(100);
LCD_cmd(0x38); // 8bit 2行 表示命令モード
LCD_cmd(0x39); // 8bit 2行 拡張命令モード
LCD_cmd(0x14); // OSC BIAS 設定1/5
// コントラスト設定
LCD_cmd(0x70 + (CONTRAST & 0x0F));
LCD_cmd(0x5C + (CONTRAST >> 4));
LCD_cmd(0x6B); // Ffollwer
__delay_ms(100);
__delay_ms(100);
LCD_cmd(0x38); // 表示命令モード
LCD_cmd(0x0C); // Display On
LCD_cmd(0x01); // Clear Display
}
//-------- 文字列出力
void LCD_str(char *str){
while(*str) //文字列の終わり(00)まで継続
LCD_dat(*str++); //文字出力しポインタ+1
}
//-------- Rom 文字列出力
void LCD_ROMstr(const char *str){
while(*str) //文字列の終わり(00)まで継続
LCD_dat(*str++); //文字出力しポインタ+1
}