开发板:orange pi zero3
镜像:ubuntu-jammy
Q:解决异常重启造成Linux系统损坏的问题
A:将/etc/fstab中,根文件系统的载入方式改为只读,如下:
UUID=097c0934-864c-4961-9bf6-4ab53f3c5f5a / ext4 ro,defaults,noatime,commit=600,errors=remount-ro 0 1
tmpfs /tmp tmpfs defaults,nosuid 0 0
默认情况下,重启后会自动进入orangepi用户,因此,将要执行的程序放到~/.profile里,即可实现开机自动执行。这样异常重启后,不会对根文件系统造成任何伤害。
如果要改为rw模式,只需要mount -o rw,remount / 即可。
Q:等待网络完全联通,否则持续循环
rtn=5
while [ $rtn -ne 0 ]; do
ping -c 1 www.baidu.com > /dev/null 2>&1
rtn=$?
done
Q:GPIO手工操作
gpio readall

GPIO列:GPIO编号
WPI: 当使用wiringpi进行编程时,使用的编号
Mode: IN/OUT
V: value, 高低电平指示(1-高 0-低)
手工操作GPIO电平:

查看结果:注意26针角的value变为了1

清楚操作:
echo 74 > unexport,完成后,gpio74目录将消失
Q: 利用wirringpi操作GPIO
orangepi zero3自带wiringpi,不需要安装
cd /usr/src/wiringOP/examples/ 这里是各种例程
以下是示例代码(GPIO部分主要参考blink相关例程)
include <wiringPi.h> int main() { wiringPiSetup(); //初始化 pinMode (16, OUTPUT) ; //设置wpi编号16的针角为OUTPUT模式 digitalWrite (16, HIGH); //设置为高电平 digitalWrite (16, LOW); //设置为低电平 }
gitee/github的使用:
git config --global user.name 'peterhu318'
git config --global user.email 'peterhu318@126.com
clone iot项目:git clone https://gitee.com/peterhu318/iot.git
push iot项目:
cd ./iot
git add .
git commit -m "describe"
git push
串口通讯(serial)测试:
机器1:win11 + sscom5
机器2:orangepi zero3 + jammy + minicom 串口pin: 8,10
先打开urlt 5,重启,在/dev/下能看到 ttyAS5,说明配置没问题了
执行minicom会说找不到/dev/modem,只要链接一下设备即可。
进入minicom设置:minicom -s进入设置:9600N8,1 一定不要设置硬件流控,否则会出现无法向win11发送情况。
总结来说:双方的参数设置一定要匹配,否则会出现一发能发,一方不能发。有一方发送乱码等各种情况。
当以上测试没有问题后,就可以上程序了。
wiringpi在/usr/src下有一个example的示例,里面有两个: serialRead及serialTest。只要改一下里面的设备名及波特率,就可以用make进行编译并测试了。
关于某些i2c设备(流量传感器)无法识别的问题:
posifa pmf83020流量传感器,用香橙派无法识别,但换成悟空派就能识别。
发现香橙派用的是5.x的内核版本,将其换成6.x的内核版本,就能够正确识别了。
关于香橙派启动慢的问题
启动下面时,总是要等大约20s左右,造成启动缓慢
Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
Begin: Running /scripts/local-premount ... Scanning for Btrfs filesystems
解决办法:将内核版本从5.x换成6.x就没有这个问题了
DWIN屏(迪文屏)入门:
屏:DMG100600Y070两块。
第一个要注意的是:这个串口屏有个RS232与TTL的开关,在排线前方芯片组的前方。短接为TTL,不短接为RS232串口模式。
测试串口通讯情况:TTL那块屏串口通讯有问题。要么无回显,要么接收与发送一致,最终未定位出原因。最后重新购买了基于RS232的串口模块后,成功。
串口模块:在win11安装驱动,在硬件驱动处,将波特率改为115200;
然后用sscom串口软件,发送AA 00 CC 33 C3 3C握手信号,设备返回AA 00 4F 4B 5F 56 31 2E 36 00 00 00 00 00 CC 33 C3 3C,应该说明是成功了。
附常用指令:

修改注释:双击那些十六进制框,就可以更改注释。
framebuffer总是存在光标的解决办法:
在/etc/profile里,加入:tput civis,就不会在framebuffer上出现光标及黑块了
要重新打开光标,tput cnorm
负作用:连同其它终端一同禁止了。暂时没有好的办法!
关于hdmi闪烁的问题:
如果连接串口至笔记本,一切正常。但当拔掉串口,HDMI屏总是闪烁,且不能进入ubuntu系统。
解决办法:将板子的串口线与usb转串口的小板子的连接线拆掉,就正常了
如何开机自动执行脚本的问题(关键词:rc.local rc-local)
================================================
要想开机后,自动执行某个脚本,经常在centos下用的rc.local。但是ubuntu系统“暂停”了这个功能。下面是恢复方法
在/lib/systemd/system下面,有一个rc-local.service文件,打开这个文件并在末尾增加如下:
[Install]
WantedBy=multi-user.target
Alias=rc-local.service
接下来就是创建/etc/rc.local,该文件的第一行必须是#!/bin/bash,最后一行exit 0,且chmod +x rc.local
然后将需要执行的脚本或程序放到rc.local里。
一切完成后,systemctl reload-daemon ; systemctl start rc-local.service
如果rc.local格式不对(如第一行不是shebong),则服务启动会失败
实践反馈:orangepi好象不需要改任何东西,只要将脚本插入/etc/rc.local即可。ubuntu按照以上做法是可以的。
增加新的分区:
===================================================================
查看新增加的分区的UUID:
dumpe2fs -h /dev/mmclk0p2:查看第二分区情况,里面会显示出uuid。如果用dev设备号,有时会出现设备号变化的问题。
UUID=5aecfb3c-5169-4c34-ba4d-9643daa69085 /data ext4 defaults,noatime,commit=0 0 0
静态编译问题:
===========================================================
在makefile文件的lib变量里,增加-static,则可进行静态编译。但可能会报很多关于libsqlite3的错误,这实际是由于math库造成。需要把 -lm参数做为最后一个库文件,即可解决。在实际应用中,依然会有两个warning,但不影响使用。
DS3231 RTC模块:
调试这个模块前,选关闭chrony服务,避免造成影响。
要在orangepi下使用,可以按照如下方法:
首先看看i2cdetect -y 3,是否能看到68的DS3231模块。
如果能看到,那么执行下面的语句:
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-3/new_device
再执行i2cdetect,此时发现标识变成了UU(代表Linux驱动接管了)。
此时,再ls /dev/rtc*,会发现多了一个rtc1,这个就是ds3231。我们会发现/dev/rtc链接到了rtc0,那是一个orangepi自带的、无法掉电保存的一个rtc。
我们执行timedatectl,会发现rtc时间是指的/dev/rtc的时间。
我们手工设置一个时间:date -s "2024-3-3"
要想将当前时间保存到ds3231,用hwclock -w -f /dev/rtc1即可。 -w代表将系统时间写入rtc,-f指明rtc设备。如果不加-f,那么就写到默认的/dev/rtc里面了,也就是rtc0里了。
此时分别查看rtc0和rtc1:
hwclock -f /dev/rtc0
hwclock -f /dev/rtc1
我们会发现,这两个的时间是不一致的。
先用timedatectl看一下RTC时间
如果要想用ds3231的rtc1做为默认的rtc,只要简单的将/dev/rtc链接到rtc1即可。ln -f -s /dev/rtc1 /dev/rtc
再用timedatectl看一下RTC时间,应该发现与之前是不一样的。
要想设备启动时,自动读取ds3231的时间,可以将以上命令放置到/etc/rc.local里,示例 如下:
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-3/new_device
sleep 3 #必须进行延迟,否则下面的命令可能不能正常执行
hwclock -s -f /dev/rtc1 #将rtc时间读入成系统时间
实际工作中,是将这些语句写成/etc/init.d/rtc_ds1307脚本里,然后ln到/etc/rc3.d/S01rtc_ds1307里来启动。
#可选:将ds3231做为各种时间命令的默认rtc
ln -f -s /dev/rtc1 /dev/rtc
踩坑:chat-gpt曾建议修改设备树的方法,最终没能成功。不过,这应该是一个最终极的、完美的解决办法,留待以后处理吧。2024.12.14
EMQX windows安装:
=============================
今天(25.8.19)emqx的公用服务出现了问题,自己搭一套还是必要的。在官网下载5.3.2版本里的windows版(高版本已经没有WIN版了),解压。
https://www.emqx.com/zh/downloads/broker/v5.3.2
bin/emqx.cmd install安装
bin/emqx.cmd console 启动服务
此时MQTT服务就可以用了。无用户认证,直接使用
要增加用户认证:
http://127.0.0.1:18083 admin/public
访问控制--客户端认证,增加一个基于username的认证项即可。
EMQX WEB CLIENT:网页版mqtt client
================================
https://mqttx.app/web-client
利用陶晶驰的设计工具(UART HMI软件,与orangepi直接通讯):
===================================================
将orangepi的串口5与windows的com3相连接。
然后打开HMI软件,并导入设计好的HMI文件,选择调试。界面出现后,选左下角的“用户MCU输入”,并设置相应的COM口及波特率(我的环境是com3+115200),此时在orangepi上运行iot,就能在windows上显示出数据
可以点右侧窗口顶部:H S ,点S,能看到ASCII码,比较直观。
DHT11读取程序:
===============================================================
这是根据网友的程序改的,来自树莓派实验论坛,修改解决了第一次启动总是读取不成功的问题。这个程序的效果不错,读取成功率明显高于之前下载的一个程序。但我改动后成功率却有所下降。
编程要点:尽量精简代码,否则过多的代码会造成时间损耗(一个printf就占用了14us左右),造成时序延迟。
在程序开始时习惯性的将GPIO设置为OUPUT,并拉高电平,结果造成不稳定,去掉反而好了。
MCU在拉电平后,通过delay保持一段时间,但是当进入INPUT后,尽量不依靠时间,而是对高低电平的时序判断进行,否则会造成程序的读取成功率不高。
for i循环中的高电平loop,按照理论应放到代码块的后面,但这样却大概率的造成死循环。原因不得而知。
本程序存在死循环风险,引用时建议通过线程引用,超时不退出时就强行杀掉线程。
基于时序的编程是极痛苦的!!!一定一定要详细的阅读文档,精确掌握通讯时序图。尽量避免这种编程方式。从编程难度,程序稳定性方面来看,远远不如i2c方式。到此为止吧,不折腾了!
#include <stdio.h> #include <stdint.h> #include <wiringPi.h> #define TIMEOUT 1000 #define PIN 5 int data[5] = { 0, 0, 0, 0, 0 }; int st = 0; //是否超时:1==超时 int dht11_read(void) { int i; pinMode(PIN, OUTPUT); //主机发送起始信号(低18;高40) digitalWrite(PIN, LOW); delay(18+2); digitalWrite(PIN, HIGH); pinMode(PIN, INPUT); pullUpDnControl(PIN, PUD_UP); delayMicroseconds(27); while ( digitalRead(PIN) == LOW ) ; while ( digitalRead(PIN) == HIGH ) ; //已经进低电平,开始读取数据 int reg_no = 0; for (int reg_no =0; reg_no < 5; reg_no++) { data[reg_no] = 0; for (i = 0; i < 8; i++) { while ( digitalRead(PIN) == HIGH ) ; while ( digitalRead(PIN) == LOW ) ; //转入高电平,在28+2时间处,读 data[reg_no] *= 2; delayMicroseconds(32); if (digitalRead(PIN) == HIGH) data[reg_no]++; } } //恢复(设为output,并拉高电平 pinMode(PIN, OUTPUT); digitalWrite(PIN, HIGH); return 0; } int main(void) { int i; if (i = wiringPiSetup() ) { printf("WiringPi init error\n"); return 0; } while (1) { dht11_read(); { printf("H:%d.%d,T:%d.%d\n",data[0],data[1],data[2],data[3]); } if ( (data[0] + data[1] + data[2] + data[3] )!= data[4] ) printf("CRC ERROR!!!\n"); delay(3000); } return 0; }
/*网友原程序,修改解决了第一次启动不能成功读取的问题*/ #include <wiringPi.h> #include <stdio.h> #include <stdlib.h> typedef unsigned char uint8; typedef unsigned int uint16; typedef unsigned long uint32; #define HIGH_TIME 32 int pinNumber = 5; uint32 databuf; uint8 readSensorData(void) { uint8 crc; uint8 i; pinMode(pinNumber, OUTPUT); // set mode to output digitalWrite(pinNumber, LOW); // output a high level delay(20); digitalWrite(pinNumber, HIGH); // output a low level pinMode(pinNumber, INPUT); // set mode to input pullUpDnControl(pinNumber, PUD_UP); delayMicroseconds(27); if (digitalRead(pinNumber) == 0) //SENSOR ANS { while (digitalRead(pinNumber) == LOW) ; //wait to high for (i = 0; i < 32; i++) { while (digitalRead(pinNumber)) ; //data clock start while (!digitalRead(pinNumber)) ; //data start delayMicroseconds(HIGH_TIME); databuf *= 2; if (digitalRead(pinNumber) == 1) //1 { databuf++; } } for (i = 0; i < 8; i++) { while (digitalRead(pinNumber)) ; //data clock start while (!digitalRead(pinNumber)) ; //data start delayMicroseconds(HIGH_TIME); crc *= 2; if (digitalRead(pinNumber) == 1) //1 { crc++; } } return 1; } else { return 0; } } int main(void) { printf("PIN:%d\n", pinNumber); if (-1 == wiringPiSetup()) { printf("Setup wiringPi failed!"); return 1; } printf("Starting...\n"); while (1) { if (readSensorData()) { printf("Sensor data read ok!\n"); printf("RH:%d.%d\n",(int) ((databuf >> 24) & 0xff), (int) ((databuf >> 16) & 0xff)); printf("TMP:%d.%d\n",(int) (databuf >> 8) & 0xff, (int)databuf & 0xff); databuf = 0; } else { printf("Sensor dosent ans!!!!!!!!!!!!!!!\n"); databuf = 0; } delay(3000); } return 0; }

浙公网安备 33010602011771号