模块介绍:
HC-SR04 超声波模块:
VCC:正极
Trig:触发
Echo:回应
GND:负极(接地)
树莓派接口:
gpio readall // 输入指令查看树莓派 io 口
+-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| | | 3.3v | | | 1 || 2 | | | 5v | | |
| 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | |
| 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | |
| 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 1 | ALT0 | TxD | 15 | 14 |
| | | 0v | | | 9 || 10 | 1 | ALT0 | RxD | 16 | 15 |
| 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 |
| 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | |
| 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 |
| | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 |
| 10 | 12 | MOSI | IN | 0 | 19 || 20 | | | 0v | | |
| 9 | 13 | MISO | IN | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 |
| 11 | 14 | SCLK | IN | 0 | 23 || 24 | 1 | IN | CE0 | 10 | 8 |
| | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 |
| 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
| 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
| 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 |
| 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | |
| 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 |
| 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 |
| | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+
接线:
Vcc:超声波模块电源脚,接5V电源
Trig:接收来自树莓派的控制信号,接 GPIO 口
Echo:发送测距结果给树莓派,接 GPIO 口
(值得注意的是:Echo 返回的是 5v信号,而树莓派的 GPIO 接收超过 3.3v 的信号可能会被烧毁,因此可以加一个分压电路)
Gnd:接地,接 0v
工作原理:
1、树莓派向 Trig 发送一个持续 10us(微秒) 的脉冲信号
2、HC-SR04 接收到树莓派发送的 10us 脉冲信号,发送 8 个 40khz 的方波,把 Echo 置为高电平,并准备接收返回的超声波
3、当 HC-SR04 接收到返回的超声波时,把 Echo 置为低电平
4、Echo 输出的高电平持续的时间就是超声波从发射到返回的时间
5、记录发送到接收之间的时间(高电平持续时间)即可测算距离
代码实现:
#include <stdio.h>
#include <wiringPi.h>
#include <sys/time.h>
#define Trig 4
#define Echo 5
float getDistance()
{
float dis;
long start;
long end;
struct timeval tv1;
struct timeval tv2;
digitalWrite(Trig, LOW); // 先通入低电平,避免后续误差过大
delayMicroseconds(2);
digitalWrite(Trig, HIGH);
delayMicroseconds(10); // 树莓派发送 10us 脉冲信号
digitalWrite(Trig, LOW);
while(digitalRead(Echo) != HIGH); // HIGH(1),检测到高电平时跳出循环
gettimeofday(&tv1, NULL); // 获取时间(此为高电平开始时间)
while(digitalRead(Echo) != LOW); // LOW(0),检测到低电平跳出循环
gettimeofday(&tv2, NULL); // 获取时间(此为低电平开始时间,即为高电平结束时间)
start = tv1.tv_sec * 1000000 + tv1.tv_usec; // 单位(微秒)
end = tv2.tv_sec * 1000000 + tv2.tv_usec; // 单位(微秒)
dis = (float)(end - start) / 1000000 * 34000 / 2; // 距离计算(高电平时间 * 音速 / 2)
return dis;
}
int main()
{
float dis;
if(wiringPiSetup() == -1){ // 硬件初始化
printf("硬件初始化失败!\n");
return -1;
}
pinMode(Trig, OUTPUT); // 配置端口为输出模式
pinMode(Echo, INPUT); // 配置端口为输入模式
pullUpDnControl(Echo, PUD_UP); // 对一个设置 IO 模式为 INPUT 的输入引脚设置拉电阻模式
// PUD_UP 启用上拉电阻,引脚电平拉到 3.3v
while(1){
dis = getDistance();
printf("distance = %0.2fcm\n",dis);
delay(1000);
}
return 0;
}
函数解析:
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
// 获取自 1970-01-01 00:00:00 到调用 gettimeofday() 函数所经历的秒数,存放在 tv 中,精确到微秒
// 获取时区信息,存放到 tz 中,不关心传入 NULL 即可
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};