推荐10个好用的PCB设计工具

以下列出的是最值得推荐的10个印制电路板(PCB)设计软件:

  1. PCBWeb Designer
  2. ZenitPCB
  3. TinyCAD
  4. Osmond PCB
  5. BSch3V
  6. ExpressPCB
  7. KiCad
  8. Fritzing
  9. DesignSpark PCB
  10. gEDA

PCB设计软件工具比较标准

需要说明的是,这并不是一个最佳的排名列表,因为不同的任务和工作流程有不同的需要,我希望这个列表能让您了解在选择最适合您需求的设计时提供参考。

评估标准:

  • 用户界面(UI)设计:当我寻找PCB设计软件时,我首先关注的是这个工具是否设置了让设计者容易上手的导航栏。当我使用软件时,我会考虑与我交互的视觉按钮。直观的UI设计确保您可以立即开始设计电路,而无需花费大量时间学习或参考手册。
  • 受欢迎度:当更多的人使用一个软件工具时,是因为它有一些很棒的功能。例如,我查看掌握该工具的容易程度,以及其开发人员是否通过培训和易于理解的教程提供了出色的支持。
  • 集成:为了使PCB软件真正实现自动化并节省时间,它需要与您已经在使用的其他软件工具集成。因此,您选择的PCB软件能够与项目管理或其他PCB设计工具集成是很重要的。
  • 成本:大多数PCB设计软件工具都非常昂贵。这就是为什么我经常根据功能和成本来比较工具。虽然我接受工具会有不同的价格,因为它们有不同的功能。但我仍然想确保一个工具的价格对我的业务的价值和它的好处是值得的。

印制电路板(PCB)设计软件关键的特点

一个PCB设计工具要满足各种重要要求,就需要具备一定的基本特性。然而,重要的是要注意,对一个人来说很棒的功能可能对其他人来说并不相关。

以下这些是内容是我认为选择PCB设计软件需要关注的:

  • 仿真:为您提供电路原理是否正确、验证与分析PCB布局布线合理性以及是否满足可制造性。
  • 层数:这是一个基本功能,支持更多层数的PCB设计工具可以管理具有更复杂PCB设计要求的更高数量的组件。 3D建模:这可以让你了解PCB设计完成后的真实的样子。
  • 3D建模:这可以让你了解PCB设计完成后的真实的样子。
  • 复杂性和速度:PCB软件工具处理不同级别的复杂性和速度。更昂贵的工具通常能够处理更复杂的设计任务。这些工具通常提供更快的速度。
  • 库:PCB设计工具必须有一套相对完整的元件库文件。
  • Web和操作系统兼容性:检查软件是否需要下载到您的计算机上,或者您是否需要将其作为SaaS使用。此外,还要确定软件是否能与设备的操作系统兼容。

以下列出的是最值得推荐的10个印制电路板(PCB)设计软件的概要性的介绍:

下面,我提供了每个PCB设计软件工具的总结。我的描述集中在最佳用例和工具的主要特性上。

  1. PCBWeb Designer– 最好的,且免费的PCB设计软件

PCBWeb Designer是一个全方位服务的电子硬件设计和制造工具。它受欢迎的原因之一是它是免费的。这意味着对于一块板上使用的元器件数量没有限制。该软件也没有对板子大小的限制。

这个软件出现在最值得推荐的PCB设计软件列表上,因为它是免费的,且有一些很棒的功能。PCBWeb Designer易于使用的连线工具使设计多页原理图成为可能。此外,该软件允许布多层板,还支持DRC检查和敷铜。用户还可以使用材料清单管理器访问Arrow的元器件目录。

  1. ZenitPCB– 适合初学的PCB设计者

ZenitPCB出现在几乎所有最好的PCB设计软件工具列表中的一个原因是,该工具是直观的,非常容易学习,这使它成为一个优秀的程序。设计者不需要专门的培训就可以完成自己的PCB设计任务。

因为这是一个简单且实用的程序,你会注意到该工具主要是高中或大学的学生和他们的老师在使用。然而,这款软件的主要缺点是它没有自动布线器或自动布局等方便的功能。

如果您是个人或半专业用途使用这个程序,它是完全免费的,但有800pin的限制。

TinyCAD是一个用于绘制电路图(原理图)的开源程序。它支持标准元件库和支持用户创建自己的元件库。该工具还支持输出多种PCB网表,并可以生成SPICE网表。

尽管在TinyCAD中创建元件库相对容易,但这个过程非常耗时。然而,作为一个开源程序,它允许用户将他们认为对他人有用的符号上传到程序中,以便其他用户可以下载它们。

在TinyCAD网站上,您可以访问教程和其他支持材料,还可以创建和下载自定义元件库。如果您遇到了一些问题,您可以在网站上报告它们并获得帮助。

TinyCAD是一个免费的工具

  1. Osmond PCB– Best PCB design software for Macintosh 

Osmond PCB的开发人员承诺该工具必须具备灵活的特点。为了实现这一承诺,他们开发了允许用户使用公制或英制单位的软件。这两种单位,也可以用于相同的设计。该工具集成的元件编辑器使更改现有元件或定义新的元件变得容易。

Osmond PCB是一个优秀的程序,因为它没有任何限制。这意味着你可以设计任意大小和任意层数的PCB。一旦您完成了设计,Osmond将提供工具来帮助您检查完成的产品是否满足所有指定的设计规则。

Osmond PCB可免费使用。然而,也接受捐款以帮助支付持续支持和更新软件的费用。

  1. BSch3V– Best PCB design software for Windows

缩写“BSch”代表“Basic Schematic”。 BSch3V的设计者将其定义为Windows的原理图绘制程序。由于BSch3V的功能是基础的,所以它主要适用于项目不是很复杂的PCB设计。

BSch3V的主要功能包括一个元件库编辑器,PCB网表生成器和元件列表生成器。

BSch3V可以免费使用。

  1. ExpressPCB– Best PCB design software for reducing lead times 

ExpressPCB已经在市场上存在了20多年。因此,这是PCB设计团队的首选软件,他们想要节省从开始的一个想法到完成产品交付所花费的时间。此外,该软件多年来一直在不断改进,确保它既适合专业人士,也适合初学者。

您可以获得两个版本的ExpressPCB: ExpressPCB Classic和ExpressPCB Plus。Classic版本更适合需要易用性的团队。它的Schematic更容易上手,而它的快速设置意味着您可以尽可能快地开始工作。Plus版本是为需要灵活性的更复杂设计的团队设计的。

您可以免费使用ExpressPCB

  1. KiCad– Best for inspecting PSB designs in 3D 

KiCad是EDA(电子设计自动化)行业的开源软件,具有用于PCB设计的原理图、PCB布局和GERBER文件输出。该工具含有设计者希望的PCB设计软件中所有的标准功能,如软件自带的原理图符号库和内置的原理图符号编辑器等。

KiCad的最新版本5.1.10增强了一些功能,比如修复了关键bug。它还改进了3D模型库、PCB封装、原理图符号和文档。

KiCad是由包括法国格勒诺布尔大学在内的几个基金会和组织赞助的免费软件。

  1. Fritzing– Best for PCB design amateurs and hobbyists  

Fritzing是一个开源硬件项目,它借鉴Processing和Arduino平台,允许用户处理电路以进行快速原型开发,共享原型文档,并设计定制的PCB。该工具是由波茨坦应用科学大学开发的,以帮助PCB爱好者和业余爱好者。

Fritzing的最新版本0.9.6,允许通过在线数据库自动更新零件库。它还有助于关键错误的修复,高DPI显示支持,以及更容易的创建和自定义元件。

作为一个开源项目,fritzzing是一个免费的工具。

  1. DesignSpark PCB– Best for schematic capturing and layout improvement 

DesignSpark PCB是一个非常优秀的免费软件,它受欢迎的程度正在飙升。你会喜欢这个软件的主要因素之一是它的直观性,无论你是初学者还是有经验的专业人士,这个程序都很容易使用。该工具有助于设计PCB板和布局,原理图绘制,并进行布局改进。

将DesignSpark PCB列入最值得推荐的10个印制电路板(PCB)设计软件最重要的一个因素是,该工具无缝集成到PCB设计师已经使用的许多工具中。

DesignSpark PCB是一个免费工具。

  1. gEDA– Best for printed circuit board design 

gEDA是一个集多个开源软件包于一体的套件。它可以生成其他文件类型,如:*.ps或*.png。该软件具有自动布线功能和许多其他功能。软件即有强大的功能而且表现得很高效。特别推荐与gEDA原理图编辑器一起使用。

