Moje Rapsberry Pi - GPIO a I2C periferie

raspipidi

Nejdříve je potřeba povolit ovladač sběrnice I2C. Sběrnice I2C (I2C-bus, Inter-IC-bus) je dvouvodičové datové propojení mezi jedním nebo několika procesory (Master) a speciálními periferními součástkami (Slave). Všechny součástky jsou připojeny na téže sběrnici a jsou cíleně vybírány svými adresami. Adresy i data se přenášejí stejnými vodiči. Sběrnice umožňuje velmi jednoduché propojení mezi několika integrovanými obvody a bezproblémové dodatečné rozšiřování například expander, LCD displej atd...

1) POVOLENÍ SBĚRNICE

Pokud používáme Raspbian budeme muset otevřít LX Terminál a zadat tento příkaz:

sudo nano /etc/modules

a přidat tyto dva řádky na konec souboru:

i2c-bcm2708
i2c-dev

Pro uložení stiskeme Ctrl + O a [enter] následované Ctrl-X.

Dále provedeme restart systému (aby se načetla změna).

V závislosti na naší distribuci také můžeme mít v souboru / etc / modprobe.d / raspi-blacklist.conf zakázanou I2C sběrnici. Pokud tento soubor nemáme není potřeba nic dělat, ale pokud máme tento soubor musíme ho upravit a zakomentovat tyto řádky:

sudo nano /etc/modprobe.d/raspi-blacklist.conf

V editoru, který se tímto příkazem otevře, se musí zakomentovat dvě řádky (připsat před ně "dvojkřížek"  # )

#blacklist spi-bcm2708
#blacklist i2c-bcm2708

Pro uložení stiskeme Ctrl + O a [enter] následované Ctrl-X.

Jakmile je vše hotovo, můžeme zadat následující příkaz pro zobrazení všech připojených zařízení (pokud používáme 512MB Raspberry Pi Model B):

Pokud máme problémy s I2C na Raspbianu, potom je potřeba aktualizovat na nejnovější verzi. I2C sběrnice umožňuje více zařízení připojených k RPI (každý s jedinečnou adresou, která může být nastaven změnou pozic jumperů na modulu.)

Je velmi užitečné mít možnost vidět, která zařízení jsou připojena k RPI. Způsob jak zařízení zjistit spočívá v instalaci I2C těchto nástrojů:

sudo apt-get install python-SMBus
sudo apt-get install i2c-tools

Provedeme restart systému pro načtení změn a můžeme testovat...

sudo i2cdetect -y 1

Pokud používáme jeden z prvních RPI (Raspberry Pi 256 MB Model B), pak budeme muset změnit příkaz:

sudo i2cdetect -y 0

Pozor! návrháři RPI prohodily I2C porty dle typu desky RPI 512M používá I2C port 1 a RPI 256M používá I2C port 0!

Výpis mé sběrnice I2C

i2cdetect

adresa 48 = AD-DA převodník PCF8591, 68 = RTC reálný čas DS1307

2) OBVOD REÁLNÉHO ČASU DS1307

Z důvodu nízké ceny mini počítače RPI (Raspberry Pi) neobsahuje modul hodin reálného času (RTC). Namísto toho se očekává, že uživatel je vždy připojen k Wi-Fi nebo Ethernetu a čas kontroluje pomocí sítě (NTP). Protože chceme udržet čas v RPI i bez připojení k síti je nutné osadit obvod reálného času a tak uchovávat v zařízení přesný čas i po vypnutí/zapnutí napájení. Modul obvodu reálného času obsahuje pouze tyto díly: DS1307, krystal, baterii 3V. Pozor v žádném případě nepřipojujte pull-up rezistory 2,2K ke sběrnici I2C a napájení obvodu +5V (tak jak uvádí doporučené zapojení v katalogu). Budeme používat RPI 1.8K pull-up rezistory připojené na 3.3V. Pokud toto nedodržíme lze RPI trvale poškodit! RPI je napájen 3,3V nikoliv 5V jako například Arduino.

Připojíme VCC RTC na 5.0V pin RPI
Připojíme GND RTC na GND pin RPI
Připojíme SDA RTC na SDA0 pin RPI
Připojíme SCL RTC na SCL0 pin RPI

ospi v12 sch rtc

Ověříme HW zapojení spuštěním příkazu:

sudo i2cdetect -y 0

