Raspberry Pi. Работаем с I2C на Python

Наконец-то появилось немного свободного времени и я решил более тщательно поковырять порты GPIO у Raspberry Pi. Если хочется просто подрыгать ногами, помигать светодиодами или пообмениваться данными через уарт, то это достаточно просто и в сети полно мануалов, хотя если кому надо, пишите, проведу небольшой ликбез. Я же решил сразу поиграться с шиной I2C и подключить к Raspberry Pi микромеханический трехосный акселерометр MMA7455 (в свое время купил на ебее уже распаянный на платке с выведенными нужными ногами на штыри, цена вопроса 7-10 баксов).

Итак, сначала подключим акс к плате:
MMA7455    RPi GPIO
SDA        PIN3(подтянуть к питанию через 4.7 КОм)
SCL        PIN5(подтянуть к питанию через 4.7 КОм)
VCC        PIN1(3.3V)
GND        PIN6(GND)


В качестве рабочего дистрибутива ОС я использую Raspbian, поскольку его рекомендуют сами разработчики платы и в нем есть все необходимые драйвера, правда сразу все не заработает. Для начала необходимо убрать модуль I2C из блэклиста и добавить его в автозагрузку. Для этого делаем в консоли следующее, открываем файл raspi-blacklist.conf и видим в нем следующее:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
blacklist spi-bcm2708
blacklist i2c-bcm2708


Закоментируем две строчки и сохраним файл:
# blacklist spi-bcm2708
# blacklist i2c-bcm2708


ПРИМЕЧАНИЕ: Все действия я провожу через SSH, поэтому не использую графические утилиты, в редакторе nano для сохранения файла необходимо нажать Ctrl-O, для выхода — Ctrl-Х.

Далее добавляем модуль I2C в автозагрузку, открываем файл /etc/modules
sudo nano /etc/modules

и добавляем в конец строку i2c-dev, должно получиться так:
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.
snd-bcm2835
i2c-dev


Перезагружаемся
sudo reboot


После перезагрузки проверяем появилось ли нужное устройство в системе:
ls /dev | grep i2c

Если в ответ на эту команду мы получили:
i2c-0
i2c-1

значит все прошло успешно.
Теперь необходимо поставить некоторые дополнительные пакеты:
sudo apt-get update
sudo apt-get install i2c-tools (необязательно, но удобно просматривать подключенные устройства и всячески работать с шиной I2C в консоли)
sudo apt-get install python-smbus

Теперь, при подключенном акселерометре, выполним команду:
sudo i2cdetect -y 0

и увидим табличку в которой отобразится адрес подключенного устройства, в случае MMA7455 — 1D, что соответствует даташиту.

Теперь надо написать простенькую программу на Python, которая будет выводить в консоль показания по трем осям акселерометра. При работе в графической оболочке можно еще установить и подключить различные модули, например pygame и визуализировать показания. Выполняем:
nano mma7455.py

и вставляем нижеприведенный листинг

# MMA7455 I2C адрес 1D                                                                                                      
# адреса
# 06 ось X
# 07 ось Y
# 08 ось Z
# 16 Режим работы  x1000101 измеряем до 2g 0x45
# 16 Режим работы  x1000001 измеряем до 8g 0x41
# 16 Режим работы  x1010101 калибровка в режиме 2g 0x55
#!/usr/bin/python
import smbus
import time
import os

class Accel():
    b = smbus.SMBus(0)
    def Calib(self):
        # включаем режим калибровки
        self.b.write_byte_data(0x1D,0x16,0x55)
        # начальная калибровка
        self.b.write_byte_data(0x1D,0x10,0)
        self.b.write_byte_data(0x1D,0x11,0)
        self.b.write_byte_data(0x1D,0x12,0)
        self.b.write_byte_data(0x1D,0x13,0)
        self.b.write_byte_data(0x1D,0x14,0)
        self.b.write_byte_data(0x1D,0x15,0)
#Получаем ускорение по оси X 
    def getX(self):
        return self.b.read_byte_data(0x1D,0x06)
#Получаем ускорение по оси Y 
    def getY(self):
        return self.b.read_byte_data(0x1D,0x07)
#Получаем ускорение по оси Z 
    def getZ(self):
        return self.b.read_byte_data(0x1D,0x08)
 
MMA7455 = Accel()
MMA7455.Calib()
 
for a in range(10000):
    x = MMA7455.getX()
    y = MMA7455.getY()
    z = MMA7455.getZ()
 
    print "x=", x
    print "y=", y
    print "z=", z
 
    time.sleep(0.1)
    os.system('clear')


Результат работы (запускать sudo python mma7455.py)

На этом пока все, если что не понятно — спрашивайте.

Комментарии (27)

RSS свернуть / развернуть
Спасибо, хороший толчок включить наконец эту плату и поработать с ней. Буду рад почитать о работе с GPIO и написании собственных драйверов для малины.
0
C GPIO там все просто, для питона можно использовать официальный модуль RPi.GPIO, на С/С++ тоже вроде не сложно, а вот с драйверами не смогу ничем помочь, поскольку никогда этим не занимался, хотя если будут в сети хорошие мануалы, то переведу и выложу сюда.
0
Спасибо большое за статейку, было бы интересно почитать ещё.

