【ARM-Linux篇】基于官方外设开发

本文详细介绍了如何在OrangePi上使用wiringPi库进行外设SDK安装、蜂鸣器开发、超声波测距、SG90舵机控制、OLED屏IIC通信以及Linux串口原生开发,涵盖了硬件连接、编程技巧和定时器应用。
摘要由CSDN通过智能技术生成

一、wiringPi外设SDK安装

git clone https://github.com/orangepi-xunlong/wiringOP//下载源码
cd wiringOP//进入文件夹
sudo ./build clean//清除编译信息
sudo ./build//编译

验证指令: gpio readall

二、蜂鸣器开发

 1 .蜂鸣器响的原理

基本IO口的应用

2.蜂鸣器配合时间函数开发

#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;
}

•小插曲:修改按下tap键4个字间隔

sudo vim /etc/vim/vimrc

set tabstop=4 设置tab键缩进4个空格

set shiftwidth=4 设置批量对齐时候的tab键空格数为4

•shell脚本小插曲:
shell脚本处理参数,可以通过$?来处理,这里的$1是要编译的文件

vi build.sh

gcc $1 -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt

三、超声波测距

1.测距原理

•怎么让它发波?

Trig,给Trig端口至少10us的高电平

•怎么知道开始发了?

Echo信号,由低电平跳转到高电平,表示开始发送波

•怎么知道接收了返回波?

Echo,由高电平跳转回低电平,表示波回来了

•怎么算时间?

Echo引脚维持高电平的时间!

波发出去的那一下,开始启动定时器

波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间

•怎么算距离?

距离=速度(340m/s)*时间/2


2.编程开发

a.时间函数

#include<sys/time.h>

int gettimeofday(struct timeval *tv,struct timezone *tz )

gettimeofday()会把目前的时间用tv 结构体返回,当地时区的信息则放到tz所指的结构中

struct timeval
{
long tv_sec;/*秒*/
long tv_usec;/*微妙*/
};

b.编程实现

#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));//等待Echo高电平,表示波回来了
    gettimeofday(&start,NULL);
    while(digitalRead(Echo));//等待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;
}

四、SG90舵机开发


1.转动原理

向黄色信号线“灌入”PWM信号。

PWM波的频率不能太高,50hz,即周期=1/频率=1/50=0.02s,20ms左右数据:不同的PWM波形对应不同的旋转角度,以20ms为周期,50hz为频率的PWM波。

定时器需要定时20ms,关心的单位0.5ms, 20ms = 0.5ms * 40。

2.Linux定时器

分析:实现定时器,通过itimerval结构体以及函数setitimer产生的信号,系统随之使用signal信号处理函数来处理产生的定时信号。从而实现定时器。

(1)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. */
};

(2)setitimer 函数

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

3.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_value.tv_sec = 1;
    itv.it_value.tv_usec = 0;
    //设定定时时间
    itv.it_interval.tv_sec = 0;
    itv.it_interval.tv_usec = 500;
    //设定定时方式
    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协议

1.Orangepi的IIC接口

由 26pin 的原理图可知, Orange Pi Zero 2 可用的 i2c 为 i2c3

•启动 linux 系统后, 先确认下/dev 下存在 i2c-3 的设备节点


•开始测试 i2c, 首先安装 i2c-tools

sudo apt-get install i2c-tools

2. 实战OLED屏幕开发

利用SourceInsight进行源码阅读

#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;
}

六、Linux串口开发

原生串口开发

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);uartTool.h
    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);}

    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿gao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值