PIC16F18346の基本動作から応用プログラムまでを学びます。

ホーム
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
    
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
printf を使う
202-05-21

PIC用のコンパイラであるXC8にも、標準文字出力関数である printf が標準で装備されています。標準文字出力関数のうち特に有益な関数は printf でしょう。整数値を自由に構成(フォーマット)して出力することが可能です。XC8の場合、この関数の初期設定は、UARTによる出力に指定されていますから、シリアルデータの出力にはそのまま使用することが可能です。 PIC回路で最も頻繁に使用するLCD表示で printf を利用可能にするには、今までのプログラムに以下を追加する必要があります。

  1. 標準ライブラリ stdio.h をインクルードする。
  2. ユーザー出力の putch を作成する。
  3. putch を呼び出すことで、一文字がLCDに表示できるようにする。

これで、標準出力チャネルはユーザー出力(LCD)に変更されます。
printf で使用れることの多いフォーマット例は、「その他ーLCD表示にprintf」 に書いておきます。

*注意*
SCL SDAの2ピンで通信を行いますが、これらは、PPSでどのピンを使用するかを指定できます。これらは双方向で使うため、ピンはオープンドレイン回路にし、TRISレジスタは入力モードに設定する必要があります。

printf使用例

以下に printf の使用例を示します。

使用例 表示結果 説明
printf("%d",123); 123 10進表示
printf("%X",123); 7B 16進大文字表示 %x は小文字表示
printf("%4X",123);  7B 桁数指定 数値の前に2つスペースが入る
char num = 0x3B;
printf("%04X",num);
003B 16進4桁 変数を指定する
桁数指定のまえにゼロを付加するとゼロ詰めになる
printf("LCD test"); LCD test 文字列を表示
char str[] = "LCD test";
printf(str);
LCD test 文字列の配列変数を表示
char num = 0xA7;
printf("out=%04X",num);
out=00A7 文字列"out="と変数を表示
char num = 0xA7;
char str[] = "IN";
printf("%s=%04X",str,num);
IN=00A7 文字列配列と数値変数、及び
直接指定文字 "=" を組み合わせて表示

プログラム

<回路図>

I2Cを利用したLCD表示器(LCD-AQM0802A)を使用するプログラムです。main.c を短くするために、LCD関連は、i2cLCD.h, i2cLCD.c に分離してあります。

<プログラム>
main.c

/*************************************
 * File: main.c
 *  データをLCDに表示する。
 *    秋月(ACM1602NI)I2C LCD表示器を使用
 *     1MHz (内部クロック)
 *     RB4 SDA
 *     RB6 SCL
 * PIC16F18346 MPLAB XC8 v2.10
 * Created on May 22, 2020, 2:37 PM
 **************************************/

#include <xc.h>
#include <stdio.h>
#include "i2cLCD.h"
#define _XTAL_FREQ 1000000      // delay_ms(x) のための定義

#pragma config FEXTOSC = OFF,RSTOSC = HFINT1  // HFINTOSC (1MHz)
#pragma config CLKOUTEN = OFF,CSWEN = OFF,FCMEN = OFF
#pragma config MCLRE = ON,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 = ON,CP = OFF,CPD = OFF


// ********************************************************
void main() {
  char num=30;
  char ch[]="abcd";
    i2c_MasterInit(100000);

    LCD_int();               // LCDを初期化
    printf("%04X",num);      // 上段に追記
    LCD_posyx(1,1);          // 下段にカーソル移動
    printf("[%s]",ch);       // 下段に追記
    while(1);
}

LCDi2c.h

/*************************************
 * File: i2cLCD.h
 *  データをLCDに表示する。
 *    秋月(ACM1602NI)I2C LCD表示器を使用
 *     1MHz (内部クロック)
 *     RB4 SDA
 *     RB6 SCL
 * PIC16F18346 MPLAB XC8 v2.10
 * Created on May 22, 2020, 2:37 PM
 **************************************/
//*********************************************************************
//  調整用定数
//*********************************************************************
#define CONTRAST  0x28          // for 3.3V
// #define CONTRAST  0x18       // for 5.0V

#define _XTAL_FREQ 1000000      // delay_ms(x) のための定義

// -------------- I2C関連定義 ----------------------------
// 各シーケンスの終了を待って復帰
// I2C特殊 condition
#define i2c_Idle()     while((SSP1CON2&0x1F)|(SSP1STATbits.R_nW))
#define i2c_Start()    SSP1CON2bits.SEN=1;while(SSP1CON2bits.SEN)
#define i2c_Stop()     SSP1CON2bits.PEN=1;while(SSP1CON2bits.PEN)
void i2c_MasterInit(const unsigned long baud);
char i2c_Write(char data);

// -------------- LCD関連定義 ----------------------------
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 *);

LCDi2c.c

// file: i2cLCD.c
#include <xc.h>
#include "i2cLCD.h"

#include <stdio.h>

//******************************************************
// LCD で printf関数が使用できるようにするため putch を設定する
//******************************************************
void putch(char data) {
        LCD_dat(data);      // LCD への一文字表示関数
}

//********************************************************************
// I2C 関連
//********************************************************************
void i2c_MasterInit(const unsigned long baud){
    // pin設定 ------------------------------------------------
    TRISB4 = 1;           // RB4を入力
    TRISB6 = 1;           // RB6を入力
    ANSB4  = 0;           // RB4をデジタル
    ANSB6  = 0;           // RB6をデジタル
    ODCB4  = 1;           // RB4をオープンドレイン
    ODCB6  = 1;           // RB6をオープンドレイン

    // PPS設定 -----------------------------------------------
    SSP1CLKPPS = 0x0E;    // RB6をCLK入力に指定
    RB6PPS     = 24;      // RB6をCLK出力に指定
    SSP1DATPPS = 0x0C;    // RB4をDATに入力指定
    RB4PPS     = 25;      // RB4をDAT出力に指定

    // SSP1設定 -----------------------------------------------
    SSP1STAT = 0b10000000;     // スルーレート制御はOff
    SSP1ADD = (_XTAL_FREQ/(4*baud))-1;      //  SSP1ADD = 0x77;
    SSP1CON1 = 0b00101000;     // I2C Master modeにする
}

char i2c_Write(char data){
    SSP1BUF = data;                 // データセット
    PIR1bits.SSP1IF = 0;           // 終了フラグクリア
    while(!PIR1bits.SSP1IF);       // 送信終了待ち
    return SSP1CON2bits.ACKSTAT;    // ACKなら「0」で復帰
}                                  // NACKは「1」で復帰

//-------- ByteI2C送信
void i2cByteWrite(char addr, char cont, char data){
		i2c_Idle();                // Bus アイドル確認
		i2c_Start();               // Start bit送信
		i2c_Write(addr);           // アドレス送信
		i2c_Write(cont);           // 制御コード送信
		i2c_Write(data);           // データ送信
		i2c_Stop();                // Stop bit送信
}

//********************************************************************
// 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
}