[Homepage][BBS][Blog][YouTube][asablo]

エアーバリアブルBBS
新エアーバリアブルBBS
初めにお読み下さい Please read first ホームページ ブログ YouTube 過去ログ倉庫
PCF8574ATと2004または1602 LCDの使用について
初めまして。

PIC12F1840、CCSS-C v5.078、MPLABX v5.00にてPCF8574ATのI2Cを使ったLCD表示ができなくて困っています。
16桁x2行LCDおよび20桁x4行LCD、どちらも初期化すらできない状態に思えます。

PCF8574ATをPICで使う例がほとんど国内に無いようなので海外のフォーラムを見ています。

具体的には以下のソースです。

#include <12F1840.h>
#use delay(internal=8MHz)
#use i2c(Master,sda=PIN_A2,scl=PIN_A1,force_hw,stream=i2c2)
#use i2c(Master,sda=PIN_A5,scl=PIN_A4,force_sw,stream=i2c1)
#fuses NOPROTECT
#fuses NOWDT
#fuses NOMCLR
#USE FAST_IO(ALL)

// 以下PCF8574AT用
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
#define LCD_FIRST_ROW 0x80
#define LCD_SECOND_ROW 0xC0
#define LCD_THIRD_ROW 0x94
#define LCD_FOURTH_ROW 0xD4
#define LCD_CLEAR 0x01
#define LCD_RETURN_HOME 0x02
#define LCD_ENTRY_MODE_SET 0x04
#define LCD_CURSOR_OFF 0x0C
#define LCD_UNDERLINE_ON 0x0E
#define LCD_BLINK_CURSOR_ON 0x0F
#define LCD_MOVE_CURSOR_LEFT 0x10
#define LCD_MOVE_CURSOR_RIGHT 0x14
#define LCD_TURN_ON 0x0C
#define LCD_TURN_OFF 0x08
#define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1E

#ifndef LCD_TYPE
#define LCD_TYPE 2 // 0=5x7, 1=5x10, 2=2 lines
#endif

int1 RS;
unsigned int8 i2c_addr, backlight_val = LCD_BACKLIGHT;

void LCD_Write_Nibble(unsigned int8 n);
void LCD_Cmd(unsigned int8 Command);
void LCD_Goto(unsigned int8 col, unsigned int8 row);
void LCD_Out(unsigned int8 LCD_Char);
void LCD_Begin(unsigned int8 _i2c_addr);
void Backlight();
void noBacklight();
void Expander_Write(unsigned int8 value);

void LCD_Write_Nibble(unsigned int8 n) {
n |= RS;
Expander_Write(n);
Expander_Write(n | 0x04);
delay_us(1);
Expander_Write(n & 0xFB);
delay_us(50);
}

void LCD_Cmd(unsigned int8 Command) {
RS = 0;
LCD_Write_Nibble(Command & 0xF0);
LCD_Write_Nibble((Command << 4) & 0xF0);
}

void LCD_Goto(unsigned int8 col, unsigned int8 row) {
switch(row) {
case 2:
LCD_Cmd(0xC0 + col-1);
break;
case 3:
LCD_Cmd(0x94 + col-1);
break;
case 4:
LCD_Cmd(0xD4 + col-1);
break;
default: // case 1:
LCD_Cmd(0x80 + col-1);
}
}

void LCD_Out(unsigned int8 LCD_Char){
RS = 1;
LCD_Write_Nibble(LCD_Char & 0xF0);
LCD_Write_Nibble((LCD_Char << 4) & 0xF0);
}

void LCD_Begin(unsigned int8 _i2c_addr) {
i2c_addr = _i2c_addr;
Expander_Write(0);
delay_ms(40);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(LCD_RETURN_HOME);
delay_ms(5);
LCD_Cmd(0x20 | (LCD_TYPE << 2));
delay_ms(50);
LCD_Cmd(LCD_TURN_ON);
delay_ms(50);
LCD_Cmd(LCD_CLEAR);
delay_ms(50);
LCD_Cmd(LCD_ENTRY_MODE_SET | LCD_RETURN_HOME);
delay_ms(50);
}

void Backlight() {
backlight_val = LCD_BACKLIGHT;
Expander_Write(0);
}

void noBacklight() {
backlight_val = LCD_NOBACKLIGHT;
Expander_Write(0);
}

void Expander_Write(unsigned int8 value) {
i2c_start(i2c2);
i2c_write(i2c2, i2c_addr);
i2c_write(i2c2, value | backlight_val);
i2c_stop(i2c2);
}


// 以下AQM1602A用
#define ST7032i_SLAVE_ADDRESS 0x7C // スレーブアドレス

char lcd_string[20]; // 送信用文字データー格納庫

// 表示ライン
#define ST7032i_FIRST_LINE_ADDRESS 0x00 // 1行目先頭
#define ST7032i_SECOND_LINE_ADDRESS 0x40 // 2行目先頭

#define ST7032i_COMMAND 0x80 // 次のデーター:コマンド 送信
#define ST7032i_DATA_CHAR 0xC0 // 次のデーター:キャラクターコード 送信 『control byte + data byte』ペア
#define ST7032i_DATA_WORD 0x40 // 次のデーター:キャラクターコード 送信 『data byte』 連続

boolean lcd_ready(int address) {
short ack;
i2c_start(i2c1);
ack = i2c_write(i2c1, address);
i2c_stop(i2c1);
return ack;
}

// Command Write
void lcd_command_write(int command) {
while (lcd_ready(ST7032i_SLAVE_ADDRESS));

i2c_start(i2c1);
i2c_write(i2c1, ST7032i_SLAVE_ADDRESS);
i2c_write(i2c1, ST7032i_COMMAND);
i2c_write(i2c1, command);
i2c_stop(i2c1);
}

