 
		PIC用のコンパイラであるXC8にも、標準文字出力関数である printf が標準で装備されています。標準文字出力関数のうち特に有益な関数は printf でしょう。整数値を自由に構成(フォーマット)して出力することが可能です。XC8の場合、この関数の初期設定は、UARTによる出力に指定されていますから、シリアルデータの出力にはそのまま使用することが可能です。 PIC回路で最も頻繁に使用するLCD表示で printf を利用可能にするには、今までのプログラムに以下を追加する必要があります。
これで、標準出力チャネルはUARTからユーザー出力(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にも変更できます。
<プログラム>
/*********************************************************************
 *  データをLCDに表示する。
 *    秋月(ACM1602NI)I2C LCD表示器を使用
 *          1MHz (内部クロック)
 * RB6 SCL
 * RB4 SDA
 *
 * PIC16F1619  MPLAB X IDE with XC8
 * Copyright (c) 2017 iwamoto All Rights Reserved
 * *******************************************************************/
#include <xc.h>
#include <stdio.h>
#include "i2cLCD.h"
#define _XTAL_FREQ  1000000
// CONFIG
#pragma config FOSC = INTOSC,PWRTE = OFF,MCLRE = ON,CP = OFF
#pragma config BOREN = ON,CLKOUTEN = OFF,IESO = ON,FCMEN = ON
#pragma config WRT = OFF,PPS1WAY = ON,ZCD = OFF,PLLEN = OFF
#pragma config STVREN = ON,BORV = LO,LPBOR = OFF,LVP = ON
#pragma config WDTCPS = WDTCPS1F,WDTE = OFF,WDTCWS = WDTCWSSW
#pragma config WDTCCS = SWC
//******************************************************
// LCD で printf関数が使用できるようにするため putch を設定する
//******************************************************
void putch(char data) {
        LCD_dat(data);      // LCD への一文字表示関数
}
/*********************************************************
                         Main application
 *********************************************************/
void main(void)
{
    OSCCON = 0x58;	// FOSC; PLL disabled; 1MHz_HF;
    // --------------------------------------------------------
    LCD_int();                  // LCDを初期化
    printf("LCD Test");
    LCD_posyx(1,0);             // 下段にカーソル移動
    printf("%04X",0x12AB);      // 数値をHEX表示する
    while (1)
    {
        // Add your application code
    }
}
i2cLCD.h
/********************************************************************* * データをLCDに表示する。File: i2cLCD.h * 秋月(ACM1602NI)I2C LCD表示器を使用 * 1MHz (内部クロック) * RB6 SCL * RB4 SDA * * PIC16F1619 MPLAB X IDE with XC8 * Copyright (c) 2017 iwamoto All Rights Reserved * *******************************************************************/ #include <xc.h> #ifndef _XTAL_FREQ #define _XTAL_FREQ 1000000 #endif #define BRGval _XTAL_FREQ/400000-1 //********************************************************************* // 調整用定数 //********************************************************************* #define CONTRAST 0x28 // for 3.3V // #define CONTRAST 0x18 // for 5.0V #define slaveDeviceAddress 0x7C //******************* プロトタイプ ******************************* 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_put(char);
i2cLCD.c
/*********************************************************************
 *  データをLCDに表示する。File:   i2cLCD.c
 *    秋月(ACM1602NI)I2C LCD表示器を使用
 *          1MHz (内部クロック)
 * RB6 SCL
 * RB4 SDA
 *
 * PIC16F1619  MPLAB X IDE with XC8
 * Copyright (c) 2017 iwamoto All Rights Reserved
 * *******************************************************************/
#include <xc.h>
#include "i2cLCD.h"
//********************************************************************
// I2C 関連
//********************************************************************
//-------- 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){
    // SSP1関連ピンの設定 ----------------------------------
    ANSB6 = 0;              // RB6をデジタル
    ANSB4 = 0;              // RB4をデジタル
    WPUB6 = 1;              // RB6を弱プルアップ
    WPUB4 = 1;              // RB4を弱プルアップ
    nWPUEN = 0;
    TRISB6 = 1;             // RB6を入力に設定
    TRISB4 = 1;             // RB4を入力に設定
    ODB6 = 1;               // RB6をオープンドレイン
    ODB4 = 1;               // RB4をオープンドレイン
    SSPCLKPPS = 0b00001110; // RB6をCLK入力に指定
    RB6PPS    = 0b00010000; // RB6をCLK出力に指定
    SSPDATPPS = 0b00001100; // RB4をDATに入力指定
    RB4PPS    = 0b00010001; // RB4をDAT出力に指定
    // SSP1設定 -----------------------------------------------
    SSP1STAT = 0b10000000;     // スルーレート制御はOff
    SSP1ADD  = BRGval;         // クロック設定 125k@1MHz
    SSP1CON1 = 0b00101000;     // I2C Master modeにする
    // --------------------------------------------------------
    __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
}