Sign in Join
Wiki copytemporary

Lazarus on Raspberry Pi/zh CN: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11树莓派上的Lazarus
22
33<img src="Lazarus_on_Raspberry_Pi_Raspian_Wheezy_version_2012-10-28.png" title="Lazarus on Raspbian Wheezy" width="200" alt="Lazarus on Raspbian Wheezy" /> *(Raspberry Pi only)*
44
55Raspberry Pi(数莓派)是一个信用卡大小的单板计算机。它由英国的Raspberry Pi基金为了激励在学校的计算机基础科学教学发起的。Raspberry Pis也可以用来作为媒体服务器以及其他用途机器人、控制工程等多种用途。 Raspberry Pi基金会推荐[[Raspbian]] Wheezy作为标准的操作系统。大家可以选择在RPI运行RISC OS、各种Linux发行版以及[[Android]]等操作系统。 Lazarus可以在原生的Raspbian操作系统下运行。
66
77## 安装与编译器Lazarus
88
99### 在 Raspbian上简单安装
1010
1111#### Raspberry Pi 1
1212
1313在 Raspbian OS上,安装Lazarus与 Free Pascal很容易。打开命令行窗口输入下面的指令:
1414
1515``` bash
1616sudo apt-get update
1717sudo apt-get upgrade
1818sudo apt-get install fpc
1919sudo apt-get install lazarus
2020```
2121
2222这里安装的是为Raspberry Pi预编译的稳定版FPC与Lazarus 。当然,需要有网络连接。安装过程大概需要30分钟,这个过程是自动完成等的。安装完成以后,你就可以从LXDE的开始菜单的“Programming”启动Lazarus了。
2323
2424Install Lazarus Rasbian Part1 en.png\|安装步骤 1 Install Lazarus Rasbian Part2 en.png\|安装步骤 2 Install Lazarus Rasbian Part3 en.png\|安装步骤 3 Install Lazarus Rasbian Part4 en.png\|安装步骤 4
2525
2626如果你需要一个新的版本,或者抱怨Lazarus 的问题, [点击](http://www.raspberrypi.org/forums/viewtopic.php?f=34&t=88145).
2727
2828#### Raspberry Pi 2
2929
3030自2015六月起,普通的“out of the box”安装方法也适用于安装树莓派2的B型。但是安装时获得的版本是相当旧的。想要获得新版FPC和Lazarus请看链接 [相关文章](http://www.tweaking4all.com/hardware/raspberry-pi/install-lazarus-pascal-on-raspberry-pi-2/).
3131
3232<File:Lazarus> 0 9 30 4 on RPi 2.png\|Lazarus "out of the box" on Raspberry Pi 2
3333
3434### 从Windows 对Raspberry Pi的交叉编译
3535
36361\. 使用 fpcup
3737
3838使用fpcup是实现交叉编译的一种方法,输入下面的指令: [[fpcup|fpcup#Linux_ARM_cross_compiler]]
3939
40402\. 使用脚本
4141
4242可以使用手动批处理文件,按照以下步骤。
4343
44442.1 先决条件
4545
4646`FPC 2.7.1或更高的安装源代码`\
4747`下载并安装Windows版本的Linaro binutils for linux gnueabihf到%FPCPATH%/bin/win32-armhf-linux `[`1`](https://launchpad.net/linaro-toolchain-binaries/trunk/2013.10/+download/gcc-linaro-arm-linux-gnueabihf-4.8-2013.10_win32.zip)
4848
49492.2 创建脚本(需要匹配实际路径)
5050
5151``` bat
5252set PATH=C:\pp\bin\i386-win32;%PATH%;
5353set FPCMAKEPATH=C:/pp
5454set FPCPATH=C:/pp
5555set OUTPATH=C:/pp271
5656%FPCMAKEPATH%/bin/i386-win32/make distclean OS_TARGET=linux CPU_TARGET=arm CROSSBINDIR=%FPCPATH%/bin/win32-armhf-linux CROSSOPT="-CpARMV6 -CfVFPV2 -OoFASTMATH" FPC=%FPCPATH%/bin/i386-win32/ppc386.exe
5757
5858%FPCMAKEPATH%/bin/i386-win32/make all OS_TARGET=linux CPU_TARGET=arm CROSSBINDIR=%FPCPATH%/bin/win32-armhf-linux CROSSOPT="-CpARMV6 -CfVFPV2 -OoFASTMATH" FPC=%FPCPATH%/bin/i386-win32/ppc386.exe
5959if errorlevel 1 goto quit
6060%FPCMAKEPATH%/bin/i386-win32/make crossinstall CROSSBINDIR=%FPCPATH%/bin/win32-armhf-linux CROSSOPT="-CpARMV6 -CfVFPV2 -OoFASTMATH" OS_TARGET=linux CPU_TARGET=arm FPC=%FPCPATH%/bin/i386-win32/ppc386.exe INSTALL_BASEDIR=%OUTPATH%
6161
6262:quit
6363pause
6464```
6565
6666使用生成的ppcrossarm.exe和 ARM RTL,你可以创建跨平台的Lazarus工程,生成Raspberry Pi和其他armhf设备的应用程序。 注意,这里不包括所有Window 库。
6767
6868### 编译源代码
6969
7070如果你想要从Subversion编译Lazarus源代码。请看 \[<http://www.michellcomputing.co.uk/blog/?p=72>: Michell Computing: Lazarus on the Raspberry Pi\]
7171
7272<File:Start> Menu with Lazarus en.png\|How to start Lazarus in Raspbian Wheezy <File:Lazarus> on Raspberry Pi.jpg\|Lazarus on Raspberry Pi <File:rpi> gpio pins.png\|Numbering of GPIO pins
7373
7474用Gentoo(及其他版本)在Raspberry上编译源码
7575
7676- Gentoo是一个基于Linux的自由操作系统
7777
7878------------------------------------------------------------------------
7979
8080如果你想安装最新版的FPC及附件,或者是集成FPC编译器:请阅读下面的指南 这是关于Gentoo的例子,本指南适用其他版本:[[Install fpc on Raspberry with Gentoo]]
8181
8282## 访问外部硬件
8383
84-<figure>
8584<img src="rpi_pinout_all_50.png" title="Raspberry Pi 外部连接引脚" width="300" />
86-<figcaption>Raspberry Pi 外部连接引脚</figcaption>
87-</figure>
8885
8986Raspberry Pi的发展的目标之一是方便轻松地访问外部设备,如传感器和控制器。Lazarus有五种方法来访问I/O设备:
9087
91881. [[Lazarus on Raspberry Pi|原生代码直接访问]],使用[[BaseUnix]]单元
92892. 通过 [[Lazarus on Raspberry Pi|封装外壳调用]]
93903. 通过 [[Lazarus on Raspberry Pi|wiringPi 库]].
94914. 使用单元 [[Lazarus on Raspberry Pi|rpi_hal]].
95925. 使用单元 [[Lazarus on Raspberry Pi|PiGpio]].
96936. 通过 [PascalIO](https://github.com/SAmeis/pascalio) 库访问.
9794
9895### 1. 原生代码直接访问
9996
10097![对Raspberry Pi的GPIO端口访问的简单测试程序\|thumb\|300px\|right](/wiki-images/d/d2/Testprogram_for_GPIO_on_RPI_annotated.png) ![程序访问GPIO的测试电路\|thumb\|300px\|right](/wiki-images/7/7c/Rpi_testcircuit_1d.png) ![演示实现电路\|thumb\|300px\|right](/wiki-images/7/7e/Rpi_testcircuit_1p_annotaded.png)
10198
10299这种访问外部硬件的方法,不需要额外的库。唯一的要求是baseunix库,这是Free Pascal的RTL部分。
103100
104101#### 通过GPIO端口控制开关
105102
106103下面将演示一个简单程序。控制GPIO的17号引脚的电压,可以用来控制LED、晶体管或继电器。 程序包含*GPIO17ToggleBox*的实例[[doc:lcl/stdctrls/ttogglebox.html|ToggleBox]]和日志返回*LogMemo*类的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]。
107104
108105例如,一个LED的阳极连接到引脚11上(BCM2835 SoC对应的GPIO为17)和LED的阴极通过一个68欧姆的电阻连接引脚6(GND)。随后,LED会随着应用程序的toggle box切换点亮和熄灭。
109106
110107该代码需要root权限运行,即从root帐号(不推荐)运行或通过“*su*'。
111108
112109*控制单元:*
113110
114111``` pascal
115112unit Unit1;
116113
117114{Demo application for GPIO on Raspberry Pi}
118115{Inspired by the Python input/output demo application by Gareth Halfacree}
119116{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
120117
121118{$mode objfpc}{$H+}
122119
123120interface
124121
125122uses
126123 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
127124 Unix, BaseUnix;
128125
129126type
130127
131128 { TForm1 }
132129
133130 TForm1 = class(TForm)
134131 LogMemo: TMemo;
135132 GPIO17ToggleBox: TToggleBox;
136133 procedure FormActivate(Sender: TObject);
137134 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
138135 procedure GPIO17ToggleBoxChange(Sender: TObject);
139136 private
140137 { private declarations }
141138 public
142139 { public declarations }
143140 end;
144141
145142const
146143 PIN_17: PChar = '17';
147144 PIN_ON: PChar = '1';
148145 PIN_OFF: PChar = '0';
149146 OUT_DIRECTION: PChar = 'out';
150147
151148var
152149 Form1: TForm1;
153150 gReturnCode: longint; {stores the result of the IO operation}
154151
155152implementation
156153
157154{$R *.lfm}
158155
159156{ TForm1 }
160157
161158procedure TForm1.FormActivate(Sender: TObject);
162159var
163160 fileDesc: integer;
164161begin
165162 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
166163 try
167164 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
168165 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
169166 LogMemo.Lines.Add(IntToStr(gReturnCode));
170167 finally
171168 gReturnCode := fpclose(fileDesc);
172169 LogMemo.Lines.Add(IntToStr(gReturnCode));
173170 end;
174171 { Set SoC pin 17 as output: }
175172 try
176173 fileDesc := fpopen('/sys/class/gpio/gpio17/direction', O_WrOnly);
177174 gReturnCode := fpwrite(fileDesc, OUT_DIRECTION[0], 3);
178175 LogMemo.Lines.Add(IntToStr(gReturnCode));
179176 finally
180177 gReturnCode := fpclose(fileDesc);
181178 LogMemo.Lines.Add(IntToStr(gReturnCode));
182179 end;
183180end;
184181
185182procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
186183var
187184 fileDesc: integer;
188185begin
189186 { Free SoC pin 17: }
190187 try
191188 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
192189 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
193190 LogMemo.Lines.Add(IntToStr(gReturnCode));
194191 finally
195192 gReturnCode := fpclose(fileDesc);
196193 LogMemo.Lines.Add(IntToStr(gReturnCode));
197194 end;
198195end;
199196
200197procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
201198var
202199 fileDesc: integer;
203200begin
204201 if GPIO17ToggleBox.Checked then
205202 begin
206203 { Swith SoC pin 17 on: }
207204 try
208205 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
209206 gReturnCode := fpwrite(fileDesc, PIN_ON[0], 1);
210207 LogMemo.Lines.Add(IntToStr(gReturnCode));
211208 finally
212209 gReturnCode := fpclose(fileDesc);
213210 LogMemo.Lines.Add(IntToStr(gReturnCode));
214211 end;
215212 end
216213 else
217214 begin
218215 { Switch SoC pin 17 off: }
219216 try
220217 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
221218 gReturnCode := fpwrite(fileDesc, PIN_OFF[0], 1);
222219 LogMemo.Lines.Add(IntToStr(gReturnCode));
223220 finally
224221 gReturnCode := fpclose(fileDesc);
225222 LogMemo.Lines.Add(IntToStr(gReturnCode));
226223 end;
227224 end;
228225end;
229226
230227end.
231228```
232229
233230*Main program:*
234231
235232``` pascal
236233program io_test;
237234
238235{$mode objfpc}{$H+}
239236
240237uses
241238 {$IFDEF UNIX}{$IFDEF UseCThreads}
242239 cthreads,
243240 {$ENDIF}{$ENDIF}
244241 Interfaces, // this includes the LCL widgetset
245242 Forms, Unit1
246243 { you can add units after this };
247244
248245{$R *.res}
249246
250247begin
251248 Application.Initialize;
252249 Application.CreateForm(TForm1, Form1);
253250 Application.Run;
254251end.
255252```
256253
257254#### 读取引脚的状态
258255
259256![读取一个GPIO引脚状态的演示程序\|thumb\|300px\|right](/wiki-images/7/73/2013-04-28-193243_1280x1024_scrot.png) ![程序访问GPIO的测试电路\|thumb\|300px\|right](/wiki-images/f/f4/Rpi_testcircuit_2d.png) ![实际电路\|thumb\|300px\|right](/wiki-images/2/2f/Rpi_testcircuit_2p_annotaded.png)
260257
261258当然也可以从GPIO端口读取一个开关的状态。
262259
263260下面的简单例子非常类似于前一个例子。使用GPIO的18号引脚,控制二进制设备如开关输入,晶体管或继电器。这个程序包含一个名称为[[doc:lcl/stdctrls/tcheckbox.html|CheckBox]]的*GPIO18CheckBox* 与*LogMemo*的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]日志返回代码。
264261
265262在实例中,第12引脚的一端连接一个按钮,按钮的一端(对应的GPIO引脚18的BCM2835 SoC)通过一个10欧姆的上拉电阻和引脚1连接(+3.3 V,看接线图)。按钮的另一端连接6号引脚(GND)。按钮的开关状态对应和程序中复选框的打开或关闭状态对应。
266263
267264注意,当按钮释放时18脚的电位为高(由通过上拉电阻连接到引脚1),当按钮压下时电压为低(因为在这种情况下,引脚18是通过开关连接到GND)。因此,按钮按下时GPIO引脚信号为0,当释放时信号为1。
268265
269266这个程序同样需要root权限
270267
271268*控制单元:*
272269
273270``` pascal
274271unit Unit1;
275272
276273{Demo application for GPIO on Raspberry Pi}
277274{Inspired by the Python input/output demo application by Gareth Halfacree}
278275{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
279276
280277{This application reads the status of a push-button}
281278
282279{$mode objfpc}{$H+}
283280
284281interface
285282
286283uses
287284 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
288285 ButtonPanel, Unix, BaseUnix;
289286
290287type
291288
292289 { TForm1 }
293290
294291 TForm1 = class(TForm)
295292 ApplicationProperties1: TApplicationProperties;
296293 GPIO18CheckBox: TCheckBox;
297294 LogMemo: TMemo;
298295 procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
299296 procedure FormActivate(Sender: TObject);
300297 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
301298 private
302299 { private declarations }
303300 public
304301 { public declarations }
305302 end;
306303
307304const
308305 PIN_18: PChar = '18';
309306 IN_DIRECTION: PChar = 'in';
310307
311308var
312309 Form1: TForm1;
313310 gReturnCode: longint; {stores the result of the IO operation}
314311
315312implementation
316313
317314{$R *.lfm}
318315
319316{ TForm1 }
320317
321318procedure TForm1.FormActivate(Sender: TObject);
322319var
323320 fileDesc: integer;
324321begin
325322 { Prepare SoC pin 18 (pin 12 on GPIO port) for access: }
326323 try
327324 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
328325 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
329326 LogMemo.Lines.Add(IntToStr(gReturnCode));
330327 finally
331328 gReturnCode := fpclose(fileDesc);
332329 LogMemo.Lines.Add(IntToStr(gReturnCode));
333330 end;
334331 { Set SoC pin 18 as input: }
335332 try
336333 fileDesc := fpopen('/sys/class/gpio/gpio18/direction', O_WrOnly);
337334 gReturnCode := fpwrite(fileDesc, IN_DIRECTION[0], 2);
338335 LogMemo.Lines.Add(IntToStr(gReturnCode));
339336 finally
340337 gReturnCode := fpclose(fileDesc);
341338 LogMemo.Lines.Add(IntToStr(gReturnCode));
342339 end;
343340end;
344341
345342procedure TForm1.ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
346343var
347344 fileDesc: integer;
348345 buttonStatus: string[1] = '1';
349346begin
350347 try
351348 { Open SoC pin 18 (pin 12 on GPIO port) in read-only mode: }
352349 fileDesc := fpopen('/sys/class/gpio/gpio18/value', O_RdOnly);
353350 if fileDesc > 0 then
354351 begin
355352 { Read status of this pin (0: button pressed, 1: button released): }
356353 gReturnCode := fpread(fileDesc, buttonStatus[1], 1);
357354 LogMemo.Lines.Add(IntToStr(gReturnCode) + ': ' + buttonStatus);
358355 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
359356 if buttonStatus = '0' then
360357 GPIO18CheckBox.Checked := true
361358 else
362359 GPIO18CheckBox.Checked := false;
363360 end;
364361 finally
365362 { Close SoC pin 18 (pin 12 on GPIO port) }
366363 gReturnCode := fpclose(fileDesc);
367364 LogMemo.Lines.Add(IntToStr(gReturnCode));
368365 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
369366 end;
370367end;
371368
372369procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
373370var
374371 fileDesc: integer;
375372begin
376373 { Free SoC pin 18: }
377374 try
378375 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
379376 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
380377 LogMemo.Lines.Add(IntToStr(gReturnCode));
381378 finally
382379 gReturnCode := fpclose(fileDesc);
383380 LogMemo.Lines.Add(IntToStr(gReturnCode));
384381 end;
385382end;
386383
387384end.
388385```
389386
390387上面的例子主程序是相同的,。
391388
392389### 2. 通过封装的外壳访问硬件
393390
394391访问硬件的另一种方法是通过封装终端命令。这是通过使用[[Executing External Programs|fpsystem]]功能。这种方法可以访问baseunix单元不支持的功能。下面的代码实现了一个具有相同功能的程序,该程序是从上面的第一个清单所产生的。
395392
396393*控制单元:*
397394
398395``` pascal
399396unit Unit1;
400397
401398{Demo application for GPIO on Raspberry Pi}
402399{Inspired by the Python input/output demo application by Gareth Halfacree}
403400{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
404401
405402{$mode objfpc}{$H+}
406403
407404interface
408405
409406uses
410407 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Unix;
411408
412409type
413410
414411 { TForm1 }
415412
416413 TForm1 = class(TForm)
417414 LogMemo: TMemo;
418415 GPIO17ToggleBox: TToggleBox;
419416 procedure FormActivate(Sender: TObject);
420417 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
421418 procedure GPIO17ToggleBoxChange(Sender: TObject);
422419 private
423420 { private declarations }
424421 public
425422 { public declarations }
426423 end;
427424
428425var
429426 Form1: TForm1;
430427 gReturnCode: longint; {stores the result of the IO operation}
431428
432429implementation
433430
434431{$R *.lfm}
435432
436433{ TForm1 }
437434
438435procedure TForm1.FormActivate(Sender: TObject);
439436begin
440437 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
441438 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/export');
442439 LogMemo.Lines.Add(IntToStr(gReturnCode));
443440 { Set SoC pin 17 as output: }
444441 gReturnCode := fpsystem('echo "out" > /sys/class/gpio/gpio17/direction');
445442 LogMemo.Lines.Add(IntToStr(gReturnCode));
446443end;
447444
448445procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
449446begin
450447 { Free SoC pin 17: }
451448 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/unexport');
452449 LogMemo.Lines.Add(IntToStr(gReturnCode));
453450end;
454451
455452procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
456453begin
457454 if GPIO17ToggleBox.Checked then
458455 begin
459456 { Swith SoC pin 17 on: }
460457 gReturnCode := fpsystem('echo "1" > /sys/class/gpio/gpio17/value');
461458 LogMemo.Lines.Add(IntToStr(gReturnCode));
462459 end
463460 else
464461 begin
465462 { Switch SoC pin 17 off: }
466463 gReturnCode := fpsystem('echo "0" > /sys/class/gpio/gpio17/value');
467464 LogMemo.Lines.Add(IntToStr(gReturnCode));
468465 end;
469466end;
470467
471468end.
472469```
473470
474471主程序与上面的例子相同。这个程序必须用根权限执行。
475472
476473### 3. wiringPi方法与函数
477474
478475Alex Schaller封装的Gordon Henderson的Arduino兼容wiringpi库,提供了一种类似Arduino电路板的编码方案。
479476
480477**Function wiringPiSetup:longint:** 使用wiringpi引脚编号方案初始化wiringpi系统
481478
482479**Procedure wiringPiGpioMode(mode:longint):** 用Broadcom的GPIO引脚编号方案wiringpi初始化系统。
483480
484481**Procedure pullUpDnControl(pin:longint;** pud:longint): 控制内部GPIO引脚上拉/下拉电阻。
485482
486483**Procedure pinMode(pin:longint; mode:longint):** 设置一个PIN的模式:输入、输出或pwm_output。
487484
488485**Procedure digitalWrite(pin:longint; value:longint):** 设置一个输出位。
489486
490487**Procedure pwmWrite(pin:longint; value:longint):** 设置一个输出PWM(脉宽调制)值,0到1024之间。
491488
492489**Function digitalRead(pin:longint):longint:** 读取一个给定引脚的值,返回1或0。
493490
494491**Procedure delay(howLong:dword):** 等待多少毫秒。
495492
496493**Procedure delayMicroseconds(howLong:dword):** 等待多少微秒。
497494
498495**Function millis:dword:** 返回程序调用wiringpisetup函数花费的毫秒数。
499496
500497### 4. rpi_hal-hardware抽象库 (GPIO, I2C and SPI 函数与方法)
501498
502499这个单元大约1700行代码,由Stefan Fischer提供,提供程序和函数访问RPI硬件I2C,SPI和GPIO:
503500
504501下面是函数和方法的摘录:
505502
506503**procedure gpio_set_pin (pin:longword;highlevel:boolean);** { 设置 RPi GPIO 引脚速率为高或低; 速率 @ 700MHz -\> 0.65MHz }
507504
508505**function gpio_get_PIN (pin:longword):boolean;** { 获取 RPi GPIO 引脚等级,当Pin为'1'时返回True,为'0'时返回false; 速率 @ 700MHz -\> 1.17MHz }
509506
510507**procedure gpio_set_input (pin:longword);** { 设置 RPi GPIO 引脚为直接输入}
511508
512509**procedure gpio_set_output(pin:longword);** { 设置 RPi GPIO 引脚为直接输出 }
513510
514511**procedure gpio_set_alt (pin,altfunc:longword);** { 设置 RPi GPIO 引脚为备用功能 0..5 }
515512
516513**procedure gpio_set_gppud (mask:longword);** { 设置RPI GPIO拉上/下登记(gppud)}
517514
518515...
519516
520517**function rpi_snr :string;** { 信噪比: 0000000012345678 }
521518
522519**function rpi_hw :string;** { 处理器类型: BCM2708 }
523520
524521**function rpi_proc:string;** { ARMv6-compatible processor rev 7 (v6l) }
525522
526523...
527524
528525**function i2c_bus_write(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
529526
530527**function i2c_bus_read (baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
531528
532529**function i2c_string_read(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : string;**
533530
534531**function i2c_string_write(baseadr,reg:word; s:string; testnr:integer) : integer;**
535532
536533...
537534
538535**procedure SPI_Write(devnum:byte; reg,data:word);**
539536
540537**function SPI_Read(devnum:byte; reg:word) : byte;**
541538
542539**procedure SPI_BurstRead2Buffer (devnum,start_reg:byte; xferlen:longword);**
543540
544541**procedure SPI_BurstWriteBuffer (devnum,start_reg:byte; xferlen:longword);** { 从缓冲区SPI的地址写入一段字节的内容 }
545542
546543...
547544
548545*测试程序 (testrpi.pas):*
549546
550547``` pascal
551548//Simple Test program, which is using rpi_hal;
552549
553550 program testrpi;
554551 uses rpi_hal;
555552 begin
556553 writeln('Show CPU-Info, RPI-HW-Info and Registers:');
557554 rpi_show_all_info;
558555 writeln('Let Status LED Blink. Using GPIO functions:');
559556 GPIO_PIN_TOGGLE_TEST;
560557 writeln('Test SPI Read function. (piggy back board with installed RFM22B Module is required!)');
561558 Test_SPI;
562559 end.
563560```
564561
565562### 5. 底层pascal单元 PiGpio(代替wiringpi C语言库的GPIO控制)
566563
567564*这个单元 (pigpio.pas[2](https://docs.google.com/file/d/0B-b-5ooIWPvGN1BIcEJzRDgyeUE/edit?usp=sharing)) 270 行代码是由Gabor Szollosi提供的 , 运行速度飞快(例如GPIO引脚输出开关频率达到8MHz) :*
568565
569566``` pascal
570567unit PiGpio;
571568{
572569 BCM2835 GPIO Registry Driver, also can use to manipulate cpu other registry areas
573570
574571 This code is tested only Broadcom bcm2835 cpu, different arm cpus may need different
575572 gpio driver implementation
576573
577574 2013 Gabor Szollosi
578575}
579576{$mode objfpc}{$H+}
580577
581578interface
582579
583580uses
584581 Classes, SysUtils;
585582
586583const
587584 REG_GPIO = $20000;//bcm2835 gpio register 0x2000 0000. new fpMap uses page offset, one page is 4096bytes
588585 // hex 0x1000 so simply calculate 0x2000 0000 / 0x1000 = 0x2000 0
589586 PAGE_SIZE = 4096;
590587 BLOCK_SIZE = 4096;
591588 // The BCM2835 has 54 GPIO pins.
592589// BCM2835 data sheet, Page 90 onwards.
593590// There are 6 control registers, each control the functions of a block
594591// of 10 pins.
595592
596593 CLOCK_BASE = (REG_GPIO + $101);
597594 GPIO_BASE = (REG_GPIO + $200);
598595 GPIO_PWM = (REG_GPIO + $20C);
599596
600597 INPUT = 0;
601598 OUTPUT = 1;
602599 PWM_OUTPUT = 2;
603600 LOW = False;
604601 HIGH = True;
605602 PUD_OFF = 0;
606603 PUD_DOWN = 1;
607604 PUD_UP = 2;
608605
609606 // PWM
610607
611608 PWM_CONTROL = 0;
612609 PWM_STATUS = 4;
613610 PWM0_RANGE = 16;
614611 PWM0_DATA = 20;
615612 PWM1_RANGE = 32;
616613 PWM1_DATA = 36;
617614
618615 PWMCLK_CNTL = 160;
619616 PWMCLK_DIV = 164;
620617
621618 PWM1_MS_MODE = $8000; // Run in MS mode
622619 PWM1_USEFIFO = $2000; // Data from FIFO
623620 PWM1_REVPOLAR = $1000; // Reverse polarity
624621 PWM1_OFFSTATE = $0800; // Ouput Off state
625622 PWM1_REPEATFF = $0400; // Repeat last value if FIFO empty
626623 PWM1_SERIAL = $0200; // Run in serial mode
627624 PWM1_ENABLE = $0100; // Channel Enable
628625
629626 PWM0_MS_MODE = $0080; // Run in MS mode
630627 PWM0_USEFIFO = $0020; // Data from FIFO
631628 PWM0_REVPOLAR = $0010; // Reverse polarity
632629 PWM0_OFFSTATE = $0008; // Ouput Off state
633630 PWM0_REPEATFF = $0004; // Repeat last value if FIFO empty
634631 PWM0_SERIAL = $0002; // Run in serial mode
635632 PWM0_ENABLE = $0001; // Channel Enable
636633
637634type
638635
639636 { TIoPort }
640637
641638 TIoPort = class // IO bank object
642639 private //
643640
644641 //function get_pinDirection(aPin: TGpIoPin): TGpioPinConf;
645642
646643 public
647644 FGpio: ^LongWord;
648645 FClk: ^LongWord;
649646 FPwm: ^LongWord;
650647 procedure SetPinMode(gpin, mode: byte);
651648 function GetBit(gpin : byte):boolean;inline; // gets pin bit}
652649 procedure ClearBit(gpin : byte);inline;// write pin to 0
653650 procedure SetBit(gpin : byte);inline;// write pin to 1
654651 procedure SetPullMode(gpin, mode: byte);
655652 procedure PwmWrite(gpin : byte; value : LongWord);inline;// write pin to pwm value
656653 end;
657654
658655 { TIoDriver }
659656
660657 TIoDriver = class
661658 private
662659
663660 public
664661 destructor Destroy;override;
665662 function MapIo:boolean;// creates io memory mapping
666663 procedure UnmapIoRegisrty(FMap: TIoPort);// close io memory mapping
667664 function CreatePort(PortGpio, PortClk, PortPwm: LongWord):TIoPort; // create new IO port
668665 end;
669666
670667var
671668
672669 fd: integer;// /dev/mem file handle
673670procedure delayNanoseconds (howLong : LongWord);
674671
675672implementation
676673
677674uses
678675 baseUnix, Unix;
679676
680677procedure delayNanoseconds (howLong : LongWord);
681678var
682679 sleeper, dummy : timespec;
683680begin
684681 sleeper.tv_sec := 0 ;
685682 sleeper.tv_nsec := howLong ;
686683 fpnanosleep (@sleeper,@dummy) ;
687684end;
688685{ TIoDriver }
689686//*******************************************************************************
690687destructor TIoDriver.Destroy;
691688begin
692689 inherited Destroy;
693690end;
694691//*******************************************************************************
695692function TIoDriver.MapIo: boolean;
696693begin
697694 Result := True;
698695 fd := fpopen('/dev/mem', O_RdWr or O_Sync); // Open the master /dev/memory device
699696 if fd < 0 then
700697 begin
701698 Result := False; // unsuccessful memory mapping
702699 end;
703700 //
704701end;
705702//*******************************************************************************
706703procedure TIoDriver.UnmapIoRegisrty(FMap:TIoPort);
707704begin
708705 if FMap.FGpio <> nil then
709706 begin
710707 fpMUnmap(FMap.FGpio,PAGE_SIZE);
711708 FMap.FGpio := Nil;
712709 end;
713710 if FMap.FClk <> nil then
714711 begin
715712 fpMUnmap(FMap.FClk,PAGE_SIZE);
716713 FMap.FClk := Nil;
717714 end;
718715 if FMap.FPwm <> nil then
719716 begin
720717 fpMUnmap(FMap.FPwm ,PAGE_SIZE);
721718 FMap.FPwm := Nil;
722719 end;
723720end;
724721//*******************************************************************************
725722function TIoDriver.CreatePort(PortGpio, PortClk, PortPwm: LongWord): TIoPort;
726723begin
727724 Result := TIoPort.Create;// new io port, pascal calls new fpMap, where offst is page sized 4096 bytes!!!
728725 Result.FGpio := FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortGpio); // port config gpio memory
729726 Result.FClk:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortClk);; // port clk
730727 Result.FPwm:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortPwm);; // port pwm
731728end;
732729//*******************************************************************************
733730procedure TIoPort.SetPinMode(gpin, mode: byte);
734731var
735732 fSel, shift, alt : byte;
736733 gpiof, clkf, pwmf : ^LongWord;
737734begin
738735 fSel := (gpin div 10)*4 ; //Select Gpfsel 0 to 5 register
739736 shift := (gpin mod 10)*3 ; //0-9 pin shift
740737 gpiof := Pointer(LongWord(Self.FGpio)+fSel);
741738 if (mode = INPUT) then
742739 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) //7 shl shift komplemens - Sets bits to zero = input
743740 else if (mode = OUTPUT) then
744741 begin
745742 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (1 shl shift);
746743 end
747744 else if (mode = PWM_OUTPUT) then
748745 begin
749746 Case gpin of
750747 12,13,40,41,45 : alt:= 4 ;
751748 18,19 : alt:= 2 ;
752749 else alt:= 0 ;
753750 end;
754751 If alt > 0 then
755752 begin
756753 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (alt shl shift);
757754 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
758755 clkf^ := $5A000011 or (1 shl 5) ; //stop clock
759756 delayNanoseconds(200);
760757 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_DIV);
761758 clkf^ := $5A000000 or (32 shl 12) ; // set pwm clock div to 32 (19.2/3 = 600KHz)
762759 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
763760 clkf^ := $5A000011 ; //start clock
764761 Self.ClearBit(gpin);
765762 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
766763 pwmf^ := 0 ; // Disable PWM
767764 delayNanoseconds(200);
768765 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_RANGE);
769766 pwmf^ := $400 ; //max: 1023
770767 delayNanoseconds(200);
771768 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_RANGE);
772769 pwmf^ := $400 ; //max: 1023
773770 delayNanoseconds(200);
774771 // Enable PWMs
775772 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_DATA);
776773 pwmf^ := 0 ; //start value
777774 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_DATA);
778775 pwmf^ := 0 ; //start value
779776 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
780777 pwmf^ := PWM0_ENABLE or PWM1_ENABLE ;
781778 end;
782779 end;
783780end;
784781//*******************************************************************************
785782procedure TIoPort.SetBit(gpin : byte);
786783var
787784 gpiof : ^LongWord;
788785begin
789786 gpiof := Pointer(LongWord(Self.FGpio) + 28 + (gpin shr 5) shl 2);
790787 gpiof^ := 1 shl gpin;
791788end;
792789//*******************************************************************************
793790procedure TIoPort.ClearBit(gpin : byte);
794791var
795792 gpiof : ^LongWord;
796793begin
797794 gpiof := Pointer(LongWord(Self.FGpio) + 40 + (gpin shr 5) shl 2);
798795 gpiof^ := 1 shl gpin;
799796end;
800797//*******************************************************************************
801798function TIoPort.GetBit(gpin : byte):boolean;
802799var
803800 gpiof : ^LongWord;
804801begin
805802 gpiof := Pointer(LongWord(Self.FGpio) + 52 + (gpin shr 5) shl 2);
806803 if (gpiof^ and (1 shl gpin)) = 0 then Result := False else Result := True;
807804end;
808805//*******************************************************************************
809806procedure TIoPort.SetPullMode(gpin, mode: byte);
810807var
811808 pudf, pudclkf : ^LongWord;
812809begin
813810 pudf := Pointer(LongWord(Self.FGpio) + 148 );
814811 pudf^ := mode; //mode = 0, 1, 2 :Off, Down, Up
815812 delayNanoseconds(200);
816813 pudclkf := Pointer(LongWord(Self.FGpio) + 152 + (gpin shr 5) shl 2);
817814 pudclkf^ := 1 shl gpin ;
818815 delayNanoseconds(200);
819816 pudf^ := 0 ;
820817 pudclkf^ := 0 ;
821818end;
822819//*******************************************************************************
823820procedure TIoPort.PwmWrite(gpin : byte; value : Longword);
824821var
825822 pwmf : ^LongWord;
826823 port : byte;
827824begin
828825 Case gpin of
829826 12,18,40 : port:= PWM0_DATA ;
830827 13,19,41,45 : port:= PWM1_DATA ;
831828 else exit;
832829 end;
833830 pwmf := Pointer(LongWord(Self.FPwm) + port);
834831 pwmf^ := value and $FFFFFBFF; // $400 complemens
835832end;
836833//*******************************************************************************
837834end.
838835```
839836
840837*Controlling Lazarus unit:(Project files[3](https://drive.google.com/folderview?id=0B-b-5ooIWPvGU043ZTZ0cUc2YkE&usp=sharing))*
841838
842839``` pascal
843840unit Unit1;
844841
845842{Demo application for GPIO on Raspberry Pi}
846843{Inspired by the Python input/output demo application by Gareth Halfacree}
847844{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
848845
849846{$mode objfpc}{$H+}
850847
851848interface
852849
853850uses
854851 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
855852 ExtCtrls, Unix, PiGpio;
856853
857854type
858855
859856 { TForm1 }
860857
861858 TForm1 = class(TForm)
862859 GPIO25In: TButton;
863860 SpeedButton: TButton;
864861 LogMemo: TMemo;
865862 GPIO23switch: TToggleBox;
866863 Timer1: TTimer;
867864 GPIO18Pwm: TToggleBox;
868865 Direction: TToggleBox;
869866 procedure DirectionChange(Sender: TObject);
870867 procedure GPIO18PwmChange(Sender: TObject);
871868 procedure GPIO25InClick(Sender: TObject);
872869 procedure FormActivate(Sender: TObject);
873870 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
874871 procedure GPIO23switchChange(Sender: TObject);
875872 procedure SpeedButtonClick(Sender: TObject);
876873 procedure Timer1Timer(Sender: TObject);
877874 private
878875 { private declarations }
879876 public
880877 { public declarations }
881878 end;
882879
883880const
884881 INPUT = 0;
885882 OUTPUT = 1;
886883 PWM_OUTPUT = 2;
887884 LOW = False;
888885 HIGH = True;
889886 PUD_OFF = 0;
890887 PUD_DOWN = 1;
891888 PUD_UP = 2;
892889 // Convert Raspberry Pi P1 pins (Px) to GPIO port
893890 P3 = 0;
894891 P5 = 1;
895892 P7 = 4;
896893 P8 = 14;
897894 P10 = 15;
898895 P11 = 17;
899896 P12 = 18;
900897 P13 = 21;
901898 P15 = 22;
902899 P16 = 23;
903900 P18 = 24;
904901 P19 = 10;
905902 P21 = 9;
906903 P22 = 25;
907904 P23 = 11;
908905 P24 = 8;
909906 P26 = 7;
910907
911908var
912909 Form1: TForm1;
913910 GPIO_Driver: TIoDriver;
914911 GpF: TIoPort;
915912 PWM :Boolean;
916913 i, d : integer;
917914 Pin,Pout,Ppwm : byte;
918915
919916implementation
920917
921918{$R *.lfm}
922919
923920{ TForm1 }
924921
925922procedure TForm1.FormActivate(Sender: TObject);
926923begin
927924 if not GPIO_Driver.MapIo then
928925 begin
929926 LogMemo.Lines.Add('Error mapping gpio registry');
930927 end
931928 else
932929 begin
933930 GpF := GpIo_Driver.CreatePort(GPIO_BASE, CLOCK_BASE, GPIO_PWM);
934931 end ;
935932 Timer1.Enabled:= True;
936933 Timer1.Interval:= 25; //25 ms controll interval
937934 Pin := P22;
938935 Pout := P16;
939936 Ppwm := P12;
940937 i:=1;
941938 GpF.SetPinMode(Pout,OUTPUT);
942939 GpF.SetPinMode(Pin,INPUT);
943940 GpF.SetPullMode(Pin,PUD_Up); // Input PullUp High level
944941end;
945942
946943procedure TForm1.GPIO25InClick(Sender: TObject);
947944begin
948945 If GpF.GetBit(Pin) then LogMemo.Lines.Add('In: '+IntToStr(1))
949946 else LogMemo.Lines.Add('In: '+IntToStr(0));
950947end;
951948
952949procedure TForm1.GPIO18PwmChange(Sender: TObject);
953950begin
954951 if GPIO18Pwm.Checked then
955952 begin
956953 GpF.SetPinMode(Ppwm,PWM_OUTPUT);
957954 PWM := True; //PWM on
958955 end
959956 else
960957 begin
961958 GpF.SetPinMode(Ppwm,INPUT);
962959 PWM := False; //PWM off
963960 end;
964961end;
965962
966963procedure TForm1.DirectionChange(Sender: TObject);
967964begin
968965 if Direction.Checked then d:=10 else d:=-10;
969966end;
970967
971968
972969procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
973970begin
974971 GpF.SetPinMode(Ppwm,INPUT);
975972 GpF.ClearBit(Pout);
976973 GpIo_Driver.UnmapIoRegisrty(GpF);
977974end;
978975
979976procedure TForm1.GPIO23switchChange(Sender: TObject);
980977
981978Begin
982979 Timer1.Enabled := False;
983980 if GPIO23switch.Checked then
984981 begin
985982 GpF.SetBit(Pout); //Turn LED on
986983 end
987984 else
988985 begin
989986 GpF.ClearBit(Pout); //Turn LED off
990987 end;
991988 Timer1.Enabled := True;
992989end;
993990
994991procedure TForm1.SpeedButtonClick(Sender: TObject);
995992var
996993 i,p,k,v: longint;
997994 ido:TDateTime;
998995begin
999996 ido:= Time;
1000997 k:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
1001998 LogMemo.Lines.Add('Start: '+TimeToStr(ido));
1002999 p:=10000000 ;
10031000 For i:=1 to p do Begin
10041001 GpF.SetBit(P16);
10051002 GpF.ClearBit(P16);
10061003 end;
10071004 ido:= Time;
10081005 v:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
10091006 LogMemo.Lines.Add('Stop: '+TimeToStr(ido)+' Frequency: '+
10101007 IntToStr(p div (v-k))+' kHz');
10111008end;
10121009
10131010procedure TForm1.Timer1Timer(Sender: TObject);
10141011begin
10151012 If PWM then Begin
10161013 If (d > 0) and (i+d < 1024) then begin
10171014 i:=i+d;
10181015 GpF.PwmWrite(Ppwm,i);
10191016 end ;
10201017 If (d < 0) and (i+d > -1) then begin
10211018 i:=i+d;
10221019 GpF.PwmWrite(Ppwm,i);
10231020 end;
10241021 end;
10251022end;
10261023
10271024
10281025end.
10291026```
10301027
10311028## 参考
10321029
10331030- Eben Upton and Gareth Halfacree. Raspberry Pi User Guide. John Wiley and Sons, Chichester 2012, ISBN 111846446X
10341031- B. J. Rao (2013) The Raspberry Pi, Pi Vision and Lazarus/FPC. [Blaise Pascal Magazine](http://www.blaisepascal.eu). 29: 14-21.
10351032
10361033## 外部链接
10371034
10381035- [Raspberry Pi 基础](http://www.raspberrypi.org)
10391036- [Raspberry Pi Spy: Raspberry Pi tutorials, scripts, help and downloads](http://www.raspberrypi-spy.co.uk)
10401037- [Lazarus wrapper unit for Gordon Henderson's wiringPi C library](http://www.lazarus.freepascal.org/index.php/topic,17404.0.html)
10411038- [Pin layout of the wiringPi library](https://projects.drogon.net/raspberry-pi/wiringpi/pins/)
10421039- [Additional information on Lazarus and Raspberry Pi at eLinux.org](http://www.elinux.org/Lazarus_on_RPi)
10431040- [Getting Started with Pascal on the Pi](http://www.pp4s.co.uk/main/gs-pi-intro.html)
10441041- [Lazberry Pi: Comprehensive information on Lazarus on the Raspberry Pi computer](http://superbitysoft.co.uk/lazberrypi/).
10451042- [Stefan Fischer's Lazarus unit rpi_hal](http://www.lazarus.freepascal.org/index.php/topic,20991.0.html).
10461043- [Improved Lazarus Unit for fast access to GPIO](http://www.meltonisl.com/software.html).
10471044
10481045---
10491046*From the Free Pascal wiki, page "Lazarus on Raspberry Pi/zh CN", as it stood on 2020-02-19 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).*

Back to history