该工具主要面向印刷电路板设计(相对于集成电路设计),软件采取通用公共许可证(GPL)去完成电子设计。由于该项目的开放性,原理图符号、PCB封装和实用程序脚本可以在gEDA社区的一个附属网站(gedasymbols.org)上自由创建并共享。

gEDA提供丰富的库文件和专业支持社区且不收取额外费用。它是一个开源电子设计工具的集合。同时,也可以单独安装。

gEDA是免费使用的

Other PCB Design Software Tools 

其他被推荐的PCB设计软件

如果您不能在这上面介绍的工具中找到满足您所有需求的PCB软件,这里还有一些其他得工具可以推荐。

  • FreePCB:一个免费的,开源的,基于微软Windows操作系统开发的PCB设计软件,软件易于学习和使用,并且还能够专业,高质量的完成设计工作。
  • Eagle:一个容易使用的图形化界面的PCB布局编辑器(EAGLE),同时,软件具有强大的原理图功能和友好的界面,很多专业人士也在使用该工具。
  • Altium:这是一个具有高可靠性的PCB设计软件,软件将帮助设计者为实现多种真实的应用场景而创建令人惊叹的PCB。软件功能非常强大,并要求运行在Windows操作系统上。
  • DipTrace: 软件高效、快速地创建设计,从而节省设计时间。对于初学者或时间紧张的人来说,DipTrace非常理想,软件具有原理图绘制功能和PCB编辑以及布线功能,还能转换为多种格式。
  • Pulsonix:这是一个易于使用,提供一个完整且专业的PCB编辑器,用户还可选购极其优秀的自动布线器。该软件在一个设计环境中结合了原理图输入和PCB布局。
  • Sprint Layout:具有逻辑清晰且非常容易上手的PCB设计工具,软件适合任何人,特别是适合初学者且急于完成设计的人。软件支持集成Excel控件,也能输出专业的生产文件Gerber。
  • EasyEDA: 软件有自带的元件库超过100万,还允许用户创建或导入元件库。
  • PCB Artist:用户能够访问一个拥有超过50万个元器件库、设计多达28层的PCB设计文件,软件还具有人为干涉的自动布线器、能完成多页原理图绘制和自然导入Eagle格式的文件。
  • Ultiboard: 软件具有很多自动化的功能,使得设计者可以很快完成PCB设计。该工具其他的功能:如电子表格视图、工具箱和设计向导,使得管理PCB设计文件更容易。
  • Solidworks PCB易于将电子原理图集成到3D模型中,通过自动化重复任务节省您的时间。

下是在讨论PCB设计工具时经常遇到的两个问题:

什么是PCB设计软件?

PCB设计软件是设计工程师借助计算机来完成印刷电路板(PCB)的计算机程序。通常,该软件程序由一些软件模块工具组成,这些工具使用户能够在项目上进行协作,访问先前创建的元件库,并确定电路原理图设计的准确性等任务。

为什么需要PCB设计软件?

PCB设计软件对于PCB设计人员来说是至关重要的,因为它允许过程的自动化,否则需要很长时间才能完成。该软件还允许协作,使得将执行项目所需的所有信息放到单个文件仓库中成为可能,在该文件仓库中,所有项目相关人都可以实时看到变化。PCB设计软件对于管理质量也是至关重要的,因为它可以确定是否满足了所有的项目规格。

猫盘装群晖系统建网站

1、安装自己的wordpress(下载最新wordpress并解压到web目录,修改目录权限方便更新)
2、设置php(phpmyadmin)(全选),否则无法链接数据库/创建wordpress数据库
3、安装wordpress
4、安装relative插件
5、下载cpolar,所在目录执行权限不够,修改目录权限或拷贝至有权限目录
5、创建脚本并设置群辉本身的计划任务(开机启动脚本)

猫盘->群晖->网站

今天折腾群晖迷你Linux系统的时候遇到一个问题,Python写的程序基本上都会带上一些扩展包,今天在安装BeautifulSoup网页解析工具的时候遇到了麻烦。由于群晖迷你Linux系统阉割了很多功能,问题如下。

在安装BeautifulSoup网页解析包时,一般使用pip工具来安装,然而没有pip。

没有pip那就只好先安装pip工具了,要安装pip工具得先安装个epel-release,使用yum安装,提示没有yum。

安装yum提示没有rpm管理器,python缺失?

既然这些软件工具安装不了,那就只好下载yum源码编译安装,然而还是报错。

解决办法

直接下载pip源码编译安装即可。

首先通过群晖套件安装python3

然后安装setuptools工具,执行如下命令下载源码

wget --no-check-certificate https://files.pythonhosted.org/packages/6a/fa/5ec0fa9095c9b72cb1c31a8175c4c6745bf5927d1045d7a70df35d54944f/setuptools-59.6.0.tar.gz

然后解压

tar -zxvf setuptools-59.6.0.tar.gz

进入解压目录

cd setuptools-59.6.0

使用python3编译

python3 setup.py build

使用python3安装

python3 setup.py install

安装pip,执行下面命令下载到当前目录

wget --no-check-certificate https://files.pythonhosted.org/packages/da/f6/c83229dcc3635cdeb51874184241a9508ada15d8baa337a41093fab58011/pip-21.3.1.tar.gz

解压

tar -zxvf pip-21.3.1.tar.gz

进入pip目录

cd pip-21.3.1

python3编译

python3 setup.py build

python3安装

python3 setup.py install

设置环境变量

export PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/syno/sbin:/usr/syno/bin:/usr/local/sbin:/usr/local/bin:/volume1/@appstore/py3k/usr/local/bin"

由于每次关机环境变量会变化,所以大家最好一次将需要的扩展包下载完,不然以后再安装就需要再执行一下最后一句命令。

然后使用如下命令安装beautifulsoup扩展

pip3 install beautifulsoup4 datetime lxml pygame requests

安装完成后,运行python,然后执行下面代码不报错即可

from bs4 import BeautifulSoup

安装pip也可以按如下方式

执行sudo apt-get install python3-pip
若报 No module named ‘distutils.util’,执行 sudo apt-get install python3-distutils
若报E: Package python3-distutils has no installation candidate,执行: sudo apt update
再重新执行:sudo apt-get install python3-distutils
再执行:sudo apt-get install pyton3-pip

树莓派制作智能镜全过程

第一部分——点子与镜子

作为一个男人,跟女友逛商城时,像是梅西百货那种的,难免会走神。我就是那号人,去年一月在纽约就发生过一回。长话短说。在我闲晃时我发现一面有灯光照明的镜子。我完全能自己做一面出来,而且比这更好。我想要属于我自己的智能镜!

magic_mirror1

一回到家,我开始构想我需要的东西:一面镜子,薄的那种,一个树莓派,一些木头和油漆,还需要大量空余时间。

关于镜子

普通的镜子是不行的。镜子是要那种单面透光那种,或更加精细功能的:后面屏幕黑屏时,它是一面镜子;而信息在屏幕上显示时就该像普通玻璃窗那样。

和警察局问询室内那面镜子原理一样,当只有一间房有光时,它就像一面镜子,其他时候它就是普通玻璃窗。

magic_mirror3

我所需要的是一面观察镜。现在,请相信我,当你问买玻璃的要一面观察镜时,会被反问一些奇怪的问题。他们那些人往往有更多新奇点子……嘿嘿,肮脏的思想永远是快乐的源泉。

终于我还是得到了一块不错的观察镜。开始找乐子吧!

第二部分——显示器

magic_mirror4

解决了镜子问题后,是时候为魔镜项目入手一台显示器了。

在为魔镜选择合适的显示器过程中,有一些纠结的决定。我是买一台新显示器还是捡一台呢?我需要什么尺寸?屏幕最薄会是多少?我如何移动控制按钮?屏幕是否够亮来盖过我的堂堂仪表?

因为我用显示器作为仪容之用,选择合适尺寸差不多就是选择合适的宽度(也就是镜子合适的高度)。在一些测量和尝试用胶带固定在墙上我想放置镜子的位置后,24英寸屏幕会是完美的选择。额外带来的好处是,绝大多数(便宜的)24英寸屏幕初始就带有1080P分辨率,正是我想在这个项目所使用的分辨率。

为了合适的屏幕类型和品牌,我几乎跑遍了方圆20公里内的电器铺。我敢肯定保安大叔在盯着我,而我正仔细检查所有屏幕背面和底部。

大多数品牌被立即否定了,因为它们的电源和视频连接线在背后。我需要转接线是在侧面的那种。

magic_mirror5

最后我选择了Iiyama显示器,它最接近我所希望的——价格便宜,边框窄小,简单触控按钮和正确转接器方向。

