AVR Atmega168 I2C LCD不想初始化

AVR Atmega168 I2C LCD does not want to initialize

我正在使用 I2C 转换器将数据发送到我的液晶显示器。 转换器基于PCF85741,lcd为日立hd44780

PCF85741与lcd的端口映射如下:

P0 -> RS

P1 -> RW

P2 -> E

P3 -> ?

P4 -> D4

P5 -> D5

P6 -> D6

P7 -> D7

文档说我的slave的默认地址是0x20,但是对于RW位我需要发送0x40。

这是我的代码:

void twi_start()
{
    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTA);

    while (!(TWCR & (1 << TWINT)));
}

void twi_stop()
{
    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

    while (!(TWCR & (1 << TWSTO)));
}

void twi_write(uint8_t byte)
{
    TWDR = byte;

    TWCR = (1 << TWINT) | (1 << TWEN);

    while (!(TWCR & (1 << TWINT)));
}

void twi_write_byte(uint8_t byte)
{
    uint8_t SLAVE_ADDRESS = 0x40;


    twi_start();
    twi_write(SLAVE_ADDRESS);
    twi_write(byte);

    twi_stop();
}

液晶初始化

void lcd_init2()
{
    for (int i = 0; i < 3; i++) {
        twi_write_byte(0x03);

        _delay_ms(20);
    }

    twi_write_byte(0x02);
    _delay_ms(20);

    //4 bit mode
    twi_write_byte(0x24); // D5 -> 1, E -> 1 
    _delay_ms(10);
    twi_write_byte(0x20); // D5 -> 1, E -> 0
    _delay_ms(10);

    //2 lines
    twi_write_byte(0x24); // D5 -> 1, E -> 1
    _delay_ms(10);
    twi_write_byte(0x20); // D5 -> 1, E -> 0 first nibble
    _delay_ms(10);

    twi_write_byte(0x84); // D7 -> 1, E -> 1
    _delay_ms(10);
    twi_write_byte(0x80); // D7 -> 1, E -> 0 second nibble 
    _delay_ms(10);
}

在这段代码之后,液晶显示器应该是4位模式,有2行,但不是 液晶显示器上没有任何变化。

1)请说明你的I2C-to-parallelIC是什么?我找不到什么是 PCF85741,我只看到 PCF8574 and PCF8574A.

的数据表

在第一种情况下,从站地址将为(包括 r/w 位)0x40...0x4F,在第二种情况下 - 0x70...0x7F。

根据我的经验,这些显示器附带的常用 I2C 电路上有 PCF8574A(即地址为 0x7*)。顺便说一下,那里的引脚 3 是用来控制背光的。

2) 确定你有地址的低位?输入 A0 A1 A2 是上拉还是接地?

同样,根据我的经验,这些电路板通常有 pull-ups 到 +5,以及电路板上的可焊跳线,用于将它们短路到地。默认情况下,跳线未焊接,因此 A0 A1 A2 具有高逻辑电平,因此设备的 I2C 地址为 0x7E(写入)/0x7F(读取)。如果板载 PCF8574T,则地址将为 0x4E/0x4F

您可以很容易地检测到 IC 是否响应,通过检查 TWSR 寄存器中的 TWS 位 (TWSR & TW_STATUS_MASK) 应该在地址传输后等于 TW_MT_SLA_ACK (0x18),或者 TW_MT_DATA_ACK (0x28) 在数据字节被传输之后。 (参见 the datasheet 部分 19.8.1 主发送器模式 第 186-188 页)

或者,更简单的,如果你的PCF8574的P3接了背光,你可以试试输出0x08 / 0x00,看看背光是亮还是灭。

3) 有关初始化序列,请参阅 图 24 4 位接口 HD44780 datasheet 第 46 页 注意位 DB5 和 DB4 为高。另外,要小心,因为你只写显示控制器,R/W 位(即输出的第 1 位)应该始终为零(注意你'重新发送 wi_write_byte(0x03); 然后 twi_write_byte(0x02); 并将位 1 设置为高)。

例子可能如下:

void send4bits(uint8_t fourbits, bool is_cmd) {
  uint8_t d = (fourbits << 4) | 0b1000;
  if (!is_cmd) d |= 1;
  twi_write_byte(d | 0b100); // E high
  twi_write_byte(d);         // E low
}

void sendcmd(uint8_t cmd) {
  send4bits(cmd >> 4, true);
  send4bits(cmd & 0xF, true);
}

void senddata(uint8_t cmd) {
  send4bits(cmd >> 4, false);
  send4bits(cmd & 0xF, false);
}


// initialization sequence

send4bits(0b0011, true);
_delay_ms(5);
send4bits(0b0011, true);
_delay_ms(1);
send4bits(0b0011, true);
// since I2C is slow enough the required 100us pause already happened here
send4bits(0b0010, true);

sendcmd(0b00101000);
sendcmd(0b00001000);
sendcmd(0b00000001);
delay_ms(2);
sendcmd(0b00000110);

sendcmd(0b00001110);

// Initialization is done

sendcmd(0x80); // Set cursor at the beginning
for (uint8_t i = 'A' ; i <= 'Z' ; i++) {
  senddata(i); // Send some random data
}