Sign in Join
Wiki copytemporary

Lazarus on Raspberry Pi/zh CN: what changed

Revision 3 to 4. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11树莓派上的Lazarus
22
33![Lazarus on Raspbian Wheezy](/wiki-images/e/ef/Lazarus_on_Raspberry_Pi_Raspian_Wheezy_version_2012-10-28.png) *(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
24-Install 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
24+![](/wiki-images/0/02/Install_Lazarus_Rasbian_Part1_en.png)
2525
26+安装步骤 1
27+
28+![](/wiki-images/4/4a/Install_Lazarus_Rasbian_Part2_en.png)
29+
30+安装步骤 2
31+
32+![](/wiki-images/5/53/Install_Lazarus_Rasbian_Part3_en.png)
33+
34+安装步骤 3
35+
36+![](/wiki-images/2/24/Install_Lazarus_Rasbian_Part4_en.png)
37+
38+安装步骤 4
39+
2640如果你需要一个新的版本,或者抱怨Lazarus 的问题, [点击](http://www.raspberrypi.org/forums/viewtopic.php?f=34&t=88145).
2741
2842#### Raspberry Pi 2
2943
3044自2015六月起,普通的“out of the box”安装方法也适用于安装树莓派2的B型。但是安装时获得的版本是相当旧的。想要获得新版FPC和Lazarus请看链接 [相关文章](http://www.tweaking4all.com/hardware/raspberry-pi/install-lazarus-pascal-on-raspberry-pi-2/).
3145
32-<File:Lazarus> 0 9 30 4 on RPi 2.png\|Lazarus "out of the box" on Raspberry Pi 2
46+![](/wiki-images/c/cc/Lazarus_0_9_30_4_on_RPi_2.png)
3347
48+Lazarus "out of the box" on Raspberry Pi 2
49+
3450### 从Windows 对Raspberry Pi的交叉编译
3551
36521\. 使用 fpcup
3753
3854使用fpcup是实现交叉编译的一种方法,输入下面的指令: [[fpcup|fpcup#Linux_ARM_cross_compiler]]
3955
40562\. 使用脚本
4157
4258可以使用手动批处理文件,按照以下步骤。
4359
44602.1 先决条件
4561
4662`FPC 2.7.1或更高的安装源代码`\
4763`下载并安装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)
4864
49652.2 创建脚本(需要匹配实际路径)
5066
5167``` bat
5268set PATH=C:\pp\bin\i386-win32;%PATH%;
5369set FPCMAKEPATH=C:/pp
5470set FPCPATH=C:/pp
5571set OUTPATH=C:/pp271
5672%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
5773
5874%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
5975if errorlevel 1 goto quit
6076%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%
6177
6278:quit
6379pause
6480```
6581
6682使用生成的ppcrossarm.exe和 ARM RTL,你可以创建跨平台的Lazarus工程,生成Raspberry Pi和其他armhf设备的应用程序。 注意,这里不包括所有Window 库。
6783
6884### 编译源代码
6985
7086如果你想要从Subversion编译Lazarus源代码。请看 \[<http://www.michellcomputing.co.uk/blog/?p=72>: Michell Computing: Lazarus on the Raspberry Pi\]
7187
72-<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
88+![](/wiki-images/8/8d/Start_Menu_with_Lazarus_en.png)
89+
90+How to start Lazarus in Raspbian Wheezy
91+
92+![](/wiki-images/8/87/Lazarus_on_Raspberry_Pi.jpg)
93+
94+Lazarus on Raspberry Pi
95+
96+![](/wiki-images/c/c7/Rpi_gpio_pins.png)
97+
98+Numbering of GPIO pins
7399
74100用Gentoo(及其他版本)在Raspberry上编译源码
75101
76102- Gentoo是一个基于Linux的自由操作系统
77103
78104------------------------------------------------------------------------
79105
80106如果你想安装最新版的FPC及附件,或者是集成FPC编译器:请阅读下面的指南 这是关于Gentoo的例子,本指南适用其他版本:[[Install fpc on Raspberry with Gentoo]]
81107
82108## 访问外部硬件
83109
84110![](/wiki-images/f/f2/Rpi_pinout_all_50.png)
85111
86112Raspberry Pi的发展的目标之一是方便轻松地访问外部设备,如传感器和控制器。Lazarus有五种方法来访问I/O设备:
87113
881141. [[Lazarus on Raspberry Pi|原生代码直接访问]],使用[[BaseUnix]]单元
891152. 通过 [[Lazarus on Raspberry Pi|封装外壳调用]]
901163. 通过 [[Lazarus on Raspberry Pi|wiringPi 库]].
911174. 使用单元 [[Lazarus on Raspberry Pi|rpi_hal]].
921185. 使用单元 [[Lazarus on Raspberry Pi|PiGpio]].
931196. 通过 [PascalIO](https://github.com/SAmeis/pascalio) 库访问.
94120
95121### 1. 原生代码直接访问
96122
97123![对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)
98124
99125这种访问外部硬件的方法,不需要额外的库。唯一的要求是baseunix库,这是Free Pascal的RTL部分。
100126
101127#### 通过GPIO端口控制开关
102128
103129下面将演示一个简单程序。控制GPIO的17号引脚的电压,可以用来控制LED、晶体管或继电器。 程序包含*GPIO17ToggleBox*的实例[[doc:lcl/stdctrls/ttogglebox.html|ToggleBox]]和日志返回*LogMemo*类的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]。
104130
105131例如,一个LED的阳极连接到引脚11上(BCM2835 SoC对应的GPIO为17)和LED的阴极通过一个68欧姆的电阻连接引脚6(GND)。随后,LED会随着应用程序的toggle box切换点亮和熄灭。
106132
107133该代码需要root权限运行,即从root帐号(不推荐)运行或通过“*su*'。
108134
109135*控制单元:*
110136
111137``` pascal
112138unit Unit1;
113139
114140{Demo application for GPIO on Raspberry Pi}
115141{Inspired by the Python input/output demo application by Gareth Halfacree}
116142{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
117143
118144{$mode objfpc}{$H+}
119145
120146interface
121147
122148uses
123149 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
124150 Unix, BaseUnix;
125151
126152type
127153
128154 { TForm1 }
129155
130156 TForm1 = class(TForm)
131157 LogMemo: TMemo;
132158 GPIO17ToggleBox: TToggleBox;
133159 procedure FormActivate(Sender: TObject);
134160 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
135161 procedure GPIO17ToggleBoxChange(Sender: TObject);
136162 private
137163 { private declarations }
138164 public
139165 { public declarations }
140166 end;
141167
142168const
143169 PIN_17: PChar = '17';
144170 PIN_ON: PChar = '1';
145171 PIN_OFF: PChar = '0';
146172 OUT_DIRECTION: PChar = 'out';
147173
148174var
149175 Form1: TForm1;
150176 gReturnCode: longint; {stores the result of the IO operation}
151177
152178implementation
153179
154180{$R *.lfm}
155181
156182{ TForm1 }
157183
158184procedure TForm1.FormActivate(Sender: TObject);
159185var
160186 fileDesc: integer;
161187begin
162188 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
163189 try
164190 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
165191 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
166192 LogMemo.Lines.Add(IntToStr(gReturnCode));
167193 finally
168194 gReturnCode := fpclose(fileDesc);
169195 LogMemo.Lines.Add(IntToStr(gReturnCode));
170196 end;
171197 { Set SoC pin 17 as output: }
172198 try
173199 fileDesc := fpopen('/sys/class/gpio/gpio17/direction', O_WrOnly);
174200 gReturnCode := fpwrite(fileDesc, OUT_DIRECTION[0], 3);
175201 LogMemo.Lines.Add(IntToStr(gReturnCode));
176202 finally
177203 gReturnCode := fpclose(fileDesc);
178204 LogMemo.Lines.Add(IntToStr(gReturnCode));
179205 end;
180206end;
181207
182208procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
183209var
184210 fileDesc: integer;
185211begin
186212 { Free SoC pin 17: }
187213 try
188214 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
189215 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
190216 LogMemo.Lines.Add(IntToStr(gReturnCode));
191217 finally
192218 gReturnCode := fpclose(fileDesc);
193219 LogMemo.Lines.Add(IntToStr(gReturnCode));
194220 end;
195221end;
196222
197223procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
198224var
199225 fileDesc: integer;
200226begin
201227 if GPIO17ToggleBox.Checked then
202228 begin
203229 { Swith SoC pin 17 on: }
204230 try
205231 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
206232 gReturnCode := fpwrite(fileDesc, PIN_ON[0], 1);
207233 LogMemo.Lines.Add(IntToStr(gReturnCode));
208234 finally
209235 gReturnCode := fpclose(fileDesc);
210236 LogMemo.Lines.Add(IntToStr(gReturnCode));
211237 end;
212238 end
213239 else
214240 begin
215241 { Switch SoC pin 17 off: }
216242 try
217243 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
218244 gReturnCode := fpwrite(fileDesc, PIN_OFF[0], 1);
219245 LogMemo.Lines.Add(IntToStr(gReturnCode));
220246 finally
221247 gReturnCode := fpclose(fileDesc);
222248 LogMemo.Lines.Add(IntToStr(gReturnCode));
223249 end;
224250 end;
225251end;
226252
227253end.
228254```
229255
230256*Main program:*
231257
232258``` pascal
233259program io_test;
234260
235261{$mode objfpc}{$H+}
236262
237263uses
238264 {$IFDEF UNIX}{$IFDEF UseCThreads}
239265 cthreads,
240266 {$ENDIF}{$ENDIF}
241267 Interfaces, // this includes the LCL widgetset
242268 Forms, Unit1
243269 { you can add units after this };
244270
245271{$R *.res}
246272
247273begin
248274 Application.Initialize;
249275 Application.CreateForm(TForm1, Form1);
250276 Application.Run;
251277end.
252278```
253279
254280#### 读取引脚的状态
255281
256282![读取一个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)
257283
258284当然也可以从GPIO端口读取一个开关的状态。
259285
260286下面的简单例子非常类似于前一个例子。使用GPIO的18号引脚,控制二进制设备如开关输入,晶体管或继电器。这个程序包含一个名称为[[doc:lcl/stdctrls/tcheckbox.html|CheckBox]]的*GPIO18CheckBox* 与*LogMemo*的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]日志返回代码。
261287
262288在实例中,第12引脚的一端连接一个按钮,按钮的一端(对应的GPIO引脚18的BCM2835 SoC)通过一个10欧姆的上拉电阻和引脚1连接(+3.3 V,看接线图)。按钮的另一端连接6号引脚(GND)。按钮的开关状态对应和程序中复选框的打开或关闭状态对应。
263289
264290注意,当按钮释放时18脚的电位为高(由通过上拉电阻连接到引脚1),当按钮压下时电压为低(因为在这种情况下,引脚18是通过开关连接到GND)。因此,按钮按下时GPIO引脚信号为0,当释放时信号为1。
265291
266292这个程序同样需要root权限
267293
268294*控制单元:*
269295
270296``` pascal
271297unit Unit1;
272298
273299{Demo application for GPIO on Raspberry Pi}
274300{Inspired by the Python input/output demo application by Gareth Halfacree}
275301{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
276302
277303{This application reads the status of a push-button}
278304
279305{$mode objfpc}{$H+}
280306
281307interface
282308
283309uses
284310 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
285311 ButtonPanel, Unix, BaseUnix;
286312
287313type
288314
289315 { TForm1 }
290316
291317 TForm1 = class(TForm)
292318 ApplicationProperties1: TApplicationProperties;
293319 GPIO18CheckBox: TCheckBox;
294320 LogMemo: TMemo;
295321 procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
296322 procedure FormActivate(Sender: TObject);
297323 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
298324 private
299325 { private declarations }
300326 public
301327 { public declarations }
302328 end;
303329
304330const
305331 PIN_18: PChar = '18';
306332 IN_DIRECTION: PChar = 'in';
307333
308334var
309335 Form1: TForm1;
310336 gReturnCode: longint; {stores the result of the IO operation}
311337
312338implementation
313339
314340{$R *.lfm}
315341
316342{ TForm1 }
317343
318344procedure TForm1.FormActivate(Sender: TObject);
319345var
320346 fileDesc: integer;
321347begin
322348 { Prepare SoC pin 18 (pin 12 on GPIO port) for access: }
323349 try
324350 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
325351 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
326352 LogMemo.Lines.Add(IntToStr(gReturnCode));
327353 finally
328354 gReturnCode := fpclose(fileDesc);
329355 LogMemo.Lines.Add(IntToStr(gReturnCode));
330356 end;
331357 { Set SoC pin 18 as input: }
332358 try
333359 fileDesc := fpopen('/sys/class/gpio/gpio18/direction', O_WrOnly);
334360 gReturnCode := fpwrite(fileDesc, IN_DIRECTION[0], 2);
335361 LogMemo.Lines.Add(IntToStr(gReturnCode));
336362 finally
337363 gReturnCode := fpclose(fileDesc);
338364 LogMemo.Lines.Add(IntToStr(gReturnCode));
339365 end;
340366end;
341367
342368procedure TForm1.ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
343369var
344370 fileDesc: integer;
345371 buttonStatus: string[1] = '1';
346372begin
347373 try
348374 { Open SoC pin 18 (pin 12 on GPIO port) in read-only mode: }
349375 fileDesc := fpopen('/sys/class/gpio/gpio18/value', O_RdOnly);
350376 if fileDesc > 0 then
351377 begin
352378 { Read status of this pin (0: button pressed, 1: button released): }
353379 gReturnCode := fpread(fileDesc, buttonStatus[1], 1);
354380 LogMemo.Lines.Add(IntToStr(gReturnCode) + ': ' + buttonStatus);
355381 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
356382 if buttonStatus = '0' then
357383 GPIO18CheckBox.Checked := true
358384 else
359385 GPIO18CheckBox.Checked := false;
360386 end;
361387 finally
362388 { Close SoC pin 18 (pin 12 on GPIO port) }
363389 gReturnCode := fpclose(fileDesc);
364390 LogMemo.Lines.Add(IntToStr(gReturnCode));
365391 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
366392 end;
367393end;
368394
369395procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
370396var
371397 fileDesc: integer;
372398begin
373399 { Free SoC pin 18: }
374400 try
375401 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
376402 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
377403 LogMemo.Lines.Add(IntToStr(gReturnCode));
378404 finally
379405 gReturnCode := fpclose(fileDesc);
380406 LogMemo.Lines.Add(IntToStr(gReturnCode));
381407 end;
382408end;
383409
384410end.
385411```
386412
387413上面的例子主程序是相同的,。
388414
389415### 2. 通过封装的外壳访问硬件
390416
391417访问硬件的另一种方法是通过封装终端命令。这是通过使用[[Executing External Programs|fpsystem]]功能。这种方法可以访问baseunix单元不支持的功能。下面的代码实现了一个具有相同功能的程序,该程序是从上面的第一个清单所产生的。
392418
393419*控制单元:*
394420
395421``` pascal
396422unit Unit1;
397423
398424{Demo application for GPIO on Raspberry Pi}
399425{Inspired by the Python input/output demo application by Gareth Halfacree}
400426{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
401427
402428{$mode objfpc}{$H+}
403429
404430interface
405431
406432uses
407433 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Unix;
408434
409435type
410436
411437 { TForm1 }
412438
413439 TForm1 = class(TForm)
414440 LogMemo: TMemo;
415441 GPIO17ToggleBox: TToggleBox;
416442 procedure FormActivate(Sender: TObject);
417443 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
418444 procedure GPIO17ToggleBoxChange(Sender: TObject);
419445 private
420446 { private declarations }
421447 public
422448 { public declarations }
423449 end;
424450
425451var
426452 Form1: TForm1;
427453 gReturnCode: longint; {stores the result of the IO operation}
428454
429455implementation
430456
431457{$R *.lfm}
432458
433459{ TForm1 }
434460
435461procedure TForm1.FormActivate(Sender: TObject);
436462begin
437463 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
438464 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/export');
439465 LogMemo.Lines.Add(IntToStr(gReturnCode));
440466 { Set SoC pin 17 as output: }
441467 gReturnCode := fpsystem('echo "out" > /sys/class/gpio/gpio17/direction');
442468 LogMemo.Lines.Add(IntToStr(gReturnCode));
443469end;
444470
445471procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
446472begin
447473 { Free SoC pin 17: }
448474 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/unexport');
449475 LogMemo.Lines.Add(IntToStr(gReturnCode));
450476end;
451477
452478procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
453479begin
454480 if GPIO17ToggleBox.Checked then
455481 begin
456482 { Swith SoC pin 17 on: }
457483 gReturnCode := fpsystem('echo "1" > /sys/class/gpio/gpio17/value');
458484 LogMemo.Lines.Add(IntToStr(gReturnCode));
459485 end
460486 else
461487 begin
462488 { Switch SoC pin 17 off: }
463489 gReturnCode := fpsystem('echo "0" > /sys/class/gpio/gpio17/value');
464490 LogMemo.Lines.Add(IntToStr(gReturnCode));
465491 end;
466492end;
467493
468494end.
469495```
470496
471497主程序与上面的例子相同。这个程序必须用根权限执行。
472498
473499### 3. wiringPi方法与函数
474500
475501Alex Schaller封装的Gordon Henderson的Arduino兼容wiringpi库,提供了一种类似Arduino电路板的编码方案。
476502
477503**Function wiringPiSetup:longint:** 使用wiringpi引脚编号方案初始化wiringpi系统
478504
479505**Procedure wiringPiGpioMode(mode:longint):** 用Broadcom的GPIO引脚编号方案wiringpi初始化系统。
480506
481507**Procedure pullUpDnControl(pin:longint;** pud:longint): 控制内部GPIO引脚上拉/下拉电阻。
482508
483509**Procedure pinMode(pin:longint; mode:longint):** 设置一个PIN的模式:输入、输出或pwm_output。
484510
485511**Procedure digitalWrite(pin:longint; value:longint):** 设置一个输出位。
486512
487513**Procedure pwmWrite(pin:longint; value:longint):** 设置一个输出PWM(脉宽调制)值,0到1024之间。
488514
489515**Function digitalRead(pin:longint):longint:** 读取一个给定引脚的值,返回1或0。
490516
491517**Procedure delay(howLong:dword):** 等待多少毫秒。
492518
493519**Procedure delayMicroseconds(howLong:dword):** 等待多少微秒。
494520
495521**Function millis:dword:** 返回程序调用wiringpisetup函数花费的毫秒数。
496522
497523### 4. rpi_hal-hardware抽象库 (GPIO, I2C and SPI 函数与方法)
498524
499525这个单元大约1700行代码,由Stefan Fischer提供,提供程序和函数访问RPI硬件I2C,SPI和GPIO:
500526
501527下面是函数和方法的摘录:
502528
503529**procedure gpio_set_pin (pin:longword;highlevel:boolean);** { 设置 RPi GPIO 引脚速率为高或低; 速率 @ 700MHz -\> 0.65MHz }
504530
505531**function gpio_get_PIN (pin:longword):boolean;** { 获取 RPi GPIO 引脚等级,当Pin为'1'时返回True,为'0'时返回false; 速率 @ 700MHz -\> 1.17MHz }
506532
507533**procedure gpio_set_input (pin:longword);** { 设置 RPi GPIO 引脚为直接输入}
508534
509535**procedure gpio_set_output(pin:longword);** { 设置 RPi GPIO 引脚为直接输出 }
510536
511537**procedure gpio_set_alt (pin,altfunc:longword);** { 设置 RPi GPIO 引脚为备用功能 0..5 }
512538
513539**procedure gpio_set_gppud (mask:longword);** { 设置RPI GPIO拉上/下登记(gppud)}
514540
515541...
516542
517543**function rpi_snr :string;** { 信噪比: 0000000012345678 }
518544
519545**function rpi_hw :string;** { 处理器类型: BCM2708 }
520546
521547**function rpi_proc:string;** { ARMv6-compatible processor rev 7 (v6l) }
522548
523549...
524550
525551**function i2c_bus_write(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
526552
527553**function i2c_bus_read (baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
528554
529555**function i2c_string_read(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : string;**
530556
531557**function i2c_string_write(baseadr,reg:word; s:string; testnr:integer) : integer;**
532558
533559...
534560
535561**procedure SPI_Write(devnum:byte; reg,data:word);**
536562
537563**function SPI_Read(devnum:byte; reg:word) : byte;**
538564
539565**procedure SPI_BurstRead2Buffer (devnum,start_reg:byte; xferlen:longword);**
540566
541567**procedure SPI_BurstWriteBuffer (devnum,start_reg:byte; xferlen:longword);** { 从缓冲区SPI的地址写入一段字节的内容 }
542568
543569...
544570
545571*测试程序 (testrpi.pas):*
546572
547573``` pascal
548574//Simple Test program, which is using rpi_hal;
549575
550576 program testrpi;
551577 uses rpi_hal;
552578 begin
553579 writeln('Show CPU-Info, RPI-HW-Info and Registers:');
554580 rpi_show_all_info;
555581 writeln('Let Status LED Blink. Using GPIO functions:');
556582 GPIO_PIN_TOGGLE_TEST;
557583 writeln('Test SPI Read function. (piggy back board with installed RFM22B Module is required!)');
558584 Test_SPI;
559585 end.
560586```
561587
562588### 5. 底层pascal单元 PiGpio(代替wiringpi C语言库的GPIO控制)
563589
564590*这个单元 (pigpio.pas[2](https://docs.google.com/file/d/0B-b-5ooIWPvGN1BIcEJzRDgyeUE/edit?usp=sharing)) 270 行代码是由Gabor Szollosi提供的 , 运行速度飞快(例如GPIO引脚输出开关频率达到8MHz) :*
565591
566592``` pascal
567593unit PiGpio;
568594{
569595 BCM2835 GPIO Registry Driver, also can use to manipulate cpu other registry areas
570596
571597 This code is tested only Broadcom bcm2835 cpu, different arm cpus may need different
572598 gpio driver implementation
573599
574600 2013 Gabor Szollosi
575601}
576602{$mode objfpc}{$H+}
577603
578604interface
579605
580606uses
581607 Classes, SysUtils;
582608
583609const
584610 REG_GPIO = $20000;//bcm2835 gpio register 0x2000 0000. new fpMap uses page offset, one page is 4096bytes
585611 // hex 0x1000 so simply calculate 0x2000 0000 / 0x1000 = 0x2000 0
586612 PAGE_SIZE = 4096;
587613 BLOCK_SIZE = 4096;
588614 // The BCM2835 has 54 GPIO pins.
589615// BCM2835 data sheet, Page 90 onwards.
590616// There are 6 control registers, each control the functions of a block
591617// of 10 pins.
592618
593619 CLOCK_BASE = (REG_GPIO + $101);
594620 GPIO_BASE = (REG_GPIO + $200);
595621 GPIO_PWM = (REG_GPIO + $20C);
596622
597623 INPUT = 0;
598624 OUTPUT = 1;
599625 PWM_OUTPUT = 2;
600626 LOW = False;
601627 HIGH = True;
602628 PUD_OFF = 0;
603629 PUD_DOWN = 1;
604630 PUD_UP = 2;
605631
606632 // PWM
607633
608634 PWM_CONTROL = 0;
609635 PWM_STATUS = 4;
610636 PWM0_RANGE = 16;
611637 PWM0_DATA = 20;
612638 PWM1_RANGE = 32;
613639 PWM1_DATA = 36;
614640
615641 PWMCLK_CNTL = 160;
616642 PWMCLK_DIV = 164;
617643
618644 PWM1_MS_MODE = $8000; // Run in MS mode
619645 PWM1_USEFIFO = $2000; // Data from FIFO
620646 PWM1_REVPOLAR = $1000; // Reverse polarity
621647 PWM1_OFFSTATE = $0800; // Ouput Off state
622648 PWM1_REPEATFF = $0400; // Repeat last value if FIFO empty
623649 PWM1_SERIAL = $0200; // Run in serial mode
624650 PWM1_ENABLE = $0100; // Channel Enable
625651
626652 PWM0_MS_MODE = $0080; // Run in MS mode
627653 PWM0_USEFIFO = $0020; // Data from FIFO
628654 PWM0_REVPOLAR = $0010; // Reverse polarity
629655 PWM0_OFFSTATE = $0008; // Ouput Off state
630656 PWM0_REPEATFF = $0004; // Repeat last value if FIFO empty
631657 PWM0_SERIAL = $0002; // Run in serial mode
632658 PWM0_ENABLE = $0001; // Channel Enable
633659
634660type
635661
636662 { TIoPort }
637663
638664 TIoPort = class // IO bank object
639665 private //
640666
641667 //function get_pinDirection(aPin: TGpIoPin): TGpioPinConf;
642668
643669 public
644670 FGpio: ^LongWord;
645671 FClk: ^LongWord;
646672 FPwm: ^LongWord;
647673 procedure SetPinMode(gpin, mode: byte);
648674 function GetBit(gpin : byte):boolean;inline; // gets pin bit}
649675 procedure ClearBit(gpin : byte);inline;// write pin to 0
650676 procedure SetBit(gpin : byte);inline;// write pin to 1
651677 procedure SetPullMode(gpin, mode: byte);
652678 procedure PwmWrite(gpin : byte; value : LongWord);inline;// write pin to pwm value
653679 end;
654680
655681 { TIoDriver }
656682
657683 TIoDriver = class
658684 private
659685
660686 public
661687 destructor Destroy;override;
662688 function MapIo:boolean;// creates io memory mapping
663689 procedure UnmapIoRegisrty(FMap: TIoPort);// close io memory mapping
664690 function CreatePort(PortGpio, PortClk, PortPwm: LongWord):TIoPort; // create new IO port
665691 end;
666692
667693var
668694
669695 fd: integer;// /dev/mem file handle
670696procedure delayNanoseconds (howLong : LongWord);
671697
672698implementation
673699
674700uses
675701 baseUnix, Unix;
676702
677703procedure delayNanoseconds (howLong : LongWord);
678704var
679705 sleeper, dummy : timespec;
680706begin
681707 sleeper.tv_sec := 0 ;
682708 sleeper.tv_nsec := howLong ;
683709 fpnanosleep (@sleeper,@dummy) ;
684710end;
685711{ TIoDriver }
686712//*******************************************************************************
687713destructor TIoDriver.Destroy;
688714begin
689715 inherited Destroy;
690716end;
691717//*******************************************************************************
692718function TIoDriver.MapIo: boolean;
693719begin
694720 Result := True;
695721 fd := fpopen('/dev/mem', O_RdWr or O_Sync); // Open the master /dev/memory device
696722 if fd < 0 then
697723 begin
698724 Result := False; // unsuccessful memory mapping
699725 end;
700726 //
701727end;
702728//*******************************************************************************
703729procedure TIoDriver.UnmapIoRegisrty(FMap:TIoPort);
704730begin
705731 if FMap.FGpio <> nil then
706732 begin
707733 fpMUnmap(FMap.FGpio,PAGE_SIZE);
708734 FMap.FGpio := Nil;
709735 end;
710736 if FMap.FClk <> nil then
711737 begin
712738 fpMUnmap(FMap.FClk,PAGE_SIZE);
713739 FMap.FClk := Nil;
714740 end;
715741 if FMap.FPwm <> nil then
716742 begin
717743 fpMUnmap(FMap.FPwm ,PAGE_SIZE);
718744 FMap.FPwm := Nil;
719745 end;
720746end;
721747//*******************************************************************************
722748function TIoDriver.CreatePort(PortGpio, PortClk, PortPwm: LongWord): TIoPort;
723749begin
724750 Result := TIoPort.Create;// new io port, pascal calls new fpMap, where offst is page sized 4096 bytes!!!
725751 Result.FGpio := FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortGpio); // port config gpio memory
726752 Result.FClk:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortClk);; // port clk
727753 Result.FPwm:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortPwm);; // port pwm
728754end;
729755//*******************************************************************************
730756procedure TIoPort.SetPinMode(gpin, mode: byte);
731757var
732758 fSel, shift, alt : byte;
733759 gpiof, clkf, pwmf : ^LongWord;
734760begin
735761 fSel := (gpin div 10)*4 ; //Select Gpfsel 0 to 5 register
736762 shift := (gpin mod 10)*3 ; //0-9 pin shift
737763 gpiof := Pointer(LongWord(Self.FGpio)+fSel);
738764 if (mode = INPUT) then
739765 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) //7 shl shift komplemens - Sets bits to zero = input
740766 else if (mode = OUTPUT) then
741767 begin
742768 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (1 shl shift);
743769 end
744770 else if (mode = PWM_OUTPUT) then
745771 begin
746772 Case gpin of
747773 12,13,40,41,45 : alt:= 4 ;
748774 18,19 : alt:= 2 ;
749775 else alt:= 0 ;
750776 end;
751777 If alt > 0 then
752778 begin
753779 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (alt shl shift);
754780 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
755781 clkf^ := $5A000011 or (1 shl 5) ; //stop clock
756782 delayNanoseconds(200);
757783 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_DIV);
758784 clkf^ := $5A000000 or (32 shl 12) ; // set pwm clock div to 32 (19.2/3 = 600KHz)
759785 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
760786 clkf^ := $5A000011 ; //start clock
761787 Self.ClearBit(gpin);
762788 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
763789 pwmf^ := 0 ; // Disable PWM
764790 delayNanoseconds(200);
765791 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_RANGE);
766792 pwmf^ := $400 ; //max: 1023
767793 delayNanoseconds(200);
768794 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_RANGE);
769795 pwmf^ := $400 ; //max: 1023
770796 delayNanoseconds(200);
771797 // Enable PWMs
772798 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_DATA);
773799 pwmf^ := 0 ; //start value
774800 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_DATA);
775801 pwmf^ := 0 ; //start value
776802 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
777803 pwmf^ := PWM0_ENABLE or PWM1_ENABLE ;
778804 end;
779805 end;
780806end;
781807//*******************************************************************************
782808procedure TIoPort.SetBit(gpin : byte);
783809var
784810 gpiof : ^LongWord;
785811begin
786812 gpiof := Pointer(LongWord(Self.FGpio) + 28 + (gpin shr 5) shl 2);
787813 gpiof^ := 1 shl gpin;
788814end;
789815//*******************************************************************************
790816procedure TIoPort.ClearBit(gpin : byte);
791817var
792818 gpiof : ^LongWord;
793819begin
794820 gpiof := Pointer(LongWord(Self.FGpio) + 40 + (gpin shr 5) shl 2);
795821 gpiof^ := 1 shl gpin;
796822end;
797823//*******************************************************************************
798824function TIoPort.GetBit(gpin : byte):boolean;
799825var
800826 gpiof : ^LongWord;
801827begin
802828 gpiof := Pointer(LongWord(Self.FGpio) + 52 + (gpin shr 5) shl 2);
803829 if (gpiof^ and (1 shl gpin)) = 0 then Result := False else Result := True;
804830end;
805831//*******************************************************************************
806832procedure TIoPort.SetPullMode(gpin, mode: byte);
807833var
808834 pudf, pudclkf : ^LongWord;
809835begin
810836 pudf := Pointer(LongWord(Self.FGpio) + 148 );
811837 pudf^ := mode; //mode = 0, 1, 2 :Off, Down, Up
812838 delayNanoseconds(200);
813839 pudclkf := Pointer(LongWord(Self.FGpio) + 152 + (gpin shr 5) shl 2);
814840 pudclkf^ := 1 shl gpin ;
815841 delayNanoseconds(200);
816842 pudf^ := 0 ;
817843 pudclkf^ := 0 ;
818844end;
819845//*******************************************************************************
820846procedure TIoPort.PwmWrite(gpin : byte; value : Longword);
821847var
822848 pwmf : ^LongWord;
823849 port : byte;
824850begin
825851 Case gpin of
826852 12,18,40 : port:= PWM0_DATA ;
827853 13,19,41,45 : port:= PWM1_DATA ;
828854 else exit;
829855 end;
830856 pwmf := Pointer(LongWord(Self.FPwm) + port);
831857 pwmf^ := value and $FFFFFBFF; // $400 complemens
832858end;
833859//*******************************************************************************
834860end.
835861```
836862
837863*Controlling Lazarus unit:(Project files[3](https://drive.google.com/folderview?id=0B-b-5ooIWPvGU043ZTZ0cUc2YkE&usp=sharing))*
838864
839865``` pascal
840866unit Unit1;
841867
842868{Demo application for GPIO on Raspberry Pi}
843869{Inspired by the Python input/output demo application by Gareth Halfacree}
844870{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
845871
846872{$mode objfpc}{$H+}
847873
848874interface
849875
850876uses
851877 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
852878 ExtCtrls, Unix, PiGpio;
853879
854880type
855881
856882 { TForm1 }
857883
858884 TForm1 = class(TForm)
859885 GPIO25In: TButton;
860886 SpeedButton: TButton;
861887 LogMemo: TMemo;
862888 GPIO23switch: TToggleBox;
863889 Timer1: TTimer;
864890 GPIO18Pwm: TToggleBox;
865891 Direction: TToggleBox;
866892 procedure DirectionChange(Sender: TObject);
867893 procedure GPIO18PwmChange(Sender: TObject);
868894 procedure GPIO25InClick(Sender: TObject);
869895 procedure FormActivate(Sender: TObject);
870896 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
871897 procedure GPIO23switchChange(Sender: TObject);
872898 procedure SpeedButtonClick(Sender: TObject);
873899 procedure Timer1Timer(Sender: TObject);
874900 private
875901 { private declarations }
876902 public
877903 { public declarations }
878904 end;
879905
880906const
881907 INPUT = 0;
882908 OUTPUT = 1;
883909 PWM_OUTPUT = 2;
884910 LOW = False;
885911 HIGH = True;
886912 PUD_OFF = 0;
887913 PUD_DOWN = 1;
888914 PUD_UP = 2;
889915 // Convert Raspberry Pi P1 pins (Px) to GPIO port
890916 P3 = 0;
891917 P5 = 1;
892918 P7 = 4;
893919 P8 = 14;
894920 P10 = 15;
895921 P11 = 17;
896922 P12 = 18;
897923 P13 = 21;
898924 P15 = 22;
899925 P16 = 23;
900926 P18 = 24;
901927 P19 = 10;
902928 P21 = 9;
903929 P22 = 25;
904930 P23 = 11;
905931 P24 = 8;
906932 P26 = 7;
907933
908934var
909935 Form1: TForm1;
910936 GPIO_Driver: TIoDriver;
911937 GpF: TIoPort;
912938 PWM :Boolean;
913939 i, d : integer;
914940 Pin,Pout,Ppwm : byte;
915941
916942implementation
917943
918944{$R *.lfm}
919945
920946{ TForm1 }
921947
922948procedure TForm1.FormActivate(Sender: TObject);
923949begin
924950 if not GPIO_Driver.MapIo then
925951 begin
926952 LogMemo.Lines.Add('Error mapping gpio registry');
927953 end
928954 else
929955 begin
930956 GpF := GpIo_Driver.CreatePort(GPIO_BASE, CLOCK_BASE, GPIO_PWM);
931957 end ;
932958 Timer1.Enabled:= True;
933959 Timer1.Interval:= 25; //25 ms controll interval
934960 Pin := P22;
935961 Pout := P16;
936962 Ppwm := P12;
937963 i:=1;
938964 GpF.SetPinMode(Pout,OUTPUT);
939965 GpF.SetPinMode(Pin,INPUT);
940966 GpF.SetPullMode(Pin,PUD_Up); // Input PullUp High level
941967end;
942968
943969procedure TForm1.GPIO25InClick(Sender: TObject);
944970begin
945971 If GpF.GetBit(Pin) then LogMemo.Lines.Add('In: '+IntToStr(1))
946972 else LogMemo.Lines.Add('In: '+IntToStr(0));
947973end;
948974
949975procedure TForm1.GPIO18PwmChange(Sender: TObject);
950976begin
951977 if GPIO18Pwm.Checked then
952978 begin
953979 GpF.SetPinMode(Ppwm,PWM_OUTPUT);
954980 PWM := True; //PWM on
955981 end
956982 else
957983 begin
958984 GpF.SetPinMode(Ppwm,INPUT);
959985 PWM := False; //PWM off
960986 end;
961987end;
962988
963989procedure TForm1.DirectionChange(Sender: TObject);
964990begin
965991 if Direction.Checked then d:=10 else d:=-10;
966992end;
967993
968994
969995procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
970996begin
971997 GpF.SetPinMode(Ppwm,INPUT);
972998 GpF.ClearBit(Pout);
973999 GpIo_Driver.UnmapIoRegisrty(GpF);
9741000end;
9751001
9761002procedure TForm1.GPIO23switchChange(Sender: TObject);
9771003
9781004Begin
9791005 Timer1.Enabled := False;
9801006 if GPIO23switch.Checked then
9811007 begin
9821008 GpF.SetBit(Pout); //Turn LED on
9831009 end
9841010 else
9851011 begin
9861012 GpF.ClearBit(Pout); //Turn LED off
9871013 end;
9881014 Timer1.Enabled := True;
9891015end;
9901016
9911017procedure TForm1.SpeedButtonClick(Sender: TObject);
9921018var
9931019 i,p,k,v: longint;
9941020 ido:TDateTime;
9951021begin
9961022 ido:= Time;
9971023 k:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
9981024 LogMemo.Lines.Add('Start: '+TimeToStr(ido));
9991025 p:=10000000 ;
10001026 For i:=1 to p do Begin
10011027 GpF.SetBit(P16);
10021028 GpF.ClearBit(P16);
10031029 end;
10041030 ido:= Time;
10051031 v:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
10061032 LogMemo.Lines.Add('Stop: '+TimeToStr(ido)+' Frequency: '+
10071033 IntToStr(p div (v-k))+' kHz');
10081034end;
10091035
10101036procedure TForm1.Timer1Timer(Sender: TObject);
10111037begin
10121038 If PWM then Begin
10131039 If (d > 0) and (i+d < 1024) then begin
10141040 i:=i+d;
10151041 GpF.PwmWrite(Ppwm,i);
10161042 end ;
10171043 If (d < 0) and (i+d > -1) then begin
10181044 i:=i+d;
10191045 GpF.PwmWrite(Ppwm,i);
10201046 end;
10211047 end;
10221048end;
10231049
10241050
10251051end.
10261052```
10271053
10281054## 参考
10291055
10301056- Eben Upton and Gareth Halfacree. Raspberry Pi User Guide. John Wiley and Sons, Chichester 2012, ISBN 111846446X
10311057- B. J. Rao (2013) The Raspberry Pi, Pi Vision and Lazarus/FPC. [Blaise Pascal Magazine](http://www.blaisepascal.eu). 29: 14-21.
10321058
10331059## 外部链接
10341060
10351061- [Raspberry Pi 基础](http://www.raspberrypi.org)
10361062- [Raspberry Pi Spy: Raspberry Pi tutorials, scripts, help and downloads](http://www.raspberrypi-spy.co.uk)
10371063- [Lazarus wrapper unit for Gordon Henderson's wiringPi C library](http://www.lazarus.freepascal.org/index.php/topic,17404.0.html)
10381064- [Pin layout of the wiringPi library](https://projects.drogon.net/raspberry-pi/wiringpi/pins/)
10391065- [Additional information on Lazarus and Raspberry Pi at eLinux.org](http://www.elinux.org/Lazarus_on_RPi)
10401066- [Getting Started with Pascal on the Pi](http://www.pp4s.co.uk/main/gs-pi-intro.html)
10411067- [Lazberry Pi: Comprehensive information on Lazarus on the Raspberry Pi computer](http://superbitysoft.co.uk/lazberrypi/).
10421068- [Stefan Fischer's Lazarus unit rpi_hal](http://www.lazarus.freepascal.org/index.php/topic,20991.0.html).
10431069- [Improved Lazarus Unit for fast access to GPIO](http://www.meltonisl.com/software.html).
10441070
10451071---
10461072*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