树莓派4 UART 多串口配置通信

相比树莓派零、1、2 以及 3 的双串口 UART0(PL011)和 UART1(mini UART),树莓派4 中新增了 4 个 PL011 串口共计有 6 个 UART,整理此笔记用作记录和配置参考。

注意,目前搜到的大多数描述树莓派 4 串口的文章,大多数开头都是禁用下蓝牙,这个做法针对树莓派0-3 是必须的,因为本身串口不够用,但对树莓派 4 来说并不需要,因为有额外 4 个串口可以利用,默认配置好的两串口一个用于蓝牙(UART0)另一个是 miniUART 可以保留设置。此方面的文章大多都是一个流程,原因是参考的最初版本是树莓派 3 的设置;树莓派 4 的额外串口设置在树莓派论坛中可以看到相关的介绍,外面的文章不太多。

UART 配置

1. 展示所有串口命令

$ dtoverlay -a | grep uart

展示 pi4 中所有串口

pi@raspberrypi:~ $ dtoverlay -a | grep uart midi-uart0 midi-uart1 miniuart-bt uart0 uart1 uart2 uart3 uart4 uart5

2. 查看特定串口信息

$ dtoverlay -h uart2

查看 UART2 的配置信息等:

pi@raspberrypi:~ $ dtoverlay -h uart2 Name: uart2 Info: Enable uart 2 on GPIOs 0-3 Usage: dtoverlay=uart2, Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off)

相关信息会展现 GPIOs 与新的 UART 串口的分配:0-3 对应 UART2, 4-7 对应 UART3,8-11 对应 UART 4,以及 12-15 对应 GUIO 5

关于 4 个针脚中后两位对应的 CTS/RTS,可参考:

https://blog.csdn.net/zeroboundary/article/details/8966586

3. 配置开启串口 UART2-5

执行编辑 config.txt 命令:

sudo nano /boot/config.txt

在文件结尾添加如下:

dtoverlay=uart2 dtoverlay=uart3 dtoverlay=uart4 dtoverlay=uart5

保存(Write Out)并退出(Exit)

重启后查看是否生效:

$ ls /dev/ttyAMA*

结果显示如下:

pi@raspberrypi:~ $ ls /dev/ttyAMA* /dev/ttyAMA0 /dev/ttyAMA1 /dev/ttyAMA2 /dev/ttyAMA3 /dev/ttyAMA4

各 UART 串口与 GPIO 对应关系:

GPIO14 = TXD0 -> ttyAMA0 GPIO0 = TXD2 -> ttyAMA1 GPIO4 = TXD3 -> ttyAMA2 GPIO8 = TXD4 -> ttyAMA3 GPIO12 = TXD5 -> ttyAMA4 GPIO15 = RXD0 -> ttyAMA0 GPIO1 = RXD2 -> ttyAMA1 GPIO5 = RXD3 -> ttyAMA2 GPIO9 = RXD4 -> ttyAMA3 GPIO13 = RXD5 -> ttyAMA4

4. 测试

4.1 串口自发自收测试

现在我们先测试 UART2 是否启用成功,比较简单的测试方式是将其 TXD 和 RXD 相连,自发自收。

根据上方对应关系,UART2 对应 TXD2 和 RXD2,对应 GPIO0 和 GPIO1,对应 ttyAMA1

注:UART0 对应的 ttyAMA0,UART1 对应的 ttyS0,UART2 到 UART5 对应的 ttyAMA1 到 ttyAMA4。

找到对应的 GPIO0 和 GPIO1 针脚连起来:

在树莓派端命令行进入 Python3 环境,通过如下模块和命令自发自收:

pi@raspberrypi:~ $ python3 Python 3.7.3 (default, Jul 25 2020, 13:03:44) [GCC 8.3.0] on linux Type “help”, “copyright”, “credits” or “license” for more information. >>> import serial >>> ted = serial.Serial(port=”/dev/ttyAMA1″, baudrate=9600) >>> ted.write(“Hello World”.encode(“gbk”)) 11 >>> ted.read(11) b’Hello World’ >>>

同理,我们可以继续用跳线帽将 GPIO4 和 5 相连测试 UART3;GPIO8 和 9 相连测试 UART4; GPIO12 和 13 相连测试 UART5。

pi@raspberrypi:~ $ python3 Python 3.7.3 (default, Jul 25 2020, 13:03:44) [GCC 8.3.0] on linux Type “help”, “copyright”, “credits” or “license” for more information. >>> import serial >>> ted = serial.Serial(port=”/dev/ttyAMA1″, baudrate=9600) >>> ted.write(“Hello World”.encode(“gbk”)) 11 >>> ted.read(11) b’Hello World’ >>> ted3 = serial.Serial(port=”/dev/ttyAMA2″, baudrate=9600) >>> ted3.write(“Hello No.3”.encode(“gbk”)) 10 >>> ted3.read(10) b’Hello No.3′ >>> ted4 = serial.Serial(port=”/dev/ttyAMA3″, baudrate=9600) >>> ted4.write(“Hello No.4”.encode(“gbk”)) 10 >>> ted4.read(10) b’Hello No.4′ >>> ted5 = serial.Serial(port=”/dev/ttyAMA4″, baudrate=9600) >>> ted5.write(“Hello No.5”.encode(“gbk”)) 10 >>> ted5.read(10) b’Hello No.5′ >>>

4.2 串口间通信测试

接下来测试 UART2 和 UART3 间的通信,将 TXD2 连接 RXD3 即 GPIO0 与 GPIO5 相连;将 TXD3 与 RXD2 连接即 GPIO4 与 GPIO1 相连。

GPIO0 = TXD2 -> ttyAMA1 GPIO4 = TXD3 -> ttyAMA2 GPIO1 = RXD2 -> ttyAMA1 GPIO5 = RXD3 -> ttyAMA2

pi@raspberrypi:~ $ python3 Python 3.7.3 (default, Jul 25 2020, 13:03:44) [GCC 8.3.0] on linux Type “help”, “copyright”, “credits” or “license” for more information. >>> import serial >>> ted = serial.Serial(port=”/dev/ttyAMA1″, baudrate=9600) >>> ted3 = serial.Serial(port=”/dev/ttyAMA2″, baudrate=9600) >>> ted.write(“Msg from UART2…”.encode(“gbk”)) 17 >>> ted3.read(17) b’Msg from UART2…’ >>> ted3.write(“Msg from UART3…”.encode(“gbk”)) 17 >>> ted.read(17) b’Msg from UART3…’ >>>

OK 挺顺利,UART2 和 UART3 间通信正常。

参考

官方 UART 配置文档:

https://www.raspberrypi.org/documentation/configuration/uart.md

论坛关于多串口的命令与指引:

https://www.raspberrypi.org/forums/viewtopic.php?t=244827#p1493698

本文遵循CC 4.0 BY-SA版权协议,原文出处:

https://blog.csdn.net/weixin_40796925/article/details/107907991

树莓派上安装 wiringPi 2.6 解决 gpio readall 命令的错误

wiringPi 是一个被广泛使用的树莓派 GPIO 库,使用 C 语言开发。wiringPi 提供了丰富的接口,GPIO控制,中断,多线程。wiringPi 的安装我们之前介绍过,只需要运行命令:

sudo apt-get install wiringpi

即可。可是在树莓派 CM4、树莓派 4B 等新版本上,运行 gpio readall 命令会出现下面的错误:

Oops – unable to determine board type… model: 20 Oops – unable to determine board type… model: 17

这是因为 wiringPi 的作者已经很久没有更新这个库,导致新出的开发板型号无法被正确识别。

找了一圈发现通过自己编译 GitHub 仓库上的源码可以解决这个问题。

git clone https://github.com/WiringPi/WiringPi.git cd ~/wiringPi ./build

再使用命令:

gpio -v

可以看到版本号是 2.6,gpio readall 也可以正常使用了。

树莓派 CM4 启用 HDMI 音频输出和 USB 接口

树莓派 CM4 和 4B 的 CPU 均为 2711,但是实际使用过程中还是会有差异。比如 USBHUB 默认没有开启、音频输出配置方面存在差别。

树莓派 4B 可以通过 HDMI 输出音频,也可以通过 3.5mm 模拟音频接口输出,另外还可以通过 I2S 外扩音频模块。对于 CM4 而言,已经没有 3.5mm 模拟音频输出接口了,那么最直接的使用方法就是通过 HDMI 输出音频,当然也可以通过 I2S 外挂解码芯片输入音频,比如 PCM5122 模块。

