admin 管理员组

文章数量: 887017

目录

 前言

一、HC-SR04超声波测距

0.超声波测距原理

✒️如何使HC-SR04发送超声波

✒️如何接收超声波返回

✒️如何通过时间算出距离

1.Linux的获取时间gettimeofday()

✒️timeval结构体

✒️gettimeofday()函数

 2.利用gettimeofday()计算时间,实现超声波测距

二、SG90舵机

0.驱动SG90舵机原理

1.Linux的定时器

✒️itimerval结构体

✒️setitimer()函数

2.实现舵机全向转动


 前言

       在上篇已经刷好了Armbian系统,安装wiringPi完成基本的开发环境准备,接下来就是基于WiringPi配合常用模块来了解了解angePi的基本外设 — 通用输入输入设备GPIO、串口UART、IIC协议等。

一、HC-SR04超声波测距

0.超声波测距原理

《第二篇 树莓派基本外设基础》— 树莓派实现

《第三篇 SG90舵机和HC-SR04测距》— 51实现

(在上面的文章里,已经记录了HC-SR04的测距原理,这里简单略过)

具体体现在代码中,只需要知道以下关键信息:

✒️如何使HC-SR04发送超声波

向TRIG引脚发送一个10us 的脉冲信号(高电平),开始发送超声波

✒️如何接收超声波返回

开始发送波的同时,ECHO会被置为高电平直到波返回,置为低电平

ECHO持续高电平的时间 = 超声波往返路程的花费的时间)

✒️如何通过时间算出距离

已知波在空气中传播速度为340 m/s。通过路程=速度×时间计算得出

1.Linux的获取时间gettimeofday()

✒️timeval结构体

图1 - struct_timeval.h

✒️gettimeofday()函数

        获取当前时间到新纪元时间Epoch的距离时间(可精确到微妙)

        Epoch是指定为1970年1月1日0时0分0秒的格林威治时间

(也就是说该函数能获取当前时间距离197011000秒那一刻xxxxxxxxxxxx微妙)

图2 - sys/time.h

 2.利用gettimeofday()计算时间,实现超声波测距

(模块坏了,没接上测试)

#include<wiringPi.h>
#include<unistd.h>
#include<sys/time.h>
#include<stdio.h>
#include<stdlib.h>

#define TRIG 23
#define ECHO 25

void init_hardware(){
    int retn;
    retn=wiringPiSetup();
    if(retn < 0){
        perror("init hardware");
        exit(-1);
    }
}

void init_pins(){
    pinMode(ECHO,INPUT);
    pinMode(TRIG,OUTPUT);
}

float measure_distance(){
    long  start_usec,stop_usec;
    struct timeval rawtime1,rawtime2;
    float distance;
    digitalWrite(TRIG,LOW);
    delayMicroseconds(2);
    digitalWrite(TRIG,HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG,LOW);//start send ultrasonic
//  printf("%d\n",digitalRead(ECHO));
    while(!(digitalRead(ECHO) == 1));
    gettimeofday(&rawtime1, NULL);
    
    while(!(digitalRead(ECHO) == 0));//low
    gettimeofday(&rawtime2,NULL);
 
    start_usec =rawtime1.tv_sec*1000000+rawtime1.tv_usec;
    stop_usec =rawtime2.tv_sec*1000000+rawtime2.tv_usec;
    distance=(float)(stop_usec-start_usec)/1000000*17000;
    return distance;
}

int main(){
    float distance;
    init_hardware();
    init_pins();
    while(1){
        distance = measure_distance();
        printf("%0.2f cm\n",distance);
        delay(1000);
    }
    return 0;
}

二、SG90舵机

0.驱动SG90舵机原理

在前面的文章里,已经记录了SG90的相关信息,这里简单略过

体现在代码中,需要以下关键信息

1.Linux的定时器

✒️itimerval结构体

图3 - sys/time.h

✒️setitimer()函数

设置定时器,可精确到us(微秒)级别,比alarm()函数精度更高

 🔖参数①:which指定定时器的定时方式(传下面三个宏)

ITIMER_REAT

根据实际时间倒计时,到达时间发送SIGALRM信号

ITIMER_VIRTUAL

根据进程消耗的用户模式CPU时间进行倒计时,到达发送SIGVTALRM信号

ITIMER_PROF

根据进程消耗的总CPU时间(即用户和系统)进行倒计时

🔖参数②:new_value

传入参数,表示定时的时长(传已初始化的itmerval结构体地址)

🔖参数③:old_value

传出参数,表示上一次定时剩余的时间(一般传NULL即可)

2.实现舵机全向转动

#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <wiringPi.h>
#include <unistd.h>
#include <stdlib.h>

#define SG90 25

int angle = 0; //初始化角度为0度。0-0度 1-45度 2-90度 3-135度 4-180度
/* 初始化硬件 */
void init_hardware(){
    if(wiringPiSetup() == -1){
        perror("init");
        exit(-1);
    }else{
        pinMode(SG90,OUTPUT);
    }
}
/* 信号处理函数:主要实现控制SG90的转向 */
void signalHandler(int signum){
    static int i = 0;
    if(i > angle){     //angle=0时,i=0不满足条件,拉高电平得到0.5ms高电平转至0度
        digitalWrite(SG90,LOW);
    }else{           //angle=2,i=0 i=1均不满足条件,拉高电平得到1ms高电平转到40度
        digitalWrite(SG90,HIGH);
    }         //angle=2,i=0 i=1 i=2均不满足条件,拉高电平得到1.5ms高电平转到90度
    if(++i == 40){   //其他角度以此类推
        i = 0;
    }
}

/* 初始化定时器 */
void init_timer(){
    struct itimerval timer;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = 500;  //每0.5ms定时到期一次 

    timer.it_value.tv_sec = 1;
    timer.it_value.tv_usec = 0;   //1s后启动定时器

    if(setitimer(ITIMER_REAL,&timer,NULL) == -1){
        perror("set timer");
        exit(-1);
    }     
    signal(SIGALRM,signalHandler); //捕获SIGALRM信号
}

int main(){
    init_hardware();
    digitalWrite(SG90,LOW);
    init_timer();
    while(1){
        printf("input 1-0,2-45,3-90,4-135,5-180\n");
        scanf("%d",&angle);
    }
    return 0;
}

本文标签: 香橙 外设 第二篇 基础 GPIO