Sign in Join
Wiki copytemporary

Lazarus on Raspberry Pi/zh CN: what changed

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

OldNewLine
11树莓派上的Lazarus
22
3-<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)*
3+![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
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-<img src="rpi_pinout_all_50.png" title="Raspberry Pi 外部连接引脚" width="300" />
84+![](/wiki-images/f/f2/Rpi_pinout_all_50.png)
8585
8686Raspberry Pi的发展的目标之一是方便轻松地访问外部设备,如传感器和控制器。Lazarus有五种方法来访问I/O设备:
8787
88881. [[Lazarus on Raspberry Pi|原生代码直接访问]],使用[[BaseUnix]]单元
89892. 通过 [[Lazarus on Raspberry Pi|封装外壳调用]]
90903. 通过 [[Lazarus on Raspberry Pi|wiringPi 库]].
91914. 使用单元 [[Lazarus on Raspberry Pi|rpi_hal]].
92925. 使用单元 [[Lazarus on Raspberry Pi|PiGpio]].
93936. 通过 [PascalIO](https://github.com/SAmeis/pascalio) 库访问.
9494
9595### 1. 原生代码直接访问
9696
9797![对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)
9898
9999这种访问外部硬件的方法,不需要额外的库。唯一的要求是baseunix库,这是Free Pascal的RTL部分。
100100
101101#### 通过GPIO端口控制开关
102102
103103下面将演示一个简单程序。控制GPIO的17号引脚的电压,可以用来控制LED、晶体管或继电器。 程序包含*GPIO17ToggleBox*的实例[[doc:lcl/stdctrls/ttogglebox.html|ToggleBox]]和日志返回*LogMemo*类的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]。
104104
105105例如,一个LED的阳极连接到引脚11上(BCM2835 SoC对应的GPIO为17)和LED的阴极通过一个68欧姆的电阻连接引脚6(GND)。随后,LED会随着应用程序的toggle box切换点亮和熄灭。
106106
107107该代码需要root权限运行,即从root帐号(不推荐)运行或通过“*su*'。
108108
109109*控制单元:*
110110
111111``` pascal
112112unit Unit1;
113113
114114{Demo application for GPIO on Raspberry Pi}
115115{Inspired by the Python input/output demo application by Gareth Halfacree}
116116{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
117117
118118{$mode objfpc}{$H+}
119119
120120interface
121121
122122uses
123123 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
124124 Unix, BaseUnix;
125125
126126type
127127
128128 { TForm1 }
129129
130130 TForm1 = class(TForm)
131131 LogMemo: TMemo;
132132 GPIO17ToggleBox: TToggleBox;
133133 procedure FormActivate(Sender: TObject);
134134 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
135135 procedure GPIO17ToggleBoxChange(Sender: TObject);
136136 private
137137 { private declarations }
138138 public
139139 { public declarations }
140140 end;
141141
142142const
143143 PIN_17: PChar = '17';
144144 PIN_ON: PChar = '1';
145145 PIN_OFF: PChar = '0';
146146 OUT_DIRECTION: PChar = 'out';
147147
148148var
149149 Form1: TForm1;
150150 gReturnCode: longint; {stores the result of the IO operation}
151151
152152implementation
153153
154154{$R *.lfm}
155155
156156{ TForm1 }
157157
158158procedure TForm1.FormActivate(Sender: TObject);
159159var
160160 fileDesc: integer;
161161begin
162162 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
163163 try
164164 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
165165 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
166166 LogMemo.Lines.Add(IntToStr(gReturnCode));
167167 finally
168168 gReturnCode := fpclose(fileDesc);
169169 LogMemo.Lines.Add(IntToStr(gReturnCode));
170170 end;
171171 { Set SoC pin 17 as output: }
172172 try
173173 fileDesc := fpopen('/sys/class/gpio/gpio17/direction', O_WrOnly);
174174 gReturnCode := fpwrite(fileDesc, OUT_DIRECTION[0], 3);
175175 LogMemo.Lines.Add(IntToStr(gReturnCode));
176176 finally
177177 gReturnCode := fpclose(fileDesc);
178178 LogMemo.Lines.Add(IntToStr(gReturnCode));
179179 end;
180180end;
181181
182182procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
183183var
184184 fileDesc: integer;
185185begin
186186 { Free SoC pin 17: }
187187 try
188188 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
189189 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
190190 LogMemo.Lines.Add(IntToStr(gReturnCode));
191191 finally
192192 gReturnCode := fpclose(fileDesc);
193193 LogMemo.Lines.Add(IntToStr(gReturnCode));
194194 end;
195195end;
196196
197197procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
198198var
199199 fileDesc: integer;
200200begin
201201 if GPIO17ToggleBox.Checked then
202202 begin
203203 { Swith SoC pin 17 on: }
204204 try
205205 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
206206 gReturnCode := fpwrite(fileDesc, PIN_ON[0], 1);
207207 LogMemo.Lines.Add(IntToStr(gReturnCode));
208208 finally
209209 gReturnCode := fpclose(fileDesc);
210210 LogMemo.Lines.Add(IntToStr(gReturnCode));
211211 end;
212212 end
213213 else
214214 begin
215215 { Switch SoC pin 17 off: }
216216 try
217217 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
218218 gReturnCode := fpwrite(fileDesc, PIN_OFF[0], 1);
219219 LogMemo.Lines.Add(IntToStr(gReturnCode));
220220 finally
221221 gReturnCode := fpclose(fileDesc);
222222 LogMemo.Lines.Add(IntToStr(gReturnCode));
223223 end;
224224 end;
225225end;
226226
227227end.
228228```
229229
230230*Main program:*
231231
232232``` pascal
233233program io_test;
234234
235235{$mode objfpc}{$H+}
236236
237237uses
238238 {$IFDEF UNIX}{$IFDEF UseCThreads}
239239 cthreads,
240240 {$ENDIF}{$ENDIF}
241241 Interfaces, // this includes the LCL widgetset
242242 Forms, Unit1
243243 { you can add units after this };
244244
245245{$R *.res}
246246
247247begin
248248 Application.Initialize;
249249 Application.CreateForm(TForm1, Form1);
250250 Application.Run;
251251end.
252252```
253253
254254#### 读取引脚的状态
255255
256256![读取一个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)
257257
258258当然也可以从GPIO端口读取一个开关的状态。
259259
260260下面的简单例子非常类似于前一个例子。使用GPIO的18号引脚,控制二进制设备如开关输入,晶体管或继电器。这个程序包含一个名称为[[doc:lcl/stdctrls/tcheckbox.html|CheckBox]]的*GPIO18CheckBox* 与*LogMemo*的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]日志返回代码。
261261
262262在实例中,第12引脚的一端连接一个按钮,按钮的一端(对应的GPIO引脚18的BCM2835 SoC)通过一个10欧姆的上拉电阻和引脚1连接(+3.3 V,看接线图)。按钮的另一端连接6号引脚(GND)。按钮的开关状态对应和程序中复选框的打开或关闭状态对应。
263263
264264注意,当按钮释放时18脚的电位为高(由通过上拉电阻连接到引脚1),当按钮压下时电压为低(因为在这种情况下,引脚18是通过开关连接到GND)。因此,按钮按下时GPIO引脚信号为0,当释放时信号为1。
265265
266266这个程序同样需要root权限
267267
268268*控制单元:*
269269
270270``` pascal
271271unit Unit1;
272272
273273{Demo application for GPIO on Raspberry Pi}
274274{Inspired by the Python input/output demo application by Gareth Halfacree}
275275{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
276276
277277{This application reads the status of a push-button}
278278
279279{$mode objfpc}{$H+}
280280
281281interface
282282
283283uses
284284 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
285285 ButtonPanel, Unix, BaseUnix;
286286
287287type
288288
289289 { TForm1 }
290290
291291 TForm1 = class(TForm)
292292 ApplicationProperties1: TApplicationProperties;
293293 GPIO18CheckBox: TCheckBox;
294294 LogMemo: TMemo;
295295 procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
296296 procedure FormActivate(Sender: TObject);
297297 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
298298 private
299299 { private declarations }
300300 public
301301 { public declarations }
302302 end;
303303
304304const
305305 PIN_18: PChar = '18';
306306 IN_DIRECTION: PChar = 'in';
307307
308308var
309309 Form1: TForm1;
310310 gReturnCode: longint; {stores the result of the IO operation}
311311
312312implementation
313313
314314{$R *.lfm}
315315
316316{ TForm1 }
317317
318318procedure TForm1.FormActivate(Sender: TObject);
319319var
320320 fileDesc: integer;
321321begin
322322 { Prepare SoC pin 18 (pin 12 on GPIO port) for access: }
323323 try
324324 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
325325 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
326326 LogMemo.Lines.Add(IntToStr(gReturnCode));
327327 finally
328328 gReturnCode := fpclose(fileDesc);
329329 LogMemo.Lines.Add(IntToStr(gReturnCode));
330330 end;
331331 { Set SoC pin 18 as input: }
332332 try
333333 fileDesc := fpopen('/sys/class/gpio/gpio18/direction', O_WrOnly);
334334 gReturnCode := fpwrite(fileDesc, IN_DIRECTION[0], 2);
335335 LogMemo.Lines.Add(IntToStr(gReturnCode));
336336 finally
337337 gReturnCode := fpclose(fileDesc);
338338 LogMemo.Lines.Add(IntToStr(gReturnCode));
339339 end;
340340end;
341341
342342procedure TForm1.ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
343343var
344344 fileDesc: integer;
345345 buttonStatus: string[1] = '1';
346346begin
347347 try
348348 { Open SoC pin 18 (pin 12 on GPIO port) in read-only mode: }
349349 fileDesc := fpopen('/sys/class/gpio/gpio18/value', O_RdOnly);
350350 if fileDesc > 0 then
351351 begin
352352 { Read status of this pin (0: button pressed, 1: button released): }
353353 gReturnCode := fpread(fileDesc, buttonStatus[1], 1);
354354 LogMemo.Lines.Add(IntToStr(gReturnCode) + ': ' + buttonStatus);
355355 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
356356 if buttonStatus = '0' then
357357 GPIO18CheckBox.Checked := true
358358 else
359359 GPIO18CheckBox.Checked := false;
360360 end;
361361 finally
362362 { Close SoC pin 18 (pin 12 on GPIO port) }
363363 gReturnCode := fpclose(fileDesc);
364364 LogMemo.Lines.Add(IntToStr(gReturnCode));
365365 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
366366 end;
367367end;
368368
369369procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
370370var
371371 fileDesc: integer;
372372begin
373373 { Free SoC pin 18: }
374374 try
375375 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
376376 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
377377 LogMemo.Lines.Add(IntToStr(gReturnCode));
378378 finally
379379 gReturnCode := fpclose(fileDesc);
380380 LogMemo.Lines.Add(IntToStr(gReturnCode));
381381 end;
382382end;
383383
384384end.
385385```
386386
387387上面的例子主程序是相同的,。
388388
389389### 2. 通过封装的外壳访问硬件
390390
391391访问硬件的另一种方法是通过封装终端命令。这是通过使用[[Executing External Programs|fpsystem]]功能。这种方法可以访问baseunix单元不支持的功能。下面的代码实现了一个具有相同功能的程序,该程序是从上面的第一个清单所产生的。
392392
393393*控制单元:*
394394
395395``` pascal
396396unit Unit1;
397397
398398{Demo application for GPIO on Raspberry Pi}
399399{Inspired by the Python input/output demo application by Gareth Halfacree}
400400{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
401401
402402{$mode objfpc}{$H+}
403403
404404interface
405405
406406uses
407407 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Unix;
408408
409409type
410410
411411 { TForm1 }
412412
413413 TForm1 = class(TForm)
414414 LogMemo: TMemo;
415415 GPIO17ToggleBox: TToggleBox;
416416 procedure FormActivate(Sender: TObject);
417417 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
418418 procedure GPIO17ToggleBoxChange(Sender: TObject);
419419 private
420420 { private declarations }
421421 public
422422 { public declarations }
423423 end;
424424
425425var
426426 Form1: TForm1;
427427 gReturnCode: longint; {stores the result of the IO operation}
428428
429429implementation
430430
431431{$R *.lfm}
432432
433433{ TForm1 }
434434
435435procedure TForm1.FormActivate(Sender: TObject);
436436begin
437437 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
438438 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/export');
439439 LogMemo.Lines.Add(IntToStr(gReturnCode));
440440 { Set SoC pin 17 as output: }
441441 gReturnCode := fpsystem('echo "out" > /sys/class/gpio/gpio17/direction');
442442 LogMemo.Lines.Add(IntToStr(gReturnCode));
443443end;
444444
445445procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
446446begin
447447 { Free SoC pin 17: }
448448 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/unexport');
449449 LogMemo.Lines.Add(IntToStr(gReturnCode));
450450end;
451451
452452procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
453453begin
454454 if GPIO17ToggleBox.Checked then
455455 begin
456456 { Swith SoC pin 17 on: }
457457 gReturnCode := fpsystem('echo "1" > /sys/class/gpio/gpio17/value');
458458 LogMemo.Lines.Add(IntToStr(gReturnCode));
459459 end
460460 else
461461 begin
462462 { Switch SoC pin 17 off: }
463463 gReturnCode := fpsystem('echo "0" > /sys/class/gpio/gpio17/value');
464464 LogMemo.Lines.Add(IntToStr(gReturnCode));
465465 end;
466466end;
467467
468468end.
469469```
470470
471471主程序与上面的例子相同。这个程序必须用根权限执行。
472472
473473### 3. wiringPi方法与函数
474474
475475Alex Schaller封装的Gordon Henderson的Arduino兼容wiringpi库,提供了一种类似Arduino电路板的编码方案。
476476
477477**Function wiringPiSetup:longint:** 使用wiringpi引脚编号方案初始化wiringpi系统
478478
479479**Procedure wiringPiGpioMode(mode:longint):** 用Broadcom的GPIO引脚编号方案wiringpi初始化系统。
480480
481481**Procedure pullUpDnControl(pin:longint;** pud:longint): 控制内部GPIO引脚上拉/下拉电阻。
482482
483483**Procedure pinMode(pin:longint; mode:longint):** 设置一个PIN的模式:输入、输出或pwm_output。
484484
485485**Procedure digitalWrite(pin:longint; value:longint):** 设置一个输出位。
486486
487487**Procedure pwmWrite(pin:longint; value:longint):** 设置一个输出PWM(脉宽调制)值,0到1024之间。
488488
489489**Function digitalRead(pin:longint):longint:** 读取一个给定引脚的值,返回1或0。
490490
491491**Procedure delay(howLong:dword):** 等待多少毫秒。
492492
493493**Procedure delayMicroseconds(howLong:dword):** 等待多少微秒。
494494
495495**Function millis:dword:** 返回程序调用wiringpisetup函数花费的毫秒数。
496496
497497### 4. rpi_hal-hardware抽象库 (GPIO, I2C and SPI 函数与方法)
498498
499499这个单元大约1700行代码,由Stefan Fischer提供,提供程序和函数访问RPI硬件I2C,SPI和GPIO:
500500
501501下面是函数和方法的摘录:
502502
503503**procedure gpio_set_pin (pin:longword;highlevel:boolean);** { 设置 RPi GPIO 引脚速率为高或低; 速率 @ 700MHz -\> 0.65MHz }
504504
505505**function gpio_get_PIN (pin:longword):boolean;** { 获取 RPi GPIO 引脚等级,当Pin为'1'时返回True,为'0'时返回false; 速率 @ 700MHz -\> 1.17MHz }
506506
507507**procedure gpio_set_input (pin:longword);** { 设置 RPi GPIO 引脚为直接输入}
508508
509509**procedure gpio_set_output(pin:longword);** { 设置 RPi GPIO 引脚为直接输出 }
510510
511511**procedure gpio_set_alt (pin,altfunc:longword);** { 设置 RPi GPIO 引脚为备用功能 0..5 }
512512
513513**procedure gpio_set_gppud (mask:longword);** { 设置RPI GPIO拉上/下登记(gppud)}
514514
515515...
516516
517517**function rpi_snr :string;** { 信噪比: 0000000012345678 }
518518
519519**function rpi_hw :string;** { 处理器类型: BCM2708 }
520520
521521**function rpi_proc:string;** { ARMv6-compatible processor rev 7 (v6l) }
522522
523523...
524524
525525**function i2c_bus_write(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
526526
527527**function i2c_bus_read (baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
528528
529529**function i2c_string_read(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : string;**
530530
531531**function i2c_string_write(baseadr,reg:word; s:string; testnr:integer) : integer;**
532532
533533...
534534
535535**procedure SPI_Write(devnum:byte; reg,data:word);**
536536
537537**function SPI_Read(devnum:byte; reg:word) : byte;**
538538
539539**procedure SPI_BurstRead2Buffer (devnum,start_reg:byte; xferlen:longword);**
540540
541541**procedure SPI_BurstWriteBuffer (devnum,start_reg:byte; xferlen:longword);** { 从缓冲区SPI的地址写入一段字节的内容 }
542542
543543...
544544
545545*测试程序 (testrpi.pas):*
546546
547547``` pascal
548548//Simple Test program, which is using rpi_hal;
549549
550550 program testrpi;
551551 uses rpi_hal;
552552 begin
553553 writeln('Show CPU-Info, RPI-HW-Info and Registers:');
554554 rpi_show_all_info;
555555 writeln('Let Status LED Blink. Using GPIO functions:');
556556 GPIO_PIN_TOGGLE_TEST;
557557 writeln('Test SPI Read function. (piggy back board with installed RFM22B Module is required!)');
558558 Test_SPI;
559559 end.
560560```
561561
562562### 5. 底层pascal单元 PiGpio(代替wiringpi C语言库的GPIO控制)
563563
564564*这个单元 (pigpio.pas[2](https://docs.google.com/file/d/0B-b-5ooIWPvGN1BIcEJzRDgyeUE/edit?usp=sharing)) 270 行代码是由Gabor Szollosi提供的 , 运行速度飞快(例如GPIO引脚输出开关频率达到8MHz) :*
565565
566566``` pascal
567567unit PiGpio;
568568{
569569 BCM2835 GPIO Registry Driver, also can use to manipulate cpu other registry areas
570570
571571 This code is tested only Broadcom bcm2835 cpu, different arm cpus may need different
572572 gpio driver implementation
573573
574574 2013 Gabor Szollosi
575575}
576576{$mode objfpc}{$H+}
577577
578578interface
579579
580580uses
581581 Classes, SysUtils;
582582
583583const
584584 REG_GPIO = $20000;//bcm2835 gpio register 0x2000 0000. new fpMap uses page offset, one page is 4096bytes
585585 // hex 0x1000 so simply calculate 0x2000 0000 / 0x1000 = 0x2000 0
586586 PAGE_SIZE = 4096;
587587 BLOCK_SIZE = 4096;
588588 // The BCM2835 has 54 GPIO pins.
589589// BCM2835 data sheet, Page 90 onwards.
590590// There are 6 control registers, each control the functions of a block
591591// of 10 pins.
592592
593593 CLOCK_BASE = (REG_GPIO + $101);
594594 GPIO_BASE = (REG_GPIO + $200);
595595 GPIO_PWM = (REG_GPIO + $20C);
596596
597597 INPUT = 0;
598598 OUTPUT = 1;
599599 PWM_OUTPUT = 2;
600600 LOW = False;
601601 HIGH = True;
602602 PUD_OFF = 0;
603603 PUD_DOWN = 1;
604604 PUD_UP = 2;
605605
606606 // PWM
607607
608608 PWM_CONTROL = 0;
609609 PWM_STATUS = 4;
610610 PWM0_RANGE = 16;
611611 PWM0_DATA = 20;
612612 PWM1_RANGE = 32;
613613 PWM1_DATA = 36;
614614
615615 PWMCLK_CNTL = 160;
616616 PWMCLK_DIV = 164;
617617
618618 PWM1_MS_MODE = $8000; // Run in MS mode
619619 PWM1_USEFIFO = $2000; // Data from FIFO
620620 PWM1_REVPOLAR = $1000; // Reverse polarity
621621 PWM1_OFFSTATE = $0800; // Ouput Off state
622622 PWM1_REPEATFF = $0400; // Repeat last value if FIFO empty
623623 PWM1_SERIAL = $0200; // Run in serial mode
624624 PWM1_ENABLE = $0100; // Channel Enable
625625
626626 PWM0_MS_MODE = $0080; // Run in MS mode
627627 PWM0_USEFIFO = $0020; // Data from FIFO
628628 PWM0_REVPOLAR = $0010; // Reverse polarity
629629 PWM0_OFFSTATE = $0008; // Ouput Off state
630630 PWM0_REPEATFF = $0004; // Repeat last value if FIFO empty
631631 PWM0_SERIAL = $0002; // Run in serial mode
632632 PWM0_ENABLE = $0001; // Channel Enable
633633
634634type
635635
636636 { TIoPort }
637637
638638 TIoPort = class // IO bank object
639639 private //
640640
641641 //function get_pinDirection(aPin: TGpIoPin): TGpioPinConf;
642642
643643 public
644644 FGpio: ^LongWord;
645645 FClk: ^LongWord;
646646 FPwm: ^LongWord;
647647 procedure SetPinMode(gpin, mode: byte);
648648 function GetBit(gpin : byte):boolean;inline; // gets pin bit}
649649 procedure ClearBit(gpin : byte);inline;// write pin to 0
650650 procedure SetBit(gpin : byte);inline;// write pin to 1
651651 procedure SetPullMode(gpin, mode: byte);
652652 procedure PwmWrite(gpin : byte; value : LongWord);inline;// write pin to pwm value
653653 end;
654654
655655 { TIoDriver }
656656
657657 TIoDriver = class
658658 private
659659
660660 public
661661 destructor Destroy;override;
662662 function MapIo:boolean;// creates io memory mapping
663663 procedure UnmapIoRegisrty(FMap: TIoPort);// close io memory mapping
664664 function CreatePort(PortGpio, PortClk, PortPwm: LongWord):TIoPort; // create new IO port
665665 end;
666666
667667var
668668
669669 fd: integer;// /dev/mem file handle
670670procedure delayNanoseconds (howLong : LongWord);
671671
672672implementation
673673
674674uses
675675 baseUnix, Unix;
676676
677677procedure delayNanoseconds (howLong : LongWord);
678678var
679679 sleeper, dummy : timespec;
680680begin
681681 sleeper.tv_sec := 0 ;
682682 sleeper.tv_nsec := howLong ;
683683 fpnanosleep (@sleeper,@dummy) ;
684684end;
685685{ TIoDriver }
686686//*******************************************************************************
687687destructor TIoDriver.Destroy;
688688begin
689689 inherited Destroy;
690690end;
691691//*******************************************************************************
692692function TIoDriver.MapIo: boolean;
693693begin
694694 Result := True;
695695 fd := fpopen('/dev/mem', O_RdWr or O_Sync); // Open the master /dev/memory device
696696 if fd < 0 then
697697 begin
698698 Result := False; // unsuccessful memory mapping
699699 end;
700700 //
701701end;
702702//*******************************************************************************
703703procedure TIoDriver.UnmapIoRegisrty(FMap:TIoPort);
704704begin
705705 if FMap.FGpio <> nil then
706706 begin
707707 fpMUnmap(FMap.FGpio,PAGE_SIZE);
708708 FMap.FGpio := Nil;
709709 end;
710710 if FMap.FClk <> nil then
711711 begin
712712 fpMUnmap(FMap.FClk,PAGE_SIZE);
713713 FMap.FClk := Nil;
714714 end;
715715 if FMap.FPwm <> nil then
716716 begin
717717 fpMUnmap(FMap.FPwm ,PAGE_SIZE);
718718 FMap.FPwm := Nil;
719719 end;
720720end;
721721//*******************************************************************************
722722function TIoDriver.CreatePort(PortGpio, PortClk, PortPwm: LongWord): TIoPort;
723723begin
724724 Result := TIoPort.Create;// new io port, pascal calls new fpMap, where offst is page sized 4096 bytes!!!
725725 Result.FGpio := FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortGpio); // port config gpio memory
726726 Result.FClk:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortClk);; // port clk
727727 Result.FPwm:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortPwm);; // port pwm
728728end;
729729//*******************************************************************************
730730procedure TIoPort.SetPinMode(gpin, mode: byte);
731731var
732732 fSel, shift, alt : byte;
733733 gpiof, clkf, pwmf : ^LongWord;
734734begin
735735 fSel := (gpin div 10)*4 ; //Select Gpfsel 0 to 5 register
736736 shift := (gpin mod 10)*3 ; //0-9 pin shift
737737 gpiof := Pointer(LongWord(Self.FGpio)+fSel);
738738 if (mode = INPUT) then
739739 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) //7 shl shift komplemens - Sets bits to zero = input
740740 else if (mode = OUTPUT) then
741741 begin
742742 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (1 shl shift);
743743 end
744744 else if (mode = PWM_OUTPUT) then
745745 begin
746746 Case gpin of
747747 12,13,40,41,45 : alt:= 4 ;
748748 18,19 : alt:= 2 ;
749749 else alt:= 0 ;
750750 end;
751751 If alt > 0 then
752752 begin
753753 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (alt shl shift);
754754 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
755755 clkf^ := $5A000011 or (1 shl 5) ; //stop clock
756756 delayNanoseconds(200);
757757 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_DIV);
758758 clkf^ := $5A000000 or (32 shl 12) ; // set pwm clock div to 32 (19.2/3 = 600KHz)
759759 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
760760 clkf^ := $5A000011 ; //start clock
761761 Self.ClearBit(gpin);
762762 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
763763 pwmf^ := 0 ; // Disable PWM
764764 delayNanoseconds(200);
765765 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_RANGE);
766766 pwmf^ := $400 ; //max: 1023
767767 delayNanoseconds(200);
768768 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_RANGE);
769769 pwmf^ := $400 ; //max: 1023
770770 delayNanoseconds(200);
771771 // Enable PWMs
772772 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_DATA);
773773 pwmf^ := 0 ; //start value
774774 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_DATA);
775775 pwmf^ := 0 ; //start value
776776 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
777777 pwmf^ := PWM0_ENABLE or PWM1_ENABLE ;
778778 end;
779779 end;
780780end;
781781//*******************************************************************************
782782procedure TIoPort.SetBit(gpin : byte);
783783var
784784 gpiof : ^LongWord;
785785begin
786786 gpiof := Pointer(LongWord(Self.FGpio) + 28 + (gpin shr 5) shl 2);
787787 gpiof^ := 1 shl gpin;
788788end;
789789//*******************************************************************************
790790procedure TIoPort.ClearBit(gpin : byte);
791791var
792792 gpiof : ^LongWord;
793793begin
794794 gpiof := Pointer(LongWord(Self.FGpio) + 40 + (gpin shr 5) shl 2);
795795 gpiof^ := 1 shl gpin;
796796end;
797797//*******************************************************************************
798798function TIoPort.GetBit(gpin : byte):boolean;
799799var
800800 gpiof : ^LongWord;
801801begin
802802 gpiof := Pointer(LongWord(Self.FGpio) + 52 + (gpin shr 5) shl 2);
803803 if (gpiof^ and (1 shl gpin)) = 0 then Result := False else Result := True;
804804end;
805805//*******************************************************************************
806806procedure TIoPort.SetPullMode(gpin, mode: byte);
807807var
808808 pudf, pudclkf : ^LongWord;
809809begin
810810 pudf := Pointer(LongWord(Self.FGpio) + 148 );
811811 pudf^ := mode; //mode = 0, 1, 2 :Off, Down, Up
812812 delayNanoseconds(200);
813813 pudclkf := Pointer(LongWord(Self.FGpio) + 152 + (gpin shr 5) shl 2);
814814 pudclkf^ := 1 shl gpin ;
815815 delayNanoseconds(200);
816816 pudf^ := 0 ;
817817 pudclkf^ := 0 ;
818818end;
819819//*******************************************************************************
820820procedure TIoPort.PwmWrite(gpin : byte; value : Longword);
821821var
822822 pwmf : ^LongWord;
823823 port : byte;
824824begin
825825 Case gpin of
826826 12,18,40 : port:= PWM0_DATA ;
827827 13,19,41,45 : port:= PWM1_DATA ;
828828 else exit;
829829 end;
830830 pwmf := Pointer(LongWord(Self.FPwm) + port);
831831 pwmf^ := value and $FFFFFBFF; // $400 complemens
832832end;
833833//*******************************************************************************
834834end.
835835```
836836
837837*Controlling Lazarus unit:(Project files[3](https://drive.google.com/folderview?id=0B-b-5ooIWPvGU043ZTZ0cUc2YkE&usp=sharing))*
838838
839839``` pascal
840840unit Unit1;
841841
842842{Demo application for GPIO on Raspberry Pi}
843843{Inspired by the Python input/output demo application by Gareth Halfacree}
844844{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
845845
846846{$mode objfpc}{$H+}
847847
848848interface
849849
850850uses
851851 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
852852 ExtCtrls, Unix, PiGpio;
853853
854854type
855855
856856 { TForm1 }
857857
858858 TForm1 = class(TForm)
859859 GPIO25In: TButton;
860860 SpeedButton: TButton;
861861 LogMemo: TMemo;
862862 GPIO23switch: TToggleBox;
863863 Timer1: TTimer;
864864 GPIO18Pwm: TToggleBox;
865865 Direction: TToggleBox;
866866 procedure DirectionChange(Sender: TObject);
867867 procedure GPIO18PwmChange(Sender: TObject);
868868 procedure GPIO25InClick(Sender: TObject);
869869 procedure FormActivate(Sender: TObject);
870870 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
871871 procedure GPIO23switchChange(Sender: TObject);
872872 procedure SpeedButtonClick(Sender: TObject);
873873 procedure Timer1Timer(Sender: TObject);
874874 private
875875 { private declarations }
876876 public
877877 { public declarations }
878878 end;
879879
880880const
881881 INPUT = 0;
882882 OUTPUT = 1;
883883 PWM_OUTPUT = 2;
884884 LOW = False;
885885 HIGH = True;
886886 PUD_OFF = 0;
887887 PUD_DOWN = 1;
888888 PUD_UP = 2;
889889 // Convert Raspberry Pi P1 pins (Px) to GPIO port
890890 P3 = 0;
891891 P5 = 1;
892892 P7 = 4;
893893 P8 = 14;
894894 P10 = 15;
895895 P11 = 17;
896896 P12 = 18;
897897 P13 = 21;
898898 P15 = 22;
899899 P16 = 23;
900900 P18 = 24;
901901 P19 = 10;
902902 P21 = 9;
903903 P22 = 25;
904904 P23 = 11;
905905 P24 = 8;
906906 P26 = 7;
907907
908908var
909909 Form1: TForm1;
910910 GPIO_Driver: TIoDriver;
911911 GpF: TIoPort;
912912 PWM :Boolean;
913913 i, d : integer;
914914 Pin,Pout,Ppwm : byte;
915915
916916implementation
917917
918918{$R *.lfm}
919919
920920{ TForm1 }
921921
922922procedure TForm1.FormActivate(Sender: TObject);
923923begin
924924 if not GPIO_Driver.MapIo then
925925 begin
926926 LogMemo.Lines.Add('Error mapping gpio registry');
927927 end
928928 else
929929 begin
930930 GpF := GpIo_Driver.CreatePort(GPIO_BASE, CLOCK_BASE, GPIO_PWM);
931931 end ;
932932 Timer1.Enabled:= True;
933933 Timer1.Interval:= 25; //25 ms controll interval
934934 Pin := P22;
935935 Pout := P16;
936936 Ppwm := P12;
937937 i:=1;
938938 GpF.SetPinMode(Pout,OUTPUT);
939939 GpF.SetPinMode(Pin,INPUT);
940940 GpF.SetPullMode(Pin,PUD_Up); // Input PullUp High level
941941end;
942942
943943procedure TForm1.GPIO25InClick(Sender: TObject);
944944begin
945945 If GpF.GetBit(Pin) then LogMemo.Lines.Add('In: '+IntToStr(1))
946946 else LogMemo.Lines.Add('In: '+IntToStr(0));
947947end;
948948
949949procedure TForm1.GPIO18PwmChange(Sender: TObject);
950950begin
951951 if GPIO18Pwm.Checked then
952952 begin
953953 GpF.SetPinMode(Ppwm,PWM_OUTPUT);
954954 PWM := True; //PWM on
955955 end
956956 else
957957 begin
958958 GpF.SetPinMode(Ppwm,INPUT);
959959 PWM := False; //PWM off
960960 end;
961961end;
962962
963963procedure TForm1.DirectionChange(Sender: TObject);
964964begin
965965 if Direction.Checked then d:=10 else d:=-10;
966966end;
967967
968968
969969procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
970970begin
971971 GpF.SetPinMode(Ppwm,INPUT);
972972 GpF.ClearBit(Pout);
973973 GpIo_Driver.UnmapIoRegisrty(GpF);
974974end;
975975
976976procedure TForm1.GPIO23switchChange(Sender: TObject);
977977
978978Begin
979979 Timer1.Enabled := False;
980980 if GPIO23switch.Checked then
981981 begin
982982 GpF.SetBit(Pout); //Turn LED on
983983 end
984984 else
985985 begin
986986 GpF.ClearBit(Pout); //Turn LED off
987987 end;
988988 Timer1.Enabled := True;
989989end;
990990
991991procedure TForm1.SpeedButtonClick(Sender: TObject);
992992var
993993 i,p,k,v: longint;
994994 ido:TDateTime;
995995begin
996996 ido:= Time;
997997 k:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
998998 LogMemo.Lines.Add('Start: '+TimeToStr(ido));
999999 p:=10000000 ;
10001000 For i:=1 to p do Begin
10011001 GpF.SetBit(P16);
10021002 GpF.ClearBit(P16);
10031003 end;
10041004 ido:= Time;
10051005 v:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
10061006 LogMemo.Lines.Add('Stop: '+TimeToStr(ido)+' Frequency: '+
10071007 IntToStr(p div (v-k))+' kHz');
10081008end;
10091009
10101010procedure TForm1.Timer1Timer(Sender: TObject);
10111011begin
10121012 If PWM then Begin
10131013 If (d > 0) and (i+d < 1024) then begin
10141014 i:=i+d;
10151015 GpF.PwmWrite(Ppwm,i);
10161016 end ;
10171017 If (d < 0) and (i+d > -1) then begin
10181018 i:=i+d;
10191019 GpF.PwmWrite(Ppwm,i);
10201020 end;
10211021 end;
10221022end;
10231023
10241024
10251025end.
10261026```
10271027
10281028## 参考
10291029
10301030- Eben Upton and Gareth Halfacree. Raspberry Pi User Guide. John Wiley and Sons, Chichester 2012, ISBN 111846446X
10311031- B. J. Rao (2013) The Raspberry Pi, Pi Vision and Lazarus/FPC. [Blaise Pascal Magazine](http://www.blaisepascal.eu). 29: 14-21.
10321032
10331033## 外部链接
10341034
10351035- [Raspberry Pi 基础](http://www.raspberrypi.org)
10361036- [Raspberry Pi Spy: Raspberry Pi tutorials, scripts, help and downloads](http://www.raspberrypi-spy.co.uk)
10371037- [Lazarus wrapper unit for Gordon Henderson's wiringPi C library](http://www.lazarus.freepascal.org/index.php/topic,17404.0.html)
10381038- [Pin layout of the wiringPi library](https://projects.drogon.net/raspberry-pi/wiringpi/pins/)
10391039- [Additional information on Lazarus and Raspberry Pi at eLinux.org](http://www.elinux.org/Lazarus_on_RPi)
10401040- [Getting Started with Pascal on the Pi](http://www.pp4s.co.uk/main/gs-pi-intro.html)
10411041- [Lazberry Pi: Comprehensive information on Lazarus on the Raspberry Pi computer](http://superbitysoft.co.uk/lazberrypi/).
10421042- [Stefan Fischer's Lazarus unit rpi_hal](http://www.lazarus.freepascal.org/index.php/topic,20991.0.html).
10431043- [Improved Lazarus Unit for fast access to GPIO](http://www.meltonisl.com/software.html).
10441044
10451045---
10461046*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