需要注意的是,默认情况下 HDMI 端口的音频输出是关闭的,虽然在系统右上角可以看到音频控制图标,但是实际并没有信号输出。

cat /proc/asound/cards

确认可以看到没有任何声卡的存在。

接下来我们开启 HDMI 的音频输出,找到 boot 分区下的 config.txt 文件,编辑其中内容。主要是确认几个地方:

1、添加一行配置。

dtoverlay=audremap

2、确认下面的内容没有被注释掉,如果没有找到这行,就手动添加一下。

dtparam=audio=on

3、确认下面的内容没有被注释掉,如果没有找到这行,就手动添加一下。

hdmi_drive=2

保存配置后重启,然后再运行 cat /proc/asound/cards 应该可以看到声卡已经有了。

可以发现音频输出只有 HDMI 1,这个 HDMI 1 是指系统下的第一路 HDMI,从原理图上讲是 HDMI 0。

打开了音频后就可以通过 HDMI 播放视频并输出音频信息,目前仅 HDMI1 可以输出音频,请注意 HDMI 连接顺序。

如果需要启用 USB 功能,在 /boot/config.txt 文件中加入下面的命令:

dtoverlay=dwc2,dr_mode=host

树莓派摄像头 MIPI 延长线方案

Cable Extension Kit(摄像头 MIPI 延长线套件)可以用于树莓派 3B+ 和树莓派 4B 的官方摄像头上,包括官方摄像头模块 500 万、800 万和 HQ 摄像头。把摄像头的 MIPI 信号转成 CML 信号后,将控制摄像头的 I2C 接口信号耦合到一对差分线进行传输。

通过普通的 CAT5 非屏蔽线最长可传输 20 米。在选对合适的线材的情况下甚至可以工作在 -20 摄氏度的低温环境。Cable Extension Kit 适合需要远距离传输摄像头信号的应用场景,如管道维修、远距离监控等。

安装便利,免驱动,使用起来也很简单。

确认摄像头

1、将树莓派摄像头模块通过软排线直接连接树莓派主板上的摄像头插槽。

2、启动树莓派并运行之前安装好了的 Raspberry Pi OS 系统。

通过 sudo raspi-config 命令启用摄像头,重启树莓派之后运行下面的命令:

raspistill -v -o test.jpg

确认摄像头是否可以工作。

验证好之后,关闭树莓派、拔出摄像头。

组装摄像头延长线

下面是 Cable Extension Kit 所包含的部件。

组装非常简单,无需额外驱动。只要把树莓派主板上的 CSI 接口通过 15 针的排线接到 RX 板上,通过 CAT5 网线连接发送模块,把摄像头通过 15 针的 FPC 排线接到发送板上,用树莓派标准的摄像头命令即可拍照和录制视频!

购买链接:http://link.nxez.com/buy/rpi-camera

工业树莓派–在激光雕刻中的应用

01 概述

工业树莓派(RevPi)是一种 DIN 导轨安装的工业小型控件,具有一整套 IO 和总线模块,可以与所有常见的模拟和数字传感器、执行器和总线系统以及基于 TCP-IP 的网络进行通信。RevPi 运行 Linux 操作系统,这使得它成为一个功能多样的多功能解决方案。

在本案例中,RevPi通过DIO扩展模块连接川崎FS03N型机器人以及PLH3D-6W-XF激光雕刻头。通过预安装的开源Node-RED软件,建立逻辑控制、通信通道以及功能强大的仪表盘。并可以通过web界面对机器人运行状态进行远程访问及控制。

02 硬件连接

下图是本案例的硬件连接实物图。最左边是24V电源,用于设备供电。旁边是RevPi Core模块,并连接了DIO扩展模块。

Core模块通过网线接入到网络内,可以进行远程访问及通信。DIO模块连接机器人及激光雕刻头进行逻辑控制。再往右边是两个AllDAQ的适配器,用于将RevPi DIO扩展模块的14个数字输入和14个数字输出连接到机器人的I/O版。

旁边蓝色的小型设备是一个耦合继电器,用于打开或关闭激光雕刻头的电源。最右边是数模转换器,可以将来自机器人的数字信号转换为激光雕刻头的0-10V模拟信号。

03 Node-RED仪表盘

本案例使用Node-RED的Dashboard组件建立操作仪表盘可以监视机器人的工作状态并进行开关控制。因为Core模块已接入以太网中,所以除了通过IO接口外,也可以TCP或UDP通信进行控制。

在本案例中,通过切换机器人控制器上的开关,可以使得机器人的状态从TEACH模式变为REPEAT模式,并在仪表盘中显示。

点击仪表盘上的Motor Power按钮可以打开电动机电源,并转换为ON状态。

也可以通过仪表盘控制机器人在某个方向上进行移动(以毫米为单位)。

单击中间Homing符号,可以使机器人回到原始位置。如果机器人处于原位,则“房子”符合将点亮。

04 Node-RED程序流

RevPi对机器人的逻辑控制及通信都是通过建立Node-RED flow实现的。

上面介绍的UI界面,也是通过这样的流程建立的。在Node-RED flow中,字符串以msg的形式存在,有效信息位于payload中,并可以通过TCP 或者UDP发送到机器人。

05 远程监控

Node-RED支持通过局域网内基于web的浏览器访问仪表盘。所以,您可以使用平板电脑或者智能手机监视机器人状态并进行控制。

在本案例中,可以通过手机发送开始“Laser-Auftrag gestartet”(开始激光工作)的信息,使机器人开始工作。并在作业结束后,可以在手机端收到“Laser-Auftrag beendet”(激光作业已完成)的提示信息。

06 附录

RevPi简介

工业树莓派Revolution Pi(简称RevPi)是基于Raspberry Pi 扩展而成的工业PC。该系列的三个基本模块都安装在细长的DIN导轨外壳中,可以通过各种合适的I/O模块和现场总线网关进行无缝扩展,并可通过预置的图形配置工具轻松配置。

为了实现符合EN 61131-2或IEC 61131-2标准的工业适用性,我们使用Raspberry Pi 计算模块作为基础。该模块看起来像一个内存条,但它没有任何外部接口。

我们为树莓派计算模块配备了符合所有重要工业标准的外部接口。而在软件方面,Revolution Pi具有经过特别改装的Raspbian操作系统,该操作系统配备了实时补丁,并且兼容为Raspberry Pi开发的大多数应用程序。

Node-RED简介

Node-RED 是构建物联网应用程序的一个强大工具。它使用可视化编程方法,允许开发人员将预定义的代码块(称为“节点”,Node)连接起来执行任务。连接的节点,通常是输入节点、处理节点和输出节点的组合,当它们连接在一起时,构成一个“流”(Flows)。

Node-RED最初是IBM在2013年末开发的一个开源项目,以满足他们快速连接硬件和设备到Web服务和其他软件的需求。作为物联网的一种粘合剂,它很快发展成为一种通用的物联网编程工具。

重要的是,Node-RED已经积累大量用户并迅速形成了一个活跃的开发人员社区,他们可以开发新的节点,同时允许程序员复用Node-RED代码来完成各种各样的任务。

RevPi已经预安装好了Node-RED编程环境,用户可以直接使用。并且我们有专门为RevPi设计的节点提供使用。Node-RED将成为您快速开发物联网应用的强大工具!

DIY 一台小方屏来显示树莓派信息

之前我们发布过 Pi Dashboard,一款树莓派仪表盘工具,用来显示树莓派运行状态和资源使用情况。这需要在电脑或手机的浏览器中打开树莓派上部署的网页来查看这些信息。

下面我们来 DIY 一个可爱的智能终端设备,通过 MQTT 协议获取任何想要监控和展示的信息,显示在一块 1.3 寸的 OLED 屏幕上。这些信息可以是类似树莓派仪表盘所展示的信息,也可以是其他你希望展示的信息,例如货币汇率、基金指数等实时数据。

该项目分为两个部分。树莓派作为信息收集者和发送者,同时 MQTT Broker(代理服务器)也搭建在树莓派上。NXEZ Cube(小方屏)作为信息接收端和显示设备。

部署主机端程序

在要监控的主机(树莓派、其他 Linux 系统的服务器或个人电脑)上运行下面的命令部署监控主机的程序。这个程序的作用是采集自身的实时数据并通过 MQTT 协议转发出来。

安装依赖项

sudo apt-get update sudo apt-get install python3-pip sudo apt-get install mosquitto mosquitto-clients