直到现在,我还是不清楚显示器外壳能否轻易被卸除,控制面板如何在显示器内部被连接上。销售人员不许我做出怪异的动作,打开显示器外壳,所以买到这台合适的显示器纯属运气。

magic_mirror6

我订购了一台24英寸Iiyama E2481HS-B1显示器。为确定显示器和镜子之间气密性良好,我拆下了外壳。在刚刚开箱就进行拆卸显示器够战战兢兢的,但……勉强成功。

这台Iiyama显示器的好处是,显示控制器(金属盒内的电子元件)为这面镜子的其他零件留下了足够的空间,而又保持了它原本的苗条外形。

magic_mirror7

实际的显示板仅有9毫米厚,而小小的边框也只是10毫米宽。加上显示控制器后,就是下列尺寸:556毫米x323毫米x46毫米(外加6毫米的镜子厚度)。这些尺寸构成了新的木头外壳尺寸。

第三部分——外壳

magic_mirror8

在量度新外壳所需尺寸后,就开始享受DIY的喜悦吧。我用松木做了个结实坚固的框架,用地板地脚线固定镜子和显示器的位置,那尺寸刚刚好(30毫米宽),还有圆角边框效果。

镜子很可能会发热,那就需要通风口了。此外,在外壳的背后还加了几个既美观又结实的挂点。

小剧透:产品最终重量6.5千克,由我做的两个挂载点所推测得来。

magic_mirror11

补充一下,我在外壳的底部开了条细缝作为电源线槽。

当然,它需要进行上色。在涂抹油灰(我在打磨抛光时后悔涂太多油灰了)、一些地漆及上土层后,新外壳完工。

magic_mirror14

有个木工小步骤我要去做的:我做了4个挂在块来安装显示器与镜子。现在准备好将它们上在镜框里面。

magic_mirror15

木工部分到此结束,进入魔镜的下一环节,安装硬件。

第四部分——安装硬件

magic_mirror16

魔镜开始成形。我订购了镜子,找到合适的显示器,完成打磨白色的外壳,是时候开始安装硬件了。

目前我手上有以下零件: 显示器 + 树莓派 + 一条HDMI线(连接树莓派和显示器) + 一条USB转micro USB转接线(用来为树莓派供电) + 一条显示器电源线

但接着我遭遇到小小挫折。在找合适的显示器时,我完全没想到看看显示器有没有一个USB口,用来驱动树莓派。我以为现在的显示器都默认装有USB口,不过我错了,它没有。

这不是不能解决的问题,但我真心希望只用一条线来驱动魔镜。所以我只能将电源分为两条线,一条给显示器,一条给240伏USB降压器。补充一点,我希望用一条普通C13电源线就能驱动智能镜。

magic_mirror17

也就是说,我要做的是中间带有USB充电器的接插电源线。在翻了我几个闲置线材抽屉后,我找到了个旧USB充电器。

magic_mirror18

拆开充电器比想象中的容易,只要一点点焊接工序,一些胶和绝缘胶布即可。我要设法做个外观高大上的电源线。

magic_mirror20

我做了试运行,确保电源线正常工作。我将所有零件连接好,插好电源线,打开显示器。树莓派启动正常,USB充电器没有发热过量。不错!

magic_mirror21

接着组装所有零件。这次没有倒霉事件:所有东西完美吻合。

magic_mirror24

另一个阶段完成了,包括所有实体部分(除了还没把两颗螺丝钉在墙上)。进入戏肉的部分:安装树莓派。

Magic Mirror: Part V – Installing the Raspberry Pi

第五部分——安装树莓派

magic-mirror25

那么,做完所有硬件之后,就轮到安装树莓派了。要达到智能镜的所有需求,树莓派就要有以下功能:

· Wifi连接 · 屏幕旋转90度,符合照镜方向 · 本地网络服务维持界面 · 在全屏幕下运行的浏览器,用于显示界面

基本安装

因为Raspbian操作系统的灵活性和背后有开源社群支持,我就选了它。下载了操作系统映像后,就把它写入SD卡。

拷贝一个映像档需要很长时间,那么有三种选择:

  1. 用树莓派技术文档中提到的rdisk方法拷贝。
  2. 拿杯咖啡,坐下,在等待中享受咖啡因的感觉。
  3. 上面两者都选。

我选了3。完成拷贝后,我启动树莓派、登入,进入命令行的sudo raspi-config开始配置向导。在这个配置中,有几件重要事项需要配置:

· 确保系统启动到桌面(取代命令行模式或调试模式)。 · 调整时区,使魔镜显示正确时间。 · 在高级选项部分,确保显存超过128MB。 如果你想做和这个一样的镜子,尽管尝试选择所有其他选项。只是记住,如果选砸了,就再泡杯咖啡重装系统吧。

Wifi连接

我不想在智能镜上加任何多余的连接线,就选择了以Wifi连接因特网。安装Wifi接收器真的依赖频宽和种类,因此写下完全过程是多余的。有最好的替代吗?看看这个神奇的网站……

老实说,这部分安装确实很花时间。一旦装好了,就能工作正常。

旋转屏幕

智能镜在设计上是纵向肖像模式,所以我需要将屏幕顺时针旋转90度,最终显示分辨率为1080 x 1920。我曾担心这会是最大的问题,最终却很容易解决了。

树莓派的BIOS设置储存在系统启动分区中。在这分区中,有一个config.txt文件,载有所有设置。要旋转显示器,在这文件内加上以下一行代码:
display_rotate=1

要让显示器连接更加可靠,我就不解释为何加上下面允许HDMI线热插拔的代码了:
hdmi_force_hotplug=1

配置文件存盘后重启树莓派,我不禁会心一笑:这感觉真好,腰不疼颈不酸了!

网络服务器

要维持界面(很简单的一个网页),我需要在树莓派上Apache服务器。这在树莓派上是其中一个很常见的应用,安装过程简直行云流水。

首先我运行下列指令,确定我用的是最新系统软件。
sudo apt-get update && apt-get upgrade -y

现在是时候真的安装Apache了:
sudo apt-get install apache2 apache2-doc apache2-utils

完成了!就是所有这些。但要保证在服务器上能用到一些PHP脚本(以后会更多的),我也加上了PHP支持:
sudo apt-get install libapache2-mod-php5 php5 php-pear php5-xcache

又完成了!重启之后,网页服务器就挂载上线运行了!我在/var/www文件夹内放置了index.php文件,将浏览器首页指向树莓派的IP地址,发现成功了。

信息模式(kioskmode)

现在就是要确定树莓派能够显示我在信息模式(kioskmode)下用Chromium浏览器显示的网页。Chromium浏览器是个能在树莓派操作系统上运行的开源浏览器。

一如既往,安装很简单:
sudo apt-get install chromium x11-xserver-utils unclutter

但这一次,它需要一些额外设置,在信息模式下禁用屏幕保护和自动重启。我在/etc/xdg/lxsession/LXDE/autostart作了编辑,在前面加上了#号。
@xscreensaver -no-splash

另外我还加了以下代码:
@xset s off @xset -dpms @xset s noblank @chromium –kiosk –incognito http://localhost

这样就能完全禁用所有屏保功能,及Chromium浏览器在开机后自动启动,开启全屏模式并导向本地主页。

存盘并再一次重启,检查工作效果。树莓派并不是世界上最快的电脑,它需要花点时间,但最终测试页还是在旋转了90度的画面上显示出来。要得!

进入项目的最后部分,界面开发。

第六部分——界面开发

回顾一下,我买了合适的镜子、显示器,做了个新外壳,安装好硬件及配置完成树莓派,那就进入最后一步——界面开发。

需求和功能

我开始项目时,我发现不能通过镜子直接进行任何交互,要不然在铮亮的镜面上会抹上油脂和什么脏东西。但还有更重要的原因,还有别的更好设备可用于用户交互。我希望智能镜只是个被动信息来源。

而更更重要的是,镜子就是镜子,不应被大量(无用的)信息所填满。只有边上能用来作摘要性显示,给本帅哥留些足够自恋的空间吧。

这样我需要以下信息类别目录来满足我对信息的需求:

· 问候语 贴心问候,每日美好的开始。

· 天气 看到我穿的衬衫吗?不错吧!嗯?今天穿T恤衫不会鸡冻吧?

· 时钟和日历 现在赶时间吗?还有足够时间顾影自怜吧?

· 消息反馈 我只是担心自己形象帅不帅吗?还有别的需要上心吗?

当然,未来版本当中有大量的改进可能,现在列出的这些应该够用了。

基本安装

前面提过,程序界面不是一个在树莓派桌面上神奇的应用,仅仅是一个全屏幕网页。我能用HTML、CSS和Javascript开发外,还有一个额外的好处,在我将它放入智能镜之前,能在我的苹果电脑上开发测试。

