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
}
我正在使用 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
}