部署程序

程序有两个版本,下面我们用 Lite 版来介绍。

cd ~ git clone https://github.com/nxez/cube-dashboard cd cube-dashboard/server-lite sudo pip3 install paho-mqtt

修改 main.py 中的 mqttServerIP 这行变量的值,改成主机的 IP 地址。并且确保这个 IP 地址可以被小方屏访问到。

sudo nano main.py

Ctrl+X 然后会提示输入 Y 保存修改。运行下面的命令启动程序。

sudo python3 main.py &

到这里如果顺利的话,程序就已经开始运行了。只是还没有设备接收这些信息并显示出来。请继续往下看。

另外还可以通过配置让这个程序在每次开机后自动启动。

编辑 rc.local 文件。

sudo nano /etc/rc.local

在 exit 0 之前添加一行(其中脚本的路径请根据实际情况修改):

sudo python3 /home/pi/cube-dashboard/server-lite/main.py &

小方屏的制作

NXEZ Cube 小方屏由一块 ESP8266 开发板驱动一块 OLED 屏幕实现。你可以购买成套的材料来 DIY,或者直接下单已组装好的成品,亦或者自行准备类似功能的材料,按照下面的电路连接方式自制一个具有同样功能的小玩意。

小方屏购买地址:

http://link.nxez.com/buy/nxez-cube

相关的说明和开发资源已在文末单独列出。

代码调试

我们开源了 ESP8266 上的 Lite 版本源码和对应的服务端。同时也提供完整功能版的服务端源码和用于 ESP8266 的完整功能版固件:

https://github.com/nxez/cube-dashboard