// 1文字送信
void lcd_char_write(int line_address, char data) {
while (lcd_ready(ST7032i_SLAVE_ADDRESS));

i2c_start(i2c1);
i2c_write(i2c1, ST7032i_SLAVE_ADDRESS);
i2c_write(i2c1, ST7032i_COMMAND);
i2c_write(i2c1, line_address | 0x80);
i2c_write(i2c1, ST7032i_DATA_CHAR);

// データー送信
i2c_write(i2c1, data);
i2c_stop(i2c1);
}

// 文字列送信
void lcd_string_write(int line_address) {
char *lcd_strings = lcd_string;

while (lcd_ready(ST7032i_SLAVE_ADDRESS));

i2c_start(i2c1);
i2c_write(i2c1, ST7032i_SLAVE_ADDRESS);
i2c_write(i2c1, ST7032i_COMMAND);
i2c_write(i2c1, line_address | 0x80);
i2c_write(i2c1, ST7032i_DATA_WORD);

// データー送信
while (*lcd_strings) {
i2c_write(i2c1, *lcd_strings++);
}
i2c_stop(i2c1);
}

// Initialize
void lcd_initialize(void) {
delay_ms(40);
lcd_command_write(0x38);
lcd_command_write(0x39);
lcd_command_write(0x14);
lcd_command_write(0x70);
lcd_command_write(0x56);
lcd_command_write(0x6C);
delay_ms(200);
lcd_command_write(0x38);
lcd_command_write(0x0C);
lcd_command_write(0x01);
delay_us(500);
}

// I2C検出用
#BIT ACKSTAT = 0x0216.6
#define I2C_ADDR_FIRST 0b0000111 // 0?0b111はシステムで予約されている
#define I2C_ADDR_LAST 0b1111000 // 0b11110000以降はシステムで予約されている

int ledtime = 0;


// main部
void main() {
// 各ポートのTRIS設定
set_tris_a(0b00001000);
port_a_pullups(0b00001000);
output_high(PIN_A0);

setup_timer_1(T1_INTERNAL|T1_DIV_BY_4); //131 ms overflow
enable_interrupts(INT_TIMER1);
disable_interrupts(GLOBAL);

unsigned int8 i = 0;

lcd_initialize();
enable_interrupts(GLOBAL);

// I2Cアドレスの検出
for (i=0; i<=0x7F; i++) {
if (i <= I2C_ADDR_FIRST || i >= I2C_ADDR_LAST) continue;

sprintf(lcd_string, "Scan %02X", i);
lcd_string_write(ST7032i_FIRST_LINE_ADDRESS);

i2c_init(i2c2);
i2c_start(i2c2);
i2c_write(i2c2, i << 1); // アドレスを1ビット左にシフトし、末尾にR/Wビット(Write=0)を付与
if (!ACKSTAT) {
sprintf(lcd_string, "Found %02X", i);
lcd_string_write(ST7032i_SECOND_LINE_ADDRESS);
delay_ms(3000);
}
i2c_stop(i2c2);
delay_ms(50);
}


i = 0;
LCD_Begin(0x3F); // Initialize LCD module with I2C

LCD_Goto(2, 1); // Go to column 2 row 1
LCD_Out("Hello, world!");

while(TRUE) {
lcd_goto(7, 2); // Go to column 7 row 2
printf(lcd_out, "%03u", i++); // Print i with 3 numbers max
delay_ms(500);
}
}

#int_TIMER1
void TIMER1_isr() {
ledtime++;
if (ledtime >= 5) {
ledtime = 0;
output_toggle(PIN_A0);
}
}


以上ソース。(ヘッダを使って記述している部分もありますが1つのソースにまとめました)

これをコンパイルして実行すると、AQM1602Aの表示が「Scan 08」のままで止まってしまいます。
割り込みはPICが生きていることをLED点滅で示す目的で使っており、点滅し続けます。

#use i2cのi2c1, i2c2を逆転して接続を変えてもAQM1602Aはきちんと表示するのでPIC自体が
壊れているということも考えにくいです。
また、PCF8574ATと2004LCD, 1602LCDは二組づつ用意していて、これらが壊れていることも
考えにくいです。

I2Cのラインにプルアップ抵抗を入れたり外してみたり、初期化や表示方法を他のフォーラムに
あった物に変えてみたり、いろいろ試したのですがどうにも表示できません。

長くなってしまいましたが、どなたかPCF8574ATの使い方を指南していただけないでしょうか?

よろしくお願いいたします。
  • 河村
  • 2018/07/30 (Mon) 19:58:19
Re: PCF8574ATと2004または1602 LCDの使用について
河村さん、はじめまして。

8 pin PICを使って2つのI2Cを動作させようとしている件ですね。
私はCCSCには明るくないので、ざっとソースを見て助言程度ですがお応えしたいとおもいます。

I2Cアドレスを自動探索している部分で止まるという事ですが、ロジックアナライザなどの測定器がない場合、
Printfデバッグ、もしくはポートによるLEDのステータスなどに頼ることになります。

LCDが表示できているのであれば、
sprintf(lcd_string, "メッセージ");
lcd_string_write(ST7032i_SECOND_LINE_ADDRESS);

の構文をいくつか差し込んで、どこで止まっているのか探った方がよいと思います。

また、自動探索をやめてPCFの実アドレスとして0x20(0x40かもしれない)を
i2c2にダイレクトで指定するなどを行ってみると良いと思います。

まずはお試しください。
  • air_variable
  • 2018/08/06 (Mon) 21:56:43

返信フォーム






プレビュー (投稿前に内容を確認)