一.平台介绍
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口
- 电源指示灯和状态指示灯
二.基于官方外设开发
2.1 wiringPi外设SDK安装
git clone https://github.com/orangepi-xunlong/wiringOP //下载源码
cd wiringOP //进入文件夹
sudo ./build clean //清除编译信息
sudo ./build //编译
通过windows浏览器打开https://github.com/orangepi-xunlong/wiringOP
下载压缩包
把压缩包通过xterm传到开发板
解压 unzip xxx.zip
cd xxx
sudo ./build
gpio readall
验证指令:gpio readall,结果如下方所示:
2.2基本IO口应用——蜂鸣器开发
-
代码:
#include <stdio.h> #include <wiringPi.h> #include <unistd.h> #define BEEP 0 //设置针脚0为蜂鸣器的控制引脚 int main (void) { wiringPiSetup () ;//初始化wiringPi库i pinMode (BEEP, OUTPUT) ;//设置IO口的输入输出,输出 while(1){ //sleep(1); usleep(100000); digitalWrite (BEEP, HIGH) ; //设置IO口输出低电平,蜂鸣器响 //sleep(1); usleep(100000); digitalWrite (BEEP, LOW) ; //设置IO口输出低电平,蜂鸣器响 } return 0; }
-
简单编译shell脚本来gcc编译函数
./build beep.c gcc $1 -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt shell脚本处理参数,可以通过$?来处理,这里的$1是要编译的文件
2.3超声波测距
-
测距原理基本说明
超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度, 计算出模块到前方障碍物的距离。
-
超声波模块HC-SR04
!
-
时序
-
时间函数
gettimeofday
是一个在 Unix 及类 Unix 系统(如 Linux)中广泛使用的系统调用,它的目的是获取当前系统的日期和时间,精确到微秒级别。这个函数允许程序获取自1970年1月1日以来的秒数(即Unix时间戳)以及额外的微秒部分。这对于需要高精度时间测量的应用特别有用,例如在性能测试、计时、实时系统或是任何需要精确时间管理的场景。#include <sys/time.h> int gettimeofday(struct timeval *tv, struct timezone *tz); //结构体: struct timeval { long tv_sec;/*秒*/ long tv_usec;/*微妙*/ }; struct timezone (在某些系统中可能已弃用或不推荐使用)结构包含了时区信息,但在大多数现代应用中,传递 NULL 给 tz 参数是常见的做法,因为时区处理现在更倾向于使用其他方法,如 localtime_r 或 gmtime_r 函数配合 struct tm。
-
测试代码:
//计算程序在当前环境中数数10万次耗时多少 #include <sys/time.h> #include <stdio.h> //int gettimeofday(struct timeval *tv,struct timezone *tz ) void mydelay() { int i,j; for(i=0;i<100;i++){ for(j=0;j<1000;j++); } } int main() { struct timeval startTime; struct timeval stopTime; gettimeofday(&startTime,NULL); mydelay(); gettimeofday(&stopTime,NULL); long diffTime = 1000000*(stopTime.tv_sec - startTime.tv_sec) + (stopTime.tv_usec - startTime.tv_usec); printf("全志H6的Linux数100000耗时%ldus\n",diffTime); return 0; }
-
超声波测距代码
#include <stdio.h> #include <sys/time.h> #include <wiringPi.h> #include <stdlib.h> #include <unistd.h> #define Trig 0 #define Echo 1 double getDistance() { double dis; struct timeval start; struct timeval stop; pinMode(Trig, OUTPUT); pinMode(Echo, INPUT); digitalWrite(Trig ,LOW); usleep(5); digitalWrite(Trig ,HIGH); usleep(10); digitalWrite(Trig ,LOW); /*above init CSB*/ while(!digitalRead(Echo)); gettimeofday(&start,NULL); while(digitalRead(Echo)); gettimeofday(&stop,NULL); long diffTime = 1000000*(stop.tv_sec-start.tv_sec)+(stop.tv_usec - start.tv_usec); printf("diffTime = %ld\n",diffTime); dis = (double)diffTime/1000000 * 34000 / 2; return dis; } int main() { double dis; if(wiringPiSetup() == -1){ fprintf(stderr,"%s","initWringPi error"); exit(-1); } while(1){ dis = getDistance(); printf("dis = %lf\n",dis); usleep(500000); } return 0; }
2.4SG90舵机开发
-
舵机基本介绍
如下图所示,最便宜的舵机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°;1ms的高电平,19ms的低电平,角度为45°;1.5ms的高电平,18.5ms的低电平,角度为90°;以此类推。
-
Linux定时器
实现定时器,通过itimerval结构体以及函数setitimer产生的信号,系统随之使用signal信号处理 函数来处理产生的定时信号。从而实现定时器。 先看itimerval的结构体:
struct itimerval { /* Value to put into `it_value' when the timer expires. */ struct timeval it_interval; /* Time to the next timer expiration. */ struct timeval it_value; }; //it_interval:计时器的初始值,一般基于这个初始值来加或者来减,看控制函数的参数配置 //it_value:程序跑到这之后,多久启动定时器 struct timeval { __time_t tv_sec; /* Seconds. */ __suseconds_t tv_usec; /* Microseconds. */ }; int setitimer (__itimer_which_t __which, const struct itimerval *__restrict __new, struct itimerval *__restrict __old) //setitimer:通过传递定时器类型(which)、指向 itimerval 结构体的指针,以及一个之前 itimerval 的地址(可选,用于获取先前的定时器设置)来调用 setitimer。
setitimer
支持三种类型的间隔定时器:- ITIMER_REAL:这是最常用的类型,它按照实际流逝的时间来计时,即使进程处于睡眠状态也会继续计时。当定时器到期时,会给进程发送
SIGALRM
信号。 - ITIMER_VIRTUAL:这种定时器测量的是进程在用户模式下消耗的CPU时间。当进程因为系统调用等原因进入内核模式时,该定时器会暂停计时。到期时发送
SIGVTALRM
信号。 - ITIMER_PROF:类似于 ITIMER_VIRTUAL,但是它不仅计算用户模式下的时间,也包括内核模式下消耗的时间(即总的CPU时间)。到期时发送
SIGPROF
信号。
- ITIMER_REAL:这是最常用的类型,它按照实际流逝的时间来计时,即使进程处于睡眠状态也会继续计时。当定时器到期时,会给进程发送
-
定时示例代码
/*该代码实现的功能是: 1s后开启定时器,然后每隔1s向终端打印hello。*/ #include <stdio.h> #include <sys/time.h> #include <stdlib.h> #include <signal.h> static int i; void signal_handler(int signum) { i++; if(i == 2000){ printf("hello\n"); i = 0; } } int main() { struct itimerval itv; //设定定时时间 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); return 0; }
这种方法需要注意的是,一个进程只能创建一个定时器。
-
SG90编程实现:键盘输入不同的值,让舵机转动,软件PWM实现
#include <stdio.h> #include <sys/time.h> Orangepi Zero2 全志H616开发学习文档 猿学社 #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; }