本例中使用51单片机驱动两轮小车,配合超声波测距模块,实现运动中测距。超声波模块使用非常常见的那种收发一体的模块。


工作原理是:
1、给模块的触发引脚至少10微秒的搞电平信号。使模块通过超声波发射头发出8个40KHz的方波信号。
2、超声波接收头收到返回信号时,通过IO口输出一个高电平信号。这个高电平信号的持续时间,就是超声波发出后,遇到物体反射回来经过的时间,由公式
测试距离 = 高电平持续时间 * 声波速度 / 2
其中声波速度为340m/s。
本次实验采用数码管,以动态扫描的方式显示数据。电路如下:
为了实现动态测距,使用部分IO口用来驱动小车的两个电机,控制小车向前移动,并在移动过程中测试前方物体距离传感器的距离。
程序如下:
/***********************************************************************************************************/
//hc-sr04 超声波测距模块
//晶振:11。0592
//接线:模块TRIG接 P2.7(P1.0显示) ECH0(P1.1显示) 接P2.6
// T1:2ms单位发生中断,累计到400(800ms)时使超声波模块开始工作,发10微秒高电平给Trig端
// T0:1微妙单位计数,最大65535。用于超声波模块回传测距数值时统计时间长度。
// 距离换算(未考虑温度补偿):声速340m/s->0.340mm/微秒,距离=时间累计*0.34/2
//数码管:共阳数码管P1接数据口,P2.0 P2.1 P2.2 P2.3接选通数码管
/***********************************************************************************************************/
#include <reg51.h>//器件配置文件
#include <intrins.h>
#define uchar unsigned char
unsigned int time=0;
unsigned int timer=0;
unsigned char posit=0;
unsigned long s=0;
unsigned long old_s=0;
bit flag =0;
bit test_flag =0;
unsigned char const table[] ={ 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xBF,0xff/*-*/};
unsigned char disbuff[4] ={ 0,0,0,0,};
sbit LED1 = P2^0; // 数码管1的电源
sbit LED2 = P2^1; // 数码管2的电源
sbit LED3 = P2^2; // 数码管3的电源
sbit LED4 = P2^3; // 数码管4的电源
sbit Trip = P2^7 ; // 输出端,超声波模块触发端
sbit SData = P2^6 ; // 输入端,数据回传
sbit motor1_a = P1^0 ; // 驱动轮马达-1-a
sbit motor1_b = P1^1 ; // 驱动轮马达-1-b
sbit motor2_a = P1^2 ; // 驱动轮马达-1-a
sbit motor2_b = P1^3 ; // 驱动轮马达-1-b
bit motor1_a_bak = 0 ; // 驱动轮马达-1-a
bit motor1_b_bak = 0; // 驱动轮马达-1-b
bit motor2_a_bak = 0; // 驱动轮马达-1-a
bit motor2_b_bak = 0; // 驱动轮马达-1-b
sbit test_led = P1^4 ;
/********************************************************/
/** 延时 */
void delay1(uchar i) {
uchar j,k;
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
/** 显示数据 */
void Display(void){
P0=table[disbuff[0]];
LED1 = 0;
_nop_();
_nop_();
LED1 = 1;
P0=table[disbuff[1]];
LED2 = 0;
_nop_();
_nop_();
LED2 = 1;
P0=table[disbuff[2]];
LED3 = 0;
_nop_();
_nop_();
LED3 = 1;
P0=table[disbuff[3]];
LED4 = 0;
_nop_();
_nop_();
LED4 = 1;
}
/** 使用12M的晶振,中断周期为1微秒。1微秒的计数 */
void Conut(void) {
unsigned int tmp1=0;
unsigned int tmp2=0;
s=TH0*256+TL0; // 取得计数值(单位:1微秒)
TH0=0;
TL0=0;
s=s*0.17; // 算出来是mm
disbuff[0]=(s - s%1000)/1000; // 米
disbuff[1]=(s%1000 - s%100)/100; // 分米
disbuff[2]=(s%100 - s%10)/10; // 厘米
disbuff[3]=s%10; // 毫米
if (flag==1) {
disbuff[0] = 10;
disbuff[1] = 10;
disbuff[2] = 10;
disbuff[3] = 10;
flag=0;
}
}
/** T0中断用来计数器溢出,超过测距范围 */
void zd0() interrupt 1 {
flag=1; //中断溢出标志
}
/** T1中断用来扫描数码管和计800MS启动模块 */
void zd3() interrupt 3 {
EA=0; //关闭总中断
TH1=0xf8;
TL1=0x30;
Display(); // 显示测试结果
if (timer < 400) {
timer++; // 启动测试的周期(单位:2毫秒)
} else { // 超过800毫秒了,准备测距
timer = 0;
if (test_flag == 0) {
test_flag = 1;
test_led = 0;
Trip=1; // 800MS 启动一次模块,利用NOP操作完成10微秒的启动脉冲
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
Trip=0;
}
}
EA=1;//开启总中断
}
/**
* 后退
*/
void back(void) {
motor1_a = 1;
motor2_a = 1;
motor1_b = 0;
motor2_b = 0;
// P1 = P1 & 0xF0;
// P1 = P1 | 0xF5;
motor1_a_bak = motor1_a;
motor1_b_bak = motor1_b;
motor2_a_bak = motor2_a;
motor2_b_bak = motor2_b;
}
/**
* 前进
*/
void go(void) {
motor1_b = 1;
motor2_b = 1;
motor1_a = 0;
motor2_a = 0;
// P1 = P1 & 0xF0;
// P1 = P1 | 0xFA;
motor1_a_bak = motor1_a;
motor1_b_bak = motor1_b;
motor2_a_bak = motor2_a;
motor2_b_bak = motor2_b;
}
/**
* 停车
*/
void stop(void) {
motor1_a = 0;
motor1_b = 0;
motor2_a = 0;
motor2_b = 0;
}
void clear(void) {
motor1_a_bak = 0;
motor1_b_bak = 0;
motor2_a_bak = 0;
motor2_b_bak = 0;
}
/**
* 右轮不动,向后转
*/
void left_back(void) {
motor1_a = 1;
motor1_b = 0;
motor2_a = 0;
motor2_b = 0;
}
/**
* 左轮不动,向后转
*/
void right_back() {
motor1_a = 0;
motor1_b = 0;
motor2_a = 1;
motor2_b = 0;
}
/**
* 右轮不动,向前转
*/
void left_go() {
motor1_a = 0;
motor1_b = 1;
motor2_a = 0;
motor2_b = 0;
}
void ret_status(void) {
motor1_a = motor1_a_bak;
motor1_b = motor1_b_bak;
motor2_a = motor2_a_bak;
motor2_b = motor2_b_bak;
}
/**
* 左轮不动,向前转
*/
void right_go() {
motor1_a = 0;
motor1_b = 0;
motor2_a = 0;
motor2_b = 1;
}
/*************主程序**************/
void main(void) {
char tmp = 0;
EA=0;
stop();
TMOD=0x11; //设T0为方式1,GATE=0;
TH0=0;
TL0=0;
TH1=0xf8; //2MS定时
TL1=0x30;
ET0=1; //允许T0中断
ET1=1; //允许T1中断
TR1=1; //开启定时器
EA=1; //开启总中断
while(1) {
if (test_flag==1) {
stop();
while(!SData) ;//当接收为零时等待,直到收到测试完成后的发送开始信号
TR0=1; //开启T0计数(计数单位为微秒)
while(SData);//等待测距数据发完
TR0=0;//关闭测距计数
test_led = 1;
Conut();//计算
// 取得距离前方障碍物的距离(单位:mm)
if (s < 50 ) {
// 前方障碍小于15mm时,停止前进
//back();
stop();
clear();
} else {
// 继续前进
go();
}
test_flag=0;
}
tmp = timer % 12;
if ((tmp % 4) == 0) {
ret_status();
} else {
stop();
}
}
}程序中使用了计数器T0和T1的中断。前者用于测距,后者用于计时和动态扫描数码管显示。程序处理不是很细致,仅供初学者学习。
我要赚赏金
