全志H616开发学习文档
Orangepi Zero2 全志H616开发学习文档
一. 简介
-
- 为什么学
学习目标依然是Linux系统,平台是ARM架构
蜂巢快递柜,配送机器人,这些应用场景用C51,STM32单片机无法实现
第三方介入库的局限性,比如刷脸支付和公交车收费设备需要集成支付宝SDK,提供的libalipay.so是Linux的库,设备必须跑Linux系统
图像识别,音频,视频等领域的技术支撑也无法脱离Linux系统
人工智能型设备通常需要更好的系统和更高的算力,所以Linux也是必不可少
能跑Linux的一般为 X86,ARM,MIPS,PowerPC等架构,而ARM市场占有率最大
综上所述就是一句话:嵌入式软件工程师如果技术栈不存在Linux-ARM的开发经验,那么面向的工作岗位就会带很多局限性,天花板有容易来的过早,在技术积累阶段对于这个知识的学习是必不可少的,但是这个方向水深,需要客观且科学的选择适合的角度学习。
-
- 学什么
这个领域的程序员一般分三个方向:
应用开发,通过跟产品业务相关,比如智能家居中控板,可以是C++QT, 可以是C GTK, 也可以是
Android页面,也可以是基于串口屏的UI交互,
后台数据交互和系统交互都是基于Linux系统的,初级工程师以这个方向入行居多,也容易上手,招聘岗位也很多
系统开发,主要任务是为硬件工程师设计的产品板操作系统,比如uboot,Linux内核,文件系统等,一般为中高级嵌入式工程师,新手如果以这个方向入行,压力相对更大,一般原厂公司会招聘,岗位相对少
算法工程师,此类算法跟数学模型挂钩,比如人脸识别的图像不调库处理,语音识别算法如讯飞语音的工程师,一般博士一大堆,硕士满天飞的现状
根据现有就业案例,大专本科生以应用开发入行为主,在工作一两年可能会根据公司安排走系统开发,也可能一直做应用,薪资待遇并不完全由技术方向决定,还是看个人发展和公司的关系,当然还有城市,学校等因素。
硕士可根据面试结果选择应用,系统,算法都行
-
- 平台介绍
学习平台至于用树莓派,海思,全志都无所谓,初级工程师掌握的是Linux-ARM的软硬件架构开发,主要是Linux系统的学习,只有入职后的中高级工程师才会考虑算法或者协议对底层硬件的差异化,第一版本这部分的内容以树莓派讲解,就业学员入职海康威视,OPPO,全志,移远等公司可以完美过度,所以板材的选择根据教程就行,学的是Linux系统
OrangePi开发板不仅仅是一款消费品,同时也是给任何想用技术来进行创作创新的人设计的。它是一款
简单、有趣、实用的工具,你可以用它去打造你身边的世界。
|
特性
CPU 全志H616四核64位1.5GHz高性能Cortex-A53处理器
GPU MaliG31MP2 SupportsOpenGLES1.0/2.0/3.2、OpenCL2.0
运行内存 1GBDDR3(与GPU共享)
存储 TF卡插槽_课程配套硬件16G,测试128G可支持、2MBSPIFlash WIFI+蓝牙 AW859A芯片、支持IEEE802.11a/b/g/n/ac、BT5.0
视频输出 MicroHDMI20a
电源 USBTypeC接口输入
外设 带有I2Cx1、SPIx1、UARTx1以及多个GPIO口电源指示灯和状态指示灯
配套操作系统支持
|
二. 刷机和系统启动
就像买了电脑,出厂带有windows操作系统,才算是正在的电脑,开发板需要烧写对应的系统固件,才能正常发挥作用
工具
Orangepi Zero2 全志H616开发板
PC机
TF卡及读卡器操作系统镜像
SDFormatter TF卡的格式化工具
Win32Diskimager 刷机工具
USB转TTL,用于系统烧写后的串口登录开发板
-
- 工具安装
SDFormatter傻瓜式安装,Win32Diskimager傻瓜式安装
-
- 刷机
课程使用的镜像是 Orangepizero2_2.2.0_ubuntu_bionic_desktop_linux4.9.170.img
-
- 登录系统
供电
TypeC口,需要插到5V/2A或者5V/3A的电源适配头,特别是开发板有接多个外设模块的时候平常USB供电用电脑可以,前提是不接多外设模块
后面做小车等项目,用电池供电可以参考如下供电方式
|
登录
使用USB转TTL模块,使用MobaXterm免费好用,类似的工具还有Putty-相对太简陋,SecurityCRT老牌工具-需要付费或者破解
USB转TTL模块GND、TX和RX引脚需要通过杜邦线连接到开发板的调试串口上 a.USB转TTL模块的GND接到开发板的GND上
b.USB转TTL模块的RX接到开发板的TX上 c.USB转TTL模块的TX接到开发板的RX上
|
电脑安装ch340驱动,学到这个阶段,你们电脑应该都装好了,没装的话自己去网盘资料下载安装使用mobaXterm登陆,默认登陆密码:
用户:orangepi 密码:orangepi用户:root 密码:orangepi
板载LED灯测试说明
|
-
- 修改登陆密码
默认密码是orangepi容易写错,为了课程方便,我改成密码为1
|
-
- 网络配置
命令扫描周围的WIFI热点 nmcli dev wifi
命令接入网络 nmcli dev wifi connect TP-LINK_3E30 password 18650711783
|
查看IP地址 ip addr show wlan0 ifconfig也可以
-
- SSH登陆开发板
这是企业开发调试必用方式,比串口来说不用接线,前提是接入网络并获得板子IP地址,且系统做了
SSH的服务器,本镜像自带SSH服务器,所以通过mobaXterm登陆就行
|
三. 基于官方外设开发
-
- wiringPi外设SDK安装
|
验证指令: gpio readall
如下方所示,外设库就完成安装了
|
-
- 蜂鸣器开发
- 蜂鸣器响的原理
- 蜂鸣器开发
基本IO口的应用
|
-
-
- 蜂鸣器配合时间函数开发
-
|
小插曲:
vim的设置,修改/etc/vim/vimrc文件,需要用超级用户权限
|
shell脚本小插曲
./build beep.c
$0 $1
shell脚本处理参数,可以通过$?来处理,这里的$1是要编译的文件
|
-
- 超声波测距
- 测距原理基本说明
- 超声波测距
超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度,计算出模块到前方障碍物的距离
型号:HC-SR04
接线参考:模块除了两个电源引脚外,还有TRIG,ECHO引脚
|
怎么让它发波
Trig,给Trig端口至少10us的高电平怎么知道开始发了
Echo信号,由低电平跳转到高电平,表示开始发送波
怎么知道接收了返回波 Echo,由高电平跳转回低电平,表示波回来了怎么算时间
Echo引脚维持高电平的时间!
波发出去的那一下,开始启动定时器
波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
怎么算距离
距离=速度(340m/s)*时间/2
时序
-
-
- 时间函数
-
函数原型
#include<sys/time.h>
int gettimeofday(struct timeval *tv,struct timezone *tz )
gettimeofday()会把目前的时间用tv 结构体返回,当地时区的信息则放到tz所指的结构中
|
测试代码
|
-
-
-
代码实现和验证
-
-
|
-
- SG90舵机开发
- 舵机基本介绍
- SG90舵机开发
如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号控制用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等
常见的有0-90°、0-180°、0-360°
|
怎么控制转角
向黄色信号线“灌入”PWM信号。
PWM波的频率不能太高,50hz,即周期=1/频率=1/50=0.02s,20ms左右数据:不同的PWM波形对应不同的旋转角度,以20ms为周期,50hz为频率的PWM波
高电平持续时间 | 低电平持续时间 | 波形图 | 角度 |
0.5ms | 19.5ms | | 0 |
1.0ms | 19ms | | 45 |
1.5ms | 18.5ms | | 90 |
2.0ms | 18ms | 如上图推理 | 135 |
2.5ms | 17.5ms | 如上图推理 | 180 |
时器需要定时20ms,关心的单位0.5ms, 20ms = 0.5ms * 40:
-
-
- Linux定时器
-
分析:实现定时器,通过itimerval结构体以及函数setitimer产生的信号,系统随之使用signal信号处理函数来处理产生的定时信号。从而实现定时器。
先看itimerval的结构体
|
setitimer()将value指向的结构体设为计时器的当前值,如果ovalue不是NULL,将返回计时器原有值。 which:三种类型
ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM。 ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM。 ITIMER_PROF //数值为2,进程和系统执行时都递减计时器的值,发送的信号是SIGPROF。
很明显,这边需要捕获对应的信号进行逻辑相关处理 signal(SIGALRM,signal_handler);
返回说明:
成功执行时,返回0。失败返回-1
实现代码:
|
这种方法需要注意的是,一个进程只能创建一个定时器
SG90编程实现:键盘输入不同的值,让舵机转动,软件PWM实现
#include <stdio.h> #include <sys/time.h> #include <stdlib.h> #include <signal.h> #include <wiringPi.h>
#define SG90Pin 5
int jd;
static int i = 0;
void signal_handler(int signum)
{
if(i <= jd){
digitalWrite(SG90Pin, HIGH);
}else{
digitalWrite(SG90Pin, LOW);
}
if(i == 40){
i = 0;
} i++;
}
int main()
{
struct itimerval itv; jd = 0; wiringPiSetup();
pinMode(SG90Pin, OUTPUT);
//设定定时时间 itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 500;
//设定开始生效,启动定时器的时间 itv.it_value.tv_sec = 1;
itv.it_value.tv_usec = 0;
//设定定时方式
if( -1 == setitimer(ITIMER_REAL, &itv, NULL)){ perror("error");
exit(-1);
}
//信号处理 signal(SIGALRM,signal_handler);
while(1){
printf("input jd: 1-0 2-45 3-90 4-135 \n"); scanf("%d",&jd);
}
return 0;
}
-
- OLED屏应用-IIC协议
- OLED屏幕
- OLED屏应用-IIC协议
|
-
-
- Orangepi的IIC接口
-
由 26pin 的原理图可知, Orange Pi Zero 2 可用的 i2c 为 i2c3
|
启动 linux 系统后, 先确认下/dev 下存在 i2c-3 的设备节点
从命令运行结果能观察到系统支持I2C-3和I2C-5的驱动,而H616的外设我们看到只有一个IIC接口,用的是IIC-3
Linux一切皆文件,每个硬件设备“对应”一个文件,由驱动程序提供映射
|
开始测试 i2c, 首先安装 i2c-tools sudo apt-get install i2c-tools
3.4.2 Oled功能代码阅读
看视频,跟着视频节奏走,视频结束后,可以自己跳转跟随代码。工作中很大部分时间都是独立完成这种类容
sourceInsight,SN码:SI3US-361500-17409 支持正版,如果这个码不能用,自行百度
3.4.3 实战OLED屏幕开发
|
-
- Linux串口开发
串口简介,回顾上官一号单片机教程
-
-
- 基于wiringPi的串口开发
-
|
if (wiringPiSetup () { | == -1) | |
fprintf (stdout, return 1 ; } | "Unable to start wiringPi: %s\n", strerror (errno)) ; | |
while(1){sleep(10);} | ||
} | printf ("\n") ; return 0 ; |
-
-
-
Linux原生串口开发
-
-
uartTool.c
|
#include <sys/types.h> #include <sys/stat.h>
#include "wiringSerial.h"
int myserialOpen (const char *device, const int baud)
{
struct termios options ; speed_t myBaud ;
int status, fd ;
switch (baud){
case 9600: myBaud = B9600 ; break ; case 115200: myBaud = B115200 ; break ;
}
if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) return -1 ;
fcntl (fd, F_SETFL, O_RDWR) ;
// Get and modify current options:
tcgetattr (fd, &options) ;
cfmakeraw (&options) ; cfsetispeed (&options, myBaud) ; cfsetospeed (&options, myBaud) ;
options.c_cflag |= (CLOCAL | CREAD) ; options.c_cflag &= ~PARENB ; options.c_cflag &= ~CSTOPB ; options.c_cflag &= ~CSIZE ; options.c_cflag |= CS8 ;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; options.c_oflag &= ~OPOST ;
options.c_cc [VMIN] = 0 ;
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)
tcsetattr (fd, TCSANOW, &options) ;
ioctl (fd, TIOCMGET, &status);
status |= TIOCM_DTR ; status |= TIOCM_RTS ;
ioctl (fd, TIOCMSET, &status);
usleep (10000) ; // 10mS
return fd ;
}
void serialSendstring (const int fd, const char *s)
{
int ret;
uartTool.h
|
uartTest.c
|
-
- 语言控制刷抖音小项目
- 装逼小项目:语言控制刷抖音
- 语言控制刷抖音小项目
|
-
-
- 语音模块配置
-
进入语音模块官网 http://www.smartpi.cn/#/,配置词条和识别后的串口输出指令,具体根据视频教程
-
- 语音模块配置
-
-
-
-
-
记录下相关指令以及上图的识别词条,方便固件烧写后的调试
-
-
-
|
-
-
-
- 固件烧写
-
-
|
-
-
-
- 固件先和电脑调试助手配合,验证数据
-
编程实现语音和开发板通信
-
-
5. 将语音模块插入开发板并编程实现基础逻辑代码,添加串口读取一个字符的接口
myserialGetchar();
|
-
-
- 手机接入Linux热拔插相关
-
-
-
- 用shell指令来操作手机屏幕,模拟手动滑屏幕
-
|
-
-
- 最后程序
-
|
-
- Linux的热拔插UDEV机制
简介
udev是一个设备管理工具,udev以守护进程的形式运行,通过侦听内核发出来的uevent来管
理/dev目录下的设备文件。udev在用户空间运行,而不在内核空间 运行。它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录
下。使用udev后,在/dev目录下就只包含系统中真正存在的设备。
-
-
- 守护进程
-
Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器 mysqld等。守护进程的名称通常以d结尾
UDEV守护进程,它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。
基本特点
生存周期长[非必须],一般操作系统启动的时候就启动,关闭的时候关闭。
守护进程和终端无关联,也就是他们没有控制终端,所以当控制终端退出,也不会导致守护进程退出
守护进程是在后台运行,不会占着终端,终端可以执行其他命令
一个守护进程的父进程是init进程,因为它真正的父进程在fork出子进程后就先于子进程exit退出了,所以它是一个由init继承的孤儿进程
linux操作系统本身是有很多的守护进程在默默执行,维持着系统的日常活动。大概30-50个
|
ppid = 0:内核进程,跟随系统启动而启动,生命周期贯穿整个系统。 cmd列名带[]这种,叫内核守护进程
老祖init:也是系统守护进程,它负责启动各运行层次特定的系统服务;所以很多进程的PPID是init,也负责收养孤儿进程。
cmd列中名字不带[]的普通守护进程(用户集守护进程)
-
-
- 守护进程开发方式
-
直接借助damon()函数完成。
(182条消息) Linux 守护进程编程鸟的博客-CSDN博客linux 守护进程
(182条消息) Linux:守护进程何小柒(qi)~的博客-CSDN博客linux守护进程
|
|
|
-
-
-
守护进程应用
-
-
需求:要求语音刷手机的程序一直保持运行,防止应用程序崩溃意外编写判断某进程是否在运行的程序:
|
守护进程不让控制程序退出
|
开机启动:
|
-
-
- 守护进程和后台进程的区别
- 守护进程和终端不挂钩;后台进程能往终端上输出东西(和终端挂钩);
- 守护进程关闭终端时不受影响,守护进程不会随着终端的退出而退出;
- UDEV的配置文件
- 守护进程和后台进程的区别
-
参考:[(182条消息) Linux 基础] -- udev 和 rules 使用规则BestW2Y的博客-CSDN博客linux rules (182条消息) Ubuntu udev rules_zhang6318的博客-CSDN博客
规则文件是 udev 里最重要的部分,默认是存放在 /etc/udev/rule.d/ 下。所有的规则文件必须以
".rules" 为后缀名。
下面是一个简单的规则:
|
KERNEL 是匹配键,NAME 和 MODE 是赋值键。这条规则的意思是:如果有一个设备的内核名称为 sda,则该条件生效,执行后面的赋值:在 /dev 下产生一个名为my_root_disk 的设备文件,并把设备文件的权限设为 0660。
udevadm info --attribute-walk --name=/dev/设备名字
|
udev 规则的匹配键
|
|
-
-
- 自动挂载U盘
-
|
-
- 基于Linux的智能垃圾桶项目型作业布置
功能需求:
靠近时,垃圾桶开启2秒,2秒后关闭垃圾桶开启带滴滴声
垃圾桶开启超过10秒,滴滴声警报垃圾桶长期开启不能让舵机有顿挫感语音控制垃圾桶开关盖
拓展需求:回顾二阶段的Socket编程,实现Sockect客户端发送指令远程打开/关闭垃圾桶,并显示垃圾桶状态
拓展需求:统计当天垃圾桶开关盖次数及开关盖指令来源并记录在文件中 拓展需求:统计当天垃圾桶开关盖次数及开关盖指令来源并记录在数据库中
四. 嵌入式数据库
-
- SQLite简介
轻量化,易用的嵌入式数据库,用于设备端的数据管理,可以理解成单点的数据库。传统服务器型数据库用于管理多端设备,更加复杂
SQLite是一个无服务器的数据库,是自包含的。这也称为嵌入式数据库,这意味着数据库引擎作为应用程序的一部分运行。
MySQL需要运行服务器,MySQL将需要客户端和服务器架构通过网络进行交互。
SQLite的优点 | SQLite的缺点 | MySQL的优点 | MySQL的缺点 |
基于文件,易于设置和使用 适合基础开发和测试轻松携带 使用标准SQL语法进行微小更改 使用方便 | 缺乏用户管理和安全功能 不容易扩展 不适合大数据库无法定制 | 使用方便 提供了许多与数据库相关的功能 良好的安全功能 易于扩展,适用于大型数据库 提供良好的速度和性能提供良好的用户管理和多种访问控制 | 需要一些技术专业知识来设置 与传统SQL相比,语法略有不同 |
基于嵌入式的数据库主要有:SQLite,Firebird,Berkeley DB,eXtremeDB
Firebird 是关系型数据库,功能强大,支持存储过程,SQL兼容等
SQLite 关系型数据库,体积小,支持ACID事务
Berkeley DB 并没有数据库服务器的概念,他的程序直接链接到应用程序中
eXtremeDB 是内存数据库,运行效率高
-
- SQLite数据库安装
下载地址
安装方式一:
sudo apt-get -y install sqlite
安装方式二:
|
|
|
如上图,安装成功过,运行sqlite3 进入SQL命令操作流程
-
- SQLite的命令用法
创建一个数据库
方式一:
|
方式二:
|
创建一张表格
|
插入一条记录
|
查看数据库的记录
|
删除一条记录
|
更改一条记录
|
删除一张表
|
增加一列
|
-
- SQLite的编程操作
- 打开/创建数据库的C接口
- SQLite的编程操作
下面的 C 代码段显示了如何连接到一个现有的数据库。如果数据库不存在,那么它就会被创建,最后将返回一个数据库对象。
|
|
|
-
-
- 创建表的C接口
-
下面的 C 代码段将用于在先前创建的数据库中创建一个表:先看这个API
sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void *data, char **errmsg)
|
|
|
|
-
-
- 插入数据的C接口
-
下面的 C 代码段显示了如何在上面创建的 COMPANY 表中创建记录:
|
-
-
- SELECT 操作
-
在我们开始讲解获取记录的实例之前,让我们先了解下回调函数的一些细节,这将在我们的实例使用到。这个回调提供了一个从 SELECT 语句获得结果的方式。它声明如下:
|
如果上面的回调在 sqlite_exec() 程序中作为第三个参数,那么 SQLite 将为 SQL 参数内执行的每个
SELECT 语句中处理的每个记录调用这个回调函数。
下面的 C 代码段显示了如何从前面创建的 COMPANY 表中获取并显示记录:
|
-
-
- UPDATE操作
-
下面的 C 代码段显示了如何使用 UPDATE 语句来更新任何记录,然后从 COMPANY 表中获取并显示更新的记录:
|
-
-
- DELETE操作
-
下面的 C 代码段显示了如何使用 DELETE 语句删除任何记录,然后从 COMPANY 表中获取并显示剩余的记录:
|