magic-mirror28

在自己写的代码基础上,我用了一些开源库文件来优化它的运行速度:

Jquery

像大多数网站那样,智能镜使用Jquery来简化DOM操作方式,对我这种懒人最为适用。

Moment.js

它对我在时间安排操作上帮助不少,尤其是在争分夺秒时更节省不少时间。

FeedToJson

将RSS订阅用JSON数据转成javascript的方便工具。

iCal Parser

将iCal数据转化为JSON。可惜这个库文件并不完美,需要一些额外的优化。

以上这些库文件,加上我自己的HTML和Javascript足够使我的镜子成精了。

设计

我的智能镜需要个酷炫设计。我本人是个严重果粉,那么在设计上要遵从苹果系的设计指标

边框、倾角、阴影效果有时是用户界面厚重感的因素,甚至能盖过显示内容的光芒。所以,专注在内容设计,把用户交互界面摆在辅助位置上。

利用足够的实体空间,它是个重要内涵,在感官上更让人注意和易于理解。

怎么做到这一点?用Helvetica Neue字体,用天气图标对应显示天气信息。

magic-mirror29

镜子在背后没有光源时就只是一面镜子,用黑色背景是个重要设定。而为了有最好的对比度,显示内容字体应为白色,在加一些灰色阴影边缘,那灰度为50吧……

我大可以加上一些其他色彩,但目前为止我只想做到简洁的黑白界面。我可不想镜子比我的尊容还要出彩。

API设计

为了接收我想在镜子上显示的数据,我用了一些开源API和反馈代码。还有谁不太清楚什么是API,维基百科里面有详尽的解释:

“电脑操作系统(Operating system)’或‘程序库’提供给应用程序调用使用的代码。”

我心中的API就像你家的DVD播放器背后那样充满接口——如果你将其他设备连接到它的话,它就变得更加有用,这些接口本质上就是API。API让设备变得功能强大、有趣,尤其对我这种电脑狂人来说。

Openweathermap.org

Openweathermap有很好的API接口,能够免费得到天气预报信息。它允许你查询区域内的信息,定义你想要的信息类别。在这里我用了两个连接,一个是当前天气,另一个是预报天气。

iCal Calendar

iCloud允许你以iCal格式分享日历。因为javascript无法做到这一点(因为多站点脚本安全问题),我需要通过PHP代理服务器来开启数据。这其实很容易,只有三行代码而已:

12<!--?php <br ?-->    $url "https://p01-calendarws.icloud.com/ca/subscribe/1/mysupersecreticloudhash";    echo file_get_contents($url);

只需查询calendar.php就能将在同一个服务器内日历表在界面上显示出来。

前面说过的iCal语法分析编辑帮我把信息解析成有用信息。可是,iCloud在他们的反馈中用了一些非标准标签,我要添加额外的代码行来将代码解析为javascript文件。

magic-mirror30

NOS新闻订阅

新闻订阅只是用到了荷兰公共广播公司的RSS订阅功能。可是,他们不支持JSON格式数据,因此我用了FeedToJson插件来把RSS数据转为JSON格式的。

其他内容,例如当前日期与实践,还有问候语都只是一些简单的javascript语句。

自动更新

你看了这篇博客这么久,应该能接受更进阶的信息了吧。那么瞪大眼看下去吧……

在开发当中,我遇到了一个很不爽的境地,就是没有键盘和鼠标连在智能镜上的问题。如果我更新界面,就没有一个简单方法在智能镜上更新页面的方法。最简单直接的方法是重启整个树莓派,但让我在调试每个更新上花时间太多了。

我用GIT分布控制系统更新文件,而每个更新版本都有本身的哈希校验提交码,我用PHP就能读取出来。这启发了我再代码行内加上一个片段,将本地页面和刚刚开发的页面进行哈希比对。如果两者不符,程序将重新载入网页,显示最新版本。

我用以下PHP代码获取当前网页上的哈希校验码:

1trim(`git rev-parse HEAD`)));

对比过程在javascript主文件内完成,但只有在HTML文件有当前版本的哈希校验值前提下才能实现:

1var gitHash = '';

现在,对比过程就很直观,每3秒进行一次:

1234567891011121314(function checkVersion()    {        $.getJSON('githash.php', {}, function(json, textStatus) {            if (json) {                if (json.gitHash != gitHash) {                    window.location.reload();                    window.location.href=window.location.href;                }            }        });        setTimeout(function() {            checkVersion();        }, 3000);    })();

所有这些神奇的操作,让更新智能镜界面变得简单。只需用SSH登入树莓派,进入合适的文件夹,然后处理一个git推送请求。

给我交出代码来!

得了得了……好奇了吧?所有代码在GitHub上都有。有件事情要说一声:代码很少标注,以面条式代码填充,通篇都是TODO语句。哈,不怕晃晕菜的,尽管扎进去吧。

未来展望

智能镜还能做更多的功能,这是一个陆续发展过程。如有新功能上的建议,请不吝提供。让我知道你想在界面上的创意。不过请记住,少为美。:)

发布于 分类 Linux

树莓派安装Ubuntu 18 64位系统

开启强制HDMI输出:(很多现在的显示器在树莓派上并不能识别)
在TF卡分区,打开config.txt文件(开机后位置: /boot/config.txt),修改如下:

hdmi_safe=1
config_hdmi_boost=4
hdmi_ignore_edid=0xa5000080
hdmi_group=2
hdmi_mode=82
一些参数介绍:

项 含义
hdmi_safe=1 安全启动HDMI
config_hdmi_boost=4 开启热插拔
hdmi_group=1 CEA电视显示器
hdmi_group=2 DMT电脑显示器
hdmi_ignore_edid=0xa5000080 忽略自动探测的分辨率
输出分辨率:
hdmi_mode=4 640×480 60Hz
hdmi_mode=9 800×600 60Hz
hdmi_mode=16 1024×768 60Hz
hdmi_mode=82 1080p 60Hz
安装桌面方法
步骤一,安装Display Server。
sudo apt-get install –no-install-recommends xserver-xorg

sudo apt-get install –no-install-recommends xinit
步骤二,安装GUI桌面环境。
1,mate桌面环境

apt-get install ubuntu-mate-desktop

2,gnome桌面环境

apt-get install gnome

3,lxde桌面环境

apt-get install lxde

4,lxqt桌面环境

apt-get install lxqt

5,xubuntu桌面

apt-get install xubuntu-desktop

6,lubuntu桌面

apt-get install lubuntu-desktop

7,xfce桌面环境

apt-get install xfce4

8,cinnamon桌面环境

apt-get install cinnamon

9,bugie桌面环境

apt-get install ubuntu-budgie-desktop

这时,重启之后就完成了

发布于 分类 Linux

树莓派开机启动GUI程序

1、如果是lite版,先安装界面,https://www.raspberrypi.org/forums/viewtopic.php?f=66&t=133691

参考上面界面,多种界面添加方法及比较。

2、将我们的程序拷贝到树莓派,依赖库之类的也添加好。

3、要想启动自己的图形界面,就需要启动X server,这个东西是在你登录树莓派输入用户名和密码之前启动的,所以我们可以在启动树莓派之前和启动X server之后启动自己的程序,/etc/profile 这个文件就是这两个程序的中间,我们直接更改这个配置文件就行了

sudo nano /etc/profile
在文件开头输入你程序的路径prg,再执行你的程序guiprogram,如下:

cd /home/pi/prg
./guiprogram

另一种方法是增加环境变量,程序guiprogram在/home/pi/Downloads/dist/下,直接执行即可

# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
if [ "`id -u`" -eq 0 ]; then
  PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
else
  PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/home/pi/.local/bin:/home/pi/Downloads/dist"
fi
export PATH
guiprogram
发布于 分类 Linux

树莓派最小桌面系统

第1部分 – 建立基础

在这一部分,我们将专注于准备Raspbian Lite。