P.S. Моя малинка ещё идёт :((
0
Подтягивать I2C на малине НЕ нужно, т.к. подтяжки уже распаяны на плате.
См. схему www.raspberrypi.org/wp-content/uploads/2012/04/Raspberry-Pi-Schematics-R1.0.pdf
Подключал к ней ADS1110 и DS1307, работают на УРА
Под ADS1110 код на сях занял буквально пару строк:

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd;                                                     // File descrition
    char *fileName = "/dev/i2c-0";                              // Name of the port we will be using
    int  address = 0x49;                                        // Address of CMPS03 shifted right one bit
    unsigned char buf[10];                                      // Buffer for data being read/ written on the i2c bus

    if ((fd = open(fileName, O_RDWR)) < 0) {                    // Open port for reading and writing
        printf("Failed to open i2c port\n");
        exit(1);
    }
    if (ioctl(fd, I2C_SLAVE, address) < 0) {                    // Set the port options and set the address of the device we wish to speak to
        printf("Unable to get bus access to talk to slave\n");
        exit(1);
    }
    buf[0] = 0x8C;                                                 // This is the register we want to read from
    if ((write(fd, buf, 1)) != 1) {                             // Send register we want to read from
        printf("Error writing to i2c slave\n");
        exit(1);
    }
    if (read(fd, buf, 3) != 3) {                                // Read back data into buf[]
        printf("Unable to read from slave\n");
        exit(1);
    }
    else {
        unsigned char highByte = buf[0];
        unsigned char lowByte = buf[1];
        unsigned long result = (highByte <<8) + lowByte;         // Calculate bearing as a word value
        printf("Voltage: %u mV\n",(result*1000)/3990); // display bearing with decimal place
    }
    return 0;
}
0
Прошу прощения, коменты не соответствуют реальности, т.к. код был взят от какого-то другого устройства и исправлен. Так что просто не обращайте внимание на коментарии к коду.
0
На какой частоте работает I2C у RPI?
0
Пишут что по умолчанию 60 кГц через SMBus, но как-то этим вопросом не задавался, можно поискать на оф. форуме малины.
0
А SPI порт? Есть что то более менее скоростное?
0
Очень интересно, а плата Rasberry обязательна, в смысле есть ли в питоне библиотеки i2c например для COM или LPT портов?
0
  • avatar
  • and
  • 27 октября 2012, 20:33
Не совсем понял вопроса, но попробую ответить:) Для работы с I2C в питоне используется библиотека SMBus, которая не зависит от железа, главное чтобы на железе был реализован интерфейс I2C и были дрова к нему. Для работы с СОМ-портами на питоне используется библиотека PySerial — http://pyserial.sourceforge.net/ — использовал ее для работы с аппаратным СОМ-портом и виртуальными через USB-RS232 — донглы и через Bluetooth. Про LPT не знаю, не было необходимости, но скорее всего что-то тоже есть.
0
Понял, спасибо. Просто хотел поиграться с I2C на обычном компе. PySerial уже пробовал, работает хорошо.
0
На PCI-E есть выводы SMCLK, SMDATA, это же вроде I2C с уровнями 3.3 В, подпаяйтесь туда)
pinouts.ru/Slots/pci_express.shtml
0
Кто-нибудь вот этот конвертер уровней юзал?

Можно заменить BSS138 на 2N7002?
0
Спаял на 2N7002 и передача через раз идёт без ошибок. Из-за чего это?
Без конвертера при 3.3 В питании такой проблемы нет. Но мне то надо устройство от 5 вольт запитать.
0
Спаял на 2N7002 и передача через раз идёт без ошибок. Из-за чего это?
эммм?..
0
Вообще как оказалось конвертер не нужен, просто резисторы к 3.3В подключить надо, т.к. там на i2c выходы типа открытый сток.
0
делал именно такой, это вариант со sparkfun.com — работал нормально.
0
0
Простите, возможно я немного туплю, но не могли бы вы объяснить что передаётся вторым аргументом функций write_byte_data(1,2,3) и read_byte_data(1,2)?
0
write_byte_data(адрес_устройства, адрес_регистра_куда_пишем, что_пишем)
read_byte_data(адрес_устройства, адрес_регистра_откуда_читаем)
0
Спасибо большое!!!
Наконец-то я понял!)
Не могли бы вы еще кое чем помочь?
У меня датчик посылает в ответ 9 — бит, то есть два байта, как мне их прочесть?
Даташит, 9 страница последний пример.
0
В библиотеке SMBus есть еще команды:
read_word_data(addr,cmd)
read_block_data(addr,cmd)
можно попробовать их. А вообще, те устройства, которые я подключал еще помимо вышеуказанного акса (компас, барометр, гироскоп) содержат выходные данные в двух регистрах, например для компаса HMC5883L:
Adress Name
0x03 Data Output X MSB register (8 бит)
0x04 Data Output X LSB register (8 бит)
соответственно, чтобы получить некоторое измеренное значение, в различных мануалах приводится следующая конструкция:
X_MSB = self.d.read_byte_data(0x77, 0x03)
X_LSB = self.d.read_byte_data(0x77, 0x04)
X = (AC1_MSB << 8) | AC1_LSB
В Вашем случае можно попробовать так же.
0
Да, я нашёл эти команды, но на них он мне отвечает вообще каким-то неадекватом, типа 390.
В даташите к датчику написано
Read Temperature [AAh]
This command reads the last temperature conversion result. The DS1621 will send 2 bytes, in the format
described earlier, which are the contents of this register.

Ну в общем буду дальше разбираться, спасибо:)
0
Адрес регистра это просто байт, который перед данными отправляется?
0
Ага, точно.
0
Все тлен (
Хваленное многотысячное Raspberry сообщество не может создать нормальный тулчейн, для кроскомпиляции под Qt
Имхо уж лучше Windows CE, там с самого рождения все собирается по человечески
0
Кто может сказать сколько миллиампер выдерживает нога GPIO у Raspberry? Где-то читал что 16ма, а где-то что 20ма. А сколько точно? И еще какая нагрузочная способность питания 3.3 и 5 вольт на плате Raspberry?
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.