树莓派超声波测距
注意:这里代码中使用的是wiringPi编码,图中GPIO 针脚定义为根据BCM编码定义
接线参考:模块除了两个电源引脚外,还有Trig,Echo引脚,这两个引脚分别接我们开发板的16号端口和
18号端口(物理引脚)
超声波时序
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,利用信号处理函数输出高电平,并退出。
执行结果:
按Ctrl+c结束后