1、下载最新的Raspbian Lite图像。(https://www.raspberrypi.org/downloads/raspbian/
2、使用Win32DiskImager把Raspbian Lite刷SD中.
3、将SD / microSD卡插入Pi。
4、将Pi连接到Internet。以太网是最快的方式。否则我们必须使用Wi-Fi,则必须在Pi完成引导后。由于我们的WI-FI是隐藏的,所以需要修改:/etc/wpa_supplicant/wpa_supplicant.conf

#sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

在文件中加入以下:

4.1也可以使用树莓派来配置WI-FI

    4.1.1运行:

          #sudo raspi-config 

          1. 选择 Network Options

          2. WI-FI(选择后输入SSID密码就可以了)

5、连接电视/显示器和键盘(此时鼠标是可选的)打开Pi,Pi应该成功启动并出现登录提示。
6、登录Raspbian。用户名是pi,密码是raspberry

第2部分 – 更新系统到最新

    1、安装更新,如果提示确认请输入Y.

      #sudo apt-get update   

      #sudo apt-get upgrade

      #sudo apt-get dist-upgrade

   2、运行完成后需要做一个清理。

      #sudo apt-get clean

第3部分 – 设定本地化

  1、首先们需安装中文的字体,不然会乱码    

sudo apt-get install ttf-wqy-zenhei ttf-wqy-microhei 安装文泉驿字体,若有中文字体则省略 
  2 、使用配置本地地址: sudo raspi-config 
  3、选择第四项 locallisation Options 
  4、I1 change locale 
  5、zh_cn.UTF8 和UTF-8 zh_GBK 空格键选择后 tab键确认 
  6、再次选择zh_cn.UTF-8 
  7、重启 sudo reboot

第4部分 – 开始安装桌面。

    下一部分重点介绍如何在Raspbian Lite上安装GUI。为了拥有GUI,我们需要以下4件事

     1.显示服务器
     2.桌面环境
     3.窗口管理器
     4.登录管理器

1、打开你的Pi并登录。我们将安装Xorg。要执行此操作,请键入:

   sudo apt-get install –no-install-recommends xserver-xorg

 然后按Enter键。将要安装许多依赖软件包,但必须安装这些软件包才能使GUI正常工作。安装中如果需要确认请输入Y。

如果只安装xserver-xorg,则无法从命令行启动Xorg Display Server。我们还需要安装xinit:

   sudo apt-get install –no-install-recommends xinit

2、Raspberry Pi Desktop(RPD)GUI 选择你想要安装的桌面。

    这里我选择的是LXDE GUI 它运行占用资源少。

    sudo apt-get install lxde-core lxappearance

    安装中如果需要确认请输入Y。

3、登录管理器安装:

     sudo apt-get install lightdm  

安装完成后我们就可以使用桌面系统了。

     startx

运行完成以上命令就可以看到你自己安装的桌面了。

4、Pi用户自动登录:

   sudo raspi-config

  1. 选择Boot Options
  2. Desktop / CLT
  3. Desktop Autologin Desktop GUI 桌面环境
  4. finish
  5. reboot

以上我们就完成了最小桌面系统。

#参考官方主页:

https://www.raspberrypi.org/forums/viewtopic.php?t=133691

下面我们来安装一些必要的软件。

1.安装Wi-FI 管理软件。     

sudo apt-get install network-manager-gnome

运行就可以看到图标了。

nm-applet

2.安装一个文本编辑器。

sudo apt-get install mousepad

3.安装Chromium.

sudo apt-get install chromium-browser

好了你现在可以上网了。

发布于 分类 Linux

树莓派使用Lazarus

树莓派上的LazarusLazarus on Raspbian Wheezy

Raspberry Pi Logo.png

本文只适合 Raspberry Pi.

Raspberry Pi(数莓派)是一个信用卡大小的单板计算机。它由英国的Raspberry Pi基金为了激励在学校的计算机基础科学教学发起的。Raspberry Pis也可以用来作为媒体服务器以及其他用途机器人、控制工程等多种用途。 Raspberry Pi基金会推荐Raspbian Wheezy作为标准的操作系统。大家可以选择在RPI运行RISC OS、各种Linux发行版以及Android等操作系统。 Lazarus可以在原生的Raspbian操作系统下运行。

Contents

 [hide

安装与编译器Lazarus

在 Raspbian上简单安装

Raspberry Pi 1

在 Raspbian OS上,安装Lazarus与 Free Pascal很容易。打开命令行窗口输入下面的指令:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install fpc
sudo apt-get install lazarus

这里安装的是为Raspberry Pi预编译的稳定版FPC与Lazarus 。当然,需要有网络连接。安装过程大概需要30分钟,这个过程是自动完成等的。安装完成以后,你就可以从LXDE的开始菜单的“Programming”启动Lazarus了。

  • 安装步骤 1
  • 安装步骤 2
  • 安装步骤 3
  • 安装步骤 4

如果你需要一个新的版本,或者抱怨Lazarus 的问题, 点击.

Raspberry Pi 2

自2015六月起,普通的“out of the box”安装方法也适用于安装树莓派2的B型。但是安装时获得的版本是相当旧的。想要获得新版FPC和Lazarus请看链接 相关文章.

  • Lazarus “out of the box” on Raspberry Pi 2

从Windows 对Raspberry Pi的交叉编译

1. 使用 fpcup

使用fpcup是实现交叉编译的一种方法,输入下面的指令: fpcup#Linux_ARM_cross_compiler

2. 使用脚本

可以使用手动批处理文件,按照以下步骤。

2.1 先决条件

FPC 2.7.1或更高的安装源代码
下载并安装Windows版本的Linaro binutils for linux gnueabihf到%FPCPATH%/bin/win32-armhf-linux [1]

2.2 创建脚本(需要匹配实际路径)

set PATH=C:\pp\bin\i386-win32;%PATH%;
set FPCMAKEPATH=C:/pp
set FPCPATH=C:/pp
set OUTPATH=C:/pp271
%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
%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
if errorlevel 1 goto quit
%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%
:quit
pause

使用生成的ppcrossarm.exe和 ARM RTL,你可以创建跨平台的Lazarus工程,生成Raspberry Pi和其他armhf设备的应用程序。 注意,这里不包括所有Window 库。

编译源代码

如果你想要从Subversion编译Lazarus源代码。请看 Michell Computing: Lazarus on the Raspberry Pi

  • How to start Lazarus in Raspbian Wheezy
  • Lazarus on Raspberry Pi
  • Numbering of GPIO pins

用Gentoo(及其他版本)在Raspberry上编译源码

  • Gentoo是一个基于Linux的自由操作系统

如果你想安装最新版的FPC及附件,或者是集成FPC编译器:请阅读下面的指南 这是关于Gentoo的例子,本指南适用其他版本:Install fpc on Raspberry with Gentoo

访问外部硬件

Raspberry Pi 外部连接引脚

Raspberry Pi的发展的目标之一是方便轻松地访问外部设备,如传感器和控制器。Lazarus有五种方法来访问I/O设备:

  1. 原生代码直接访问,使用BaseUnix单元
  2. 通过 封装外壳调用
  3. 通过 wiringPi 库.
  4. 使用单元 rpi_hal.
  5. 使用单元 PiGpio.
  6. 通过 PascalIO 库访问.

1. 原生代码直接访问

对Raspberry Pi的GPIO端口访问的简单测试程序程序访问GPIO的测试电路演示实现电路

这种访问外部硬件的方法,不需要额外的库。唯一的要求是baseunix库,这是Free Pascal的RTL部分。

通过GPIO端口控制开关

下面将演示一个简单程序。控制GPIO的17号引脚的电压,可以用来控制LED、晶体管或继电器。 程序包含GPIO17ToggleBox的实例ToggleBox和日志返回LogMemo类的实例TMemo

例如,一个LED的阳极连接到引脚11上(BCM2835 SoC对应的GPIO为17)和LED的阴极通过一个68欧姆的电阻连接引脚6(GND)。随后,LED会随着应用程序的toggle box切换点亮和熄灭。

该代码需要root权限运行,即从root帐号(不推荐)运行或通过“su ‘

控制单元:

unit Unit1;
{Demo application for GPIO on Raspberry Pi}
{Inspired by the Python input/output demo application by Gareth Halfacree}
{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  Unix, BaseUnix;
type
  { TForm1 }
  TForm1 = class(TForm)
    LogMemo: TMemo;
    GPIO17ToggleBox: TToggleBox;
    procedure FormActivate(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure GPIO17ToggleBoxChange(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
const
  PIN_17: PChar = '17';
  PIN_ON: PChar = '1';
  PIN_OFF: PChar = '0';
  OUT_DIRECTION: PChar = 'out';
var
  Form1: TForm1;
  gReturnCode: longint; {stores the result of the IO operation}
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormActivate(Sender: TObject);
var
  fileDesc: integer;
begin
  { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
  try
    fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
    gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  finally
    gReturnCode := fpclose(fileDesc);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end;
  { Set SoC pin 17 as output: }
  try
    fileDesc := fpopen('/sys/class/gpio/gpio17/direction', O_WrOnly);
    gReturnCode := fpwrite(fileDesc, OUT_DIRECTION[0], 3);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  finally
    gReturnCode := fpclose(fileDesc);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end;
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
  fileDesc: integer;
begin
  { Free SoC pin 17: }
  try
    fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
    gReturnCode := fpwrite(fileDesc, PIN_17[0], 2);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  finally
    gReturnCode := fpclose(fileDesc);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end;
end;
procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
var
  fileDesc: integer;
begin
  if GPIO17ToggleBox.Checked then
  begin
    { Swith SoC pin 17 on: }
    try
      fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
      gReturnCode := fpwrite(fileDesc, PIN_ON[0], 1);
      LogMemo.Lines.Add(IntToStr(gReturnCode));
    finally
      gReturnCode := fpclose(fileDesc);
      LogMemo.Lines.Add(IntToStr(gReturnCode));
    end;
  end
  else
  begin
    { Switch SoC pin 17 off: }
    try
      fileDesc := fpopen('/sys/class/gpio/gpio17/value', O_WrOnly);
      gReturnCode := fpwrite(fileDesc, PIN_OFF[0], 1);
      LogMemo.Lines.Add(IntToStr(gReturnCode));
    finally
      gReturnCode := fpclose(fileDesc);
      LogMemo.Lines.Add(IntToStr(gReturnCode));
    end;
  end;
end;
end.

Main program:

program io_test;
{$mode objfpc}{$H+}
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, Unit1
  { you can add units after this };
{$R *.res}
begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

读取引脚的状态

读取一个GPIO引脚状态的演示程序程序访问GPIO的测试电路实际电路

当然也可以从GPIO端口读取一个开关的状态。

下面的简单例子非常类似于前一个例子。使用GPIO的18号引脚,控制二进制设备如开关输入,晶体管或继电器。这个程序包含一个名称为CheckBoxGPIO18CheckBox 与LogMemo的实例TMemo日志返回代码。

在实例中,第12引脚的一端连接一个按钮,按钮的一端(对应的GPIO引脚18的BCM2835 SoC)通过一个10欧姆的上拉电阻和引脚1连接(+3.3 V,看接线图)。按钮的另一端连接6号引脚(GND)。按钮的开关状态对应和程序中复选框的打开或关闭状态对应。

注意,当按钮释放时18脚的电位为高(由通过上拉电阻连接到引脚1),当按钮压下时电压为低(因为在这种情况下,引脚18是通过开关连接到GND)。因此,按钮按下时GPIO引脚信号为0,当释放时信号为1。

这个程序同样需要root权限

控制单元:

unit Unit1;
{Demo application for GPIO on Raspberry Pi}
{Inspired by the Python input/output demo application by Gareth Halfacree}
{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
{This application reads the status of a push-button}
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ButtonPanel, Unix, BaseUnix;
type
  { TForm1 }
  TForm1 = class(TForm)
    ApplicationProperties1: TApplicationProperties;
    GPIO18CheckBox: TCheckBox;
    LogMemo: TMemo;
    procedure ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
    procedure FormActivate(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  private
    { private declarations }
  public
    { public declarations }
  end;
const
  PIN_18: PChar = '18';
  IN_DIRECTION: PChar = 'in';
var
  Form1: TForm1;
  gReturnCode: longint; {stores the result of the IO operation}
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormActivate(Sender: TObject);
var
  fileDesc: integer;
begin
  { Prepare SoC pin 18 (pin 12 on GPIO port) for access: }
  try
    fileDesc := fpopen('/sys/class/gpio/export', O_WrOnly);
    gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  finally
    gReturnCode := fpclose(fileDesc);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end;
  { Set SoC pin 18 as input: }
  try
    fileDesc := fpopen('/sys/class/gpio/gpio18/direction', O_WrOnly);
    gReturnCode := fpwrite(fileDesc, IN_DIRECTION[0], 2);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  finally
    gReturnCode := fpclose(fileDesc);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end;
end;
procedure TForm1.ApplicationProperties1Idle(Sender: TObject; var Done: Boolean);
var
  fileDesc: integer;
  buttonStatus: string[1] = '1';
begin
  try
    { Open SoC pin 18 (pin 12 on GPIO port) in read-only mode: }
    fileDesc := fpopen('/sys/class/gpio/gpio18/value', O_RdOnly);
    if fileDesc > 0 then
    begin
      { Read status of this pin (0: button pressed, 1: button released): }
      gReturnCode := fpread(fileDesc, buttonStatus[1], 1);
      LogMemo.Lines.Add(IntToStr(gReturnCode) + ': ' + buttonStatus);
      LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
      if buttonStatus = '0' then
        GPIO18CheckBox.Checked := true
      else
        GPIO18CheckBox.Checked := false;
    end;
  finally
    { Close SoC pin 18 (pin 12 on GPIO port) }
    gReturnCode := fpclose(fileDesc);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
    LogMemo.SelStart := Length(LogMemo.Lines.Text) - 1;
  end;
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
  fileDesc: integer;
begin
  { Free SoC pin 18: }
  try
    fileDesc := fpopen('/sys/class/gpio/unexport', O_WrOnly);
    gReturnCode := fpwrite(fileDesc, PIN_18[0], 2);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  finally
    gReturnCode := fpclose(fileDesc);
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end;
end;
end.

上面的例子主程序是相同的,。

2. 通过封装的外壳访问硬件

访问硬件的另一种方法是通过封装终端命令。这是通过使用fpsystem功能。这种方法可以访问baseunix单元不支持的功能。下面的代码实现了一个具有相同功能的程序,该程序是从上面的第一个清单所产生的。

控制单元:

unit Unit1;
{Demo application for GPIO on Raspberry Pi}
{Inspired by the Python input/output demo application by Gareth Halfacree}
{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Unix;
type
  { TForm1 }
  TForm1 = class(TForm)
    LogMemo: TMemo;
    GPIO17ToggleBox: TToggleBox;
    procedure FormActivate(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure GPIO17ToggleBoxChange(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
var
  Form1: TForm1;
  gReturnCode: longint; {stores the result of the IO operation}
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormActivate(Sender: TObject);
begin
  { Prepare SoC pin 17 (pin 11 on GPIO port) for access: }
  gReturnCode := fpsystem('echo "17" > /sys/class/gpio/export');
  LogMemo.Lines.Add(IntToStr(gReturnCode));
  { Set SoC pin 17 as output: }
  gReturnCode := fpsystem('echo "out" > /sys/class/gpio/gpio17/direction');
  LogMemo.Lines.Add(IntToStr(gReturnCode));
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  { Free SoC pin 17: }
  gReturnCode := fpsystem('echo "17" > /sys/class/gpio/unexport');
  LogMemo.Lines.Add(IntToStr(gReturnCode));
end;
procedure TForm1.GPIO17ToggleBoxChange(Sender: TObject);
begin
  if GPIO17ToggleBox.Checked then
  begin
    { Swith SoC pin 17 on: }
    gReturnCode := fpsystem('echo "1" > /sys/class/gpio/gpio17/value');
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end
  else
  begin
    { Switch SoC pin 17 off: }
    gReturnCode := fpsystem('echo "0" > /sys/class/gpio/gpio17/value');
    LogMemo.Lines.Add(IntToStr(gReturnCode));
  end;
end;
end.

主程序与上面的例子相同。这个程序必须用根权限执行。

3. wiringPi方法与函数

Alex Schaller封装的Gordon Henderson的Arduino兼容wiringpi库,提供了一种类似Arduino电路板的编码方案。

Function wiringPiSetup:longint: 使用wiringpi引脚编号方案初始化wiringpi系统

Procedure wiringPiGpioMode(mode:longint): 用Broadcom的GPIO引脚编号方案wiringpi初始化系统。

Procedure pullUpDnControl(pin:longint; pud:longint): 控制内部GPIO引脚上拉/下拉电阻。

Procedure pinMode(pin:longint; mode:longint): 设置一个PIN的模式:输入、输出或pwm_output。

Procedure digitalWrite(pin:longint; value:longint): 设置一个输出位。

Procedure pwmWrite(pin:longint; value:longint): 设置一个输出PWM(脉宽调制)值,0到1024之间。

Function digitalRead(pin:longint):longint: 读取一个给定引脚的值,返回1或0。

Procedure delay(howLong:dword): 等待多少毫秒。

Procedure delayMicroseconds(howLong:dword): 等待多少微秒。

Function millis:dword: 返回程序调用wiringpisetup函数花费的毫秒数。

4. rpi_hal-hardware抽象库 (GPIO, I2C and SPI 函数与方法)

这个单元大约1700行代码,由Stefan Fischer提供,提供程序和函数访问RPI硬件I2C,SPI和GPIO:

下面是函数和方法的摘录:

procedure gpio_set_pin (pin:longword;highlevel:boolean); { 设置 RPi GPIO 引脚速率为高或低; 速率 @ 700MHz -> 0.65MHz }

function gpio_get_PIN (pin:longword):boolean; { 获取 RPi GPIO 引脚等级,当Pin为’1’时返回True,为’0’时返回false; 速率 @ 700MHz -> 1.17MHz } 

procedure gpio_set_input (pin:longword); { 设置 RPi GPIO 引脚为直接输入}

procedure gpio_set_output(pin:longword); { 设置 RPi GPIO 引脚为直接输出 }

procedure gpio_set_alt (pin,altfunc:longword); { 设置 RPi GPIO 引脚为备用功能 0..5 }

procedure gpio_set_gppud (mask:longword); { 设置RPI GPIO拉上/下登记(gppud)}

function rpi_snr :string; { 信噪比: 0000000012345678 }

function rpi_hw  :string; { 处理器类型: BCM2708 }

function rpi_proc:string; { ARMv6-compatible processor rev 7 (v6l) }

function i2c_bus_write(baseadr,reg:word; var data:databuf_t; lgt:byte; testnr:integer) : integer;

function i2c_bus_read (baseadr,reg:word; var data:databuf_t; lgt:byte; testnr:integer) : integer;

function i2c_string_read(baseadr,reg:word; var data:databuf_t; lgt:byte; testnr:integer) : string;

function i2c_string_write(baseadr,reg:word; s:string; testnr:integer) : integer;

procedure SPI_Write(devnum:byte; reg,data:word);

function SPI_Read(devnum:byte; reg:word) : byte;

procedure SPI_BurstRead2Buffer (devnum,start_reg:byte; xferlen:longword);

procedure SPI_BurstWriteBuffer (devnum,start_reg:byte; xferlen:longword); { 从缓冲区SPI的地址写入一段字节的内容 }

… 

测试程序 (testrpi.pas):

//Simple Test program, which is using rpi_hal;
  program testrpi;
  uses rpi_hal;
  begin
    writeln('Show CPU-Info, RPI-HW-Info and Registers:');
    rpi_show_all_info;
    writeln('Let Status LED Blink. Using GPIO functions:');
    GPIO_PIN_TOGGLE_TEST;
    writeln('Test SPI Read function. (piggy back board with installed RFM22B Module is required!)');
    Test_SPI;
  end.

5. 底层pascal单元 PiGpio(代替wiringpi C语言库的GPIO控制)

这个单元 (pigpio.pas[2]) 270 行代码是由Gabor Szollosi提供的 , 运行速度飞快(例如GPIO引脚输出开关频率达到8MHz) :

unit PiGpio;
{
 BCM2835 GPIO Registry Driver, also can use to manipulate cpu other registry areas
 This code is tested only Broadcom bcm2835 cpu, different arm cpus may need different
 gpio driver implementation
 2013 Gabor Szollosi
}
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils;
const
  REG_GPIO = $20000;//bcm2835 gpio register 0x2000 0000. new fpMap uses page offset, one page is 4096bytes
  // hex 0x1000 so simply calculate 0x2000 0000 / 0x1000  = 0x2000 0
  PAGE_SIZE = 4096;
  BLOCK_SIZE = 4096;
    // The BCM2835 has 54 GPIO pins.
//	BCM2835 data sheet, Page 90 onwards.
//	There are 6 control registers, each control the functions of a block
//	of 10 pins.
  CLOCK_BASE = (REG_GPIO + $101);
  GPIO_BASE =  (REG_GPIO + $200);
  GPIO_PWM =   (REG_GPIO + $20C);
     INPUT = 0;
     OUTPUT = 1;
     PWM_OUTPUT = 2;
     LOW = False;
     HIGH = True;
     PUD_OFF = 0;
     PUD_DOWN = 1;
     PUD_UP = 2;
   // PWM
  PWM_CONTROL = 0;
  PWM_STATUS  = 4;
  PWM0_RANGE  = 16;
  PWM0_DATA   = 20;
  PWM1_RANGE  = 32;
  PWM1_DATA   = 36;
  PWMCLK_CNTL =	160;
  PWMCLK_DIV  =	164;
  PWM1_MS_MODE    = $8000;  // Run in MS mode
  PWM1_USEFIFO    = $2000; // Data from FIFO
  PWM1_REVPOLAR   = $1000;  // Reverse polarity
  PWM1_OFFSTATE   = $0800;  // Ouput Off state
  PWM1_REPEATFF   = $0400;  // Repeat last value if FIFO empty
  PWM1_SERIAL     = $0200;  // Run in serial mode
  PWM1_ENABLE     = $0100;  // Channel Enable
  PWM0_MS_MODE    = $0080;  // Run in MS mode
  PWM0_USEFIFO    = $0020;  // Data from FIFO
  PWM0_REVPOLAR   = $0010;  // Reverse polarity
  PWM0_OFFSTATE   = $0008;  // Ouput Off state
  PWM0_REPEATFF   = $0004;  // Repeat last value if FIFO empty
  PWM0_SERIAL     = $0002;  // Run in serial mode
  PWM0_ENABLE     = $0001;  // Channel Enable
type
  { TIoPort }
  TIoPort = class // IO bank object
  private         //
    //function get_pinDirection(aPin: TGpIoPin): TGpioPinConf;
  public
   FGpio: ^LongWord;
   FClk: ^LongWord;
   FPwm: ^LongWord;
   procedure SetPinMode(gpin, mode: byte);
   function GetBit(gpin : byte):boolean;inline; // gets pin bit}
   procedure ClearBit(gpin : byte);inline;// write pin to 0
   procedure SetBit(gpin : byte);inline;// write pin to 1
   procedure SetPullMode(gpin, mode: byte);
   procedure PwmWrite(gpin : byte; value : LongWord);inline;// write pin to pwm value
  end;
  { TIoDriver }
  TIoDriver = class
  private
  public
    destructor Destroy;override;
    function MapIo:boolean;// creates io memory mapping
    procedure UnmapIoRegisrty(FMap: TIoPort);// close io memory mapping
    function CreatePort(PortGpio, PortClk, PortPwm: LongWord):TIoPort; // create new IO port
  end;
var
    fd: integer;// /dev/mem file handle
procedure delayNanoseconds (howLong : LongWord);
implementation
uses
  baseUnix, Unix;
procedure delayNanoseconds (howLong : LongWord);
var
  sleeper, dummy : timespec;
begin
  sleeper.tv_sec  := 0 ;
  sleeper.tv_nsec := howLong ;
  fpnanosleep (@sleeper,@dummy) ;
end;
{ TIoDriver }
//*******************************************************************************
destructor TIoDriver.Destroy;
begin
  inherited Destroy;
end;
//*******************************************************************************
function TIoDriver.MapIo: boolean;
begin
 Result := True;
 fd := fpopen('/dev/mem', O_RdWr or O_Sync); // Open the master /dev/memory device
  if fd < 0 then
  begin
    Result := False; // unsuccessful memory mapping
  end;
 //
end;
//*******************************************************************************
procedure TIoDriver.UnmapIoRegisrty(FMap:TIoPort);
begin
  if FMap.FGpio <> nil then
 begin
   fpMUnmap(FMap.FGpio,PAGE_SIZE);
   FMap.FGpio := Nil;
 end;
 if FMap.FClk <> nil then
 begin
   fpMUnmap(FMap.FClk,PAGE_SIZE);
   FMap.FClk := Nil;
 end;
 if FMap.FPwm <> nil then
 begin
   fpMUnmap(FMap.FPwm ,PAGE_SIZE);
   FMap.FPwm := Nil;
 end;
end;
//*******************************************************************************
function TIoDriver.CreatePort(PortGpio, PortClk, PortPwm: LongWord): TIoPort;
begin
  Result := TIoPort.Create;// new io port, pascal calls new fpMap, where offst is page sized 4096 bytes!!!
  Result.FGpio := FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortGpio); // port config gpio memory
  Result.FClk:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortClk);; // port clk
  Result.FPwm:= FpMmap(Nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, fd, PortPwm);; // port pwm
end;
//*******************************************************************************
procedure TIoPort.SetPinMode(gpin, mode: byte);
var
  fSel, shift, alt : byte;
  gpiof, clkf, pwmf : ^LongWord;
begin
  fSel := (gpin div 10)*4 ;  //Select Gpfsel 0 to 5 register
  shift := (gpin mod 10)*3 ;  //0-9 pin shift
  gpiof := Pointer(LongWord(Self.FGpio)+fSel);
  if (mode = INPUT) then
    gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift))  //7 shl shift komplemens - Sets bits to zero = input
  else if (mode = OUTPUT) then
  begin
    gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (1 shl shift);
  end
  else if (mode = PWM_OUTPUT) then
  begin
    Case gpin of
      12,13,40,41,45 : alt:= 4 ;
      18,19          : alt:= 2 ;
      else alt:= 0 ;
    end;
    If alt > 0 then
    begin
      gpiof^ := gpiof^ and ($FFFFFFFF - (7 shl shift)) or (alt shl shift);
      clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
      clkf^ := $5A000011 or (1 shl 5) ;                  //stop clock
      delayNanoseconds(200);
      clkf := Pointer(LongWord(Self.FClk)+PWMCLK_DIV);
      clkf^ := $5A000000 or (32 shl 12) ;	// set pwm clock div to 32 (19.2/3 = 600KHz)
      clkf := Pointer(LongWord(Self.FClk)+PWMCLK_CNTL);
      clkf^ := $5A000011 ;                               //start clock
      Self.ClearBit(gpin);
      pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
      pwmf^ := 0 ;		 	        // Disable PWM
      delayNanoseconds(200);
      pwmf := Pointer(LongWord(Self.FPwm)+PWM0_RANGE);
      pwmf^ := $400 ;                             //max: 1023
      delayNanoseconds(200);
      pwmf := Pointer(LongWord(Self.FPwm)+PWM1_RANGE);
      pwmf^ := $400 ;                             //max: 1023
      delayNanoseconds(200);
      // Enable PWMs
      pwmf := Pointer(LongWord(Self.FPwm)+PWM0_DATA);
      pwmf^ := 0 ;                                //start value
      pwmf := Pointer(LongWord(Self.FPwm)+PWM1_DATA);
      pwmf^ := 0 ;                                //start value
      pwmf := Pointer(LongWord(Self.FPwm)+PWM_CONTROL);
      pwmf^ := PWM0_ENABLE or PWM1_ENABLE ;
    end;
  end;
end;
//*******************************************************************************
procedure TIoPort.SetBit(gpin : byte);
var
   gpiof : ^LongWord;
begin
  gpiof := Pointer(LongWord(Self.FGpio) + 28 + (gpin shr 5) shl 2);
  gpiof^ := 1 shl gpin;
end;
//*******************************************************************************
procedure TIoPort.ClearBit(gpin : byte);
var
   gpiof : ^LongWord;
begin
  gpiof := Pointer(LongWord(Self.FGpio) + 40 + (gpin shr 5) shl 2);
  gpiof^ := 1 shl gpin;
end;
//*******************************************************************************
function TIoPort.GetBit(gpin : byte):boolean;
var
   gpiof : ^LongWord;
begin
  gpiof := Pointer(LongWord(Self.FGpio) + 52 + (gpin shr 5) shl 2);
  if (gpiof^ and (1 shl gpin)) = 0 then Result := False else Result := True;
end;
//*******************************************************************************
procedure TIoPort.SetPullMode(gpin, mode: byte);
var
   pudf, pudclkf : ^LongWord;
begin
  pudf := Pointer(LongWord(Self.FGpio) + 148 );
  pudf^ := mode;   //mode = 0, 1, 2 :Off, Down, Up
  delayNanoseconds(200);
  pudclkf := Pointer(LongWord(Self.FGpio) + 152 + (gpin shr 5) shl 2);
  pudclkf^ := 1 shl gpin ;
  delayNanoseconds(200);
  pudf^ := 0 ;
  pudclkf^ := 0 ;
end;
//*******************************************************************************
procedure TIoPort.PwmWrite(gpin : byte; value : Longword);
var
   pwmf : ^LongWord;
   port : byte;
begin
  Case gpin of
      12,18,40 : port:= PWM0_DATA ;
      13,19,41,45 : port:= PWM1_DATA ;
      else exit;
  end;
  pwmf := Pointer(LongWord(Self.FPwm) + port);
  pwmf^ := value and $FFFFFBFF; // $400 complemens
end;
//*******************************************************************************
end.

Controlling Lazarus unit:(Project files[3])

unit Unit1;
{Demo application for GPIO on Raspberry Pi}
{Inspired by the Python input/output demo application by Gareth Halfacree}
{written for the Raspberry Pi User Guide, ISBN 978-1-118-46446-5}
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, Unix, PiGpio;
type
  { TForm1 }
  TForm1 = class(TForm)
    GPIO25In: TButton;
    SpeedButton: TButton;
    LogMemo: TMemo;
    GPIO23switch: TToggleBox;
    Timer1: TTimer;
    GPIO18Pwm: TToggleBox;
    Direction: TToggleBox;
    procedure DirectionChange(Sender: TObject);
    procedure GPIO18PwmChange(Sender: TObject);
    procedure GPIO25InClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure GPIO23switchChange(Sender: TObject);
    procedure SpeedButtonClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
const
     INPUT = 0;
     OUTPUT = 1;
     PWM_OUTPUT = 2;
     LOW = False;
     HIGH = True;
     PUD_OFF = 0;
     PUD_DOWN = 1;
     PUD_UP = 2;
 // Convert Raspberry Pi P1 pins (Px) to GPIO port
     P3 = 0;
     P5 = 1;
     P7 = 4;
     P8 = 14;
     P10 = 15;
     P11 = 17;
     P12 = 18;
     P13 = 21;
     P15 = 22;
     P16 = 23;
     P18 = 24;
     P19 = 10;
     P21 = 9;
     P22 = 25;
     P23 = 11;
     P24 = 8;
     P26 = 7;
var
  Form1: TForm1;
  GPIO_Driver: TIoDriver;
  GpF: TIoPort;
  PWM :Boolean;
  i, d : integer;
  Pin,Pout,Ppwm : byte;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormActivate(Sender: TObject);
begin
  if not GPIO_Driver.MapIo then
  begin
     LogMemo.Lines.Add('Error mapping gpio registry');
  end
  else
  begin
    GpF := GpIo_Driver.CreatePort(GPIO_BASE, CLOCK_BASE, GPIO_PWM);
  end ;
  Timer1.Enabled:= True;
  Timer1.Interval:= 25;     //25 ms controll interval
  Pin := P22;
  Pout := P16;
  Ppwm := P12;
  i:=1;
  GpF.SetPinMode(Pout,OUTPUT);
  GpF.SetPinMode(Pin,INPUT);
  GpF.SetPullMode(Pin,PUD_Up);    // Input PullUp High level
end;
procedure TForm1.GPIO25InClick(Sender: TObject);
begin
  If GpF.GetBit(Pin) then LogMemo.Lines.Add('In: '+IntToStr(1))
                     else LogMemo.Lines.Add('In: '+IntToStr(0));
end;
procedure TForm1.GPIO18PwmChange(Sender: TObject);
begin
  if GPIO18Pwm.Checked then
  begin
    GpF.SetPinMode(Ppwm,PWM_OUTPUT);
    PWM := True;                          //PWM on
  end
  else
  begin
    GpF.SetPinMode(Ppwm,INPUT);
    PWM := False;                          //PWM off
  end;
end;
procedure TForm1.DirectionChange(Sender: TObject);
begin
  if Direction.Checked then d:=10 else d:=-10;
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
    GpF.SetPinMode(Ppwm,INPUT);
    GpF.ClearBit(Pout);
    GpIo_Driver.UnmapIoRegisrty(GpF);
end;
procedure TForm1.GPIO23switchChange(Sender: TObject);
Begin
  Timer1.Enabled := False;
  if GPIO23switch.Checked then
  begin
    GpF.SetBit(Pout); //Turn LED on
  end
  else
  begin
    GpF.ClearBit(Pout); //Turn LED off
  end;
  Timer1.Enabled := True;
end;
procedure TForm1.SpeedButtonClick(Sender: TObject);
var
  i,p,k,v: longint;
  ido:TDateTime;
begin
  ido:= Time;
  k:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
  LogMemo.Lines.Add('Start: '+TimeToStr(ido));
  p:=10000000 ;
  For i:=1 to p  do Begin
    GpF.SetBit(P16);
    GpF.ClearBit(P16);
  end;
  ido:= Time;
  v:= TimeStampToMSecs(DateTimeToTimeStamp(ido));
  LogMemo.Lines.Add('Stop: '+TimeToStr(ido)+' Frequency: '+
                                IntToStr(p div (v-k))+' kHz');
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  If PWM then Begin
    If (d > 0) and (i+d < 1024) then begin
          i:=i+d;
          GpF.PwmWrite(Ppwm,i);
    end ;
    If (d < 0) and (i+d > -1) then begin
          i:=i+d;
          GpF.PwmWrite(Ppwm,i);
    end;
  end;
end;
end.
发布于 分类 Linux