Нужна помощь в работе с i2c интерфейсом
Модератор: Модераторы разделов
-
- Сообщения: 142
- ОС: KUbuntu
Нужна помощь в работе с i2c интерфейсом
Всем привет! Ребята, если кто-то знает как работать с интерфейсом i2c на Python, C, C++ и может объяснить, отзовитесь. Для реализации проекта нужно работать с LCD через i2c и использовать i2c как расширитель I/O портов.
Буду рад любой помощи, как бесплатной, так и платной (в разумных пределах).
Буду рад любой помощи, как бесплатной, так и платной (в разумных пределах).
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
А гуглить не пробовали? Есть же куча мануалов.
Если вкратце, то открывается файл устройства,задаётся адрес на шинеи дальше уже туда отправляются команды.
Вот пример хелловорлда для такого экранчика с микросхемой расширения I/O PCF8574:
P. S. Помнится, малинщики-питонисты любят использовать библиотеку smbus.
Если вкратце, то открывается файл устройства,
Код: Выделить всё
file = open(filename, O_RDWR);
Код: Выделить всё
ioctl(file, I2C_SLAVE, addr);
Вот пример хелловорлда для такого экранчика с микросхемой расширения I/O PCF8574:
Код: Выделить всё
#include <linux/i2c-dev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
enum pcf8574_pinout {
lcd_rs_pin = 0,
lcd_rw_pin = 1,
lcd_e_pin = 2,
lcd_bl_pin = 3,
lcd_d4_pin = 4,
lcd_d5_pin = 5,
lcd_d6_pin = 6,
lcd_d7_pin = 7
};
typedef enum lcd_rw {
lcd_write = 0,
lcd_read = 1
} lcd_rw_t;
typedef enum lcd_rs {
lcd_instruction = 0,
lcd_data = 1
} lcd_rs_t;
int i2c_send(int file, char byte);
int lcd_backlight_off(int file);
int lcd_backlight_on(int file);
int lcd_backlight_apply(int file);
int lcd_init(int file);
int lcd_home(int file);
int lcd_print(int file, char *text);
int lcd_on(int file);
int lcd_off(int file);
int lcd_clear(int file);
int lcd_modeset(int file);
int lcd_funcset(int file);
int lcd_addr(int file, char addr);
int lcd_send(int file, lcd_rs_t rs, lcd_rw_t rw, char data);
int lcd_send4_int(int file, char data);
int i2c_lcd_send(int file, char byte);
int backlight = 1 << lcd_bl_pin; // подсветка по умолчанию включена
int main()
{
int addr = 0x27; // адрес устройства на шине I2C (выставляется джамперами)
char *filename = "/dev/i2c-1"; // файл интерфейса
int file;
if ((file = open(filename, O_RDWR)) < 0) { // используется open(), а не fopen(), чтобы избежать буферизации
fprintf(stderr, "Can not open file `%s'\n", filename);
exit(1);
}
if (ioctl(file, I2C_SLAVE, addr) < 0) {
fputs("Failed to acquire bus access and/or talk to slave.\n", stderr);
exit(1);
}
if (! lcd_init(file)) { // инициализация дисплея (нужна один раз после включения)
fputs("Error initializing display\n", stderr);
exit(1);
}
lcd_on(file); // включение дисплея
lcd_backlight_on(file); // включение подсветки
lcd_addr(file, 0x00); // курсор устанавливается в начало первой строки
lcd_print(file, "It works!!!");
lcd_addr(file, 0x40); // курсор устанавливается в начало второй строки
lcd_print(file, "Hello world!");
return 0;
}
int lcd_backlight_off(int file)
{
backlight = 0;
return lcd_backlight_apply(file);
}
int lcd_backlight_on(int file)
{
backlight = 1 << lcd_bl_pin;
return lcd_backlight_apply(file);
}
int lcd_backlight_apply(int file)
{
return i2c_send(file, backlight | 1 << lcd_e_pin); // чтобы байт не интерпретировался как команда, надо установить E в 1
}
int lcd_init(int file)
{
int i;
usleep(15000); // такая долгая задержка нужна только после включения питания
// мы не знаем, работает дисплей в 8-битном, или в 4-битном режиме
i = lcd_send4_int(file, (1 << lcd_d5_pin) | (1 << lcd_d4_pin));
if (i < 1)
return 0;
usleep(4100);
i = lcd_send4_int(file, (1 << lcd_d5_pin) | (1 << lcd_d4_pin));
if (i < 1)
return 0;
usleep(100);
i = lcd_send4_int(file, (1 << lcd_d5_pin) | (1 << lcd_d4_pin));
if (i < 1)
return 0;
// дисплей в 8-битном режиме
i = lcd_send4_int(file, 1 << lcd_d5_pin);
if (i < 1)
return 0;
// теперь дисплей в 4-битном режиме
i = lcd_funcset(file);
if (i < 1)
return 0;
i = lcd_off(file);
if (i < 1)
return 0;
i = lcd_clear(file);
if (i < 1)
return 0;
i = lcd_modeset(file); // установка режима ввода
if (i < 1)
return 0;
return 1;
}
int lcd_print(int file, char *text)
{
char *ptr = text;
int i;
while (*ptr != '\0') {
i = lcd_send(file, lcd_data, lcd_write, *ptr);
if (i < 1) {
break;
} else {
ptr++;
}
}
return ptr - text;
}
int lcd_funcset(int file)
{
int i;
i = lcd_send(file, lcd_instruction, lcd_write, 0x28); // 4-битный ввод данных, 2 строки дисплея, шрифт 5x8 точек
if (i > 0)
usleep(37);
return i;
}
int lcd_on(int file)
{
int i;
i = lcd_send(file, lcd_instruction, lcd_write, 0x0C); // не отображать курсор, не использовать мерцание символа
if (i > 0)
usleep(37);
return i;
}
int lcd_off(int file)
{
int i;
i = lcd_send(file, lcd_instruction, lcd_write, 0x08); // не отображать курсор, не использовать мерцание символа
if (i > 0)
usleep(37);
return i;
}
int lcd_clear(int file)
{
int i;
i = lcd_send(file, lcd_instruction, lcd_write, 0x01);
return i;
}
int lcd_modeset(int file)
{
int i;
i = lcd_send(file, lcd_instruction, lcd_write, 0x06); // увеличивать адрес DDRAM на 1 (ввод слева направо), отключить сдвиг дисплея
if (i > 0)
usleep(37);
return i;
}
int lcd_home(int file)
{
int i;
i = lcd_send(file, lcd_instruction, lcd_write, 0x02);
if (i > 0)
usleep(1520);
return i;
}
int lcd_addr(int file, char addr)
{
int i;
i = lcd_send(file, lcd_instruction, lcd_write, 1 << 7 | addr);
if (i > 0)
usleep(37);
return i;
}
int lcd_send(int file, lcd_rs_t rs, lcd_rw_t rw, char data)
{
char byte;
rs = rs & 1;
rw = rw & 1;
rs = rs << lcd_rs_pin;
rw = rw << lcd_rw_pin;
// данные передаются в 4-битном режиме, сначала 4 старших бита
byte =
(((data >> 7) & 1) << lcd_d7_pin) |
(((data >> 6) & 1) << lcd_d6_pin) |
(((data >> 5) & 1) << lcd_d5_pin) |
(((data >> 4) & 1) << lcd_d4_pin) |
rw | rs;
i2c_lcd_send(file, byte);
// потом 4 младших бита
byte =
(((data >> 3) & 1) << lcd_d7_pin) |
(((data >> 2) & 1) << lcd_d6_pin) |
(((data >> 1) & 1) << lcd_d5_pin) |
(((data >> 0) & 1) << lcd_d4_pin) |
rw | rs;
return i2c_lcd_send(file, byte);
}
int lcd_send4_int(int file, char data)
{
char byte = data &
~(1 << lcd_rs_pin) &
~(1 << lcd_rw_pin);
return i2c_lcd_send(file, byte);
}
int i2c_lcd_send(int file, char byte)
{
int i;
// чтобы данные не были считаны раньше времени, E устанавливается в 1
byte = byte | (1 << lcd_e_pin) | backlight;
i = i2c_send(file, byte);
if (i < 1)
return 0;
// теперь данные можно прочитать, E устанавливается в 0
byte = byte & ~(1 << lcd_e_pin);
i = i2c_send(file, byte);
if (i < 1)
return 0;
// и снова E возвращается в 1, чтобы при следующей записи не прочитался мусор
byte = byte | (1 << lcd_e_pin);
i = i2c_send(file, byte);
return i;
}
int i2c_send(int file, char byte)
{
const char *buf = &byte;
return write(file, buf, 1);
}
P. S. Помнится, малинщики-питонисты любят использовать библиотеку smbus.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 992
- ОС: openSUSE
Re: Нужна помощь в работе с i2c интерфейсом
Возможно пригодится http://undefined-reference-to-name.blogspo...74-gnuinux.html. Всё довольно просто
-
- Сообщения: 2565
- ОС: Debian
Re: Нужна помощь в работе с i2c интерфейсом
Я использую такой "велосипед"
Код: Выделить всё
int i2c_read(const i2c_hndl *hndl,
const unsigned int reg)
{
struct i2c_rdwr_ioctl_data data;
struct i2c_msg *msgs;
__u8 buf[sizeof(__u8) * 3] = {0};
int r = -1;
if (NULL == hndl || !hndl->addr)
return -1;
if (hndl->reg_width >= I2C_MAX || hndl->val_width >= I2C_MAX)
return -1;
if (I2C_16BIT == hndl->reg_width) {
buf[0] = (__u8)(reg >> 8);
buf[1] = (__u8)(reg & 0xFF);
} else if (I2C_24BIT == hndl->reg_width) {
buf[0] = (__u8)(reg >> 16);
buf[1] = (__u8)((reg >> 8) & 0xFF);
buf[2] = (__u8)(reg & 0xFF);
} else if (I2C_8BIT == hndl->reg_width)
buf[0] = (__u8)(reg & 0xFF);
memset(&data, 0, sizeof(data));
msgs = calloc(2, sizeof(struct i2c_msg));
if (NULL == msgs)
return r;
msgs[0].addr = hndl->addr >> 1;
msgs[0].buf = buf;
msgs[0].flags = 0;
msgs[0].len = (__u16)(hndl->reg_width + 1);
msgs[1].addr = hndl->addr >> 1;
msgs[1].flags = I2C_M_RD;
msgs[1].len = (__u16)(hndl->val_width + 1);
msgs[1].buf = buf;
data.msgs = msgs;
data.nmsgs = 2;
r = ioctl(hndl->fd, I2C_RDWR, &data);
free(msgs);
if (r < 0)
return r;
if (I2C_16BIT == hndl->val_width)
r = (buf[0] << 8) | buf[1];
else if (I2C_8BIT == hndl->val_width)
r = buf[0];
else if (I2C_24BIT == hndl->val_width)
r = (buf[0] << 16) | (buf[1] << 8) | buf[2];
return r;
}
int i2c_write(const i2c_hndl *hndl,
const unsigned int reg,
const unsigned int val,
const unsigned char check)
{
struct i2c_rdwr_ioctl_data data;
struct i2c_msg *msgs = NULL;
__u8 buf[sizeof(__u8) * 6] = {0};
int r = -1;
if (NULL == hndl || !hndl->addr)
return -1;
if (hndl->reg_width >= I2C_MAX || hndl->val_width >= I2C_MAX)
return -1;
if (I2C_16BIT == hndl->reg_width) {
buf[0] = (__u8)(reg >> 8);
buf[1] = (__u8)(reg & 0xFF);
if (I2C_16BIT == hndl->val_width) {
buf[2] = (__u8)(val >> 8);
buf[3] = (__u8)(val & 0xFF);
} else if (I2C_24BIT == hndl->val_width) {
buf[2] = (__u8)(val >> 16);
buf[3] = (__u8)((val >> 8) & 0xFF);
buf[4] = (__u8)(val & 0xFF);
} else if (I2C_8BIT == hndl->val_width)
buf[2] = (__u8)(val & 0xFF);
} else if (I2C_8BIT == hndl->reg_width) {
buf[0] = (__u8)(reg & 0xFF);
if (I2C_16BIT == hndl->val_width) {
buf[1] = (__u8)(val >> 8);
buf[2] = (__u8)(val & 0xFF);
} else if (I2C_24BIT == hndl->val_width) {
buf[1] = (__u8)(val >> 16);
buf[2] = (__u8)((val >> 8) & 0xFF);
buf[3] = (__u8)(val & 0xFF);
} else if (I2C_8BIT == hndl->val_width)
buf[1] = (__u8)(val & 0xFF);
} else if (I2C_24BIT == hndl->reg_width) {
buf[0] = (__u8)(reg >> 16);
buf[1] = (__u8)((reg >> 8) & 0xFF);
buf[2] = (__u8)(val & 0xFF);
if (I2C_16BIT == hndl->val_width) {
buf[3] = (__u8)(val >> 8);
buf[4] = (__u8)(val & 0xFF);
} else if (I2C_24BIT == hndl->val_width) {
buf[3] = (__u8)(val >> 16);
buf[4] = (__u8)((val >> 8) & 0xFF);
buf[5] = (__u8)(val & 0xFF);
} else if (I2C_8BIT == hndl->val_width)
buf[3] = (__u8)(val & 0xFF);
}
memset(&data, 0, sizeof(data));
msgs = calloc(2, sizeof(struct i2c_msg));
if (NULL == msgs)
return r;
msgs[0].addr = hndl->addr >> 1;
msgs[0].buf = buf;
msgs[0].flags = 0;
msgs[0].len = (__u16)(hndl->reg_width + 1 + hndl->val_width + 1);
data.msgs = msgs;
data.nmsgs = 1;
r = ioctl(hndl->fd, I2C_RDWR, &data);
free(msgs);
if (r < 0)
return r;
if (check)
return !(i2c_read(hndl, reg) == (int)val);
return 0;
}
-
- Сообщения: 142
- ОС: KUbuntu
Re: Нужна помощь в работе с i2c интерфейсом
Спасибо за советы, гуглить пробовал, но так не знаю с чего начать и запросы, наверное, кривые ввожу. Т.е. инфы много, но все говорят как просто это сделать, но не объясняют как оно работает.
Вот например, где брать адреса этих пинов?
Да и вообще кто знал что они разные, у каждой микросхемы. Попытался поискать даташит на мою, но пина "lcd_bl" я так и не нашел, что такое bl?
Пины поменял, хотел попробовать скомпилировать и вот что вышло:
Что делаю не так?
Еще раз спасибо за поддержку, именно таки примеров я не находил в сети
Вот например, где брать адреса этих пинов?
Код: Выделить всё
lcd_rs_pin = 0,
lcd_rw_pin = 1,
lcd_e_pin = 2,
lcd_bl_pin = 3,
lcd_d4_pin = 4,
lcd_d5_pin = 5,
lcd_d6_pin = 6,
lcd_d7_pin = 7
Да и вообще кто знал что они разные, у каждой микросхемы. Попытался поискать даташит на мою, но пина "lcd_bl" я так и не нашел, что такое bl?
Пины поменял, хотел попробовать скомпилировать и вот что вышло:
Spoiler
lcd_c.cpp: In function ‘int main()’:
lcd_c.cpp:53:22: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
lcd_c.cpp:71:34: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
lcd_c.cpp:73:35: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
lcd_c.cpp: In function ‘int lcd_init(int)’:
lcd_c.cpp:100:66: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp:104:66: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp:108:66: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp:112:44: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp: In function ‘int lcd_send(int, lcd_rs_t, lcd_rw_t, char)’:
lcd_c.cpp:211:15: error: invalid conversion from ‘int’ to ‘lcd_rs_t {aka lcd_rs}’ [-fpermissive]
lcd_c.cpp:212:15: error: invalid conversion from ‘int’ to ‘lcd_rw_t {aka lcd_rw}’ [-fpermissive]
lcd_c.cpp:213:16: error: invalid conversion from ‘int’ to ‘lcd_rs_t {aka lcd_rs}’ [-fpermissive]
lcd_c.cpp:214:16: error: invalid conversion from ‘int’ to ‘lcd_rw_t {aka lcd_rw}’ [-fpermissive]
lcd_c.cpp:53:22: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
lcd_c.cpp:71:34: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
lcd_c.cpp:73:35: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
lcd_c.cpp: In function ‘int lcd_init(int)’:
lcd_c.cpp:100:66: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp:104:66: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp:108:66: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp:112:44: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.cpp: In function ‘int lcd_send(int, lcd_rs_t, lcd_rw_t, char)’:
lcd_c.cpp:211:15: error: invalid conversion from ‘int’ to ‘lcd_rs_t {aka lcd_rs}’ [-fpermissive]
lcd_c.cpp:212:15: error: invalid conversion from ‘int’ to ‘lcd_rw_t {aka lcd_rw}’ [-fpermissive]
lcd_c.cpp:213:16: error: invalid conversion from ‘int’ to ‘lcd_rs_t {aka lcd_rs}’ [-fpermissive]
lcd_c.cpp:214:16: error: invalid conversion from ‘int’ to ‘lcd_rw_t {aka lcd_rw}’ [-fpermissive]
Что делаю не так?
Еще раз спасибо за поддержку, именно таки примеров я не находил в сети
-
- Сообщения: 142
- ОС: KUbuntu
Re: Нужна помощь в работе с i2c интерфейсом
Чуть позже возник еще один вопрос. По ссылке от FlySnake, цитирую:
0х20 - это адрес микросхемы.
0х5А - это адрес пина, но какого? т.е. если я не ошибаюсь до 16 пинов, как узнать, скажем, адрес 8 пина?
Ну и собственно пишем в микросхему с адресом 0x20:
import smbus
bus = smbus.SMBus(1) # 1 - bus number
bus.write_byte(0x20, 0x5A)
И прочитаем из 0x21
data = bus.read_byte(0x21)
0х20 - это адрес микросхемы.
0х5А - это адрес пина, но какого? т.е. если я не ошибаюсь до 16 пинов, как узнать, скажем, адрес 8 пина?
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Прозванивать, для распространённых вариантов - гуглить. А если плата не китайский noname, как в моём случае, то читать datasheet.
Не у микросхемы, а у платы расширения. У самой-то микросхемы выводы всегда на одном месте, а вот куда их развели - отдельный вопрос.
Подсветка экрана, то есть 15 пин HD44780 (он должен быть разведён не напрямую, конечно, а через транзистор). Вы тоже с такими экранами планируете работать?
Компилируете сишный код компилятором C++.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Это не адрес пина, это байт данных. Он устанавливает значения сразу всех пинов. Младший бит - для пина P0 и так далее, до старшего - P7. То есть в данном случае пины P1, P3, P4, P6 устанавливаются в high, остальные - в low. Всего портов у PCF8574 восемь.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 142
- ОС: KUbuntu
Re: Нужна помощь в работе с i2c интерфейсом
Bizdelnick писал(а): ↑23.02.2014 10:30
Это не адрес пина, это байт данных. Он устанавливает значения сразу всех пинов. Младший бит - для пина P0 и так далее, до старшего - P7. То есть в данном случае пины P1, P3, P4, P6 устанавливаются в high, остальные - в low. Всего портов у PCF8574 восемь.
Я пробовал компилировать и через C (gcc), вот что он мне показал:
Код: Выделить всё
lcd_c.c: In function ‘lcd_init’:
lcd_c.c:100:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.c:104:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.c:108:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
lcd_c.c:112:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
Насчет расширителя портов, т.е. слушать отдельно, например, 5 порт и 8 возможности нет? Скорее всего это глупый вопрос, но с i2c столкнулся пару месяцев назад. Т.е. все эти адреса должны быть расписаны в даташите? Плато вроде китайская, но написано что построена на базе PCA8574
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Странно, у меня с -Wall собирает молча. В любом случае это не критично.
С чтением я не связывался, но, насколько я понимаю, надо точно так же читать один байт и разбирать его по битам. Главное - порты ввода нужно предварительно установить в high.
Upd. То есть как-то так:
Код: Выделить всё
int port = 5;
if (input & (1 << port) == 0) {
printf("port %d is LOW\n", port);
} else {
printf("port %d is HIGH\n", port);
}
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 142
- ОС: KUbuntu
Re: Нужна помощь в работе с i2c интерфейсом
Попробовал запустить скомпилированное, получил Error initializing display, куда копать?
-
- Сообщения: 992
- ОС: openSUSE
Re: Нужна помощь в работе с i2c интерфейсом
VladVol писал(а): ↑23.02.2014 12:37Я пробовал компилировать и через C (gcc), вот что он мне показал:
Код: Выделить всё
lcd_c.c: In function ‘lcd_init’: lcd_c.c:100:5: warning: large integer implicitly truncated to unsigned type [-Woverflow] lcd_c.c:104:5: warning: large integer implicitly truncated to unsigned type [-Woverflow] lcd_c.c:108:5: warning: large integer implicitly truncated to unsigned type [-Woverflow] lcd_c.c:112:5: warning: large integer implicitly truncated to unsigned type [-Woverflow]
Это лишь ворнинги. Прога должна была собраться, а ворнинги следует пофиксить, покажите код где это происходит.
VladVol писал(а): ↑23.02.2014 12:37Насчет расширителя портов, т.е. слушать отдельно, например, 5 порт и 8 возможности нет? Скорее всего это глупый вопрос, но с i2c столкнулся пару месяцев назад. Т.е. все эти адреса должны быть расписаны в даташите? Плато вроде китайская, но написано что построена на базе PCA8574
Реагировать на изменение уровня на 5 пине PCA8574 ? Можно. В зависимости от требуемой задержки на отклик можно с помощью прерывания либо опросом. В Вашем случае предполагаю что нужно читать состояние busy дисплея. Для этого опроса хватит. Читаете микруху и смотрите состояние нужных битов.
Код: Выделить всё
data = (bus.read_byte(0x21)
pin5 = (data >> 5) & 1 # результат 1 или 0
Проверять правильность подключения. Проверять осциллографом ходят ли данные по шине. Если осциллографа нет, то подключить светодиод (с резистором!) на какой-нить вывод PCF8574 и попробовать записать в неё по очереди единичку и нолик в бит по номеру пина со светодиодом, или тупо 0xFF и 0x00 во все выходы. Если будет мыргать значит дальше копать в правильность подключения и соответствия пинов в расширителя и дисплея, правильность кода.
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Права доступа к файлу проверьте. Вероятно, нужно пользователя в какую-нибудь группу добавить. Адрес правильный?
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 142
- ОС: KUbuntu
Re: Нужна помощь в работе с i2c интерфейсом
Bizdelnick писал(а): ↑23.02.2014 13:27
Права доступа к файлу проверьте. Вероятно, нужно пользователя в какую-нибудь группу добавить. Адрес правильный?
Спасибо за помощь, но наверное просто не рабочий LCD I2C модуль. Не один пример не работает.
Хотя я еще не пробовал пример IMB, можно где-то посмотреть полный код? Подключаются ли какие-то заголовки?
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Распиновка точно правильная? Прозванивали?
Если экран с подсветкой, можно проверить хотя бы её - при отправке 0xFF должна включаться, 0x00 - отключаться.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 142
- ОС: KUbuntu
Re: Нужна помощь в работе с i2c интерфейсом
Bizdelnick писал(а): ↑26.02.2014 12:23
Распиновка точно правильная? Прозванивали?
Если экран с подсветкой, можно проверить хотя бы её - при отправке 0xFF должна включаться, 0x00 - отключаться.
Экран с подсветкой, если не сложно, можно пример скрипта куда можно подставить 0xFF?
Прозвонил все, контакты на экране соответствуют распиновке по даташит

-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Код: Выделить всё
#include <linux/i2c-dev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int i2c_send(int file, char byte);
int main()
{
int addr = 0x27; // адрес устройства на шине I2C (выставляется джамперами)
char *filename = "/dev/i2c-1"; // файл интерфейса
int file;
if ((file = open(filename, O_RDWR)) < 0) { // используется open(), а не fopen(), чтобы избежать буферизации
fprintf(stderr, "Can not open file `%s'\n", filename);
exit(1);
}
if (ioctl(file, I2C_SLAVE, addr) < 0) {
fputs("Failed to acquire bus access and/or talk to slave.\n", stderr);
exit(1);
}
i2c_send(file, 0xFF);
return 0;
}
int i2c_send(int file, char byte)
{
const char *buf = &byte;
return write(file, buf, 1);
}
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 142
- ОС: KUbuntu
Re: Нужна помощь в работе с i2c интерфейсом
Подсветка не работает, лобо она не регулируется программно. Перепробовал еще пару скриптов на Пйтоне, не один не дал результата, наверное проблема с железякой, хотя с какой?)) Попробую купить еще один lcd i2c дисплей, о результатах отпишусь.
Спасибо всем!
Спасибо всем!
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
А может подключили неправильно? i2cdetect вообще устройство видит?
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 6
- ОС: Ubuntu
Re: Нужна помощь в работе с i2c интерфейсом
Добрый день
Bizdelnick, не могли бы вы подсказать где вы нашли кучу мануалов, а то я весь интернет перерыл и нашел только пару нерабочих примеров. Это кроме уймы программ на Ардуино и Авр. Ваш пример у меня запустился, к слову, это лучшее, что я нашел, но сообщения показывает какими-то символами. Возможно это вызвано тем, что дисплей у меня 20х4. Нет ли у вас примера для такого размера экранов? Пользуюсь платой PhyBoard-Wega-AM335x на Линуксе 3.2.0. Адрес PCF8574 и распиновка дисплея имеются
Спасибо
Bizdelnick, не могли бы вы подсказать где вы нашли кучу мануалов, а то я весь интернет перерыл и нашел только пару нерабочих примеров. Это кроме уймы программ на Ардуино и Авр. Ваш пример у меня запустился, к слову, это лучшее, что я нашел, но сообщения показывает какими-то символами. Возможно это вызвано тем, что дисплей у меня 20х4. Нет ли у вас примера для такого размера экранов? Пользуюсь платой PhyBoard-Wega-AM335x на Линуксе 3.2.0. Адрес PCF8574 и распиновка дисплея имеются
Спасибо
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Больше всего найдёте по запросу google://raspberry pi i2c. Ничего (или почти ничего) специфичного для платформы в работе с I2C нет, так что если у Вас не RPi - всё равно Вам это подойдёт.
Если не ошибаюсь, кроме адресов символов отличий быть не должно. Смотрите даташит HD44780 и меняйте аргументы lcd_addr(). Хотя не исключено, что Вы с распиновкой всё-таки ошиблись.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 6
- ОС: Ubuntu
Re: Нужна помощь в работе с i2c интерфейсом
Больше всего найдёте по запросу google://raspberry pi i2c. Ничего (или почти ничего) специфичного для платформы в работе с I2C нет, так что если у Вас не RPi - всё равно Вам это подойдёт
Я думал вы имеете ввиду мануалы по работе с дисплеями через i2c. С i2c вроде и так проблем не много, с дисплеем больше.
Если не ошибаюсь, кроме адресов символов отличий быть не должно. Смотрите даташит HD44780 и меняйте аргументы lcd_addr(). Хотя не исключено, что Вы с распиновкой всё-таки ошиблись.
Я не силён в программировании дисплеев и вообще понимаю их с трудом, поэтому идею поиграться с адресами воспринял так: в цикле от 0 до 150 выводил номер итерации на дисплей с задержкой в 3/4 секунды, просто чтобы успевать следить. Резултаты таковы - начиная с 19 итерации(то есть адреса 0х13) закончились всякие метания разных символов по экрану и по очереди начали выводиться числа в 3й ряд. Потом с 64го(0х40) пошли номера во второй строке, потом с 84(0х54) на 4й строке и где-то со 121(0х79, но точно не уверен, сложно отловить) пошли цифры в первой строке. А потом начиная со 147(0х93) снова пошли в 3й строке.
При этом когда я поставил в примере хеллоуворлда перенос lcd_addr() на эти адреса(плюс/минус 1) на дисплее ничего нет. А когда попытался прогнать тот же самый цикл с 19 итерации увидел ту же самую картину - сначала символы в разных местах экрана, а потом с 35й итерации цифры пошли в конце третьей строки и дальше как раньше.
В распиновке ошибиться сложно, так как видно дорожки, но для уверенности я прозвонил
Код: Выделить всё
lcd_rs_pin = 0,
lcd_rw_pin = 1,
lcd_e_pin = 2,
lcd_bl_pin = 3,
lcd_d4_pin = 4,
lcd_d5_pin = 5,
lcd_d6_pin = 6,
lcd_d7_pin = 7
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Посмотрел даташит - я всё-таки ошибся, в function set (функция lcd_funcset()) указывается число строк дисплея. Но выбрать можно только из 1 или 2 строк (стр. 29)... Попробуйте вместо 0x28 отправлять 0x20 - это однострочный режим.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 6
- ОС: Ubuntu
Re: Нужна помощь в работе с i2c интерфейсом
Bizdelnick писал(а): ↑02.04.2014 18:08Посмотрел даташит - я всё-таки ошибся, в function set (функция lcd_funcset()) указывается число строк дисплея. Но выбрать можно только из 1 или 2 строк (стр. 29)... Попробуйте вместо 0x28 отправлять 0x20 - это однострочный режим.
Попробовал по вашему совету поэкспериментировать с function set в соответствии с даташитом. После включения однолинейного режима ситуация не изменилась никак. Изменилась только после того как я изменил интерфейс на 8-ми битный: в таком варианте он начинает писать числа уже с 3й итерации, но почему-то с центра первой строки, а в дальнейшем опять же скачет по строкам как-то странно - когда заканчивается первая курсор перепрыгивает в начало третьей, пишет в неё до конца, обратно возвращается на первую с начала, не дописывая до середины соскакивает на то же положение, но второй строки и т.д.
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 6
- ОС: Ubuntu
Re: Нужна помощь в работе с i2c интерфейсом
В качестве эксперимента, а может быть от отчаяния
В любом случае, переставлял на однолинейный, менял шрифт - то же самое, что я описывал выше - сначала вопросительные знаки и прочие символы в разных точках дисплея, а потом начиная с 19й итерации пишет в 3й строке. Есть идеи?

