Sign in Join
Wiki copytemporary

Lazarus on Raspberry Pi/zh CN: what changed

Revision 4 to 5. 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
2424![](/wiki-images/0/02/Install_Lazarus_Rasbian_Part1_en.png)
2525
2626安装步骤 1
2727
2828![](/wiki-images/4/4a/Install_Lazarus_Rasbian_Part2_en.png)
2929
3030安装步骤 2
3131
3232![](/wiki-images/5/53/Install_Lazarus_Rasbian_Part3_en.png)
3333
3434安装步骤 3
3535
3636![](/wiki-images/2/24/Install_Lazarus_Rasbian_Part4_en.png)
3737
3838安装步骤 4
3939
4040如果你需要一个新的版本,或者抱怨Lazarus 的问题, [点击](http://www.raspberrypi.org/forums/viewtopic.php?f=34&t=88145).
4141
4242#### Raspberry Pi 2
4343
4444自2015六月起,普通的“out of the box”安装方法也适用于安装树莓派2的B型。但是安装时获得的版本是相当旧的。想要获得新版FPC和Lazarus请看链接 [相关文章](http://www.tweaking4all.com/hardware/raspberry-pi/install-lazarus-pascal-on-raspberry-pi-2/).
4545
4646![](/wiki-images/c/cc/Lazarus_0_9_30_4_on_RPi_2.png)
4747
4848Lazarus "out of the box" on Raspberry Pi 2
4949
5050### 从Windows 对Raspberry Pi的交叉编译
5151
52521\. 使用 fpcup
5353
5454使用fpcup是实现交叉编译的一种方法,输入下面的指令: [[fpcup|fpcup#Linux_ARM_cross_compiler]]
5555
56562\. 使用脚本
5757
5858可以使用手动批处理文件,按照以下步骤。
5959
60602.1 先决条件
6161
62-`FPC 2.7.1或更高的安装源代码`\
63-`下载并安装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)
62+```text
63+FPC 2.7.1或更高的安装源代码
64+下载并安装Windows版本的Linaro binutils for linux gnueabihf到%FPCPATH%/bin/win32-armhf-linux [https://launchpad.net/linaro-toolchain-binaries/trunk/2013.10/+download/gcc-linaro-arm-linux-gnueabihf-4.8-2013.10_win32.zip]
65+```
6466
65672.2 创建脚本(需要匹配实际路径)
6668
6769``` bat
6870set PATH=C:\pp\bin\i386-win32;%PATH%;
6971set FPCMAKEPATH=C:/pp
7072set FPCPATH=C:/pp
7173set OUTPATH=C:/pp271
7274%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
7375
7476%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
7577if errorlevel 1 goto quit
7678%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%
7779
7880:quit
7981pause
8082```
8183
8284使用生成的ppcrossarm.exe和 ARM RTL,你可以创建跨平台的Lazarus工程,生成Raspberry Pi和其他armhf设备的应用程序。 注意,这里不包括所有Window 库。
8385
8486### 编译源代码
8587
8688如果你想要从Subversion编译Lazarus源代码。请看 \[<http://www.michellcomputing.co.uk/blog/?p=72>: Michell Computing: Lazarus on the Raspberry Pi\]
8789
8890![](/wiki-images/8/8d/Start_Menu_with_Lazarus_en.png)
8991
9092How to start Lazarus in Raspbian Wheezy
9193
9294![](/wiki-images/8/87/Lazarus_on_Raspberry_Pi.jpg)
9395
9496Lazarus on Raspberry Pi
9597
9698![](/wiki-images/c/c7/Rpi_gpio_pins.png)
9799
98100Numbering of GPIO pins
99101
100102用Gentoo(及其他版本)在Raspberry上编译源码
101103
102104- Gentoo是一个基于Linux的自由操作系统
103105
104106------------------------------------------------------------------------
105107
106108如果你想安装最新版的FPC及附件,或者是集成FPC编译器:请阅读下面的指南 这是关于Gentoo的例子,本指南适用其他版本:[[Install fpc on Raspberry with Gentoo]]
107109
108110## 访问外部硬件
109111
110112![](/wiki-images/f/f2/Rpi_pinout_all_50.png)
111113
112114Raspberry Pi的发展的目标之一是方便轻松地访问外部设备,如传感器和控制器。Lazarus有五种方法来访问I/O设备:
113115
1141161. [[Lazarus on Raspberry Pi|原生代码直接访问]],使用[[BaseUnix]]单元
1151172. 通过 [[Lazarus on Raspberry Pi|封装外壳调用]]
1161183. 通过 [[Lazarus on Raspberry Pi|wiringPi 库]].
1171194. 使用单元 [[Lazarus on Raspberry Pi|rpi_hal]].
1181205. 使用单元 [[Lazarus on Raspberry Pi|PiGpio]].
1191216. 通过 [PascalIO](https://github.com/SAmeis/pascalio) 库访问.
120122
121123### 1. 原生代码直接访问
122124
123125![对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)
124126
125127这种访问外部硬件的方法,不需要额外的库。唯一的要求是baseunix库,这是Free Pascal的RTL部分。
126128
127129#### 通过GPIO端口控制开关
128130
129131下面将演示一个简单程序。控制GPIO的17号引脚的电压,可以用来控制LED、晶体管或继电器。 程序包含*GPIO17ToggleBox*的实例[[doc:lcl/stdctrls/ttogglebox.html|ToggleBox]]和日志返回*LogMemo*类的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]。
130132
131133例如,一个LED的阳极连接到引脚11上(BCM2835 SoC对应的GPIO为17)和LED的阴极通过一个68欧姆的电阻连接引脚6(GND)。随后,LED会随着应用程序的toggle box切换点亮和熄灭。
132134
133135该代码需要root权限运行,即从root帐号(不推荐)运行或通过“*su*'。
134136
135137*控制单元:*
136138
137139``` pascal
138140unit Unit1;
139141
140142{Demo application for GPIO on Raspberry Pi}
141143{Inspired by the Python input/output demo application by Gareth Halfacree}
142144{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
143145
144146{$mode objfpc}{$H+}
145147
146148interface
147149
148150uses
149151 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
150152 Unix, BaseUnix;
151153
152154type
153155
154156 { TForm1 }
155157
156158 TForm1 = class(TForm)
157159 LogMemo: TMemo;
158160 GPIO17ToggleBox: TToggleBox;
159161 procedure FormActivate(Sender: TObject);
160162 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
161163 procedure GPIO17ToggleBoxChange(Sender: TObject);
162164 private
163165 { private declarations }
164166 public
165167 { public declarations }
166168 end;
167169
168170const
169171 PIN_17: PChar = '17';
170172 PIN_ON: PChar = '1';
171173 PIN_OFF: PChar = '0';
172174 OUT_DIRECTION: PChar = 'out';
173175
174176var
175177 Form1: TForm1;
176178 gReturnCode: longint; {stores the result of the IO operation}
177179
178180implementation
179181
180182{$R *.lfm}
181183
182184{ TForm1 }
183185
184186procedure TForm1.FormActivate(Sender: TObject);
185187var
186188 fileDesc: integer;
187189begin
188190 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
189191 try
190192 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
191193 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
192194 LogMemo.Lines.Add(IntToStr(gReturnCode));
193195 finally
194196 gReturnCode := fpclose(fileDesc);
195197 LogMemo.Lines.Add(IntToStr(gReturnCode));
196198 end;
197199 { Set SoC pin 17 as output: }
198200 try
199201 fileDesc := fpopen('/sys/class/gpio/gpio17/direction', O_WrOnly);
200202 gReturnCode := fpwrite(fileDesc, OUT_DIRECTION[0], 3);
201203 LogMemo.Lines.Add(IntToStr(gReturnCode));
202204 finally
203205 gReturnCode := fpclose(fileDesc);
204206 LogMemo.Lines.Add(IntToStr(gReturnCode));
205207 end;
206208end;
207209
208210procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
209211var
210212 fileDesc: integer;
211213begin
212214 { Free SoC pin 17: }
213215 try
214216 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
215217 gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
216218 LogMemo.Lines.Add(IntToStr(gReturnCode));
217219 finally
218220 gReturnCode := fpclose(fileDesc);
219221 LogMemo.Lines.Add(IntToStr(gReturnCode));
220222 end;
221223end;
222224
223225procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
224226var
225227 fileDesc: integer;
226228begin
227229 if GPIO17ToggleBox.Checked then
228230 begin
229231 { Swith SoC pin 17 on: }
230232 try
231233 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
232234 gReturnCode := fpwrite(fileDesc, PIN_ON[0], 1);
233235 LogMemo.Lines.Add(IntToStr(gReturnCode));
234236 finally
235237 gReturnCode := fpclose(fileDesc);
236238 LogMemo.Lines.Add(IntToStr(gReturnCode));
237239 end;
238240 end
239241 else
240242 begin
241243 { Switch SoC pin 17 off: }
242244 try
243245 fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
244246 gReturnCode := fpwrite(fileDesc, PIN_OFF[0], 1);
245247 LogMemo.Lines.Add(IntToStr(gReturnCode));
246248 finally
247249 gReturnCode := fpclose(fileDesc);
248250 LogMemo.Lines.Add(IntToStr(gReturnCode));
249251 end;
250252 end;
251253end;
252254
253255end.
254256```
255257
256258*Main program:*
257259
258260``` pascal
259261program io_test;
260262
261263{$mode objfpc}{$H+}
262264
263265uses
264266 {$IFDEF UNIX}{$IFDEF UseCThreads}
265267 cthreads,
266268 {$ENDIF}{$ENDIF}
267269 Interfaces, // this includes the LCL widgetset
268270 Forms, Unit1
269271 { you can add units after this };
270272
271273{$R *.res}
272274
273275begin
274276 Application.Initialize;
275277 Application.CreateForm(TForm1, Form1);
276278 Application.Run;
277279end.
278280```
279281
280282#### 读取引脚的状态
281283
282284![读取一个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)
283285
284286当然也可以从GPIO端口读取一个开关的状态。
285287
286288下面的简单例子非常类似于前一个例子。使用GPIO的18号引脚,控制二进制设备如开关输入,晶体管或继电器。这个程序包含一个名称为[[doc:lcl/stdctrls/tcheckbox.html|CheckBox]]的*GPIO18CheckBox* 与*LogMemo*的实例[[doc:lcl/stdctrls/tmemo.html|TMemo]]日志返回代码。
287289
288290在实例中,第12引脚的一端连接一个按钮,按钮的一端(对应的GPIO引脚18的BCM2835 SoC)通过一个10欧姆的上拉电阻和引脚1连接(+3.3 V,看接线图)。按钮的另一端连接6号引脚(GND)。按钮的开关状态对应和程序中复选框的打开或关闭状态对应。
289291
290292注意,当按钮释放时18脚的电位为高(由通过上拉电阻连接到引脚1),当按钮压下时电压为低(因为在这种情况下,引脚18是通过开关连接到GND)。因此,按钮按下时GPIO引脚信号为0,当释放时信号为1。
291293
292294这个程序同样需要root权限
293295
294296*控制单元:*
295297
296298``` pascal
297299unit Unit1;
298300
299301{Demo application for GPIO on Raspberry Pi}
300302{Inspired by the Python input/output demo application by Gareth Halfacree}
301303{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
302304
303305{This application reads the status of a push-button}
304306
305307{$mode objfpc}{$H+}
306308
307309interface
308310
309311uses
310312 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
311313 ButtonPanel, Unix, BaseUnix;
312314
313315type
314316
315317 { TForm1 }
316318
317319 TForm1 = class(TForm)
318320 ApplicationProperties1: TApplicationProperties;
319321 GPIO18CheckBox: TCheckBox;
320322 LogMemo: TMemo;
321323 procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
322324 procedure FormActivate(Sender: TObject);
323325 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
324326 private
325327 { private declarations }
326328 public
327329 { public declarations }
328330 end;
329331
330332const
331333 PIN_18: PChar = '18';
332334 IN_DIRECTION: PChar = 'in';
333335
334336var
335337 Form1: TForm1;
336338 gReturnCode: longint; {stores the result of the IO operation}
337339
338340implementation
339341
340342{$R *.lfm}
341343
342344{ TForm1 }
343345
344346procedure TForm1.FormActivate(Sender: TObject);
345347var
346348 fileDesc: integer;
347349begin
348350 { Prepare SoC pin 18 (pin 12 on GPIO port) for access: }
349351 try
350352 fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
351353 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
352354 LogMemo.Lines.Add(IntToStr(gReturnCode));
353355 finally
354356 gReturnCode := fpclose(fileDesc);
355357 LogMemo.Lines.Add(IntToStr(gReturnCode));
356358 end;
357359 { Set SoC pin 18 as input: }
358360 try
359361 fileDesc := fpopen('/sys/class/gpio/gpio18/direction', O_WrOnly);
360362 gReturnCode := fpwrite(fileDesc, IN_DIRECTION[0], 2);
361363 LogMemo.Lines.Add(IntToStr(gReturnCode));
362364 finally
363365 gReturnCode := fpclose(fileDesc);
364366 LogMemo.Lines.Add(IntToStr(gReturnCode));
365367 end;
366368end;
367369
368370procedure TForm1.ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
369371var
370372 fileDesc: integer;
371373 buttonStatus: string[1] = '1';
372374begin
373375 try
374376 { Open SoC pin 18 (pin 12 on GPIO port) in read-only mode: }
375377 fileDesc := fpopen('/sys/class/gpio/gpio18/value', O_RdOnly);
376378 if fileDesc > 0 then
377379 begin
378380 { Read status of this pin (0: button pressed, 1: button released): }
379381 gReturnCode := fpread(fileDesc, buttonStatus[1], 1);
380382 LogMemo.Lines.Add(IntToStr(gReturnCode) + ': ' + buttonStatus);
381383 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
382384 if buttonStatus = '0' then
383385 GPIO18CheckBox.Checked := true
384386 else
385387 GPIO18CheckBox.Checked := false;
386388 end;
387389 finally
388390 { Close SoC pin 18 (pin 12 on GPIO port) }
389391 gReturnCode := fpclose(fileDesc);
390392 LogMemo.Lines.Add(IntToStr(gReturnCode));
391393 LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
392394 end;
393395end;
394396
395397procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
396398var
397399 fileDesc: integer;
398400begin
399401 { Free SoC pin 18: }
400402 try
401403 fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
402404 gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
403405 LogMemo.Lines.Add(IntToStr(gReturnCode));
404406 finally
405407 gReturnCode := fpclose(fileDesc);
406408 LogMemo.Lines.Add(IntToStr(gReturnCode));
407409 end;
408410end;
409411
410412end.
411413```
412414
413415上面的例子主程序是相同的,。
414416
415417### 2. 通过封装的外壳访问硬件
416418
417419访问硬件的另一种方法是通过封装终端命令。这是通过使用[[Executing External Programs|fpsystem]]功能。这种方法可以访问baseunix单元不支持的功能。下面的代码实现了一个具有相同功能的程序,该程序是从上面的第一个清单所产生的。
418420
419421*控制单元:*
420422
421423``` pascal
422424unit Unit1;
423425
424426{Demo application for GPIO on Raspberry Pi}
425427{Inspired by the Python input/output demo application by Gareth Halfacree}
426428{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
427429
428430{$mode objfpc}{$H+}
429431
430432interface
431433
432434uses
433435 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Unix;
434436
435437type
436438
437439 { TForm1 }
438440
439441 TForm1 = class(TForm)
440442 LogMemo: TMemo;
441443 GPIO17ToggleBox: TToggleBox;
442444 procedure FormActivate(Sender: TObject);
443445 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
444446 procedure GPIO17ToggleBoxChange(Sender: TObject);
445447 private
446448 { private declarations }
447449 public
448450 { public declarations }
449451 end;
450452
451453var
452454 Form1: TForm1;
453455 gReturnCode: longint; {stores the result of the IO operation}
454456
455457implementation
456458
457459{$R *.lfm}
458460
459461{ TForm1 }
460462
461463procedure TForm1.FormActivate(Sender: TObject);
462464begin
463465 { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
464466 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/export');
465467 LogMemo.Lines.Add(IntToStr(gReturnCode));
466468 { Set SoC pin 17 as output: }
467469 gReturnCode := fpsystem('echo "out" > /sys/class/gpio/gpio17/direction');
468470 LogMemo.Lines.Add(IntToStr(gReturnCode));
469471end;
470472
471473procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
472474begin
473475 { Free SoC pin 17: }
474476 gReturnCode := fpsystem('echo "17" > /sys/class/gpio/unexport');
475477 LogMemo.Lines.Add(IntToStr(gReturnCode));
476478end;
477479
478480procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
479481begin
480482 if GPIO17ToggleBox.Checked then
481483 begin
482484 { Swith SoC pin 17 on: }
483485 gReturnCode := fpsystem('echo "1" > /sys/class/gpio/gpio17/value');
484486 LogMemo.Lines.Add(IntToStr(gReturnCode));
485487 end
486488 else
487489 begin
488490 { Switch SoC pin 17 off: }
489491 gReturnCode := fpsystem('echo "0" > /sys/class/gpio/gpio17/value');
490492 LogMemo.Lines.Add(IntToStr(gReturnCode));
491493 end;
492494end;
493495
494496end.
495497```
496498
497499主程序与上面的例子相同。这个程序必须用根权限执行。
498500
499501### 3. wiringPi方法与函数
500502
501503Alex Schaller封装的Gordon Henderson的Arduino兼容wiringpi库,提供了一种类似Arduino电路板的编码方案。
502504
503505**Function wiringPiSetup:longint:** 使用wiringpi引脚编号方案初始化wiringpi系统
504506
505507**Procedure wiringPiGpioMode(mode:longint):** 用Broadcom的GPIO引脚编号方案wiringpi初始化系统。
506508
507509**Procedure pullUpDnControl(pin:longint;** pud:longint): 控制内部GPIO引脚上拉/下拉电阻。
508510
509511**Procedure pinMode(pin:longint; mode:longint):** 设置一个PIN的模式:输入、输出或pwm_output。
510512
511513**Procedure digitalWrite(pin:longint; value:longint):** 设置一个输出位。
512514
513515**Procedure pwmWrite(pin:longint; value:longint):** 设置一个输出PWM(脉宽调制)值,0到1024之间。
514516
515517**Function digitalRead(pin:longint):longint:** 读取一个给定引脚的值,返回1或0。
516518
517519**Procedure delay(howLong:dword):** 等待多少毫秒。
518520
519521**Procedure delayMicroseconds(howLong:dword):** 等待多少微秒。
520522
521523**Function millis:dword:** 返回程序调用wiringpisetup函数花费的毫秒数。
522524
523525### 4. rpi_hal-hardware抽象库 (GPIO, I2C and SPI 函数与方法)
524526
525527这个单元大约1700行代码,由Stefan Fischer提供,提供程序和函数访问RPI硬件I2C,SPI和GPIO:
526528
527529下面是函数和方法的摘录:
528530
529531**procedure gpio_set_pin (pin:longword;highlevel:boolean);** { 设置 RPi GPIO 引脚速率为高或低; 速率 @ 700MHz -\> 0.65MHz }
530532
531533**function gpio_get_PIN (pin:longword):boolean;** { 获取 RPi GPIO 引脚等级,当Pin为'1'时返回True,为'0'时返回false; 速率 @ 700MHz -\> 1.17MHz }
532534
533535**procedure gpio_set_input (pin:longword);** { 设置 RPi GPIO 引脚为直接输入}
534536
535537**procedure gpio_set_output(pin:longword);** { 设置 RPi GPIO 引脚为直接输出 }
536538
537539**procedure gpio_set_alt (pin,altfunc:longword);** { 设置 RPi GPIO 引脚为备用功能 0..5 }
538540
539541**procedure gpio_set_gppud (mask:longword);** { 设置RPI GPIO拉上/下登记(gppud)}
540542
541543...
542544
543545**function rpi_snr :string;** { 信噪比: 0000000012345678 }
544546
545547**function rpi_hw :string;** { 处理器类型: BCM2708 }
546548
547549**function rpi_proc:string;** { ARMv6-compatible processor rev 7 (v6l) }
548550
549551...
550552
551553**function i2c_bus_write(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
552554
553555**function i2c_bus_read (baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : integer;**
554556
555557**function i2c_string_read(baseadr,reg:word; var <data:databuf_t>; lgt:byte; testnr:integer) : string;**
556558
557559**function i2c_string_write(baseadr,reg:word; s:string; testnr:integer) : integer;**
558560
559561...
560562
561563**procedure SPI_Write(devnum:byte; reg,data:word);**
562564
563565**function SPI_Read(devnum:byte; reg:word) : byte;**
564566
565567**procedure SPI_BurstRead2Buffer (devnum,start_reg:byte; xferlen:longword);**
566568
567569**procedure SPI_BurstWriteBuffer (devnum,start_reg:byte; xferlen:longword);** { 从缓冲区SPI的地址写入一段字节的内容 }
568570
569571...
570572
571573*测试程序 (testrpi.pas):*
572574
573575``` pascal
574576//Simple Test program, which is using rpi_hal;
575577
576578 program testrpi;
577579 uses rpi_hal;
578580 begin
579581 writeln('Show CPU-Info, RPI-HW-Info and Registers:');
580582 rpi_show_all_info;
581583 writeln('Let Status LED Blink. Using GPIO functions:');
582584 GPIO_PIN_TOGGLE_TEST;
583585 writeln('Test SPI Read function. (piggy back board with installed RFM22B Module is required!)');
584586 Test_SPI;
585587 end.
586588```
587589
588590### 5. 底层pascal单元 PiGpio(代替wiringpi C语言库的GPIO控制)
589591
590-*这个单元 (pigpio.pas[2](https://docs.google.com/file/d/0B-b-5ooIWPvGN1BIcEJzRDgyeUE/edit?usp=sharing)) 270 行代码是由Gabor Szollosi提供的 , 运行速度飞快(例如GPIO引脚输出开关频率达到8MHz) :*
592+*这个单元 (pigpio.pas[1](https://docs.google.com/file/d/0B-b-5ooIWPvGN1BIcEJzRDgyeUE/edit?usp=sharing)) 270 行代码是由Gabor Szollosi提供的 , 运行速度飞快(例如GPIO引脚输出开关频率达到8MHz) :*
591593
592594``` pascal
593595unit PiGpio;
594596{
595597 BCM2835 GPIO Registry Driver, also can use to manipulate cpu other registry areas
596598
597599 This code is tested only Broadcom bcm2835 cpu, different arm cpus may need different
598600 gpio driver implementation
599601
600602 2013 Gabor Szollosi
601603}
602604{$mode objfpc}{$H+}
603605
604606interface
605607
606608uses
607609 Classes, SysUtils;
608610
609611const
610612 REG_GPIO = $20000;//bcm2835 gpio register 0x2000 0000. new fpMap uses page offset, one page is 4096bytes
611613 // hex 0x1000 so simply calculate 0x2000 0000 / 0x1000 = 0x2000 0
612614 PAGE_SIZE = 4096;
613615 BLOCK_SIZE = 4096;
614616 // The BCM2835 has 54 GPIO pins.
615617// BCM2835 data sheet, Page 90 onwards.
616618// There are 6 control registers, each control the functions of a block
617619// of 10 pins.
618620
619621 CLOCK_BASE = (REG_GPIO + $101);
620622 GPIO_BASE = (REG_GPIO + $200);
621623 GPIO_PWM = (REG_GPIO + $20C);
622624
623625 INPUT = 0;
624626 OUTPUT = 1;
625627 PWM_OUTPUT = 2;
626628 LOW = False;
627629 HIGH = True;
628630 PUD_OFF = 0;
629631 PUD_DOWN = 1;
630632 PUD_UP = 2;
631633
632634 // PWM
633635
634636 PWM_CONTROL = 0;
635637 PWM_STATUS = 4;
636638 PWM0_RANGE = 16;
637639 PWM0_DATA = 20;
638640 PWM1_RANGE = 32;
639641 PWM1_DATA = 36;
640642
641643 PWMCLK_CNTL = 160;
642644 PWMCLK_DIV = 164;
643645
644646 PWM1_MS_MODE = $8000; // Run in MS mode
645647 PWM1_USEFIFO = $2000; // Data from FIFO
646648 PWM1_REVPOLAR = $1000; // Reverse polarity
647649 PWM1_OFFSTATE = $0800; // Ouput Off state
648650 PWM1_REPEATFF = $0400; // Repeat last value if FIFO empty
649651 PWM1_SERIAL = $0200; // Run in serial mode
650652 PWM1_ENABLE = $0100; // Channel Enable
651653
652654 PWM0_MS_MODE = $0080; // Run in MS mode
653655 PWM0_USEFIFO = $0020; // Data from FIFO
654656 PWM0_REVPOLAR = $0010; // Reverse polarity
655657 PWM0_OFFSTATE = $0008; // Ouput Off state
656658 PWM0_REPEATFF = $0004; // Repeat last value if FIFO empty
657659 PWM0_SERIAL = $0002; // Run in serial mode
658660 PWM0_ENABLE = $0001; // Channel Enable
659661
660662type
661663
662664 { TIoPort }
663665
664666 TIoPort = class // IO bank object
665667 private //
666668
667669 //function get_pinDirection(aPin: TGpIoPin): TGpioPinConf;
668670
669671 public
670672 FGpio: ^LongWord;
671673 FClk: ^LongWord;
672674 FPwm: ^LongWord;
673675 procedure SetPinMode(gpin, mode: byte);
674676 function GetBit(gpin : byte):boolean;inline; // gets pin bit}
675677 procedure ClearBit(gpin : byte);inline;// write pin to 0
676678 procedure SetBit(gpin : byte);inline;// write pin to 1
677679 procedure SetPullMode(gpin, mode: byte);
678680 procedure PwmWrite(gpin : byte; value : LongWord);inline;// write pin to pwm value
679681 end;
680682
681683 { TIoDriver }
682684
683685 TIoDriver = class
684686 private
685687
686688 public
687689 destructor Destroy;override;
688690 function MapIo:boolean;// creates io memory mapping
689691 procedure UnmapIoRegisrty(FMap: TIoPort);// close io memory mapping
690692 function CreatePort(PortGpio, PortClk, PortPwm: LongWord):TIoPort; // create new IO port
691693 end;
692694
693695var
694696
695697 fd: integer;// /dev/mem file handle
696698procedure delayNanoseconds (howLong : LongWord);
697699
698700implementation
699701
700702uses
701703 baseUnix, Unix;
702704
703705procedure delayNanoseconds (howLong : LongWord);
704706var
705707 sleeper, dummy : timespec;
706708begin
707709 sleeper.tv_sec := 0 ;
708710 sleeper.tv_nsec := howLong ;
709711 fpnanosleep (@sleeper,@dummy) ;
710712end;
711713{ TIoDriver }
712714//*******************************************************************************
713715destructor TIoDriver.Destroy;
714716begin
715717 inherited Destroy;
716718end;
717719//*******************************************************************************
718720function TIoDriver.MapIo: boolean;
719721begin
720722 Result := True;
721723 fd := fpopen('/dev/mem', O_RdWr or O_Sync); // Open the master /dev/memory device
722724 if fd < 0 then
723725 begin
724726 Result := False; // unsuccessful memory mapping
725727 end;
726728 //
727729end;
728730//*******************************************************************************
729731procedure TIoDriver.UnmapIoRegisrty(FMap:TIoPort);
730732begin
731733 if FMap.FGpio <> nil then
732734 begin
733735 fpMUnmap(FMap.FGpio,PAGE_SIZE);
734736 FMap.FGpio := Nil;
735737 end;
736738 if FMap.FClk <> nil then
737739 begin
738740 fpMUnmap(FMap.FClk,PAGE_SIZE);
739741 FMap.FClk := Nil;
740742 end;
741743 if FMap.FPwm <> nil then
742744 begin
743745 fpMUnmap(FMap.FPwm ,PAGE_SIZE);
744746 FMap.FPwm := Nil;
745747 end;
746748end;
747749//*******************************************************************************
748750function TIoDriver.CreatePort(PortGpio, PortClk, PortPwm: LongWord): TIoPort;
749751begin
750752 Result := TIoPort.Create;// new io port, pascal calls new fpMap, where offst is page sized 4096 bytes!!!
751753 Result.FGpio := FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortGpio); // port config gpio memory
752754 Result.FClk:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortClk);; // port clk
753755 Result.FPwm:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortPwm);; // port pwm
754756end;
755757//*******************************************************************************
756758procedure TIoPort.SetPinMode(gpin, mode: byte);
757759var
758760 fSel, shift, alt : byte;
759761 gpiof, clkf, pwmf : ^LongWord;
760762begin
761763 fSel := (gpin div 10)*4 ; //Select Gpfsel 0 to 5 register
762764 shift := (gpin mod 10)*3 ; //0-9 pin shift
763765 gpiof := Pointer(LongWord(Self.FGpio)+fSel);
764766 if (mode = INPUT) then
765767 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) //7 shl shift komplemens - Sets bits to zero = input
766768 else if (mode = OUTPUT) then
767769 begin
768770 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (1 shl shift);
769771 end
770772 else if (mode = PWM_OUTPUT) then
771773 begin
772774 Case gpin of
773775 12,13,40,41,45 : alt:= 4 ;
774776 18,19 : alt:= 2 ;
775777 else alt:= 0 ;
776778 end;
777779 If alt > 0 then
778780 begin
779781 gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (alt shl shift);
780782 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
781783 clkf^ := $5A000011 or (1 shl 5) ; //stop clock
782784 delayNanoseconds(200);
783785 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_DIV);
784786 clkf^ := $5A000000 or (32 shl 12) ; // set pwm clock div to 32 (19.2/3 = 600KHz)
785787 clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
786788 clkf^ := $5A000011 ; //start clock
787789 Self.ClearBit(gpin);
788790 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
789791 pwmf^ := 0 ; // Disable PWM
790792 delayNanoseconds(200);
791793 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_RANGE);
792794 pwmf^ := $400 ; //max: 1023
793795 delayNanoseconds(200);
794796 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_RANGE);
795797 pwmf^ := $400 ; //max: 1023
796798 delayNanoseconds(200);
797799 // Enable PWMs
798800 pwmf := Pointer(LongWord(Self.FPwm)+PWM0_DATA);
799801 pwmf^ := 0 ; //start value
800802 pwmf := Pointer(LongWord(Self.FPwm)+PWM1_DATA);
801803 pwmf^ := 0 ; //start value
802804 pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
803805 pwmf^ := PWM0_ENABLE or PWM1_ENABLE ;
804806 end;
805807 end;
806808end;
807809//*******************************************************************************
808810procedure TIoPort.SetBit(gpin : byte);
809811var
810812 gpiof : ^LongWord;
811813begin
812814 gpiof := Pointer(LongWord(Self.FGpio) + 28 + (gpin shr 5) shl 2);
813815 gpiof^ := 1 shl gpin;
814816end;
815817//*******************************************************************************
816818procedure TIoPort.ClearBit(gpin : byte);
817819var
818820 gpiof : ^LongWord;
819821begin
820822 gpiof := Pointer(LongWord(Self.FGpio) + 40 + (gpin shr 5) shl 2);
821823 gpiof^ := 1 shl gpin;
822824end;
823825//*******************************************************************************
824826function TIoPort.GetBit(gpin : byte):boolean;
825827var
826828 gpiof : ^LongWord;
827829begin
828830 gpiof := Pointer(LongWord(Self.FGpio) + 52 + (gpin shr 5) shl 2);
829831 if (gpiof^ and (1 shl gpin)) = 0 then Result := False else Result := True;
830832end;
831833//*******************************************************************************
832834procedure TIoPort.SetPullMode(gpin, mode: byte);
833835var
834836 pudf, pudclkf : ^LongWord;
835837begin
836838 pudf := Pointer(LongWord(Self.FGpio) + 148 );
837839 pudf^ := mode; //mode = 0, 1, 2 :Off, Down, Up
838840 delayNanoseconds(200);
839841 pudclkf := Pointer(LongWord(Self.FGpio) + 152 + (gpin shr 5) shl 2);
840842 pudclkf^ := 1 shl gpin ;
841843 delayNanoseconds(200);
842844 pudf^ := 0 ;
843845 pudclkf^ := 0 ;
844846end;
845847//*******************************************************************************
846848procedure TIoPort.PwmWrite(gpin : byte; value : Longword);
847849var
848850 pwmf : ^LongWord;
849851 port : byte;
850852begin
851853 Case gpin of
852854 12,18,40 : port:= PWM0_DATA ;
853855 13,19,41,45 : port:= PWM1_DATA ;
854856 else exit;
855857 end;
856858 pwmf := Pointer(LongWord(Self.FPwm) + port);
857859 pwmf^ := value and $FFFFFBFF; // $400 complemens
858860end;
859861//*******************************************************************************
860862end.
861863```
862864
863-*Controlling Lazarus unit:(Project files[3](https://drive.google.com/folderview?id=0B-b-5ooIWPvGU043ZTZ0cUc2YkE&usp=sharing))*
865+*Controlling Lazarus unit:(Project files[2](https://drive.google.com/folderview?id=0B-b-5ooIWPvGU043ZTZ0cUc2YkE&usp=sharing))*
864866
865867``` pascal
866868unit Unit1;
867869
868870{Demo application for GPIO on Raspberry Pi}
869871{Inspired by the Python input/output demo application by Gareth Halfacree}
870872{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
871873
872874{$mode objfpc}{$H+}
873875
874876interface
875877
876878uses
877879 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
878880 ExtCtrls, Unix, PiGpio;
879881
880882type
881883
882884 { TForm1 }
883885
884886 TForm1 = class(TForm)
885887 GPIO25In: TButton;
886888 SpeedButton: TButton;
887889 LogMemo: TMemo;
888890 GPIO23switch: TToggleBox;
889891 Timer1: TTimer;
890892 GPIO18Pwm: TToggleBox;
891893 Direction: TToggleBox;
892894 procedure DirectionChange(Sender: TObject);
893895 procedure GPIO18PwmChange(Sender: TObject);
894896 procedure GPIO25InClick(Sender: TObject);
895897 procedure FormActivate(Sender: TObject);
896898 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
897899 procedure GPIO23switchChange(Sender: TObject);
898900 procedure SpeedButtonClick(Sender: TObject);
899901 procedure Timer1Timer(Sender: TObject);
900902 private
901903 { private declarations }
902904 public
903905 { public declarations }
904906 end;
905907
906908const
907909 INPUT = 0;
908910 OUTPUT = 1;
909911 PWM_OUTPUT = 2;
910912 LOW = False;
911913 HIGH = True;
912914 PUD_OFF = 0;
913915 PUD_DOWN = 1;
914916 PUD_UP = 2;
915917 // Convert Raspberry Pi P1 pins (Px) to GPIO port
916918 P3 = 0;
917919 P5 = 1;
918920 P7 = 4;
919921 P8 = 14;
920922 P10 = 15;
921923 P11 = 17;
922924 P12 = 18;
923925 P13 = 21;
924926 P15 = 22;
925927 P16 = 23;
926928 P18 = 24;
927929 P19 = 10;
928930 P21 = 9;
929931 P22 = 25;
930932 P23 = 11;
931933 P24 = 8;
932934 P26 = 7;
933935
934936var
935937 Form1: TForm1;
936938 GPIO_Driver: TIoDriver;
937939 GpF: TIoPort;
938940 PWM :Boolean;
939941 i, d : integer;
940942 Pin,Pout,Ppwm : byte;
941943
942944implementation
943945
944946{$R *.lfm}
945947
946948{ TForm1 }
947949
948950procedure TForm1.FormActivate(Sender: TObject);
949951begin
950952 if not GPIO_Driver.MapIo then
951953 begin
952954 LogMemo.Lines.Add('Error mapping gpio registry');
953955 end
954956 else
955957 begin
956958 GpF := GpIo_Driver.CreatePort(GPIO_BASE, CLOCK_BASE, GPIO_PWM);
957959 end ;
958960 Timer1.Enabled:= True;
959961 Timer1.Interval:= 25; //25 ms controll interval
960962 Pin := P22;
961963 Pout := P16;
962964 Ppwm := P12;
963965 i:=1;
964966 GpF.SetPinMode(Pout,OUTPUT);
965967 GpF.SetPinMode(Pin,INPUT);
966968 GpF.SetPullMode(Pin,PUD_Up); // Input PullUp High level
967969end;
968970
969971procedure TForm1.GPIO25InClick(Sender: TObject);
970972begin
971973 If GpF.GetBit(Pin) then LogMemo.Lines.Add('In: '+IntToStr(1))
972974 else LogMemo.Lines.Add('In: '+IntToStr(0));
973975end;
974976
975977procedure TForm1.GPIO18PwmChange(Sender: TObject);
976978begin
977979 if GPIO18Pwm.Checked then
978980 begin
979981 GpF.SetPinMode(Ppwm,PWM_OUTPUT);
980982 PWM := True; //PWM on
981983 end
982984 else
983985 begin
984986 GpF.SetPinMode(Ppwm,INPUT);
985987 PWM := False; //PWM off
986988 end;
987989end;
988990
989991procedure TForm1.DirectionChange(Sender: TObject);
990992begin
991993 if Direction.Checked then d:=10 else d:=-10;
992994end;
993995
994996
995997procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
996998begin
997999 GpF.SetPinMode(Ppwm,INPUT);
9981000 GpF.ClearBit(Pout);
9991001 GpIo_Driver.UnmapIoRegisrty(GpF);
10001002end;
10011003
10021004procedure TForm1.GPIO23switchChange(Sender: TObject);
10031005
10041006Begin
10051007 Timer1.Enabled := False;
10061008 if GPIO23switch.Checked then
10071009 begin
10081010 GpF.SetBit(Pout); //Turn LED on
10091011 end
10101012 else
10111013 begin
10121014 GpF.ClearBit(Pout); //Turn LED off
10131015 end;
10141016 Timer1.Enabled := True;
10151017end;
10161018
10171019procedure TForm1.SpeedButtonClick(Sender: TObject);
10181020var
10191021 i,p,k,v: longint;
10201022 ido:TDateTime;
10211023begin
10221024 ido:= Time;
10231025 k:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
10241026 LogMemo.Lines.Add('Start: '+TimeToStr(ido));
10251027 p:=10000000 ;
10261028 For i:=1 to p do Begin
10271029 GpF.SetBit(P16);
10281030 GpF.ClearBit(P16);
10291031 end;
10301032 ido:= Time;
10311033 v:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
10321034 LogMemo.Lines.Add('Stop: '+TimeToStr(ido)+' Frequency: '+
10331035 IntToStr(p div (v-k))+' kHz');
10341036end;
10351037
10361038procedure TForm1.Timer1Timer(Sender: TObject);
10371039begin
10381040 If PWM then Begin
10391041 If (d > 0) and (i+d < 1024) then begin
10401042 i:=i+d;
10411043 GpF.PwmWrite(Ppwm,i);
10421044 end ;
10431045 If (d < 0) and (i+d > -1) then begin
10441046 i:=i+d;
10451047 GpF.PwmWrite(Ppwm,i);
10461048 end;
10471049 end;
10481050end;
10491051
10501052
10511053end.
10521054```
10531055
10541056## 参考
10551057
10561058- Eben Upton and Gareth Halfacree. Raspberry Pi User Guide. John Wiley and Sons, Chichester 2012, ISBN 111846446X
10571059- B. J. Rao (2013) The Raspberry Pi, Pi Vision and Lazarus/FPC. [Blaise Pascal Magazine](http://www.blaisepascal.eu). 29: 14-21.
10581060
10591061## 外部链接
10601062
10611063- [Raspberry Pi 基础](http://www.raspberrypi.org)
10621064- [Raspberry Pi Spy: Raspberry Pi tutorials, scripts, help and downloads](http://www.raspberrypi-spy.co.uk)
10631065- [Lazarus wrapper unit for Gordon Henderson's wiringPi C library](http://www.lazarus.freepascal.org/index.php/topic,17404.0.html)
10641066- [Pin layout of the wiringPi library](https://projects.drogon.net/raspberry-pi/wiringpi/pins/)
10651067- [Additional information on Lazarus and Raspberry Pi at eLinux.org](http://www.elinux.org/Lazarus_on_RPi)
10661068- [Getting Started with Pascal on the Pi](http://www.pp4s.co.uk/main/gs-pi-intro.html)
10671069- [Lazberry Pi: Comprehensive information on Lazarus on the Raspberry Pi computer](http://superbitysoft.co.uk/lazberrypi/).
10681070- [Stefan Fischer's Lazarus unit rpi_hal](http://www.lazarus.freepascal.org/index.php/topic,20991.0.html).
10691071- [Improved Lazarus Unit for fast access to GPIO](http://www.meltonisl.com/software.html).
10701072
10711073---
10721074*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