如果你不需要二次开发,想直接使用完整版固件的功能,请参考产品主页里的安装说明(https://make.quwj.com/project/379)和这里的烧录方法来完成。这样就跳过代码调试步骤了。

对于二次开发来说,Lite 版本已经够用了。这个简化版大大简化了你修改程序需要关注的要素。

我们先下载 Lite 版源码,用 Visual Studio Code 打开。在此之前,你需要为 Visual Studio Code 安装 PlatformIO 插件并安装 ESP8266 相关的支持。具体方法 Google 一下就有。

源码需要修改 app-lite/src/settings.h 中的几处配置。

// WIFI const char* WIFI_SSID = “WIFI_SSID”; const char* WIFI_PWD = “WIFI_PWD”; //MQTT Broker char mqttBroker[16] = “192.168.1.204”; char mqttBrokerPort[6] = “1883”;

在 WIFI 的部分配置好可用的 WIFI 名称和密码。在 MQTT Broker 部分将 mqttBroker 配置为树莓派的 IP 地址(需要确认小方屏可以访问到这个 IP)。如果你打算将 MQTT 代理服务搭建在树莓派之外的服务器上,那这里就改成其他服务器的地址即可。端口号 1883 是默认值,如果没有自定义的话也就不需要修改。

修改好之后通过 Visual Studio Code 将代码上传到小方屏的 ESP8266 开发板上这步就算完成了。

一切顺利的话,给小方屏通电,就能看到效果了。

Lite 版用于二次开发使用,你可以通过编程加入个性化的数据来显示。只需要修改服务端和 ESP8266 的代码即可。

完整版功能效果如下。

包含以下控制选项。

小方屏相关资源

产品主页:

https://make.quwj.com/project/376

购买地址:

http://link.nxez.com/buy/nxez-cube

组装视频:

https://www.bilibili.com/video/BV1pv411j7cB/

硬件和固件资源列表:

https://make.quwj.com/member/2/bookmarks?category=92

DIY 讨论组:

https://talk.quwj.com/node/cube

把工业树莓派连接至 Ubidots 云平台

应用背景

Ubidots是一个物联网云平台,通过设备友好的API(可通过HTTP / MQTT / TCP / UDP协议访问)简单安全地将硬件和数字输入连接到Ubidots Cloud。它可以从任何启用互联网的设备将数据发送到云端,比如 Arduino、树莓派、Particle、Espressif、Onion,等等。此外,它还提供了多种类型的服务,比如设备连接管理以及数据可视化,开发人员可以基于实时数据和可视化工具配置操作和报警。

工业级树莓派能与以太网进行连接,自然也可以与Ubidots云平台进行数据的通信。下面我们就来讲讲工业树莓派如何连接Ubidots。

连接方法

RevPi Core具有定制的Raspbian系统可以通过运行python脚本随机生成压力、温度和湿度读数并将数据发送到Ubidots云平台。

首先通过RevPi Core终端使用nano编辑器创建Python脚本(可以通过putty远程连接,也可以外接显示屏,进入终端窗口):

nano ubidots_revpi.py

将以下代码粘贴到nano编辑器中,并将代码中的TOKEN替换成您自己的,获取方法见下图:

################################################################################ # This script simulates different sensors values using the random module and make # a HTTP request to Ubidots Cloud (https://ubidots.com/) # # Author: M. Hernandez ################################################################################ import requests import time import random from uuid import getnode as get_mac # Assign your Ubidots TOKEN TOKEN = “Assign_your_Ubidots_token” # Set the delay desired to post the data DELAY = 1 ”’ This method build the JSON to be sent to the Ubidots Cloud ”’ def build_json(variable_1, value_1, variable_2, value_2, variable_3, value_3): try: data = {variable_1: value_1, variable_2: value_2, variable_3: value_3} return data except: return None ”’ This method make the HTTP Request to the Ubidots Cloud ”’ def post_variable(device, value_1, value_2, value_3): try: url = “https://industrial.api.ubidots.com/api/v1.6/devices/” + device headers = {“X-Auth-Token”: TOKEN, “Content-Type”: “application/json”} data = build_json(“temperature”, value_1, “humidity”, value_2, “pressure”, value_3) response = requests.post(url=url, headers=headers, json=data) return response.json() except: pass if __name__ == “__main__”: while True: mac = get_mac() # get the mac address of your device device_mac = ‘:’.join((“%012X” % mac)[i:i+2] for i in range(0, 12, 2)) temp_value = random.randint(0,15)*2 hum_value = random.randint(20,50) press_value = random.randint(2,50)*2 print post_variable(device_mac, temp_value, hum_value, press_value) time.sleep(DELAY)

按Ctrl + O,确认要写入的文件名(ubidots_revpi.py) ,然后按Enter 。要关闭nanno编辑器,请按Ctrl + X。输入以下命令运行脚本:

python ubidots_revpi.py

脚本开始运行后,您将看到来自Ubidots服务器的成功状态代码响应201:

转到您的Ubidots帐户并确认已接收到数据。您将在“设备”部分中看到一个自动创建的新设备,该设备名称为RevPi Core的MAC地址。

再单击“设备”部分中的任何设备,就可以以可视化的方式看到RevPi Core模块发送给Ubidots云平台的数据。如您所见,示例代码提供了三个变量:湿度,压力和温度。

本文使用的模块

RevPi Core 是处理不需要四核性能的简单任务的理想设备,它配备了Raspberry Pi计算模块1。该计算模块基本上由两个IC组成:一个具有512 MB RAM和4 GB eMMC闪存的Broadcom BCM2835 SoC,时钟频率为700MHz。操作系统是定制的Raspbian incl并预先安装了RT补丁。

RevPi Core 使用了最先进的高效DC-DC转换器(总体效率大于80%),从而可以有效减少发热。模块不仅可以在20.4 V至28.8 V标准化的电源电压范围运行,也可以在10.2 V输入电压下运行,这意味着您甚至可以使用汽车电池或太阳能电池板作为电源。先进的保护电路可确保即使在输入电源线上受到大量电磁干扰的情况下,模块也能连续运行(前提是正确连接了功能性接地)。

像Raspberry Pi一样,RevPi Core 也配备了通用接口:

1个RJ45以太网插座

2个USB 2.0插座

1个Micro HDMI插座

1个Micro USB 2.0插槽

2 个PiBridge(用于RevPi模块扩展)

RevPi Core 模块可以适应恶劣的工业环境:

电源:12-24 VDC -15%/ +20%,max.10W

工作温度:-40°C至55°C

ESD保护:符合EN 61131-2和IEC 61000-6-2的4 kV / 8 kV

浪涌/冲击测试:根据EN 61131-2和IEC 61000-6-2进行

EMI测试:根据EN 61131-2和IEC 61000-6-2

UL认证(UL文件编号E494534)

树莓派 ACT LED 指示灯闪烁模式代表的状态

与之前的树莓派型号有所不同,树莓派4B 使用内置于 EEPROM 中的程序来做启动引导。

这意味着启动代码可以做得更加灵活,并具有网络启动和 USB 启动的能力。

当引导程序在 SD 卡上检测到有效的 start.elf 文件时,ACT LED 会闪烁 4 次。

如果遇到树莓派无法启动,板载的 LED 会按照预设的规律闪烁,来提示我们故障的原因。

LED 将在 N 次长亮(0次或多次)之后开始短闪。通常,闪烁的模式会在闪烁周期完成后的两秒再次重复。

下面一张表格,列明了指示灯闪烁的规律释义。

长亮 短闪 指示的状态 0 3 泛指启动失败 0 4 start*.elf 文件未找到 0 7 内核镜像(Kernel image)文件未找到 0 8 SDRAM 内存故障 0 9 SDRAM 内存不足 0 10 处于 HALT 状态 2 1 分区不是 FAT 格式 2 2 无法读取分区 2 3 扩展分区不是 FAT 格式 2 4 文件签名/哈希不匹配 – Pi 4 4 4 不支持的主板型号 4 5 致命的固件错误 4 6 A 型电源故障 4 7 B 型电源故障

举例:

树莓派基金会单独发售 RP2040 芯片,价格仅 1 美元

今年初,树莓派基金会发布了其第一个微控制器级开发板 Raspberry Pi Pico。擅长低时延 I/O 通信和模拟信号输入的 Pico 搭载的是树莓派基金会自家设计的树莓派芯片 RP2040。

近日,树莓派基金会宣布 RP2040 芯片将以独立的产品开售,售价 1 美元。我们认为这将加速树莓派生态的建设。

下面让我们看看这个芯片的主要参数。如果你想全面了解,可以直接查看官方提供的 Datasheet 文档。

RP2040 芯片是 7×7mm QFN-56 封装的,具体规格参数如下:

– 双核 Arm Cortex-M0 + @ 133MHz

– 芯片内置 264KB SRAM 和 2MB 的板载闪存

– 通过专用 QSPI 总线支持最高 16MB 的片外闪存

– DMA 控制器

– 30 个 GPIO 引脚,其中 4 个可用作模拟输入

– 2 个 UART、2 个 SPI 控制器和 2 个 I2C 控制器

– 16 个 PWM 通道

– USB 1.1 主机和设备支持

– 8 个树莓派可编程 I/O(PIO)状态机,用于自定义外围设备支持

– 支持 UF2 的 USB 大容量存储启动模式,用于拖放式编程

使用 Arduino IDE 为树莓派 Pico 编程开发

树莓派 Pico 是今年树莓派基金会推出的微控制器(MCU)产品,其功能丰富且成本低,非常适合我们的项目。我们很多人都使用 Arduino IDE 来对微控制器进行编程。Python 和 C/C++ 都非常适合来进行 Pico 的编程。

而下面的要介绍的是使用 Arduino IDE 来作为树莓派 Pico 的开发环境,就和开发 Arduino 程序一样去做 Pico 上的开发,将树莓派 Pico 集成到 Arduino 的生态中。这样做的原因之一是可以直接使用丰富的 Arduino 底层库、允许集成模块、传感器和其他复杂的东西,而无需从头开始编写所有代码。

所以事不宜迟,让我们开始吧!

准备好 Arduino IDE

通过菜单 Tools>Boards>Boards Manager 来搜索开发板,输入关键词 ‘pico’ 找到并下载安装到 Arduino IDE。

上传示例程序

将 Pico 连上电脑,菜单 Tools>Port 中选择 Pico 对应的 COM 端口。

在菜单 Files>Examples>Basics>Blink 中打开 Blink 示例程序,点击 Upload 上传到 Pico。

当 IDE 显示已经上传完成,就可以看到 Pico 板载的 LED 开始闪烁。

via

树莓派上安装和配置 vsftpd 的教程

在网盘流行的当下,FTP 这种文件传输协议似乎有些「古老」。但是无论如何,FTP 方案有成熟的软件生态、完善的权限控制。你几乎无需做任何开发,只需要选择适合的软件即可创建一个文件共享服务器。可以用于工作文档的存储、分享,或者是数字产品的发布。如果你也和我一样,想在树莓派上搭建 FTP 服务器,下面以 vsftpd 为例,介绍如何安装和配置一个带完整权限控制的 FTP 服务。

对于不同用户进行不同的权限控制。考虑到服务器的安全性,所以关闭实体用户登录,使用虚拟帐号验证机制,并对不同虚拟帐号设置不同的权限。为了保证服务器的性能,还需要根据用户的等级,限制客户端的连接数及下载速度。

安装 vsftpd

sudo apt-get install vsftpd vim db-util

创建用户数据库

1、创建用户文本文件

先建立用户文本文件 vsftpd_virtualuser.txt,添加两个虚拟帐号,公共帐号 share 及客户帐号 upload。

sudo mkdir /etc/vsftpd touch /etc/vsftpd/vsftpd_virtualuser.txt vim /etc/vsftpd/vsftpd_virtualuser.txt

格式:

虚拟帐号 1 密码 虚拟帐号 2 密码

例如:

share 123456 upload 456789

保存退出。

2、生成数据库

保存虚拟帐号和密码的文本文件无法被系统帐号直接调用。我们需要使用 db_load 命令生成 db 数据库文件。

sudo db_load -T -t hash -f /etc/vsftpd/vsftpd_virtualuser.txt /etc/vsftpd/vsftpd_virtualuser.db

3、修改数据库文件访问权限

数据库文件中保存着虚拟帐号的密码信息,为了防止非法用户盗取,我们可以修改该文件的访问权限。生成的认证文件的权限应设置为只对 root 用户可读可写,即 600。

sudo chmod 600 /etc/vsftpd/vsftpd_virtualuser.db

配置 PAM 文件

为了使服务器能够使用数据库文件,对客户端进行身份验证,需要调用系统的 PAM 模块.PAM(Plugable Authentication Module)为可插拔认证模块,不必重新安装应用系统,通过修改指定的配置文件,调整对该程序的认证方式。PAM 模块配置文件路径为/etc/pam.d/目录,此目录下保存着大量与认证有关的配置文件,并以服务名称命名。

修改 vsftpd 对应的 PAM 配置文件 /etc/pam.d/vsftpd,将默认配置使用“#”全部注释,添加相应字段。

auth required pam_userdb.so db=/etc/vsftpd/vsftpd_virtualuser account required pam_userdb.so db=/etc/vsftpd/vsftpd_virtualuser

创建虚拟帐号对应的系统用户

对于公共帐号和客户帐号,因为需要配置不同的权限,所以可以将两个帐号的目录进行隔离,控制用户的文件访问。公共帐号 share 对应系统帐号 ftpshare,并指定其主目录为 /home/pi/ftp/share,而客户帐号 upload 对应系统帐号 ftpupload,指定主目录为 /home/pi/ftp/upload。

如果不设置可执行用户登录会报不能更改目录错误。

mkdir /home/pi/ftp mkdir /home/pi/ftp/share mkdir /home/pi/ftp/upload sudo useradd -d /home/pi/ftp/share ftpshare sudo useradd -d /home/pi/ftp/upload ftpupload sudo chmod -R 500 /home/pi/ftp/share/ sudo chmod -R 700 /home/pi/ftp/upload/

公共帐号 share 只允许下载,修改 share 目录其他用户权限为 rx 可读可执行。

客户帐号 upload 允许上传和下载,所以对 upload 目录权限设置为 rwx,可读可写可执行。

建立配置文件

设置多个虚拟帐号的不同权限,若使用一个配置文件无法实现此功能,需要为每个虚拟帐号建立独立的配置文件,并根据需要进行相应的设置。

1、修改 vsftpd.conf 主配置文件

配置主配置文件 /etc/vsftpd.conf 添加虚拟帐号的共同设置并添加 user_config_dir 字段,定义虚拟帐号的配置文件目录。

禁用匿名用户登录并启用本地用户登录设置:

anonymous_enable=NO local_enable=YES # 将所有本地用户限制在家目录中,NO 则不限制 chroot_local_user=YES # 配置 vsftpd 使用的 PAM 模块为 vsftpd pam_service_name=vsftpd # 设置虚拟帐号的主目录为/vuserconfig user_config_dir=/etc/vsftpd/vuserconfig # 设置 FTP 服务器最大接入客户端数为 300 个 max_clients=300 # 设置每个 IP 地址最大连接数为 10 个 max_per_ip=10 allow_writeable_chroot=YES pasv_enable=YES pasv_min_port=10000 pasv_max_port=20000

2、建立虚拟帐号配置文件

在 user_config_dir 指定路径下,建立与虚拟帐号同名的配置文件并添加相应的配置字段。

首先建立公共帐号 share 的配置文件:

sudo mkdir /etc/vsftpd/vuserconfig sudo vi /etc/vsftpd/vuserconfig/share

# 开启虚拟帐号登录 guest_enable=yes # 设置 ftp 对应的系统帐号为 ftpshare guest_username=ftpshare # 允许匿名用户浏览器整个服务器的文件系统 anon_world_readable_only=no # 限定传输速率为 500KB/s anon_max_rate=500000

注意:

vsftpd 对于文件传输速度限制并不是绝对锁定在一个数值上哈,而是在 80%~120%之间变化。比如设置 100KB/s ,则实际是速度在 80KB/s~120KB/s 之间变化。

下面是客户帐号的配置文件 upload:

sudo vi /etc/vsftpd/vuserconfig/upload

# 开启虚拟帐号登录 guest_enable=yes # 设置 ftp 对应的系统帐号为 ftpupload guest_username=ftpupload # 允许匿名用户浏览器整个服务器的文件系统 anon_world_readable_only=no # 允许在文件系统写入权限 write_enable=yes # 允许创建文件夹 anon_mkdir_write_enable=yes # 开启匿名帐号的上传功能 anon_upload_enable=yes # 限定传输速度为 1000KB/s anon_max_rate=1000000 如果需要删除权限,可在配置中添加: anon_other_write_enable=YES

重启 vsftpd 使配置生效

sudo systemctl restart vsftpd sudo service vsftpd restart

树莓派如何结合Codesys实现CANopen主站

在之前的文章里已经介绍了如何使用虹科工业树莓派结合Codesys实现软PLC以及建立工程的步骤。本文将更进一步,介绍如何使用Codesys实现CANopen主站功能。所需的Codesys package文件以及相关软件在之前的文章中已经详细叙述,再次不再展示。由于实现CANopen主站需要硬件CAN口的支持,所以本文采用Connect模块和ConCAN模块进行。ConCAN模块仅适用于Connect模块,其作用相当于给Connect模块添加了一个CAN接口。

实现CANopen Master

最新的Revolution Pi Codesys库独立于PiCtory运行,在启动应用程序时自动覆盖config.rsc文件,因此无需在PiCtory中配置模块。

您需要执行以下步骤:

1、在Codesys IDE中配置Connect模块,并将ConCAN模块配置在右边。

2、配置脚本以设置波特率

sudo nano /var/opt/codesys/rts_set_baud.sh

#!/bin/sh BITRATE=`expr $2 \\* 1000` ifconfig $1 down echo ip link set $1 type can bitrate $BITRATE ip link set $1 type can bitrate $BITRATE ifconfig $1 up

sudo chmod +x /var/opt/codesys/rts_set_baud.sh sudo revpi-config enable revpi-con-can

3、从PiCtory中或者使用以下命令启用ConCAN模块

sudo revpi-config enable revpi-con-can

4、下载Codesys应用程序到设备

5、重启设备

6、Con CAN模块应随后可与Codesys配合使用

以下是一个示例,该示例具有一个运行CAN Open master的Con CAN模块并与Kunbus CAN Open Gateway通信。

附件:

文件下载

用树莓派4B打造纯ATV 10代替电视盒子

家里的电视买的比较早,“创*“什么的牌子,开机有广告。而且用了几年了,速度比较卡。无法接受的是不让装第三方软件,下定决心要搞一个性能比较猛的盒子了。但是看了一圈,普遍都不再预算范围内。

恰巧工作上用到树莓派4,当然用3也是可以的。理论上两个设备的固件是一样的。那决定用这个设备来尝试一下搭建一台用着还算比较爽的 ATV。

本文大部分参考原文翻译:

https://konstakang.com/devices/rpi4/

首先购买一片树莓派4B,现在买一片低配的版本就可以了,2G的大概在270元左右,还有要买一片红外接收头,100欧的电阻一只(建议安装)。参考网上的接图。

图片来自:

用红外遥控器遥控树莓派(XBMC)

图片中使用了 GPIO18 脚,Raspberry Pi OS 默认定义的引脚是 GPIO17,如果你想要调试 Raspberry Pi OS 环境,那需要注意这一点;我建议你在VCC串接一只R100的电阻并在5V取电,测试效果也不错。如果你没有R100,作为测试你可以在3.3V取电。

遥控接收管有很多型号,他们推荐的TSOP4838或者我推荐的VS1838B都可以,甚至价格更加便宜。

烧录ATV镜像到SD卡;使用 Raspberry PI Imager 就可以了。

https://konstakang.com/devices/rpi3/LineageOS17.1/

以下基本上是对原文 FAQ 的翻译;

Q: 怎样开启开发者模式(Root,终端窗口前提条件)?

A: 设置 -> 关于 -> 点击 ‘Build number’ 若干次。

Q: 开启root权限?

A: 开发者选项 -> Root 权限;不建议开启,你懂的。

Q: 开启终端应用?

A: 开发者选项 -> 本地终端。

Q: 高级重启?

A: 开发者选项 -> 高级重启。

Q: 只看到启动画面,不进入主屏幕?

A: 估计是屏幕不支持适配,试着在Windows下修改 /boot/resolution.txt 里面的分辨率设置. 删除 /boot/resolution.txt 这个文件的话,系统也会尝试多次适配。

Q: 存储空间和SD卡大小不一致?

A: 启动到recovery,参考开启高级重启;重启到TWRP,刷入我们的扩容包。

扩容包下载地址:

https://www.androidfilehost.com/?fid=8889791610682901036

需要你自行复制到U盘或者SD存储。

Q: 没有物理按键?

A: 插键盘

F1 = Home,

F2 = Back,

F3 = Multi-tasking,

F4 = Menu,

F5 = Power,

F11 = Volume down,

F12 = Volume up.

Q: 自己弄一个物理电源按键?

A: GPIO21 和 GND之 间加一个按钮。在设置中开启相关选项即可(需重启生效)。居然这个按钮还支持启动到Recovery(长按有效)。

Q: 在HDMI和3.5之间切换音频?

A: 设置中找到Raspi相关选项,可以切换。并且支持DAC(我没有测试)。

Q: 启用适配红外遥控》

A: 在设置中找到树莓派相关选项,打开相关设置。原文中指定了一个配置文件的页面:

https://github.com/lineage-rpi/android_external_ir-keytable/tree/lineage-17.1/rc_keymaps

其实没啥大用,本文会稍微详细讲解一下:

首先在/boot/下rc_keymap建立一个rc_keymap,注意没有扩展名。文件的格式注意设置为Unix(LF)+UTF-8。Notepad++默认的Windows格式是不会生效的。这一点官方文档上没有强调,困扰了很久。

接下来第一行

type: nec 这里是小写的,很多文档写成了大写,测试下来会报错,但是启动的时候又不会显示这些报错。

最后是键值获取和定义,ATV嘛,肯定有一些普遍的键值,上下左右什么的。

开启root权限,还有本地终端应用,开启IR Remote(这三步必须)。

打开终端,输入:

su ir-keytable -p nec #这步非必须,将遥控协议转为nec,注意是小写。如果你的遥控不能回显,可以试着执行这步。 #Protocols changed to nec 表示成功; Ir-keytable -t #键值检测,非常有用,按ctrl+c退出。

这个时候系统会给出一个提示符,要求你按遥控上的按键。我建议你只安装我们给出的列表顺序按键就可以了。基本上满足ATV的要求了。

首先是方向键上,记录下scancode=后面的值(就是键值)。逐个替换下面的键值,最后保存到 /boot/rc_keymap 这个文件即可。如果你用Windows,可以在移动磁盘里用notepad+新建一个文件,格式要求见上文。

# table lg akb7291, type: nec 0x408 KEY_POWER 0x443 KEY_MENU 0x45b KEY_HOMEPAGE 0x440 KEY_UP 0x406 KEY_RIGHT 0x407 KEY_LEFT 0x428 KEY_BACK 0x441 KEY_DOWN 0x444 KEY_ENTER 0x4aa KEY_ENTER 0x403 KEY_VOLUMEDOWN 0x402 KEY_VOLUMEUP

注意:

1、首先确认你的遥控器是红外遥控,方法是用手机摄像头拍摄一下,如果有光的就是红外遥控。如果是蓝牙的,可以直接用设置-遥控器和配件进行配对,效果也很好。非广告插入,敏感体质请绕行。

2、米家的遥控器使用了自有的协议,解码存在问题;在获取键值过程中通常无效。

3、原文中的KEY_OK没有测试成功,换KEY_ENTER后测试有效。 文中用到了AKB7291这个遥控器,如果你没有把握可以直接买这个。

本文来自 @最爱肉松 的投稿:

https://make.quwj.com/project/358

如何在树莓派 Pico 上使用 Unix:FUZIX

FUZIX 由英国计算机科学家 Alan Cox 创建,是用于小型计算机的轻量级 Unix 操作系统。其最初是为 8 位 Zilog Z80 处理器编写的。

David Given 已将 FUZIX 移植到各种架构上,并于近期发布了树莓派 Pico 的 RP2040 微型芯片的端口。

Given 将 Fuzix 描述为「老式的 Unix 克隆」。 「它将在很小的空间中运行,同时还可以扩展到具有合理数量的RAM(例如兆字节)的计算机,同时还提供了一个相当不错的老式 Unix 环境,它具有多个进程,经典的 Bourne shell 等等。」

FUZIX 仅使用树莓派 Pico 的一个内核,并运行用户可执行文件使用 64KB 的代码和数据、最多 15 个进程、Unix 文件系统、SD 卡支持以及树莓派 Pico 的 UART0 上的串行控制台。

下面介绍如何在树莓派或另一台基于 Linux 的计算机上,让树莓派 Pico 用上 FUZIX。

从源码编译 FUZIX

编译 FUZIX 并不复杂。如果你还没有准备好树莓派 Pico 的工具链,请通过在终端运行下面的命令来安装。

如果 wget 还没有安装,请执行 sudo apt install wget 命令。然后下载安装脚本,执行。

wget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh chmod +x pico_setup.sh ./pico_setup.sh

然后从 FUZIX 仓库获取源码。

git clone https://github.com/davidgiven/FUZIX.git cd FUZIX git checkout rpipico cd Kernel/platform-rpipico/

修改 Makefile 的第一行,设置为 pico-sdk 的路径。例如:

export PICO_SDK_PATH = /home/pi/pico/pico-sdk

然后就可以编译 FUZIX UF2 文件和 root 文件系统了。

make world -j ./update-flash.sh

如果一切顺利,在 build/fuzix.uf2 中会出现 UF2 文件,在当前工作目录中有一个 filesystem.img 文件。

现在,您可以按常规方式将 UF2 文件上传到 Pico 上,参考 https://pico.org.cn/ 。

1、按住 BOOTSEL 按钮,然后将 Pico 插入树莓派或 PC 的 USB 接口。

2、Pico 会被识别为大容量存储设备。

3、将下载的 UF2 文件放入 RPI-RP2 卷上。

该卷将自动卸载,树莓派 Pico 就已经开始运行 Unix 了。

创建可引导启动的 SD 卡

上面所得到的 filesystem.img 镜像文件并不具备引导启动的能力。下面将介绍在树莓派或其他类似的 Linux 平台上构建文件系统的方法。

先找一张 microSD 卡,由于我们只需要 34MB,所以几乎是随便找一张什么容量的都可以。这里使用了一张 4GB 的卡。插入读卡器,再通过 USB 插到 PC 上。构建 FUZIX 所需的分区表。这包含两个分区:

1、2MB 的交换分区

2、32MB 的根分区(将根文件系统,即 filesystem.img 复制进去)

使用 lsblk 命令,如果你有空白的未格式化的卡,会显示为 /dev/sda。

$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 1 3.7G 0 disk mmcblk0 179:0 0 14.9G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 14.6G 0 part / $

如果是格式化过的卡,则会是下面这样子。

$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 1 3.7G 0 disk └─sda1 8:1 1 3.7G 0 part /media/pi/USB mmcblk0 179:0 0 14.9G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 14.6G 0 part / $

上面 /media/pi/USB 所挂载的就是 FAT 格式的 SD 卡的 MBR 分区。

要卸载 SD 卡直接使用命令卸载。

$ umount /dev/sda1

然后使用 lsblk 命令会成这个样子。

$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 1 3.7G 0 disk └─sda1 8:1 1 3.7G 0 part mmcblk0 179:0 0 14.9G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 14.6G 0 part / $

此时,我们可以通过将卡的第一部分清零并删除「磁盘起始(start of disk)」结构来删除当前分区表。

$ sudo dd if=/dev/zero of=/dev/sda bs=512 count=1

之后再次运行 lsblk,将会看到 sda1 分区已被删除。接下来,我们将使用 fdisk 创建一个新的分区表。输入以下内容:

$ sudo fdisk /dev/sda

进入 fdisk 提示符。然后键入 o 以创建新的 DOS 磁盘卷标。

Command (m for help): o Created a new DOS disklabel with disk identifier 0x6e8481a2.

键入 n 创建新分区。

Command (m for help): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p Partition number (1-4, default 1): 1 First sector (2048-7744511, default 2048): 2048 Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-7744511, default 7744511): +2M Created a new partition 1 of type ‘Linux’ and of size 2 MiB.

