在家庭自动化过程中,发现可用的VK-G4气体流量计具有一个有趣的功能:在初级放电装置中内置了一块磁铁,可以关闭安装在设备本身外部的簧片开关(即无需连接它即可)。煤气公司)。这甚至在柜台本身的护照上也有说明。没错,建议您使用“ IN-Z 61低频脉冲发生器”,但实际上,它只是安装在仪表上的磁簧开关,价格高昂。因此,决定使用最便宜的具有数字输出(即集成了施密特触发器)的霍尔传感器,而不是IN-Z 61。从市场上购买了SS441A型霍尔传感器。根据SS44xA上的数据表,第三位数字对其磁敏感度进行编码,从而确定传感器在燃气表上的物理位置。作为控制系统,我使用运行Linux(香草内核4.2+)的单板Banana PI计算机。 SS44xA的物理连接非常简单:我们将输出(-)连接到公共电线;输出(+)连接到+ 5V(而不是+ 3.3V);引脚(D)连接到GPIO端口,并通过4.7kΩ电阻拉至+ 3.3V。但是,当我找不到可以仅计算给定GPIO端口上脉冲数的内核树内驱动程序时,我感到惊讶!我了解Linux不是实时操作系统,而只是计数低频脉冲...真的就是我遇到了这样的问题吗?仔细查看了最新的内核资源后,发现了两个中间解决方案:- 使用标准的UIO驱动程序。如果在应用程序中将这样的设备作为文件打开并写入相应的值,则从该设备进行的后续读取操作将被挂起,直到由于相应的GPIO上的信号电平变化而引起中断为止;
- gpio_keys. GPIO «» (button) «» (switch), , .
使用这些解决方案中的任何一个都将需要守护程序应用程序,该应用程序必须处于活动状态才能执行脉冲计数。这不是最佳解决方案,因为如果由于某种原因完成了此操作,我们可以跳过一定数量的脉冲,这对于记账目的非常关键。因此,为了最小化风险,决定编写我们自己的设备驱动程序,该设备驱动程序可以直接在内核级别运行。因此,满足:一个驱动程序,可使用设备树技术配置任意GPIO线上的脉冲计数。前提条件- 使用的Linux内核版本4.x或更高版本
- 用于构建它的内核头文件(通常位于目标系统上的/ usr / include / linux中)
- -
- Device Tree
- Device Tree ( dtc)
对于我的工作,我使用来自Armbian的程序集,并且在他们的网站上,您还可以获取内核资源,并以此为基础编写了程序集。但是,原则上,对目标组件没有任何限制。我不在这里描述外部模块的组装(以及什么?原则上,有很多这样的描述),因此我们相信您已经为内核组装了现成的counters.ko gpio-pulse.ko模块。我以Banana PI为例描述了进一步的过程,但可以类似地将其转移到任何其他平台。打开连接器说明板在板上。我们对CON3连接器(GPIO接头)感兴趣。我们选择所需的任何触点并确定其功能(例如,我喜欢连接PH2插座端口的CON3连接器上的引脚12)。我们使用Allwinner A20数据表(GPIO多路复用功能表)进行检查-所选端口应支持中断的生成(在我的情况下,Multi 6列中为EINT2)。接下来,我们需要根据GPIO确定引脚号,该GPIO对应于选定的端口(PH2)。对我而言,直接在工作设备上确定它更容易:#grep'(PH2)'/sys/kernel/debug/pinctrl/1c20800.pinctrl/pinmux-pins引脚226(PH2):(MUX UNCLAIMED)(GPIO UNCLAIMED)同时并确保该端口当前未被任何东西使用(MUX和GPIO UNCLAIMED)。现在,您可以创建设备树配置。Linux内核的源代码在arch / arm / boot / dts文件夹中,提供了一些设备的示例,对于Banana,PI文件称为sun7i-a20-bananapi.dts,在其中进行了以下更改:/ {
model = "Banana Pi BPI-M1";
compatible = "sinovoip,bpi-m1", "allwinner,sun7i-a20";
...
counters {
compatible = "gpio-pulse-counter";
gas-meter@0 {
label = "Gas meter";
pinctrl-names = "default";
pinctrl-0 = <&ext_counter_bananapi>;
gpios = <&pio 7 2 GPIO_ACTIVE_LOW>;
interrupt-parent = <&pio>;
interrupt-names = "counter-edge-falling";
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
};
};
&pio {
...
ext_counter_bananapi: counter_pins@0 {
allwinner,pins = "PH2";
allwinner,function = "gpio_in";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
节点中的gpios参数计算如下:- 首先是指向pio标签的链接;
- 接下来是存储库编号,其中包含所需的GPIO端口。对于Allwinner A20,每个存储区包含32个端口,因此存储区号定义为GPIO引脚除以32的整数部分;
- 接下来是银行内的密码。因为 每个存储体有32个引脚,则该值计算为GPIO引脚除以32的余数;
- 最后一个参数指示哪个信号电平被认为是活动的
节点中的interrupts参数计算如下:- 第一个参数指示GPIO控制器的中断号(对于EINT2,它将为2)
- 第二个参数是IRQ_TYPE_EDGE_FALLING,它允许在信号从高电平变为低电平时生成中断(因为我们有一个集电极开路传感器并拉至+ VCC)
我们编译修改后的设备树文件:dtc -I dts -O dtb sun7i-a20-bananapi.dts > sun7i-a20-bananapi.dtb
使用生成的sun7i-a20-bananapi.dtb,我们覆盖/boot/dtb/sun7i-a20-bananapi.dtb中的文件。将内核模块counters.ko gpio-pulse.ko 写入/ lib / modules / $(uname -r)/内核/驱动程序并加载目标系统。在加载的目标系统上,我们给出命令depmod -a
然后重新启动。之后,我们看一下dmesg命令的输出:
...
[ 4.745570] counters: Class driver loaded.
[ 4.749235] gpio_pulse: Device
...
太好了,模块已加载且正常运行。我们首先以编程方式检查功能:
0
1
3
(我们通过软件模仿了一个信号)。现在,我们连接霍尔传感器,并通过在其上放一些磁铁(例如,从冰箱上的磁性标签上)确保其可操作性。后记
最后,我有时间发布图片。所以:实际上是传感器。它的敏感部分是没有斜角的那一侧(也就是说,我们将其按最小的放电压力压到仪表上)。
然后我们用电工胶带固定传感器。
为获得强度,将一块泡沫切入燃气表中以适应凹槽的大小,然后将传感器固定到其上。
然后我们用电工胶带将其和电线固定
好。这就是结果。
对于紧固件的决定,请不要踢脚,因为 房屋仍在维修和固定中,实际上是一个原型。