香橙派和树莓派基于官方外设开发
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
下载压缩包
把压缩包通过mobaxterm传到开发板
解压 unzip xxx.zip
cd xxx
sudo ./build
gpio readall
验证指令:gpio readall
如下图所示,外设库就完成安装了
2.蜂鸣器开发
2.1蜂鸣器响的原理
置低电平响
置高电平不响
2.2蜂鸣器配合时间函数开发
2.2.1 demo1
#include<stdio.h>
#include<wiringPi.h>
#include<unistd.h>
#define BEEP 2 // 设置2引脚为蜂鸣器控制引脚
int main(void)
{
wiringPiSetup(); // 初始化wriping库
pinMode(BEEP, OUTPUT); // 设置蜂鸣器为输出引脚
while(1)
{
digitalWrite(BEEP, LOW); // 输出低电平
sleep(5);
break;
}
digitalWrite(BEEP,HIGH);
return 0;
}
2.2.2 demo2
#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;
}
如果你在vim的环境编辑,方便缩进可以修改一下缩进
vim的设置,修改/etc/vim/vimrc文件,需要用超级用户权限
sudo vim /etc/vim/vimrc
set tabstop=4 设置tab键缩进4个空格
set shiftwidth=4 设置批量对齐时候的tab键空格数为4
不过我在这里更推荐vscode编写,http://t.csdn.cn/GdZte,远程开发
shell脚本小插曲
./build beep.c
$0 $1
shell脚本处理参数,可以通过$?来处理,这里的$1是要编译的文件
简易编译的shell脚本:
gcc $1 -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt
3.超声波测距
1. 怎么让它发波
Trig,给Trig端口至少10us的高电平
2. 怎么知道开始发了
Echo信号,由低电平跳转到高电平,表示开始发送波
3. 怎么知道接收了返回波
Echo,由高电平跳转回低电平,表示波回来了
4.怎么算时间
Echo引脚维持高电平的时间!
5. 波发出去的那一下,开始启动定时器
波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
6. 怎么算距离
距离=速度(340m/s)*时间/2
时序
3.2时间函数
函数原型:
#include<sys/time.h>
int gettimeofday(struct timeval *tv,struct timezone *tz )
gettimeofday()会把目前的时间用tv 结构体返回,当地时区的信息则放到tz所指的结构中
struct timeval
{
long tv_sec;/*秒*/
long tv_usec;/*微妙*/
};
测试代码
//计算程序在当前环境中数数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;
}
3.3代码实现和验证
#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;
}
4.SG90舵机开发
4.1舵机基本介绍
如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号控制用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等常见的有0-90°、0-180°、0-360°
4.2Linux定时器
分析:实现定时器,通过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()将value指向的结构体设为计时器的当前值,如果ovalue不是NULL,将返回计时器原有值。
which:三种类型
ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM。
ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM。
ITIMER_PROF //数值为2,进程和系统执行时都递减计时器的值,发送的信号是SIGPROF。
很明显,这边需要捕获对应的信号进行逻辑相关处理 signal(SIGALRM,signal_handler);
返回说明:
成功执行时,返回0。失败返回-1
实现代码
/*该代码实现的功能是: 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;
//设定定时方式
if( -1 == setitimer(ITIMER_REAL, &itv, NULL)){
perror("error");
exit(-1);
}
//信号处理
signal(SIGALRM,signal_handler);
while(1);
return 0;
}
这种方法需要注意的是,一个进程只能创建一个定时器
4.3 .SG90编程实现:键盘输入不同的值,让舵机转动,软件PWM实现
#include<stdio.h>
#include<sys/time.h>
#include<stdlib.h>
#include<signal.h>
#include<wiringPi.h>
#define SG90pin 8
int jd;
void signal_handler(int signum)
{
static int i=0;
if(i<=jd)
{
digitalWrite(SG90pin,HIGH);
}
else
{
digitalWrite(SG90pin,LOW);
}
if(i==40)
{
i=0;
}
i++;
}
int main()
{
struct itimerval itv;
jd=0;
if(wiringPiSetup()==-1)
{
perror("error");
exit(-1);
}
pinMode(SG90pin,OUTPUT);
//1.设定定时时间
itv.it_interval.tv_sec=0;
itv.it_interval.tv_usec=500;
//2.设定开始生效,启动定时器的时间
itv.it_value.tv_sec=1;
itv.it_value.tv_usec=0;
//3.设定定时方式
if(setitimer(ITIMER_REAL,&itv,NULL)==-1)
{
perror("error");
exit(-1);
}
//4.信号处理
signal(SIGALRM,signal_handler);
while(1)
{
printf("input jd:1 -0 2-45 3-90 4-135 5-180\n");
scanf("%d",&jd);
}
return 0;
}
5.OLED模块
5.1OLED屏幕模块
5.2IIC协议
5.2.1.概述:
IIC全称Inter-Integrated Circuit (集成电路总线)
是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双
工同步通信方式
5.2.2.特点
5.2.2.1 简单和有效性
由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降
低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件
5.2.2.2多主控
其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。
5.2.3协议信息
IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。
//起始位,停止位,数据位,速度
这些信号中,起始信号是必需的,结束信号和应答信号
-
起始信号
-
终止信号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Asg0RIiB-1688746961767)(C:\Users\xie19\Pictures\Camera Roll\屏幕截图 2023-07-07 234444.png)]
-
应答信号
发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ysoeEZE-1688746961767)(C:\Users\xie19\Pictures\Camera Roll\屏幕截图 2023-07-07 234743.png)]
- 数据发送的时序[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c8w7XqiM-1688746961768)(C:\Users\xie19\Pictures\Camera Roll\屏幕截图 2023-07-07 234832.png)]
5.2.4 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
5.2.5oled开发
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include "oled.h"
#include "font.h"
int oled_show(struct display_info *disp) {
int i;
char buf[100];
oled_putstrto(disp, 0, 9+1, "Welcome to My HomeAssitant");
disp->font = font2;
oled_putstrto(disp, 0, 20, " ---Mr.chen HenShuai--- ");
disp->font = font2;
oled_send_buffer(disp);
return 0;
}
void show_error(int err, int add) {
printf("\nERROR: %i, %i\n\n", err, add);
}
void show_usage(char *progname) {
printf("\nUsage:\n%s <I2C bus device node >\n", progname);
}
int main(int argc, char **argv) {
int e;
char filename[32];
struct display_info disp;
if (argc < 2) {
show_usage(argv[0]);
return -1;
}
memset(&disp, 0, sizeof(disp));
sprintf(filename, "%s", argv[1]);
disp.address = OLED_I2C_ADDR;
disp.font = font2;
e = oled_open(&disp, filename);
e = oled_init(&disp);
oled_show(&disp);
return 0;
}
6.串口
6.1串口基本认知
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口(Serial Interface)是指数据一位一位地顺序传送。其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢
- 是设备间接线通信的一种方式
- 数据一位一位地顺序传送
- 双向通信,全双工
- 传送速度相对较慢
6.2串口接线方式
RXD:数据输入引脚,数据接受;
TXD:数据发送引脚,数据发送;
交叉接线
6.3基于wiringPi的串口开发
/*
* serialTest.c:
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <stdlib.h>
int fd;
void* Sendhandler()
{
char *sendBuf;
sendBuf = (char *)malloc(32*sizeof(32));
while(1){
memset(sendBuf,'\0',32);
scanf("%s",sendBuf);
while(*sendBuf){
serialPutchar (fd, *sendBuf++) ;
}
}
}
void* Revhandler()
{
while(1){
while (serialDataAvail(fd))
{
printf ("%c", serialGetchar(fd)) ;
fflush (stdout) ;
}
}
}
int main ()
{
int count ;
unsigned int nextTime ;
pthread_t idSend;
pthread_t idRev;
if ((fd = serialOpen ("/dev/ttyS5", 115200)) < 0)
{
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno))
;
return 1 ;
}
pthread_create(&idSend, NULL,Sendhandler,NULL);
pthread_create(&idRev, NULL,Revhandler,NULL);
if (wiringPiSetup () == -1)
{
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
while(1){sleep(10);}
printf ("\n") ;
return 0 ;
}
6.4Linux原生串口开发(实现不基于wiringpi库的串口)
uartTool.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#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;
ret = write (fd, s, strlen (s));
if (ret < 0)
printf("Serial Puts Error\n");
}
int serialGetstring (const int fd, char *buffer)
{
int n_read;
n_read = read(fd, buffer,32);
return n_read;
}
uartTool.h
int myserialOpen (const char *device, const int baud);
void serialSendstring (const int fd, const char *s);
int serialGetstring (const int fd, char *buffer);
uartTest.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include "uartTool.h"
int fd;
void* readSerial()
{
char buffer[32];
while(1){
memset(buffer,'\0',sizeof(buffer));
serialGetstring(fd, buffer);
printf("GET->%s\n",buffer);
}
}
void* sendSerial()
{
char buffer[32];
while(1){
memset(buffer,'\0',sizeof(buffer));
scanf("%s",buffer);
serialSendstring(fd, buffer);
}
}
int main(int argc, char **argv)
{
char deviceName[32] = {'\0'};
pthread_t readt;
pthread_t sendt;
if(argc < 2){
printf("uage:%s /dev/ttyS?\n",argv[0]);
return -1;
}
strcpy(deviceName, argv[1]);
if( (fd = myserialOpen(deviceName, 115200)) == -1){
printf("open %s error\n",deviceName);
return -1;
}
pthread_create(&readt, NULL, readSerial,NULL);
pthread_create(&sendt, NULL, sendSerial,NULL);
while(1){sleep(10);}
}
7.继电器组
7.1概述
继电器(英文名称:relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器
7.2继电器实战
实现功能:输入不同的指令,点亮不同的LED灯
实现方式一:
#include<wiringPi.h>
#include<stdio.h>
#include<string.h>
#define sw1 16
#define sw2 15
#define sw3 13
#define sw4 10
void pinModeOutPut()
{
pinMode(sw1,OUTPUT);
pinMode(sw2,OUTPUT);
pinMode(sw3,OUTPUT);
pinMode(sw4,OUTPUT);
}
void allHigh()
{
digitalWrite(sw1,HIGH);
digitalWrite(sw2,HIGH);
digitalWrite(sw3,HIGH);
digitalWrite(sw4,HIGH);
}
void allLow()
{
digitalWrite(sw1,LOW);
digitalWrite(sw2,LOW);
digitalWrite(sw3,LOW);
digitalWrite(sw4,LOW);
}
int main()
{
char cmd[12]={0};
if(wiringPiSetup()==-1)
{
printf("init error\n");
return -1;
}
pinModeOutPut();
allHigh();
while(1)
{
printf("1/2/3/4代表灯,on-打开,off-关闭\n");
memset(cmd,0,sizeof(cmd));
fgets(cmd, 12, stdin);
if(strncmp(cmd,"1on",3)==0)
{
digitalWrite(sw1,LOW);
}
else if(strncmp(cmd,"2on",3)==0)
{
digitalWrite(sw2,LOW);
}
else if(strncmp(cmd,"3on",3)==0)
{
digitalWrite(sw3,LOW);
}
else if(strncmp(cmd,"4on",3)==0)
{
digitalWrite(sw4,LOW);
}
else if(strncmp(cmd,"1off",4)==0)
{
digitalWrite(sw1,HIGH);
}
else if(strncmp(cmd,"2off",4)==0)
{
digitalWrite(sw2,HIGH);
}
else if(strncmp(cmd,"3off",4)==0)
{
digitalWrite(sw3,HIGH);
}
else if(strncmp(cmd,"4off",4)==0)
{
digitalWrite(sw4,HIGH);
}
else if(strncmp(cmd,"allon",5)==0)
{
allLow();
}
else if(strncmp(cmd,"alloff",6)==0)
{
allHigh();
}
}
return 0;
}
实现方式二:
#include <wiringPi.h>
#include <stdio.h>
#include <string.h>
#define sw1 16
#define sw2 15
#define sw3 13
#define sw4 10
#define one 1
#define two 2
#define there 3
#define four 4
#define five 5
#define six 6
#define seven 7
#define eight 8
#define night 9
#define ten 10
void pinModeOutPut()
{
pinMode(sw1, OUTPUT);
pinMode(sw2, OUTPUT);
pinMode(sw3, OUTPUT);
pinMode(sw4, OUTPUT);
}
void allHigh()
{
digitalWrite(sw1, HIGH);
digitalWrite(sw2, HIGH);
digitalWrite(sw3, HIGH);
digitalWrite(sw4, HIGH);
}
void allLow()
{
digitalWrite(sw1, LOW);
digitalWrite(sw2, LOW);
digitalWrite(sw3, LOW);
digitalWrite(sw4, LOW);
}
int get_cmd_type(char *cmd)
{
if (strncmp(cmd, "one", 3) == 0)
return 1;
if (strncmp(cmd, "two", 3) == 0)
return 2;
if (strncmp(cmd, "there", 5) == 0)
return 3;
if (strncmp(cmd, "four", 4) == 0)
return 4;
if (strncmp(cmd, "five", 4) == 0)
return 5;
if (strncmp(cmd, "six", 3) == 0)
return 6;
if (strncmp(cmd, "seven", 5) == 0)
return 7;
if (strncmp(cmd, "eight", 5) == 0)
return 8;
if (strncmp(cmd, "night", 5) == 0)
return 9;
if (strncmp(cmd, "ten", 3) == 0)
return 10;
return -1;
}
int main()
{
char cmd[12] = {0};
int ret;
if (wiringPiSetup() == -1)
{
printf("init error\n");
return -1;
}
pinModeOutPut();
allHigh();
while (1)
{
printf("1/2/3/4/9-on,5/6/7/8/10-off,9-allon,10-alloff\n");
memset(cmd, 0, sizeof(cmd));
fgets(cmd, 12, stdin);
ret = get_cmd_type(cmd);
switch (ret)
{
case 1:
digitalWrite(sw1, LOW);
break;
case 2:
digitalWrite(sw2, LOW);
break;
case 3:
digitalWrite(sw3, LOW);
break;
case 4:
digitalWrite(sw4, LOW);
break;
case 5:
digitalWrite(sw1, HIGH);
break;
case 6:
digitalWrite(sw2, HIGH);
break;
case 7:
digitalWrite(sw3, HIGH);
break;
case 8:
digitalWrite(sw4, HIGH);
break;
case 9:
allLow();
break;
case 10:
allHigh();
break;
default:
printf("cmd error\n");
break;
}
}
return 0;
}
digitalWrite(sw2, LOW);
break;
case 3:
digitalWrite(sw3, LOW);
break;
case 4:
digitalWrite(sw4, LOW);
break;
case 5:
digitalWrite(sw1, HIGH);
break;
case 6:
digitalWrite(sw2, HIGH);
break;
case 7:
digitalWrite(sw3, HIGH);
break;
case 8:
digitalWrite(sw4, HIGH);
break;
case 9:
allLow();
break;
case 10:
allHigh();
break;
default:
printf("cmd error\n");
break;
}
}
return 0;
}