根据磁盘的初始状态,系统可能会提示分区包含 vfat 签名。如果询问,按 Y 确认即可。

下面我们将该分区类型设置为 7F。

Command (m for help): t Selected partition 1 Hex code (type L to list all codes): 7F Changed type of partition ‘Linux’ to ‘unknown’.

创建 2MB 的交换分区。

下面创建第二个分区,32MB 的根文件系统。

Command (m for help): n Partition type p primary (1 primary, 0 extended, 3 free) e extended (container for logical partitions) Select (default p): p Partition number (2-4, default 2): 2 First sector (6144-7744511, default 6144): 6144 Last sector, +/-sectors or +/-size{K,M,G,T,P} (6144-7744511, default 7744511): +32M Created a new partition 2 of type ‘Linux’ and of size 32 MiB.

然后在 fdisk 提示符下键入 p 。

Command (m for help): p Disk /dev/sda: 3.7 GiB, 3965190144 bytes, 7744512 sectors Disk model: STORAGE DEVICE Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xe121b9a3 Device Boot Start End Sectors Size Id Type /dev/sda1 2048 6143 4096 2M 7f unknown /dev/sda2 6144 71679 65536 32M 83 Linux

键入 w 写入并保存分区表。

最后,将 filesystem.img 文件复制到 32MB 的分区中。

