树莓派外设开发之超声波

树莓派超声波测距

  • 树莓派Gpio引脚图:

image-20220804132306609

注意:这里代码中使用的是wiringPi编码,图中GPIO 针脚定义为根据BCM编码定义

  • 超声波模块介绍:

接线参考:模块除了两个电源引脚外,还有Trig,Echo引脚,这两个引脚分别接我们开发板的16号端口和
18号端口(物理引脚)

image-20220804123800084

超声波时序

image-20220804164043926

  • 蜂鸣器模块

1.GND 接地引脚(接树莓派14号物理引脚)

2.I/O 输入输出引脚(接树莓派11号物理引脚——GPIO 17)

​ 3.VCC 接电源引脚(接树莓派4号物理引脚)

  • 相关函数介绍:

使用wiringPi时,你必须在执行任何操作前初始化树莓派,否则程序不能正常工作。可以调用下表函数之一进行初始化,它们都会返回一个int , 返回 -1 表示初始化失败。

int wiringPiSetup (void)返回:执行状态,-1表示失败当使用这个函数初始化树莓派引脚时,程序使用的是wiringPi 引脚编号表。引脚的编号为 0~16需要root权限
int wiringPiSetupGpio (void)返回执行状态,-1表示失败当使用这个函数初始化树莓派引脚时,程序中使用的是BCM GPIO 引脚编号表。需要root权限

时间控制函数:

unsigned int millis (void)这个函数返回 一个 从你的程序执行 wiringPiSetup 初始化函数(或者wiringPiSetupGpio ) 到 当前时间 经过的 毫秒数。 返回类型是unsigned int,最大可记录 大约49天的毫秒时长。
unsigned int micros (void)这个函数返回 一个 从你的程序执行 wiringPiSetup 初始化函数(或者wiringPiSetupGpio ) 到 当前时间 经过的 微秒数。 返回类型是unsigned int,最大可记录 大约71分钟的时长。
void delay (unsigned int howLong)将当前执行流暂停 指定的毫秒数。因为Linux本身是多线程的,所以实际暂停时间可能会长一些。参数是unsigned int 类型,最大延时时间可达49天
void delayMicroseconds (unsigned int howLong)将执行流暂停 指定的微秒数(1000微秒 = 1毫秒 = 0.001秒)。 因为Linux本身是多线程的,所以实际暂停时间可能会长一些。参数是unsigned int 类型,最大延时时间可达71分钟
  • **gettimeofday(struct timeval tv, struct timezone tz);

gettimeofday函数是Linux系统下标准C函数,在Windows下使用会返回-1错误,这个函数返回的是1970年1月1日00:00:00到现在经过的秒数,函数的正常传入时需要用到两个参数。其参数tv是保存获取时间结果的结构体,参数tz用于保存时区结果:struct timezone{int tz_minuteswest;int tz_dsttime;}timezone 参数若不使用则传入NULL即可,这里还有一个小故事:timeval中的tv_sec是time_t类型的,即long的类型。在32位下为4个字节,能够表示的最大正整数是2147483647,而这个表示的时间最大能到2038-01-19 03:14:07 (UTC),超过了之后就变为-2147483648,溢出回1901-12-13 20:45:54(UTC),这就是linux2038年的问题。而64位系统下的time_t类型即long类型长度为8个字节,可以用到更多年,这么长的时间完全不用担心溢出的问题。

代码如下:

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

#define Trig    4       //wiringPi库引脚
#define Echo    5
#define Buzzer  0

void ultraInit(void)
{
        pinMode(Echo, INPUT);  //设置端口为输入
        pinMode(Trig, OUTPUT);  //设置端口为输出
        pinMode(Buzzer, OUTPUT);  //设置端口为输出
        digitalWrite(Buzzer, HIGH);//初始化蜂鸣器输出高电平
}

float disHandle(void)
{
        struct timeval tv1;  //timeval是time.h中的预定义结构体 其中包含两个一个是秒,一个是微秒
        /*
           struct timeval
           {
           time_t tv_sec;  //Seconds.
           suseconds_t tv_usec;  //Microseconds.
           };
         */

        struct timeval tv2;
        float dis;    
        long start, stop;


        digitalWrite(Trig, LOW);
        delayMicroseconds(2);

        digitalWrite(Trig, HIGH);
        delayMicroseconds(10);      //发出触发信号
        digitalWrite(Trig, LOW);

        while(!(digitalRead(Echo) == 1));
        gettimeofday(&tv1, NULL);           //获取发出超声波时间

        while(!(digitalRead(Echo) == 0));
        gettimeofday(&tv2, NULL);           //获取接收到超声波的时间

        start = tv1.tv_sec * 1000000 + tv1.tv_usec;   //微秒级的时间
        stop  = tv2.tv_sec * 1000000 + tv2.tv_usec;

        dis = (float)(stop - start) / 1000000 * 34000 / 2;  //求出距离

        return dis;
}

void sighandle(int signum)
{
        digitalWrite(Buzzer, HIGH);
        printf("quit\n");
        exit(0);
}


int main(void)
{
        float dis;

        signal(SIGINT,  sighandle);   //信号处理函数,SIGINT信号在用户键入INTR字符(通常是Ctrl-C)时发出
        if(wiringPiSetup() == -1){    //初始化树莓派引脚
                printf("setup wiringPi failed !");
                return 1;
        }

        ultraInit();

        while(1){
                dis = disHandle();
                if(dis < 15){
                        digitalWrite(Buzzer, LOW);
                        printf("distance = %0.2f cm warning! \n",dis);
                }else{
                        digitalWrite(Buzzer, HIGH);
                        printf("distance = %0.2f cm\n",dis);
                }
                delay(500);
        }
        return 0;
}

开始测距当距离小于设定值时,蜂鸣器报警,结束按CTRL+C,利用信号处理函数输出高电平,并退出。

执行结果:

image-20220804150404370

image-20220804160839825 按Ctrl+c结束后 image-20220804160943068
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值