Lazarus on Raspberry Pi/de: what changed
Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.
| Old | New | Line | |
|---|---|---|---|
| 1 | 1 | <img src="Lazarus_on_Raspberry_Pi_Raspian_Wheezy_version_2012-10-28.png" title="Lazarus unter Raspbian Wheezy" width="200" alt="Lazarus unter Raspbian Wheezy" /> *(Raspberry Pi only)* | |
| 2 | 2 | ||
| 3 | 3 | Der **Raspberry Pi** ist ein kreditkartengroßer Einplatinenrechner. Er wurde in Großbritannien von der Raspberry Pi Foundation ursprünglich entwickelt, um den grundlegenden Informatikunterricht in Schulen zu fördern. Raspberry Pis können aber nicht nur für die Ausbildung, sondern für die unterschiedlichsten Zwecke, z. B. als Medienserver, Robotersteuerungen und für die Regelungstechnik eingesetzt werden. | |
| 4 | 4 | ||
| 5 | 5 | Die Raspberry Pi Foundation empfiehlt als Standard-Betriebssystem Raspbian Wheezy. Alternative Betriebssysteme für den RPI sind z. B. RISC OS und verschiedene Linux-Distributionen, einschließlich Android. | |
| 6 | 6 | ||
| 7 | 7 | Lazarus läuft nativ unter dem Betriebssystem Raspbian. | |
| 8 | 8 | ||
| 9 | 9 | ## Lazarus installieren und/oder compilieren | |
| 10 | 10 | ||
| 11 | 11 | ### Einfache Installation unter Raspbian | |
| 12 | 12 | ||
| 13 | 13 | Hinweis: | |
| 14 | 14 | ||
| 15 | 15 | In der Wheezy Version (2014-09-09) muss folgende Paketquelle in etc/apt/sources.list hinzugefügt werden. | |
| 16 | 16 | ||
| 17 | 17 | deb <http://plugwash.raspbian.org/wsf> wheezy-wsf main | |
| 18 | 18 | ||
| 19 | 19 | Diese Information bezieht sich auf den Artikel: | |
| 20 | 20 | ||
| 21 | 21 | [Raspberrypi.org FPC-Fix](http://www.raspberrypi.org/forums/viewtopic.php?f=34&t=88145) | |
| 22 | 22 | ||
| 23 | 23 | #### Raspberry Pi 1 | |
| 24 | 24 | ||
| 25 | 25 | Lazarus und Free Pascal können unter Raspbian OS schnell und einfach installiert werden. Es ist dafür nur nötig, ein Terminal-Fenster zu öffnen und die folgenden Kommandos einzugeben: | |
| 26 | 26 | ||
| 27 | 27 | ``` pascal | |
| 28 | 28 | sudo apt-get update | |
| 29 | 29 | sudo apt-get upgrade | |
| 30 | 30 | sudo apt-get install fpc | |
| 31 | 31 | sudo apt-get install lazarus | |
| 32 | 32 | ``` | |
| 33 | 33 | ||
| 34 | 34 | Damit wird, natürlich unter der Voraussetzung einer funktionierenden Netzwerkverbindung, eine vorkompilierte Lazarus-Version auf dem Raspberry Pi installiert. Die Installation kann, je nach Version und Netzwerkgeschwindigkeit, etwa 30 Minuten erfordern, sie läuft aber überwiegend automatisch ab. Nach der Installation kann Lazarus direkt über das "Programming"-Untermenü des LXDE Startmenüs gestartet werden. | |
| 35 | 35 | ||
| 36 | 36 | Install Lazarus Rasbian Part1 de.png\|Installation 1 Install Lazarus Rasbian Part2 de.png\|Installation 2 Install Lazarus Rasbian Part3 de.png\|Installation 3 Install Lazarus Rasbian Part4 de.png\|Installation 4 | |
| 37 | 37 | ||
| 38 | 38 | #### Raspberry Pi 2 | |
| 39 | 39 | ||
| 40 | 40 | Seit Juni 2015 funktioniert die oben angeführte "out of the box" Installationsmethode auch auf dem Raspberry Pi 2 Model B. Allerdings ist nach gegenwärtigem Stand die installierte Version recht alt. Wer die neuesten Versionen des Free Pascal Compilers und der Lazarus IDE installieren möchte, findet eine Anleitung in [diesem Artikel](http://www.tweaking4all.com/hardware/raspberry-pi/install-lazarus-pascal-on-raspberry-pi-2/). | |
| 41 | 41 | ||
| 42 | 42 | <File:Lazarus> 0 9 30 4 on RPi 2.png\|Lazarus "out of the box" auf dem Raspberry Pi 2 | |
| 43 | 43 | ||
| 44 | 44 | ### Übersetzen aus den Quelltexten | |
| 45 | 45 | ||
| 46 | 46 | Alternativ kann Lazarus auch aus den Subversion-Quelltexten übersetzt werden. Einzelheiten sind unter \[<http://www.michellcomputing.co.uk/blog/?p=72>: Michell Computing: Lazarus on the Raspberry Pi\] beschrieben. | |
| 47 | 47 | ||
| 48 | 48 | <File:Start> Menu with Lazarus de.png\|Starten von Lazarus unter Raspbian Wheezy <File:Lazarus> on Raspberry Pi.jpg\|Lazarus auf dem Raspberry Pi <File:rpi> gpio pins.png\|Nummerierung der GPIO-Anschlüsse | |
| 49 | 49 | ||
| 50 | 50 | ## Zugriff auf externe Hardware | |
| 51 | 51 | ||
| 52 | - | ||
| 53 | 52 | <img src="rpi_pinout_all_50.png" title="Belegung der externen Anschlüsse des Raspberry Pi" width="300" /> | |
| 54 | - | ||
| 55 | - | ||
| 56 | 53 | ||
| 57 | 54 | Eines der Ziele bei der Entwicklung des Raspberry Pi bestand darin, einfachen und schnellen Zugriff auf esterne Geräte wie Sensoren und Aktuatoren zu ermöglichen. Es gibt vier Möglichkeiten, die E/A-Optionen unter Lazarus und Free Pascal zu nutzen: | |
| 58 | 55 | ||
| 59 | 56 | 1. [[Lazarus on Raspberry Pi/de|Direktzugriff]] über die [[doc:rtl/baseunix/index.html|BaseUnix]]-Unit | |
| 60 | 57 | 2. Zugriff über [[Lazarus on Raspberry Pi/de|gekapselte Shell-Aufrufe]] | |
| 61 | 58 | 3. Zugriff über die [[Lazarus on Raspberry Pi/de|wiringPi library]]. | |
| 62 | 59 | 4. Zugriff über die Unit [[Lazarus on Raspberry Pi/de|rpi_hal]]. | |
| 63 | 60 | ||
| 64 | 61 | ### 1. Nativer Hardware-Zugriff | |
| 65 | 62 | ||
| 66 | 63 |    Diese Methode bietet Zugriff auf externe Hardware, ohne zusätzliche Bibliotheken oder Packages zu benötigen. Die einzige Voraussetzung ist die BaseUnix-Bibliothek, die zur RTL gehört und mit Free Pascal automatisch mitinstalliert wird. | |
| 67 | 64 | ||
| 68 | 65 | #### Schalten eines Gerätes über den GPIO-Port | |
| 69 | 66 | ||
| 70 | 67 | Im folgenden Beispiel ist ein einfaches Programm aufgelistet, das den GPIO-Pin 17 als Ausgang zum Schalten einer LED, eines Transistors oder eines Relais benutzt. Es enthält eine [[doc:lcl/stdctrls/ttogglebox.html|ToggleBox]] mit dem Namen *GPIO17ToggleBox* und zur Aufzeichnung von Return-Codes ein [[doc:lcl/stdctrls/tmemo.html|TMemo]]-Feld mit der Bezeichnung *LogMemo*. | |
| 71 | 68 | ||
| 72 | 69 | Hardwareseitig wurde die Anode einer LED mit Pin 11 des Anschlusses auf dem Pi (entsprechend GPIO-Pin 17 des BCM2835 SOC) und ihre Kathode über einen 68-Ohm-Schutzwiderstand mit Pin 6 des Pi-Anschlusses (GND = Masse) verbunden (s. auch die Beschreibung bei Upton and Halfacree). Damit kann die LED durch die ToggleBox des Programms ein- und ausgeschaltet werden. | |
| 73 | 70 | ||
| 74 | 71 | Das Programm muss mit Root-Rechten ausgeführt werden, d. h. entweder von einem Root-Account aus (aus Sicherheitsgründen weniger zu empfehlen) oder über das Shell-Kommando **su**. | |
| 75 | 72 | ||
| 76 | 73 | *Steuerungs-Unit:* | |
| 77 | 74 | ||
| 78 | 75 | ``` pascal | |
| 79 | 76 | unit Unit1; | |
| 80 | 77 | ||
| 81 | 78 | {Demo application for GPIO on Raspberry Pi} | |
| 82 | 79 | {Inspired by the Python input/output demo application by Gareth Halfacree} | |
| 83 | 80 | {written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5} | |
| 84 | 81 | ||
| 85 | 82 | {$mode objfpc}{$H+} | |
| 86 | 83 | ||
| 87 | 84 | interface | |
| 88 | 85 | ||
| 89 | 86 | uses | |
| 90 | 87 | Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, | |
| 91 | 88 | Unix, BaseUnix; | |
| 92 | 89 | ||
| 93 | 90 | type | |
| 94 | 91 | ||
| 95 | 92 | { TForm1 } | |
| 96 | 93 | ||
| 97 | 94 | TForm1 = class(TForm) | |
| 98 | 95 | LogMemo: TMemo; | |
| 99 | 96 | GPIO17ToggleBox: TToggleBox; | |
| 100 | 97 | procedure FormActivate(Sender: TObject); | |
| 101 | 98 | procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); | |
| 102 | 99 | procedure GPIO17ToggleBoxChange(Sender: TObject); | |
| 103 | 100 | private | |
| 104 | 101 | { private declarations } | |
| 105 | 102 | public | |
| 106 | 103 | { public declarations } | |
| 107 | 104 | end; | |
| 108 | 105 | ||
| 109 | 106 | const | |
| 110 | 107 | PIN_17: PChar = '17'; | |
| 111 | 108 | PIN_ON: PChar = '1'; | |
| 112 | 109 | PIN_OFF: PChar = '0'; | |
| 113 | 110 | OUT_DIRECTION: PChar = 'out'; | |
| 114 | 111 | ||
| 115 | 112 | var | |
| 116 | 113 | Form1: TForm1; | |
| 117 | 114 | gReturnCode: longint; {stores the result of the IO operation} | |
| 118 | 115 | ||
| 119 | 116 | implementation | |
| 120 | 117 | ||
| 121 | 118 | {$R *.lfm} | |
| 122 | 119 | ||
| 123 | 120 | { TForm1 } | |
| 124 | 121 | ||
| 125 | 122 | procedure TForm1.FormActivate(Sender: TObject); | |
| 126 | 123 | var | |
| 127 | 124 | fileDesc: integer; | |
| 128 | 125 | begin | |
| 129 | 126 | { Prepare SoC pin 17 (pin 11 on GPIO port) for access: } | |
| 130 | 127 | try | |
| 131 | 128 | fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly); | |
| 132 | 129 | gReturnCode := fpwrite(fileDesc, PIN_17[0], 2); | |
| 133 | 130 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 134 | 131 | finally | |
| 135 | 132 | gReturnCode := fpclose(fileDesc); | |
| 136 | 133 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 137 | 134 | end; | |
| 138 | 135 | { Set SoC pin 17 as output: } | |
| 139 | 136 | try | |
| 140 | 137 | fileDesc := fpopen('/sys/class/gpio/gpio17/direction', O_WrOnly); | |
| 141 | 138 | gReturnCode := fpwrite(fileDesc, OUT_DIRECTION[0], 3); | |
| 142 | 139 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 143 | 140 | finally | |
| 144 | 141 | gReturnCode := fpclose(fileDesc); | |
| 145 | 142 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 146 | 143 | end; | |
| 147 | 144 | end; | |
| 148 | 145 | ||
| 149 | 146 | procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction); | |
| 150 | 147 | var | |
| 151 | 148 | fileDesc: integer; | |
| 152 | 149 | begin | |
| 153 | 150 | { Free SoC pin 17: } | |
| 154 | 151 | try | |
| 155 | 152 | fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly); | |
| 156 | 153 | gReturnCode := fpwrite(fileDesc, PIN_17[0], 2); | |
| 157 | 154 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 158 | 155 | finally | |
| 159 | 156 | gReturnCode := fpclose(fileDesc); | |
| 160 | 157 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 161 | 158 | end; | |
| 162 | 159 | end; | |
| 163 | 160 | ||
| 164 | 161 | procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject); | |
| 165 | 162 | var | |
| 166 | 163 | fileDesc: integer; | |
| 167 | 164 | begin | |
| 168 | 165 | if GPIO17ToggleBox.Checked then | |
| 169 | 166 | begin | |
| 170 | 167 | { Swith SoC pin 17 on: } | |
| 171 | 168 | try | |
| 172 | 169 | fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly); | |
| 173 | 170 | gReturnCode := fpwrite(fileDesc, PIN_ON[0], 1); | |
| 174 | 171 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 175 | 172 | finally | |
| 176 | 173 | gReturnCode := fpclose(fileDesc); | |
| 177 | 174 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 178 | 175 | end; | |
| 179 | 176 | end | |
| 180 | 177 | else | |
| 181 | 178 | begin | |
| 182 | 179 | { Switch SoC pin 17 off: } | |
| 183 | 180 | try | |
| 184 | 181 | fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly); | |
| 185 | 182 | gReturnCode := fpwrite(fileDesc, PIN_OFF[0], 1); | |
| 186 | 183 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 187 | 184 | finally | |
| 188 | 185 | gReturnCode := fpclose(fileDesc); | |
| 189 | 186 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 190 | 187 | end; | |
| 191 | 188 | end; | |
| 192 | 189 | end; | |
| 193 | 190 | ||
| 194 | 191 | end. | |
| 195 | 192 | ``` | |
| 196 | 193 | ||
| 197 | 194 | *Hauptprogramm:* | |
| 198 | 195 | ||
| 199 | 196 | ``` pascal | |
| 200 | 197 | program io_test; | |
| 201 | 198 | ||
| 202 | 199 | {$mode objfpc}{$H+} | |
| 203 | 200 | ||
| 204 | 201 | uses | |
| 205 | 202 | {$IFDEF UNIX}{$IFDEF UseCThreads} | |
| 206 | 203 | cthreads, | |
| 207 | 204 | {$ENDIF}{$ENDIF} | |
| 208 | 205 | Interfaces, // this includes the LCL widgetset | |
| 209 | 206 | Forms, Unit1 | |
| 210 | 207 | { you can add units after this }; | |
| 211 | 208 | ||
| 212 | 209 | {$R *.res} | |
| 213 | 210 | ||
| 214 | 211 | begin | |
| 215 | 212 | Application.Initialize; | |
| 216 | 213 | Application.CreateForm(TForm1, Form1); | |
| 217 | 214 | Application.Run; | |
| 218 | 215 | end. | |
| 219 | 216 | ``` | |
| 220 | 217 | ||
| 221 | 218 | #### Den Status eines Anschlusses lesen | |
| 222 | 219 | ||
| 223 | 220 |    | |
| 224 | 221 | ||
| 225 | 222 | Umgekehrt ist es natürlich auch möglich, den Status z. B. eines Schalters abzufragen, der mit dem GPIO-Port verbunden ist. | |
| 226 | 223 | ||
| 227 | 224 | Das folgende einfache Beispiel ist dem vorherigen sehr ähnlich. Es benutzt den GPIO-Pin 18 als Eingang für ein binäres Gerät, z. B. einen Schalter, einen Transistor oder ein Relais. Das Programm enthält eine [[doc:lcl/stdctrls/tcheckbox.html|CheckBox]] mit der Bezeichnung *GPIO18CheckBox* und zur Aufzeichnung von Return-Codes ein [[doc:lcl/stdctrls/tmemo.html|TMemo]]-Feld mit dem Namen *LogMemo*. | |
| 228 | 225 | ||
| 229 | 226 | Im Beispiel wurde ein Pol eines Tasters mit Pin 12 an der Anschlussleiste des Pi (entsprechend GPIO-Pin 18 des BCM2835 SOCs) und über einen 10-kOhm Pull-Up-Widerstand mit Pin 1 (+3.3V, siehe Schaltplan) verbunden. Der andere Pol wurde mit Pin 6 der Anschlussleiste (GND = Masse) verdrahtet. Das Programm liest den Status des Tasters aus und schaltet dementsprechend die CheckBox an oder aus. | |
| 230 | 227 | ||
| 231 | 228 | Das Potential des Pins 18 ist hoch, wenn der Taster nicht gedrückt wird (wegen der Verbindung mit Pin 1 über den Pull-Up-Widerstand) und niedrig, wenn er gedrückt wird (da in dieser Situation Pin 18 über den Taster mit Masse verbunden wird). Der GPIO-Pin meldet daher 0, wenn der Taster gedrückt wird und 1, wenn er losgelassen wird. | |
| 232 | 229 | ||
| 233 | 230 | Auch dieses Programm ist mit Root-Rechten auszuführen. | |
| 234 | 231 | ||
| 235 | 232 | *Steuerung-Unit:* | |
| 236 | 233 | ||
| 237 | 234 | ``` pascal | |
| 238 | 235 | unit Unit1; | |
| 239 | 236 | ||
| 240 | 237 | {Demo application for GPIO on Raspberry Pi} | |
| 241 | 238 | {Inspired by the Python input/output demo application by Gareth Halfacree} | |
| 242 | 239 | {written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5} | |
| 243 | 240 | ||
| 244 | 241 | {This application reads the status of a push-button} | |
| 245 | 242 | ||
| 246 | 243 | {$mode objfpc}{$H+} | |
| 247 | 244 | ||
| 248 | 245 | interface | |
| 249 | 246 | ||
| 250 | 247 | uses | |
| 251 | 248 | Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, | |
| 252 | 249 | ButtonPanel, Unix, BaseUnix; | |
| 253 | 250 | ||
| 254 | 251 | type | |
| 255 | 252 | ||
| 256 | 253 | { TForm1 } | |
| 257 | 254 | ||
| 258 | 255 | TForm1 = class(TForm) | |
| 259 | 256 | ApplicationProperties1: TApplicationProperties; | |
| 260 | 257 | GPIO18CheckBox: TCheckBox; | |
| 261 | 258 | LogMemo: TMemo; | |
| 262 | 259 | procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean); | |
| 263 | 260 | procedure FormActivate(Sender: TObject); | |
| 264 | 261 | procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); | |
| 265 | 262 | private | |
| 266 | 263 | { private declarations } | |
| 267 | 264 | public | |
| 268 | 265 | { public declarations } | |
| 269 | 266 | end; | |
| 270 | 267 | ||
| 271 | 268 | const | |
| 272 | 269 | PIN_18: PChar = '18'; | |
| 273 | 270 | IN_DIRECTION: PChar = 'in'; | |
| 274 | 271 | ||
| 275 | 272 | var | |
| 276 | 273 | Form1: TForm1; | |
| 277 | 274 | gReturnCode: longint; {stores the result of the IO operation} | |
| 278 | 275 | ||
| 279 | 276 | implementation | |
| 280 | 277 | ||
| 281 | 278 | {$R *.lfm} | |
| 282 | 279 | ||
| 283 | 280 | { TForm1 } | |
| 284 | 281 | ||
| 285 | 282 | procedure TForm1.FormActivate(Sender: TObject); | |
| 286 | 283 | var | |
| 287 | 284 | fileDesc: integer; | |
| 288 | 285 | begin | |
| 289 | 286 | { Prepare SoC pin 18 (pin 12 on GPIO port) for access: } | |
| 290 | 287 | try | |
| 291 | 288 | fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly); | |
| 292 | 289 | gReturnCode := fpwrite(fileDesc, PIN_18[0], 2); | |
| 293 | 290 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 294 | 291 | finally | |
| 295 | 292 | gReturnCode := fpclose(fileDesc); | |
| 296 | 293 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 297 | 294 | end; | |
| 298 | 295 | { Set SoC pin 18 as input: } | |
| 299 | 296 | try | |
| 300 | 297 | fileDesc := fpopen('/sys/class/gpio/gpio18/direction', O_WrOnly); | |
| 301 | 298 | gReturnCode := fpwrite(fileDesc, IN_DIRECTION[0], 2); | |
| 302 | 299 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 303 | 300 | finally | |
| 304 | 301 | gReturnCode := fpclose(fileDesc); | |
| 305 | 302 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 306 | 303 | end; | |
| 307 | 304 | end; | |
| 308 | 305 | ||
| 309 | 306 | procedure TForm1.ApplicationProperties1Idle(Sender: TObject; var Done: Boolean); | |
| 310 | 307 | var | |
| 311 | 308 | fileDesc: integer; | |
| 312 | 309 | buttonStatus: string[1] = '1'; | |
| 313 | 310 | begin | |
| 314 | 311 | try | |
| 315 | 312 | { Open SoC pin 18 (pin 12 on GPIO port) in read-only mode: } | |
| 316 | 313 | fileDesc := fpopen('/sys/class/gpio/gpio18/value', O_RdOnly); | |
| 317 | 314 | if fileDesc > 0 then | |
| 318 | 315 | begin | |
| 319 | 316 | { Read status of this pin (0: button pressed, 1: button released): } | |
| 320 | 317 | gReturnCode := fpread(fileDesc, buttonStatus[1], 1); | |
| 321 | 318 | LogMemo.Lines.Add(IntToStr(gReturnCode) + ': ' + buttonStatus); | |
| 322 | 319 | LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1; | |
| 323 | 320 | if buttonStatus = '0' then | |
| 324 | 321 | GPIO18CheckBox.Checked := true | |
| 325 | 322 | else | |
| 326 | 323 | GPIO18CheckBox.Checked := false; | |
| 327 | 324 | end; | |
| 328 | 325 | finally | |
| 329 | 326 | { Close SoC pin 18 (pin 12 on GPIO port) } | |
| 330 | 327 | gReturnCode := fpclose(fileDesc); | |
| 331 | 328 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 332 | 329 | LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1; | |
| 333 | 330 | end; | |
| 334 | 331 | end; | |
| 335 | 332 | ||
| 336 | 333 | procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction); | |
| 337 | 334 | var | |
| 338 | 335 | fileDesc: integer; | |
| 339 | 336 | begin | |
| 340 | 337 | { Free SoC pin 18: } | |
| 341 | 338 | try | |
| 342 | 339 | fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly); | |
| 343 | 340 | gReturnCode := fpwrite(fileDesc, PIN_18[0], 2); | |
| 344 | 341 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 345 | 342 | finally | |
| 346 | 343 | gReturnCode := fpclose(fileDesc); | |
| 347 | 344 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 348 | 345 | end; | |
| 349 | 346 | end; | |
| 350 | 347 | ||
| 351 | 348 | end. | |
| 352 | 349 | ``` | |
| 353 | 350 | ||
| 354 | 351 | Das Hauptprogramm ist identisch zu dem des obigen Beispiels. | |
| 355 | 352 | ||
| 356 | 353 | ### 2. Hardware-Zugriff über gekapselte Shell-Aufrufe | |
| 357 | 354 | ||
| 358 | 355 | Eine andere Möglichkeit, auf Hardware zuzugreifen, besteht in der Nutzung gekapselter Shell-Aufrufe. Dies geschieht mit Hilfe der [[Executing External Programs|fpsystem]]-Funktion. Auf diese Weise ist es möglich, auf Funktionen zuzugreifen, die von der BaseUnix-Unit nicht unterstützt werden. Der folgende Code hat die selbe Funktionalität wie das Programm des ersten Listings oben. | |
| 359 | 356 | ||
| 360 | 357 | *Steuerungs-Unit:* | |
| 361 | 358 | ||
| 362 | 359 | ``` pascal | |
| 363 | 360 | unit Unit1; | |
| 364 | 361 | ||
| 365 | 362 | {Demo application for GPIO on Raspberry Pi} | |
| 366 | 363 | {Inspired by the Python input/output demo application by Gareth Halfacree} | |
| 367 | 364 | {written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5} | |
| 368 | 365 | ||
| 369 | 366 | {$mode objfpc}{$H+} | |
| 370 | 367 | ||
| 371 | 368 | interface | |
| 372 | 369 | ||
| 373 | 370 | uses | |
| 374 | 371 | Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Unix; | |
| 375 | 372 | ||
| 376 | 373 | type | |
| 377 | 374 | ||
| 378 | 375 | { TForm1 } | |
| 379 | 376 | ||
| 380 | 377 | TForm1 = class(TForm) | |
| 381 | 378 | LogMemo: TMemo; | |
| 382 | 379 | GPIO17ToggleBox: TToggleBox; | |
| 383 | 380 | procedure FormActivate(Sender: TObject); | |
| 384 | 381 | procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); | |
| 385 | 382 | procedure GPIO17ToggleBoxChange(Sender: TObject); | |
| 386 | 383 | private | |
| 387 | 384 | { private declarations } | |
| 388 | 385 | public | |
| 389 | 386 | { public declarations } | |
| 390 | 387 | end; | |
| 391 | 388 | ||
| 392 | 389 | var | |
| 393 | 390 | Form1: TForm1; | |
| 394 | 391 | gReturnCode: longint; {stores the result of the IO operation} | |
| 395 | 392 | ||
| 396 | 393 | implementation | |
| 397 | 394 | ||
| 398 | 395 | {$R *.lfm} | |
| 399 | 396 | ||
| 400 | 397 | { TForm1 } | |
| 401 | 398 | ||
| 402 | 399 | procedure TForm1.FormActivate(Sender: TObject); | |
| 403 | 400 | begin | |
| 404 | 401 | { Prepare SoC pin 17 (pin 11 on GPIO port) for access: } | |
| 405 | 402 | gReturnCode := fpsystem('echo "17" > /sys/class/gpio/export'); | |
| 406 | 403 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 407 | 404 | { Set SoC pin 17 as output: } | |
| 408 | 405 | gReturnCode := fpsystem('echo "out" > /sys/class/gpio/gpio17/direction'); | |
| 409 | 406 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 410 | 407 | end; | |
| 411 | 408 | ||
| 412 | 409 | procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction); | |
| 413 | 410 | begin | |
| 414 | 411 | { Free SoC pin 17: } | |
| 415 | 412 | gReturnCode := fpsystem('echo "17" > /sys/class/gpio/unexport'); | |
| 416 | 413 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 417 | 414 | end; | |
| 418 | 415 | ||
| 419 | 416 | procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject); | |
| 420 | 417 | begin | |
| 421 | 418 | if GPIO17ToggleBox.Checked then | |
| 422 | 419 | begin | |
| 423 | 420 | { Swith SoC pin 17 on: } | |
| 424 | 421 | gReturnCode := fpsystem('echo "1" > /sys/class/gpio/gpio17/value'); | |
| 425 | 422 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 426 | 423 | end | |
| 427 | 424 | else | |
| 428 | 425 | begin | |
| 429 | 426 | { Switch SoC pin 17 off: } | |
| 430 | 427 | gReturnCode := fpsystem('echo "0" > /sys/class/gpio/gpio17/value'); | |
| 431 | 428 | LogMemo.Lines.Add(IntToStr(gReturnCode)); | |
| 432 | 429 | end; | |
| 433 | 430 | end; | |
| 434 | 431 | ||
| 435 | 432 | end. | |
| 436 | 433 | ``` | |
| 437 | 434 | ||
| 438 | 435 | Das Hauptprogramm ist identisch zu dem der obigen Beispiele. Es erfordert wieder Root-Rechte. | |
| 439 | 436 | ||
| 440 | 437 | ### 3. wiringPi-Prozeduren und Funktionen | |
| 441 | 438 | ||
| 442 | 439 | Mit Hilfe von Alex Schallers Wrapper-Unit für Gordon Hendersons Arduino-kompatible wiringPi-Bibliothek kann ein Nummerierungs-Schema verwendet werden, das dem der Arduino-Boards entspricht. | |
| 443 | 440 | ||
| 444 | 441 | ``` pascal | |
| 445 | 442 | Function wiringPiSetup:longint; {Initialisiert das wiringPi-System entsprechend dem wiringPi Pin-Nummerierungs-Schema.} | |
| 446 | 443 | ||
| 447 | 444 | Procedure wiringPiGpioMode(mode:longint); {Initialisiert das wiringPi-System mit dem Broadcom GPIO-Pin-Nummerierungs-Schema.} | |
| 448 | 445 | ||
| 449 | 446 | Procedure pullUpDnControl(pin:longint; pud:longint); {steuert die internen pull-up/down-Widerstände eines GPIO-Pins.} | |
| 450 | 447 | ||
| 451 | 448 | Procedure pinMode(pin:longint; mode:longint); {setzt den Betriebsmodus eines Pins auf entweder INPUT, OUTPUT oder PWM_OUTPUT.} | |
| 452 | 449 | ||
| 453 | 450 | Procedure digitalWrite(pin:longint; value:longint); {setzt ein Ausgabe-Bit.} | |
| 454 | 451 | ||
| 455 | 452 | Procedure pwmWrite(pin:longint; value:longint); {setzt einen Ausgabe-PWM-Wert zwischen 0 und 1024.} | |
| 456 | 453 | ||
| 457 | 454 | Function digitalRead(pin:longint):longint; {liest den Wert des übergebenen Pins, gibt 1 oder 0.} | |
| 458 | 455 | ||
| 459 | 456 | Procedure delay(howLong:dword); {wartet howLong Millisekunden.} | |
| 460 | 457 | ||
| 461 | 458 | Procedure delayMicroseconds(howLong:dword); {wartet howLong Mikrosekunden.} | |
| 462 | 459 | ||
| 463 | 460 | Function millis:dword; {gibt die Zahl der Millisekunden zurück, seit das Programm eine der wiringPiSetup-Funktionen aufgerufen hat.} | |
| 464 | 461 | ``` | |
| 465 | 462 | ||
| 466 | 463 | ### 4. rpi_hal-Hardware Abstraction Library (GPIO, I2C und SPI Funktionen und Prozeduren) | |
| 467 | 464 | ||
| 468 | 465 | Diese Unit mit ca. 1700 Lines of Code wird von Stefan Fischer zur Verfügung gestellt und bietet Prozeduren und Funktionen, die auf die rpi HW Zugriff auf I2C, SPI und GPIO bietet: | |
| 469 | 466 | ||
| 470 | 467 | Ein Auszug der verfügbaren Funktionen und Prozeduren: | |
| 471 | 468 | ||
| 472 | 469 | **procedure gpio_set_pin (pin:longword;highlevel:boolean);** { Set RPi GPIO pin to high or low level; Speed @ 700MHz -\> 0.65MHz } | |
| 473 | 470 | ||
| 474 | 471 | **function gpio_get_PIN (pin:longword):boolean;** { Get RPi GPIO pin Level is true when Pin level is '1'; false when '0'; Speed @ 700MHz -\> 1.17MHz } | |
| 475 | 472 | ||
| 476 | 473 | **procedure gpio_set_input (pin:longword);** { Set RPi GPIO pin to input direction } | |
| 477 | 474 | ||
| 478 | 475 | **procedure gpio_set_output(pin:longword);** { Set RPi GPIO pin to output direction } | |
| 479 | 476 | ||
| 480 | 477 | **procedure gpio_set_alt (pin,altfunc:longword);** { Set RPi GPIO pin to alternate function nr. 0..5 } | |
| 481 | 478 | ||
| 482 | 479 | **procedure gpio_set_gppud (mask:longword);** { set RPi GPIO Pull-up/down Register (GPPUD) with mask } | |
| 483 | 480 | ||
| 484 | 481 | ... | |
| 485 | 482 | ||
| 486 | 483 | **function rpi_snr :string;** { delivers SNR: 0000000012345678 } | |
| 487 | 484 | ||
| 488 | 485 | **function rpi_hw :string;** { delivers Processor Type: BCM2708 } | |
| 489 | 486 | ||
| 490 | 487 | **function rpi_proc:string;** { ARMv6-compatible processor rev 7 (v6l) } | |
| 491 | 488 | ||
| 492 | 489 | ... | |
| 493 | 490 | ||
| 494 | 491 | **function i2c_bus_write(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;** | |
| 495 | 492 | ||
| 496 | 493 | **function i2c_bus_read (baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;** | |
| 497 | 494 | ||
| 498 | 495 | **function i2c_string_read(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : string;** | |
| 499 | 496 | ||
| 500 | 497 | **function i2c_string_write(baseadr,reg:word; s:string; testnr:integer) : integer;** | |
| 501 | 498 | ||
| 502 | 499 | ... | |
| 503 | 500 | ||
| 504 | 501 | **procedure SPI_Write(devnum:byte; reg,data:word);** | |
| 505 | 502 | ||
| 506 | 503 | **function SPI_Read(devnum:byte; reg:word) : byte;** | |
| 507 | 504 | ||
| 508 | 505 | **procedure SPI_BurstRead2Buffer (devnum,start_reg:byte; xferlen:longword);** | |
| 509 | 506 | ||
| 510 | 507 | **procedure SPI_BurstWriteBuffer (devnum,start_reg:byte; xferlen:longword);** { Write 'len' Bytes from Buffer SPI Dev startig at address 'reg' } | |
| 511 | 508 | ||
| 512 | 509 | ... | |
| 513 | 510 | ||
| 514 | 511 | *Test Program (testrpi.pas):* | |
| 515 | 512 | ||
| 516 | 513 | ``` pascal | |
| 517 | 514 | //Simple Test program, which is using rpi_hal; | |
| 518 | 515 | ||
| 519 | 516 | program testrpi; | |
| 520 | 517 | uses rpi_hal; | |
| 521 | 518 | begin | |
| 522 | 519 | writeln('Show CPU-Info, RPI-HW-Info and Registers:'); | |
| 523 | 520 | rpi_show_all_info; | |
| 524 | 521 | writeln('Let Status LED Blink. Using GPIO functions:'); | |
| 525 | 522 | GPIO_PIN_TOGGLE_TEST; | |
| 526 | 523 | writeln('Test SPI Read function. (piggy back board with installed RFM22B Module is required!)'); | |
| 527 | 524 | Test_SPI; | |
| 528 | 525 | end. | |
| 529 | 526 | ``` | |
| 530 | 527 | ||
| 531 | 528 | ### 5. PascalIO | |
| 532 | 529 | ||
| 533 | 530 | Mit dem Package [PascalIO](https://github.com/SAmeis/pascalio) kann objektorientiert auf die Schnittstellen zugegriffen werden. Es beinhaltet Klassen für die GPIO-Pins sowie für den I2C- und SPI-Bus. | |
| 534 | 531 | ||
| 535 | 532 | #### GPIO | |
| 536 | 533 | ||
| 537 | 534 | ##### Input | |
| 538 | 535 | ||
| 539 | 536 | ``` pascal | |
| 540 | 537 | program Project1; | |
| 541 | 538 | uses fpgpio; | |
| 542 | 539 | var | |
| 543 | 540 | pin_21: TGpioPin; | |
| 544 | 541 | begin | |
| 545 | 542 | pin_21 := TGpioLinuxPin.Create(21); | |
| 546 | 543 | pin_21.Direction := gdIn; | |
| 547 | 544 | WriteLn('Pin 21 hat den Wert: ', pin_21.Value); | |
| 548 | 545 | pin_21.Destroy; | |
| 549 | 546 | end. | |
| 550 | 547 | ``` | |
| 551 | 548 | ||
| 552 | 549 | ##### Output | |
| 553 | 550 | ||
| 554 | 551 | ``` pascal | |
| 555 | 552 | program Project1; | |
| 556 | 553 | uses sysutils, fpgpio; | |
| 557 | 554 | var | |
| 558 | 555 | i: Integer; | |
| 559 | 556 | pin_21: TGpioPin; | |
| 560 | 557 | begin | |
| 561 | 558 | pin_21 := TGpioLinuxPin.Create(21); | |
| 562 | 559 | pin_21.Direction := gdOut; | |
| 563 | 560 | for i := 0 to 10 do | |
| 564 | 561 | begin | |
| 565 | 562 | pin_21.Value := (i and $01) = 0; | |
| 566 | 563 | sleep(1000); | |
| 567 | 564 | end; | |
| 568 | 565 | pin_21.Destroy; | |
| 569 | 566 | end. | |
| 570 | 567 | ``` | |
| 571 | 568 | ||
| 572 | 569 | ##### Interrupt | |
| 573 | 570 | ||
| 574 | 571 | ``` pascal | |
| 575 | 572 | program Project1; | |
| 576 | 573 | uses fpgpio; | |
| 577 | 574 | var | |
| 578 | 575 | pin_21: TGpioPin; | |
| 579 | 576 | NewValue: Boolean; | |
| 580 | 577 | begin | |
| 581 | 578 | pin_21 := TGpioLinuxPin.Create(21); | |
| 582 | 579 | pin_21.Direction := gdIn; | |
| 583 | 580 | pin_21.InterruptMode := [gimRising, gimFalling]; | |
| 584 | 581 | try | |
| 585 | 582 | repeat | |
| 586 | 583 | if input.WaitForInterrupt(TGpioLinuxPin.INTERRUPT_WAIT_INFINITE, NewValue) then | |
| 587 | 584 | Writeln('Interrupt on Pin ', input.PinID, ' with value ', NewValue) | |
| 588 | 585 | else | |
| 589 | 586 | WriteLn('Timeout'); | |
| 590 | 587 | until False; | |
| 591 | 588 | except | |
| 592 | 589 | // e.g. on sig int | |
| 593 | 590 | pin_21.Destroy; | |
| 594 | 591 | end; | |
| 595 | 592 | end. | |
| 596 | 593 | ``` | |
| 597 | 594 | ||
| 598 | 595 | ## Literatur | |
| 599 | 596 | ||
| 600 | 597 | - Eben Upton and Gareth Halfacree. Raspberry Pi User Guide. John Wiley and Sons, Chichester 2012, ISBN 111846446X | |
| 601 | 598 | ||
| 602 | 599 | ## Externe Links | |
| 603 | 600 | ||
| 604 | 601 | - [Raspberry Pi Foundation](http://www.raspberrypi.org) | |
| 605 | 602 | - [Raspberry Pi Spy: Raspberry Pi tutorials, scripts, help and downloads](http://www.raspberrypi-spy.co.uk) | |
| 606 | 603 | - [Lazarus wrapper unit for Gordon Henderson's wiringPi C library](http://www.lazarus.freepascal.org/index.php/topic,17404.0.html) | |
| 607 | 604 | - [Pin layout of the wiringPi library](https://projects.drogon.net/raspberry-pi/wiringpi/pins/) | |
| 608 | 605 | - [Additional information on Lazarus and Raspberry Pi at eLinux.org](http://www.elinux.org/Lazarus_on_RPi) | |
| 609 | 606 | - [Getting Started with Pascal on the Pi](http://www.pp4s.co.uk/main/gs-pi-intro.html) | |
| 610 | 607 | - [Lazberry Pi: Umfangreiche Informationen zu Lazarus auf dem Raspberry Pi (englisch)](http://superbitysoft.co.uk/lazberrypi/). | |
| 611 | 608 | - [Stefan Fischer's Lazarus unit rpi_hal](http://www.lazarus.freepascal.org/index.php/topic,20991.0.html). | |
| 612 | 609 | ||
| 613 | 610 | --- | |
| 614 | 611 | *From the Free Pascal wiki, page "Lazarus on Raspberry Pi/de", as it stood on 2020-02-18 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