$ sudo dd if=filesystem.img of=/dev/sda2 65535+0 records in 65535+0 records out 33553920 bytes (34 MB, 32 MiB) copied, 14.1064 s, 2.4 MB/s $

是时候弹出 SD 卡,连接面包板了!

在面包板上接线

如果你是在树莓派上开发,并且之前没有试用过在树莓派上使用 UART 串口,请参考入门指南的第 4.5 节操作。

按照图上所示,连接树莓派、树莓派 Pico、SD 卡模块。

如果你是在笔记本电脑上开发,则可以使用 SparkFun FTDI Basic Breakout 之类的模块将 UART 串口连接到计算机。

无论是哪种方式,树莓派 Pico 上的引脚和 SD 卡模块的引脚对应关系都是一样的,如下:

接好之后,将格式化了的 microSD 卡弹出,插到 SD 卡模块上。然后将树莓派 Pico 通电,FUZIX 就会自动启动了。

连接到 FUZIX

如果你使用树莓派连接 Pico,需要先启用 UART 串行通信。

$ sudo raspi-config

依次选择 Interfacing Options → Serial,出现 “Would you like a login shell to be accessible over serial?” 选择 “No”,然后 “Would you like the serial port hardware to be enabled?” 选择 “Yes”。

退出 raspi-config 时你需要选择 “Yes” 并重启树莓派。

你还可以使用 minicom 连接到 FUZIX:

$ sudo apt install minicom $ minicom -b 115200 -o -D /dev/serial0

如果你使用 macOS 或者 Windows,你可以用 minicom、screen 或者常用的终端程序。

如果这时候你没有看到任何输出,请拔下树莓派 Pico 并重新插入即可。

最后,输入日期和时间,当出现登录提示时,请以 root 身份登录而无需输入密码。开始你的 FUZIX 探索之旅吧!

使用 MCC 118 对交流电进行监测分析

作者:mc_six