na příkazovém řádku bychom měli vidět ID # 68 - to je adresa RTC obvodu DS1307. Pokud máme RPI REV 2 budeme muset spustit:

sudo i2cdetect -y 1

Nyní, když máme modul RTC připojen a ověřen můžeme modul vidět pomocí i2cdetect (68 = RTC reálný čas DS1307).

Můžeme spustit RTC modul.

sudo modprobe rtc-ds1307

Dále jako root spustíme (zadáme sudo bash )

echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-0/new_device ( pokud máme rev 1 Pi )
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device ( pokud máme rev 2 Pi )

Dále zkontrolujeme čas pomocí:

sudo hwclock -r

Příkaz čte čas z DS1307 modulu. Pokud je to poprvé, kdy byl modul použit bude hlásit 01.1.2000 a budemee muset čas nastavit ručně.

rtc1

Nejprve budeme muset nastavit správný čas v RPI (nejjednodušší způsob je se připojit do sítě Ethernet nebo WiFi a tak automaticky nastavit čas ze sítě). Jakmile je nastaven správný čas spustíme:

sudo hwclock -w

pro zapsání systémového času do RTC. Poté můžeme ověřit že je čas uložen v RTC:

sudo hwclock -r

rtc2

Dále budeme jistě chtít přidat jádro RTC modulu do seznamu souboru /etc/modules když RPI zapneme (bootování).

Spustíme sudo nano /etc/modules a přidáme rtc-ds1307 na konec souboru a uložíme.

rtc3

Dále vytvoříme startovací sekvenci v rc. local / etc / rc.local

sudo nano /etc/rc.local

a přidáme řádky:

echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-0/new_device ( pokud máme rev 1 Pi)
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device ( pokud máme rev 2 Pi)
sudo hwclock -s (pro obě verze )

před exit 0. Při příštím spuštění systému bude čas automaticky synchronizován z obvodu hodin RTC.

2b) jiný lepší způsob spouštění synchronizace času RPI-RTC-NTP

Otevřeme v editoru /lib/udev/hwclock-set:

sudo nano /lib/udev/hwclock-set

změníme výrazy z “—systz” na "—hctosys". (bez uvozovek)

#!/bin/sh
# Reset the System Clock to UTC if the hardware clock from which it
# was copied by the kernel was in localtime.
dev=$1
if [ -e /sys/fs/cgroup/systemd ] ; then
    exit 0
fi
if [ -f /etc/default/rcS ] ; then
   . /etc/default/rcS
fi
# These defaults are user-overridable in /etc/default/hwclock
BADYEAR=no
HWCLOCKACCESS=yes
HWCLOCKPARS=
HCTOSYS_DEVICE=rtc0
if [ -f /etc/default/hwclock ] ; then
   . /etc/default/hwclock
fi
if [ yes = "$BADYEAR" ] ; then
   /sbin/hwclock --rtc=$dev --hctosys --badyear
else
   /sbin/hwclock --rtc=$dev --hctosys
fi

Vytvoříme script /etc/init.d/rtcdev:

sudo nano /etc/init.d/rtcdev

#! /bin/sh
### BEGIN INIT INFO
# Provides: rtcdev
# Required-Start: kmod
# Required-Stop:
# X-Start-Before: hwclock
# X-Stop-After:
# Default-Start: S
# Default-Stop:
# Short-Description: creates RTC device
### END INIT INFO
. /lib/lsb/init-functions
case "$1" in
   start)
      if [ ! -e /dev/rtc0 ]; then
         log_action_msg "Creating RTC device..."
         echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
      fi
      ;;
   restart|reload|force-reload)
         echo "Error: argument '$1' not supported" >&2
         exit 3
         ;;
   stop)
         # No-op
         ;;
   *)
         echo "Usage: $0 start|stop" >&2
         exit 3
         ;;
esac
exit 0

 

Nastavíme práva souboru:

sudo chmod 755 /etc/init.d/rtcdev

Povolíme script:

sudo update-rc.d rtcdev defaults

sudo update-rc.d rtcdev enable

Restartujeme RPI:

sudo reboot

Zkontrolujeme čas v RTC:

sudo hwclock -r

Zkontrolujeme systémový čas:

date

Pokud je systémový čas OK uložíme ho do RTC:

sudo hwclock -w

Pokud jsou oba časy špatně nastavíme čas ručně (pokud v RTC nic není uloženo a nemáme připojení k Internetu):

