GPIO programming på RPi

From OmegaV-wiki
Jump to: navigation, search
Generelt om Raspberry Pi: Raspberry_Pi

Med Raspberry Pi (RPi, Pi) har man et antall mulige måter å koble til eksterne ting på. Den enkleste måten er å bruke såkalte GPIO-pinner. Man har også en Serial Peripheral Interface bus (SPI), Inter-IC bus (I2C) og Universal Asynchronous Receiver/Transmitter (UART). RPi har et sett av hardware-begrensninger som absolutt må overholdes til alle tider (Absolute Maximum Ratings). De er som følger:

  • Max 3.3V på alle GPIO-pinner.
  • Max 6mA strøm gjennom hver enkelt GPIO-pinne.

De fleste andre begrensninger ligger i software. (Embedded) Linux er ikke et Real-Time Operating System (RTOS), derfor er det vanskelig å kommunisere med enheter som krever nøyaktig timing, som f.eks. ultrasoniske avstandsmålere (sonar). Måten man vanligvis vil kommunisere med slike enheter er gjennom en av de nevnte seriellbuser, SPI, I2C eller UART. Dette minsker ofte kompleksiteten i koden, da man slipper å implementere mange algoritmer og datastrukturer selv.


Contents

Forberedelser

Før man kan gå i gang med å bruke Input/Output-funksjonaliteten (IO) på RPi, må man bestemme seg for hvordan man vil gjøre det. Mao., skal man styre pinnene manuelt i kommandolinjen, eller skal man skrive et C/C++ eller Python-program for å håndtere IO. Helt i starten kan det være greit å gjøre det i kommandolinjen, men den virkelige kraften i systemet ligger i å skrive programmer som reagerer på en bestemt måte. Et bibliotek [eng: software library], en nedlastbar samling av funksjoner, gjør vanligvis jobben mye enklere for oss. Funksjonene i et bibliotek gjør nøyaktig det samme som vi måtte gjort uten dem. De gjør det bare enklere for oss å gjøre det vi vil, og lar oss fokusere på de store strukturelle problemene istedet. I skrivende stund er wiringPi et slikt bibliotek. De fleste eksempler og guider her vil ta utgangspunkt i dette utmerkede biblioteket.

GPIO

Alle IO-pinner på RPi er GPIO-pinner. Noen pinner har også andre funksjoner, som SPI osv. De kan kun ha én modus av gangen. WiringPi gir deg enkel tilgang til følgende innstillinger:

  • Input/Output
  • Pullup/Pulldown/Tri-State
  • Output drive LOW/HIGH
  • PWM-verdi (PWM)

PWM-funksjonen er ikke så viktig, men den er verdt å merke seg. Den er kun tilgjengelig på én GPIO-pinne som også er koblet til lydutgangen. Med disse funksjonene kan man drive lysdioder (LEDs), ta input fra trykknapper (push buttons), bit-bange og mye annet.

Eks.: Ta input fra en trykknapp og slå av og på en LED henholdsvis

<source lang="cpp">

  1. include <wiringPi.h> // Needed for IO functions

int main(){ wiringPiSetup(); // Initializing IO registers pinMode(0,OUTPUT); // Set wiringPi pin 0 to output pinMode(1,INPUT); // Set wiringPi pin 1 to input pullUpDnControl(1,PUD_UP); // Enable pull-up resistor on wiringPi pin 1 while(1){ // Endless loop if(!digitalRead(1)){ // If wiringPi pin 1 is pulled low by external device digitalWrite(0,HIGH); // Drive wiringPi pin 0 high... delay(500); // ... wait for 500ms to get a good look... digitalWrite(0,LOW); // ... drive wiringPi pin 0 low... delay(500); // ... and wait for another 500ms. } delay(10); // Wait for 10ms to avoid using too much CPU time }

       return 0;

}

</source> C++-koden over vil blinke LEDen på wiringPi pinne 1, hvis wiringPi pinne 0 settes til 0V/GND. Se i denne tabellen for oversikt over hvor de forskjellige pinnene er. Husk å bruke en motstand i serie med LEDen på pinne 1, hvis ikke vil du trekke mye mer strøm enn 6mA, og din RPi vil få et kort liv!

SPI

