Нужна помощь в работе с i2c интерфейсом

Модератор: Модераторы разделов

VladVol
Сообщения: 142
ОС: KUbuntu

Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Всем привет! Ребята, если кто-то знает как работать с интерфейсом i2c на Python, C, C++ и может объяснить, отзовитесь. Для реализации проекта нужно работать с LCD через i2c и использовать i2c как расширитель I/O портов.

Буду рад любой помощи, как бесплатной, так и платной (в разумных пределах).
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

А гуглить не пробовали? Есть же куча мануалов.
Если вкратце, то открывается файл устройства,

Код: Выделить всё

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.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
IMB
Сообщения: 2561
ОС: Debian

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение IMB »

Я использую такой "велосипед"

Код: Выделить всё

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;
}
Спасибо сказали:
VladVol
Сообщения: 142
ОС: KUbuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Спасибо за советы, гуглить пробовал, но так не знаю с чего начать и запросы, наверное, кривые ввожу. Т.е. инфы много, но все говорят как просто это сделать, но не объясняют как оно работает.
Вот например, где брать адреса этих пинов?

Код: Выделить всё

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]


Что делаю не так?

Еще раз спасибо за поддержку, именно таки примеров я не находил в сети
Спасибо сказали:
VladVol
Сообщения: 142
ОС: KUbuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Чуть позже возник еще один вопрос. По ссылке от FlySnake, цитирую:
Ну и собственно пишем в микросхему с адресом 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 пина?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

VladVol писал(а):
22.02.2014 22:37
Вот например, где брать адреса этих пинов?

Прозванивать, для распространённых вариантов - гуглить. А если плата не китайский noname, как в моём случае, то читать datasheet.

VladVol писал(а):
22.02.2014 22:37
Да и вообще кто знал что они разные, у каждой микросхемы.

Не у микросхемы, а у платы расширения. У самой-то микросхемы выводы всегда на одном месте, а вот куда их развели - отдельный вопрос.

VladVol писал(а):
22.02.2014 22:37
Попытался поискать даташит на мою, но пина "lcd_bl" я так и не нашел, что такое bl?

Подсветка экрана, то есть 15 пин HD44780 (он должен быть разведён не напрямую, конечно, а через транзистор). Вы тоже с такими экранами планируете работать?

VladVol писал(а):
22.02.2014 22:37
Что делаю не так?

Компилируете сишный код компилятором C++.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

VladVol писал(а):
22.02.2014 23:27
0х5А - это адрес пина, но какого? т.е. если я не ошибаюсь до 16 пинов, как узнать, скажем, адрес 8 пина?

Это не адрес пина, это байт данных. Он устанавливает значения сразу всех пинов. Младший бит - для пина P0 и так далее, до старшего - P7. То есть в данном случае пины P1, P3, P4, P6 устанавливаются в high, остальные - в low. Всего портов у PCF8574 восемь.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
VladVol
Сообщения: 142
ОС: KUbuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Bizdelnick писал(а):
23.02.2014 10:30
VladVol писал(а):
22.02.2014 23:27
0х5А - это адрес пина, но какого? т.е. если я не ошибаюсь до 16 пинов, как узнать, скажем, адрес 8 пина?

Это не адрес пина, это байт данных. Он устанавливает значения сразу всех пинов. Младший бит - для пина 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
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

VladVol писал(а):
23.02.2014 12:37
Я пробовал компилировать и через C (gcc), вот что он мне показал:

Странно, у меня с -Wall собирает молча. В любом случае это не критично.

VladVol писал(а):
23.02.2014 12:37
Насчет расширителя портов, т.е. слушать отдельно например 5 порт и 8 возможности нет?

С чтением я не связывался, но, насколько я понимаю, надо точно так же читать один байт и разбирать его по битам. Главное - порты ввода нужно предварительно установить в 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);
}
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
VladVol
Сообщения: 142
ОС: KUbuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Попробовал запустить скомпилированное, получил Error initializing display, куда копать?

Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE
Контактная информация:

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение FlySnake »

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


VladVol писал(а):
23.02.2014 12:37
Попробовал запустить скомпилированное, получил Error initializing display, куда копать?