sudo hwclock --set --date="yyyy-mm-dd hh:mm:ss"

příklad:

sudo hwclock --set --date="2014-06-13 10:29:05"

Vytvoříme cron script pro kalibraci RTC času ze systému každý týden:

sudo nano /etc/cron.weekly/calrtc

#!/bin/sh
hwclock -w

Tento script nastaví RTC ze systémového času. Tento skript by měl být použit pouze v případě, že RPI připojení k internetu ve většině času. Jestliže ne, měli bychom občas nastavit RTC ručně. 

Nastavíme soubrou práva:

sudo chmod 755 /etc/cron.weekly/calrtc

Pokud se skript nachází v adresáři / etc / chron.weekly / budou se tyto scripty spouštět automaticky jednou týdně. Žádné další nastavení nejsou potřeba.

Vytvoříme cron script pro nastavení RTC pro drift každý den (nepřesnost obvodu RTC se musí dolaďovat):

sudo nano /etc/cron.daily/adjrtc

#!/bin/sh
hwclock --adjust

Nastavíme soubrou práva:

sudo chmod 755 /etc/cron.daily/adjrtc

Takto bude hw čas RTC používat opravu zpoždění každý den.

Nastavíme program ntp pro nastavování RTC když je k dispozici Internetové připojení:

sudo nano /etc/ntp.conf

Najdeme řádek se servery a přidám řádky:

server 127.127.1.1
fudge 127.127.1.1 stratum 12

Dále uložíme soubor (CTRL+O) a restartujeme RPI.

Provedeme test:

ntpq -p

Mělo by se zobrazit něco jako toto:
==============================================================================
-50.7.254.4      147.231.2.6      2 u   37   64  377   24.412   -7.064   1.994
+mx2.hodor.cz    147.231.100.5    3 u   43   64  377    6.330    3.098   1.882
*u001.net.paskov 195.113.144.201  2 u   45   64  377   10.744    2.560   1.436
+50.7.252.194    195.154.243.19   3 u   39   64  377   24.266    0.301   1.487
 LOCAL(1)        .LOCL.          12 l 1191   64    0    0.000    0.000   0.000

Poslední řádek LOCAL(1) je RTC jako časový server. Toto bude použito pouze jako poslední možnost programu NTP. Ve skutečnosti program, který dělá práci, se nazývá Ntpd, což je démon, který běží na pozadí. Systém by měl nyní zachovat přesný čas systému a hardwaru (RTC hodiny). V případě delšího výpadku internetu bude RTC sloužit k udržení aktuálního času.

Veškeré podrobnosti o programu ntp viz:

http://doc.ntp.org/4.2.0/index.html#conf

Pro použití ntpdate:

sudo service ntp stop

sudo ntpdate |pool.ntp.org|

sudo service ntp start

3) AD-DA převodník PCF8591

Převodník má 4 AD vstupy a jeden DA výstup jeho rozlišení je 8 bitů. Adresa AD převodníku je 0x48 (pokud jsou vstupy A0-A3 připojeny na gnd).

Schema připojení převodníku ke sběrnici I2C

 

pcf8591

Program v Pythonu pro čtení AD vstupů:


# AD prevodnik PCF8591 (4x A/D + 1 x D/A)

#!/usr/bin/python
import smbus
import time

# I2C sbernice novejsi RPI=1 starsi RPI=0
ADC = smbus.SMBus(1)

# Rutina precteni AD
def ctiVSTUP(X): # X = cislo ad kanalu (1 - 4)
        ADC.write_byte_data(0x48, (0x40 + X),X)
        time.sleep(0.2)
        hodnota = ADC.read_byte(0x48) # cteme A/D
        return hodnota # vrati hodnotu daneho vstupu

# Rutina zapsani na vystup DA
def VYSTUP(Y):
        ADC.write_byte_data(0x48, 0x40,Y)
        time.sleep(0.2)

while True:  # Smycka
        an1 = ctiVSTUP(1)
        an2 = ctiVSTUP(2)
        an3 = ctiVSTUP(3)
        an4 = ctiVSTUP(4)
        print ("AD1, AD2, AD3, AD4")
        print (an1,an2,an3,an4) # prectene hodnoty
        print ("zapisuji 255 na DA")
        VYSTUP(255)  # zapsana hodnota napriklad 255
        time.sleep(0.5)