-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Ищите ошибку... Я тоже очень долго тыкался, когда разбирался с этим экраном.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Спасибо сказали:
-
- Сообщения: 6
- ОС: Ubuntu
Re: Нужна помощь в работе с i2c интерфейсом
И всё же еще один вопрос. Только что раскуривал библиотеку LiquidCrystal от Ардуино, проверял работу LCD на ней - работает чудно. Так вот, там установлен однострочный 8-ми битный режим 5х10. Могу ли я использовать те же настройки для своей платы и как сильно изменится от этого программа?
-
- Модератор
- Сообщения: 21115
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Нужна помощь в работе с i2c интерфейсом
Можете, конечно. Изменится только тот единственный байт, отправляемый lcd_funcset(). По уму, конечно, не надо было его хардкодить, но у меня стояла задача показать работу, а не сделать красиво.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 6
- ОС: Ubuntu
Re: Нужна помощь в работе с i2c интерфейсом
Забавно, после того как настроил дисплей на одну строку, 8-битный интерфейс и поковырял библиотеку от Ардуино нашел факт, что адресс перемещения сам высчитывается как addr = 0x80 | (column + rowaddr). Сообщение теперь выводит и даже не ошибается со строкой - только на 2 клетки ошибается с колонкой(нужно будет еще поколдовать с адресами). И один очень неприятный факт - с такими настройками перестал очищать экран, вместо этого он просто перемещает написанное по дисплею, даже когда оставляешь в программе только инициализацию, активацию и очистку дисплея. Вы случайно с таким не сталкивались?
Добавлено: подколдовал с адресами, addr = 0x80 | (column + rowaddr - 2) и вот уже всё с нуля показывается
И напрасно. Эту программу чуть-чуть допилить, сделать чуть более универсальной и можно из неё настрогать библиотеку типа LiquidCrystal_I2C на Ардуинке для таких как я
Добавлено: подколдовал с адресами, addr = 0x80 | (column + rowaddr - 2) и вот уже всё с нуля показывается
но у меня стояла задача показать работу, а не сделать красиво
И напрасно. Эту программу чуть-чуть допилить, сделать чуть более универсальной и можно из неё настрогать библиотеку типа LiquidCrystal_I2C на Ардуинке для таких как я