Проверять правильность подключения. Проверять осциллографом ходят ли данные по шине. Если осциллографа нет, то подключить светодиод (с резистором!) на какой-нить вывод PCF8574 и попробовать записать в неё по очереди единичку и нолик в бит по номеру пина со светодиодом, или тупо 0xFF и 0x00 во все выходы. Если будет мыргать значит дальше копать в правильность подключения и соответствия пинов в расширителя и дисплея, правильность кода.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

VladVol писал(а):
23.02.2014 13:06
Попробовал запустить скомпилированное, получил Error initializing display, куда копать?

Права доступа к файлу проверьте. Вероятно, нужно пользователя в какую-нибудь группу добавить. Адрес правильный?
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
VladVol
Сообщения: 142
ОС: KUbuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Bizdelnick писал(а):
23.02.2014 13:27
VladVol писал(а):
23.02.2014 13:06
Попробовал запустить скомпилированное, получил Error initializing display, куда копать?

Права доступа к файлу проверьте. Вероятно, нужно пользователя в какую-нибудь группу добавить. Адрес правильный?

Спасибо за помощь, но наверное просто не рабочий LCD I2C модуль. Не один пример не работает.
Хотя я еще не пробовал пример IMB, можно где-то посмотреть полный код? Подключаются ли какие-то заголовки?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

VladVol писал(а):
26.02.2014 12:10
Спасибо за помощь, но наверное просто не рабочий LCD I2C модуль. Не один пример не работает.

Распиновка точно правильная? Прозванивали?
Если экран с подсветкой, можно проверить хотя бы её - при отправке 0xFF должна включаться, 0x00 - отключаться.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
VladVol
Сообщения: 142
ОС: KUbuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Bizdelnick писал(а):
26.02.2014 12:23
VladVol писал(а):
26.02.2014 12:10
Спасибо за помощь, но наверное просто не рабочий LCD I2C модуль. Не один пример не работает.

Распиновка точно правильная? Прозванивали?
Если экран с подсветкой, можно проверить хотя бы её - при отправке 0xFF должна включаться, 0x00 - отключаться.

Экран с подсветкой, если не сложно, можно пример скрипта куда можно подставить 0xFF?
Прозвонил все, контакты на экране соответствуют распиновке по даташит :mellow:
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

VladVol писал(а):
26.02.2014 21:51
Экран с подсветкой, если не сложно, можно пример скрипта куда можно подставить 0xFF?

Код: Выделить всё

#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);
}
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
VladVol
Сообщения: 142
ОС: KUbuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение VladVol »

Подсветка не работает, лобо она не регулируется программно. Перепробовал еще пару скриптов на Пйтоне, не один не дал результата, наверное проблема с железякой, хотя с какой?)) Попробую купить еще один lcd i2c дисплей, о результатах отпишусь.
Спасибо всем!
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

А может подключили неправильно? i2cdetect вообще устройство видит?
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
PavloP
Сообщения: 6
ОС: Ubuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение PavloP »

Добрый день
Bizdelnick, не могли бы вы подсказать где вы нашли кучу мануалов, а то я весь интернет перерыл и нашел только пару нерабочих примеров. Это кроме уймы программ на Ардуино и Авр. Ваш пример у меня запустился, к слову, это лучшее, что я нашел, но сообщения показывает какими-то символами. Возможно это вызвано тем, что дисплей у меня 20х4. Нет ли у вас примера для такого размера экранов? Пользуюсь платой PhyBoard-Wega-AM335x на Линуксе 3.2.0. Адрес PCF8574 и распиновка дисплея имеются
Спасибо
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

PavloP писал(а):
02.04.2014 13:58
Bizdelnick, не могли бы вы подсказать где вы нашли кучу мануалов

Больше всего найдёте по запросу google://raspberry pi i2c. Ничего (или почти ничего) специфичного для платформы в работе с I2C нет, так что если у Вас не RPi - всё равно Вам это подойдёт.

PavloP писал(а):
02.04.2014 13:58
сообщения показывает какими-то символами. Возможно это вызвано тем, что дисплей у меня 20х4. Нет ли у вас примера для такого размера экранов?