我们是通讯行业动力维护专业,因为外市电(三相交流电)的波动会对我们的设备造成一定的影响。于是想做一个交流电监测的应用,监测交流电的过压或欠压,所以我做了这么一个实时监测的工具。它可以在过压和欠压一定程度的时候告警。或者进行长期监测并记录电压数据,分析可能发生过压或欠压的原因。

树莓派作为一个简单易用功能强大的计算平台,很好地支持 Python。而且刚好有 MCC 118 数据采集模块(HAT)可以直接扩展出数据采集功能,MCC 118 提供 8 通道模拟电压输入,基于树莓派的数据采集/数据记录系统。每张 MCC 118 最大采样率为 100kS/s,可以进行单电压点和电压波形采集。

项目的代码就是在 MCC DAQ HATs 提供的 SDK 示例代码中,continuous_scan.py 的基础上修改来的。实现一个高速的采集及告警设备,来监测外市电的波动情况。

长期监测主要通过长期数据记录,分析是否有未超出告警范围的波动,以分析供电质量。

这只是一个工程样机,可以进行实时(延时3秒+)告警和储存发生告警时的电压波形;可以进行长期监测(不实时告警)、也可以长期监测并实时告警。

内部构造如下图,其中 MCC 118 在图中正上方。

告警分为4种:本机的光告警、本机的声告警、继电器输出的外部告警、物联网平台(OneNet)告警。

目前支持两路三相交流电监测,每路三相电的 A、B、C 相分别用。黄、绿、红,发光二极管告警。

物联网平台的告警页面。分别是:一路三相电的一相告警,以及一路三相电的三相告警。

采集到的正常交流电波形如下图。

数据分析部分是用 NumPy 进行交流电每个周期的最大值、最小值判断,然后确定是否报警,是否写入硬盘。

还有一个程序每一做任何判断,把采集到的所有数据都直接记录到硬盘,大概一小时会生成 1.2G 的数据。

也是用 Python 写的脚本,通过 NumPy 把数据做一个转换 ,然后用 NumPy 的 amax 和 amin 对数值进行分析判断。如果数据超过阈值,就写硬盘文件,同时用 GPIO 输出控制 LED 来发出预警信号。

以下是完整代码,其中关键代码已经添加了注释。

#!/usr/bin/env python # -*- coding: utf-8 -*- “”” MCC 118 Functions Demonstrated: mcc118.a_in_scan_start mcc118.a_in_scan_read mcc118.a_in_scan_stop mcc118.a_in_scan_cleanup Purpose: Perform a continuous acquisition on 1 or more channels. Description: Continuously acquires blocks of analog input data for a user-specified group of channels until the acquisition is stopped by the user. The last sample of data for each channel is displayed for each block of data received from the device. MCC118共8个通道,可以监测两个三相变压器的6路市电,分别为变压器1的A、B、C相和变压器2的A、B、C相 “”” from __future__ import print_function from daqhats import mcc118, OptionFlags, HatIDs, HatError from daqhats_utils import select_hat_device, enum_mask_to_string, \ chan_list_to_mask import os import threading import numpy as np import datetime import time from socket import * import RPi.GPIO as GPIO # ===GPIO setup===================================================================== GPIO.setmode(GPIO.BCM) led_list=[5,6,19,16,20,21] #LED使用的GPIO GPIO.setup(led_list, GPIO.OUT, initial=GPIO.LOW) delta = datetime.timedelta(minutes=5) # =================================================================================== READ_ALL_AVAILABLE = -1 CURSOR_BACK_2 = ‘\x1b[2D’s ERASE_TO_END_OF_LINE = ‘\x1b[0K’ # =================================================================================== arraydata=[[0 for i in range(72000)] for h in range(10)] #定义一个采样缓存数组,72000为read_request_size*信道数,10为#连续采样的次数c_time # =======OneNet param=================================================================== device_id = “Your 设备ID” # Your 设备ID api_key = “Your API_KEY” # Your API_KEY HOST = ‘api.heclouds.com’ PORT = 80 BUFSIZ = 1024 ADDR = (HOST, PORT) # =======Channel set================================================================== # Store the channels in a list and convert the list to a channel mask that # can be passed as a parameter to the MCC 118 functions. channels = [0, 1, 2, 3, 4, 5] channel_mask = chan_list_to_mask(channels) num_channels = len(channels) samples_per_channel = 0 options = OptionFlags.CONTINUOUS scan_rate = 10000.0 #采样速率 最大值为100k/信道数 read_request_size = 12000 #每通道此次采样的点数 c_time = 10 #连续采样的次数 timeout = 5.0 # =======上下限================================================================= volt=220 #根据需要设定标准电压 thread=0.2 #根据需要设定 upline=volt*(1+thread)*1.414*0.013558 #0.013558是根据电阻分压确定的 downline=volt*(1-thread)*1.414*0.013558 #0.013558是根据电阻分压确定的 # =======LED监测================================================================= base_time=datetime.datetime.now() #定义时间临时数组 led_stime=[base_time,base_time,base_time,base_time,base_time,base_time] #定义状态临时数组 led_status=[-1,-1,-1,-1,-1,-1] #===================================================================================== def led_detect(): global led_stime,led_status #变压器的A、B、C相 transno=[“Trans1A”,”Trans1B”,”Trans1C”,”Trans2A”,”Trans2B”,”Trans2C”] try: #判断每个LED的状态 while PORT > 0 : time.sleep(1) if GPIO.input(5) == GPIO.HIGH and led_status[0]<0 : led_stime[0]=datetime.datetime.now() led_status[0]=1 if GPIO.input(6) == GPIO.HIGH and led_status[1]<0 : led_stime[1]=datetime.datetime.now() led_status[1]=1 if GPIO.input(19) == GPIO.HIGH and led_status[2]<0 : led_stime[2]=datetime.datetime.now() led_status[2]=1 if GPIO.input(16) == GPIO.HIGH and led_status[3]<0 : led_stime[3]=datetime.datetime.now() led_status[3]=1 if GPIO.input(20) == GPIO.HIGH and led_status[4]<0 : led_stime[4]=datetime.datetime.now() led_status[4]=1 if GPIO.input(21) == GPIO.HIGH and led_status[5]<0 : led_stime[5]=datetime.datetime.now() led_status[5]=1 #相应引脚延时5分钟熄灭,并向平台发送数据清除告警 for i in range(6): now=datetime.datetime.now() if now > ( led_stime[i] + delta ) and led_status[i]>=0 : GPIO.output(led_list[i], GPIO.LOW) led_status[i]=-1 t5 = threading.Thread(target=senddata, args=(transno[i],”0″)) t5.start() except KeyboardInterrupt: # Clear the ‘^C’ from the display. print(CURSOR_BACK_2, ERASE_TO_END_OF_LINE, ‘

‘) print(‘Stopping’) # ========senddata to OneNet============================================================== def senddata(T_dev,alm): Content = “” Content += “{\”datastreams\”:[{\”id\”: \””+T_dev+”\”,\”datapoints\”: [{\”value\”: ” + alm + “}]}” Content += “]}\r

” value = len(Content) data = “” data += “POST /devices/” + device_id + “/datapoints HTTP/1.1\r

” data += “Host:api.heclouds.com\r

” data += “Connection: close\r

” data += “api-key:” + api_key + “\r

” data += “Content-Length:” + str(value) + “\r

” data += “\r