Serial Peripheral Interface (SPI) er ikke en standard i og for seg, snarere en vanlig måte å kommunisere serielt på. Serielt betyr «etter hverandre». For å bruke SPI på RPi må den først aktiveres. Dette kan gjøres på flere forskjellige måter. F.eks. kan man skrive <source lang="lolcode"> gpio load spi</source> i kommandolinjen, hvis man har wiringPi installert. Evt. kan man sette driveren til å lastes inn ved systemoppstart (boot), ved å legge til linjen <source lang="lolcode"> spi-bcm2708 </source> i filen /etc/modules og omstarte.

Eks.: Sende seriell data til shift register

<source lang="cpp">

  1. include <stdio.h> // Needed for error handling
  2. include <string.h> // Same as above
  3. include <errno.h> // Same as above
  1. include <wiringPi.h> // Needed for delay() function
  2. include <wiringPiSPI.h> // Needed for SPI functions

using namespace std; // Instead of writing std:: before all standard functions

int main(){ int fd = 0; fd = wiringPiSPISetup(0,500000); if (fd < 0){ fprintf(stderr,"Unable to open serial device: %sn",strerror(errno)); return 1; } // If setup functions returned error value, then print message to standard error ouput while(1){

for (int i = 0; i < 4; i++){ unsigned char charToSend = (0x01 << i); // Prepare the char to be sent int receivedInt = wiringPiSPIDataRW(0,&charToSend,1); // Send the char on CH0, 1 byte to send delay(500); // Wait for 500ms to get a good look at the LEDs } }

printf("Exiting\n"); // Program execution never actually reaches this...

return 0; // ... or this, but they are included anyway }

</source> Denne C++-koden vil sende 0001, 0010, 0100 og 1000 i en uendelig loop ut av SPI'en (helt til du dreper programmet med ctrl-c). Koble opp et shift register (f.eks. 74HC595) med LEDs + motstander koblet til utgang Q0, Q1, Q2 og Q3 og se hva som skjer.

I2C

I2C er svært mye brukt i embedded systems, fordi den lar deg koble opp mange enheter på samme bus, dvs. i dette tilfellet med bare to ledninger! Det kan fort spare deg for mye rot. Ofte er det enklere å bruke en seriellbus som I2C istedenfor å kommunisere direkte med eksterne enheter (sensorer etc.). Foreløpig finnes det ikke noe eksempel her for I2C, men DS1307 er en mye brukt Real Time Clock (RTC) med I2C-interface. Kanskje det kommer et eksempel med den eller serial EEPROMs etter hvert. RPi har to I2C'er tilgjengelige, I2C0 og I2C1. Den første er tilgjengelig på P5-headeren, mens den andre er på P1-headeren.

UART

Universal Asynchronous Receiver/Transmitter er litt mer kompleks enn SPI, men bruker til sammenligning bare én ledning for enveis kommunikasjon (simplex). Det er også mulig med toveis kommunikasjon (full duplex). SPI og I2C er tradisjonelt såkalt multidrop bus'er, mens UART vanligvis går mellom to enheter (peer to peer). UART kommuniserer på samme måte som standarden RS-232/EIA-232 med den forskjellen at RS-232/EIA-232 og UART opererer med vilt forskjellige spenningsnivåer. Derfor er det nødvendig med en «level converter» for å koble de to sammen, f.eks. MAX3232. Ellers kan du være sikker på at RPi blir svett i trøya og dør.

Eks.: Sende seriell data over UART

<source lang="cpp">

  1. include <stdio.h> // Needed for error handling
  2. include <string.h> // Same as above
  3. include <errno.h> // Same as above
  1. include <wiringPi.h> // Needed for delay() function
  2. include <wiringSerial.h> // Needed for UART functions

using namespace std; // Instead of writing std:: before all standard functions

int main(){ int fd = 0; // Create device handle fd = serialOpen("/dev/ttyAMA0",9600); // Open serial port ttyAMA0, 9600 bit/s setting if (fd < 0) { fprintf(stderr,"Unable to open serial dvice: %sn",strerror(errno)); return 1; } // If unable to open serial port, print message to standard error output

for (int i = 'a'; i < 'z'; i++){ // From a to z... serialPutchar(fd,i); // ... send the character with the UART delay(500); // To get a good look }

serialClose(fd); // Close the serial port to free up resources printf("Exiting\n"); // Debug information return 0; } </source> Denne C++-koden sender bokstavene a til z over UARTen med 500ms mellomrom.

Personal tools