Если не ошибаюсь, кроме адресов символов отличий быть не должно. Смотрите даташит HD44780 и меняйте аргументы lcd_addr(). Хотя не исключено, что Вы с распиновкой всё-таки ошиблись.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
PavloP
Сообщения: 6
ОС: Ubuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение PavloP »

Больше всего найдёте по запросу 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
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

Посмотрел даташит - я всё-таки ошибся, в function set (функция lcd_funcset()) указывается число строк дисплея. Но выбрать можно только из 1 или 2 строк (стр. 29)... Попробуйте вместо 0x28 отправлять 0x20 - это однострочный режим.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
PavloP
Сообщения: 6
ОС: Ubuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение PavloP »

Bizdelnick писал(а):
02.04.2014 18:08
Посмотрел даташит - я всё-таки ошибся, в function set (функция lcd_funcset()) указывается число строк дисплея. Но выбрать можно только из 1 или 2 строк (стр. 29)... Попробуйте вместо 0x28 отправлять 0x20 - это однострочный режим.

Попробовал по вашему совету поэкспериментировать с function set в соответствии с даташитом. После включения однолинейного режима ситуация не изменилась никак. Изменилась только после того как я изменил интерфейс на 8-ми битный: в таком варианте он начинает писать числа уже с 3й итерации, но почему-то с центра первой строки, а в дальнейшем опять же скачет по строкам как-то странно - когда заканчивается первая курсор перепрыгивает в начало третьей, пишет в неё до конца, обратно возвращается на первую с начала, не дописывая до середины соскакивает на то же положение, но второй строки и т.д.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

PavloP писал(а):
02.04.2014 18:27
изменил интерфейс на 8-ми битный

Зачем? У Вас же 4-битный.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
PavloP
Сообщения: 6
ОС: Ubuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение PavloP »

В качестве эксперимента, а может быть от отчаяния:) В любом случае, переставлял на однолинейный, менял шрифт - то же самое, что я описывал выше - сначала вопросительные знаки и прочие символы в разных точках дисплея, а потом начиная с 19й итерации пишет в 3й строке. Есть идеи?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

Ищите ошибку... Я тоже очень долго тыкался, когда разбирался с этим экраном.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
PavloP
Сообщения: 6
ОС: Ubuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение PavloP »

И всё же еще один вопрос. Только что раскуривал библиотеку LiquidCrystal от Ардуино, проверял работу LCD на ней - работает чудно. Так вот, там установлен однострочный 8-ми битный режим 5х10. Могу ли я использовать те же настройки для своей платы и как сильно изменится от этого программа?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20793
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение Bizdelnick »

PavloP писал(а):
03.04.2014 11:11
там установлен однострочный 8-ми битный режим 5х10. Могу ли я использовать те же настройки для своей платы и как сильно изменится от этого программа?

Можете, конечно. Изменится только тот единственный байт, отправляемый lcd_funcset(). По уму, конечно, не надо было его хардкодить, но у меня стояла задача показать работу, а не сделать красиво.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
PavloP
Сообщения: 6
ОС: Ubuntu

Re: Нужна помощь в работе с i2c интерфейсом

Сообщение PavloP »

Забавно, после того как настроил дисплей на одну строку, 8-битный интерфейс и поковырял библиотеку от Ардуино нашел факт, что адресс перемещения сам высчитывается как addr = 0x80 | (column + rowaddr). Сообщение теперь выводит и даже не ошибается со строкой - только на 2 клетки ошибается с колонкой(нужно будет еще поколдовать с адресами). И один очень неприятный факт - с такими настройками перестал очищать экран, вместо этого он просто перемещает написанное по дисплею, даже когда оставляешь в программе только инициализацию, активацию и очистку дисплея. Вы случайно с таким не сталкивались?

Добавлено: подколдовал с адресами, addr = 0x80 | (column + rowaddr - 2) и вот уже всё с нуля показывается
но у меня стояла задача показать работу, а не сделать красиво

И напрасно. Эту программу чуть-чуть допилить, сделать чуть более универсальной и можно из неё настрогать библиотеку типа LiquidCrystal_I2C на Ардуинке для таких как я:)
Спасибо сказали:
Ответить