” data += Content tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(ADDR) tcpCliSock.send(data.encode()) #data1 = tcpCliSock.recv(BUFSIZ).decode() #print(data1) # =====writefile========================================================================== def writefile(arrayatt, fnat): print(“write file “, datetime.datetime.now()) np.savetxt(fnat, arrayatt.T, fmt=”%1.2f”, delimiter=” “) print(“\033[0;31m”,”finish write “, datetime.datetime.now(),”\033[0m”) #====Analyse and writefile and Alarm======================================================= def analyse(array,fnat): break_1_1 = -1 break_2_1 = -1 break_1_2 = -1 break_2_2 = -1 break_1_3 = -1 break_2_3 = -1 break_1 = -1 break_2 = -1 print(“analyse file “, datetime.datetime.now()) #等于read_request_size = 12000 lll = read_request_size file1 = “1-“+fnat file2 = “2-“+fnat a=np.array(array) b = np.empty([3, c_time*read_request_size], dtype=float) # 变压器1定义一个数组 c = np.empty([3, c_time*read_request_size], dtype=float) # 变压器2定义一个数组 #板子的数据记录格式是:CH0、CH1、CH2、CH3、CH4、CH5、CH0、CH1、CH2、CH3、CH4、CH5、CH0、CH1、CH2、CH3、CH4、CH5、CH0、CH1、CH2、CH3、CH4、CH5、CH0、CH1、CH2、CH3、CH4、CH5、 #通过下面拆分成6个CH每个CH一个list以便进行分CH判断 b[0] = np.concatenate((a[0, 0::6], a[1, 0::6], a[2, 0::6], a[3, 0::6], a[4, 0::6], a[5, 0::6], a[6, 0::6],a[7, 0::6], a[8, 0::6], a[9, 0::6])) #提取变压器1,A相数据 b[1] = np.concatenate((a[0, 1::6], a[1, 1::6], a[2, 1::6], a[3, 1::6], a[4, 1::6], a[5, 1::6], a[6, 1::6],a[7, 1::6], a[8, 1::6], a[9, 1::6])) #提取变压器1,B相数据 b[2] = np.concatenate((a[0, 2::6], a[1, 2::6], a[2, 2::6], a[3, 2::6], a[4, 2::6], a[5, 2::6], a[6, 2::6],a[7, 2::6], a[8, 2::6], a[9, 2::6])) #提取变压器1,C相数据 c[0] = np.concatenate((a[0, 3::6], a[1, 3::6], a[2, 3::6], a[3, 3::6], a[4, 3::6], a[5, 3::6], a[6, 3::6],a[7, 3::6], a[8, 3::6], a[9, 3::6])) #提取变压器2,A相数据 c[1] = np.concatenate((a[0, 4::6], a[1, 4::6], a[2, 4::6], a[3, 4::6], a[4, 4::6], a[5, 4::6], a[6, 4::6],a[7, 4::6], a[8, 4::6], a[9, 4::6])) #提取变压器2,B相数据 c[2] = np.concatenate((a[0, 5::6], a[1, 5::6], a[2, 5::6], a[3, 5::6], a[4, 5::6], a[5, 5::6], a[6, 5::6],a[7, 5::6], a[8, 5::6], a[9, 5::6])) #提取变压器2,C相数据 #=====判断越线================================================================================= # 200 是 scan_rate = 10000.0 除以 50(交流电的频率)得出 每个周期 采样200个点 # 600 是 120000/200=600 read_request_size*c_time本次总的采样点数,除以每周期200点,总共600个周期 # 如果 scan_rate = 5000.0 就是 100, alens 是 120000/100=1200 for i in range(600): #每个CH拆分成每个正弦波周期进行峰值判断 a1 = b[0][(i * 200):((i + 1) * 200 – 1)] b1 = b[1][(i * 200):((i + 1) * 200 – 1)] c1 = b[2][(i * 200):((i + 1) * 200 – 1)] a2 = c[0][(i * 200):((i + 1) * 200 – 1)] b2 = c[1][(i * 200):((i + 1) * 200 – 1)] c2 = c[2][(i * 200):((i + 1) * 200 – 1)] #每一项分别判断上下限并分别告警 if np.amax(a1) > upline or np.amax(a1) < downline : if break_1_1 <0: GPIO.output(5, GPIO.HIGH) #相应引脚置高电平,点亮LED break_1_1 = 1 t3 = threading.Thread(target=senddata, args=("Trans1A","100")) #调用上传进程 t3.start() if np.amax(b1) > upline or np.amax(b1) < downline : if break_1_2< 0: GPIO.output(6, GPIO.HIGH) #相应引脚置高电平,点亮LED break_1_2 = 1 t3 = threading.Thread(target=senddata, args=("Trans1B","100")) #调用上传进程 t3.start() if np.amax(c1) > upline or np.amax(c1) < downline: if break_1_3 < 0: GPIO.output(19, GPIO.HIGH) #相应引脚置高电平,点亮LED break_1_3 = 1 t3 = threading.Thread(target=senddata, args=("Trans1C","100")) #调用上传进程 t3.start() if np.amax(a2) > upline or np.amax(a2) < downline: if break_2_1 < 0: GPIO.output(16, GPIO.HIGH) #相应引脚置高电平,点亮LED break_2_1=1 t3 = threading.Thread(target=senddata, args=("Trans2A","100")) #调用上传进程 t3.start() if np.amax(b2) > upline or np.amax(b2) < downline: if break_2_2 < 0: GPIO.output(20, GPIO.HIGH) #相应引脚置高电平,点亮LED break_2_1 =1 t3 = threading.Thread(target=senddata, args=("Trans2B","100")) #调用上传进程 t3.start() if np.amax(c2) > upline or np.amax(c2) < downline: if break_2_3 < 0: GPIO.output(21, GPIO.HIGH) #相应引脚置高电平,点亮LED break_2_2 = 1 t3 = threading.Thread(target=senddata, args=("Trans2C","100")) #调用上传进程 t3.start() #每个变压器任何一项有告警就调用写文件进程写文件 if np.amax(a1) > upline or np.amax(a1) < downline or np.amax(b1) > upline or np.amax(b1) < downline or np.amax(c1) > upline or np.amax(c1) < downline: if break_1 < 0: t1 = threading.Thread(target=writefile, args=(b, file1,)) #调用写文件进程 t1.start() break_1 = 2 if np.amax(a2) > upline or np.amax(a2) < downline or np.amax(b2) > upline or np.amax(b2) < downline or np.amax(c2) > upline or np.amax(c2) < downline: if break_2 < 0: t1 = threading.Thread(target=writefile, args=(c, file2,)) #调用写文件进程 t1.start() break_2 = 2 print("\033[0;32m","analyse finish ", datetime.datetime.now(),"\033[0m") #font color # ============================================================================================ def main(): """ This function is executed automatically when the module is run directly. """ # ============================================================================================ try: # Select an MCC 118 HAT device to use. address = select_hat_device(HatIDs.MCC_118) hat = mcc118(address) ''' print(' Selected MCC 118 HAT device at address', address) actual_scan_rate = hat.a_in_scan_actual_rate(num_channels, scan_rate) print(' MCC 118 continuous scan example') print(' Functions demonstrated:') print(' mcc118.a_in_scan_start') print(' mcc118.a_in_scan_read') print(' mcc118.a_in_scan_stop') print(' Channels: ', end='') print(', '.join([str(chan) for chan in channels])) print(' Requested scan rate: ', scan_rate) print(' Actual scan rate: ', actual_scan_rate) print(' Options: ', enum_mask_to_string(OptionFlags, options)) # ============================================================================================ try: input(' Press ENTER to continue ...') except (NameError, SyntaxError): pass ''' # Configure and start the scan. # Since the continuous option is being used, the samples_per_channel # parameter is ignored if the value is less than the default internal # buffer size (10000 * num_channels in this case). If a larger internal # buffer size is desired, set the value of this parameter accordingly. print('Starting scan ... Press Ctrl-C to stop ') hat.a_in_scan_start(channel_mask, samples_per_channel, scan_rate,options) # ============================================================================================ try: while True: fna = str(datetime.datetime.now()) + ".txt" #连续采样10次 for i in range(c_time): read_result = hat.a_in_scan_read(read_request_size, timeout) # read channel Data arraydata[i]=read_result.data if read_result.hardware_overrun: print(' Hardware overrun ') break elif read_result.buffer_overrun: print(' Buffer overrun ') break hat.a_in_scan_stop() hat.a_in_scan_cleanup() hat.a_in_scan_start(channel_mask, samples_per_channel, scan_rate,options) #调用分析进程 arraydatat = arraydata t2 = threading.Thread(target=analyse, args=(arraydatat, fna, )) t2.start() except KeyboardInterrupt: # Clear the '^C' from the display. print(CURSOR_BACK_2, ERASE_TO_END_OF_LINE, ' ') print('Stopping') hat.a_in_scan_stop() hat.a_in_scan_cleanup() except (HatError, ValueError) as err: print(' ', err) if __name__ == '__main__': #表用进程实时监测告警状态,判断是否到时间消除告警 t4 = threading.Thread(target=led_detect) t4.start() main() 程序部署 参考这篇教程安装好 MCC DAQ HATs 的 SDK 和代码示例。 https://shumeipai.nxez.com/2018/10/18/get-started-with-the-evaluation-for-mcc-118.html 将上面的程序保存为 main.py 然后在程序所在目录运行下面的命令即可启动程序。 sudo python main.py 有任何问题欢迎访问趣小组交流: https://talk.quwj.com/topic/916 获取更多关于Measurement Computing的信息,请访问官网:china.mccdaq.com