为了使移动机器人能自动避障行走,就必须装备测距系统,以使其及时获取距障碍物的距离信息(距离和方向)。介绍了三方向(前、左、右)超声波测距系统,就是为机器人了解其前方、左侧和右侧的环境而提供一个运动距离信息。在超声波测距中,通常因温度和时间检测的误差,使得测距的精度不高。 功能介绍 超声波测距主要应用于倒车提醒、建筑工地、工业现场等的 距离测量。 超声波在气体、液体及固体中以不同速度传播,定向性好、能量集中、传输过程中衰减较小、反射能力较强。超声波能以一定速度定向传播、遇障碍物后形成反射,利用这一特性,通过测定超声波往返所用时间就可计算出实际距离,从而实现无接触测量物体距离。超声波测距迅速、方便,且不受光线等因素影响,广泛应用于水文液位测量、建筑施工工地的测量、现场的位置监控、 振动仪车辆倒车障碍物的检测、移动机器入探测定位等领域。本文设计的数字式超声波测距仪通过对超声波往返时间内输入到计数器特定频率的 时钟脉冲进行计数,进而显示对应的测量距离。 硬件介绍 超声波测距模块: 超声波测距模块有好多种类型,比较常用的有URM37 超声波传感器默认是232接口,可以调为 TTL接口,URM05大功率超声波传感器测试距离能到10米,算是测试距离比较远的一款了,另外还有比较常用的国外的几款SRF系列的超声波模块,超声波模块精度能到1cm 界面设计 file:///C:/Users/%E9%A3%8E%E6%B2%99/AppData/Local/Temp/ksohtml6652/wps1.png代码设计 Main.c #include "sys.h" #include "chaoshengbo.h"
#define START_WIN_TEMP_VP 0x2000 //控件:数据变量
u16 val;
void main(void) { time0Init(); //超声波定时器初始化 sys_init();//系统初始化 while(1) { Get_Val(); //获取超声波距离 if(val) //如果数据有效 { sys_write_vp(START_WIN_TEMP_VP,(u8*)&val,1);//将数据显示在控件 } sys_delay_about_ms(300); //延时1000ms } } Sys.c #include "sys.h"
static idata u16 delay_tick = 0; //用来实现精确延时的
//核心寄存器初始化 void sys_cpu_init() { EA = 0; RS0 = 0; RS1 = 0;
CKCON = 0x00; T2CON = 0x70; DPC = 0x00; PAGESEL = 0x01; D_PAGESEL = 0x02; //DATA RAM 0x8000-0xFFFF MUX_SEL = 0x00; //UART2,UART3关闭,WDT关闭 RAMMODE = 0x00; PORTDRV = 0x01; //驱动强度+/-8mA IEN0 = 0x00; //关闭所有中断 IEN1 = 0x00; IEN2 = 0x00; IP0 = 0x00; //中断优先级默认 IP1 = 0x00;
WDT_OFF(); //关闭开门狗 }
//定时器2初始化,定时间隔为1ms void sys_timer2_init() { T2CON = 0x70; TH2 = 0x00; TL2 = 0x00;
TRL2H = 0xBC; //1ms的定时器 TRL2L = 0xCD;
IEN0 |= 0x20; //启动定时器2 TR2 = 0x01; EA = 1; }
//系统初始化 void sys_init() { sys_cpu_init();//核心寄存器初始化 sys_timer2_init();//定时器2初始化 }
//软件大致延时,单位ms //如果修改了优化等级,那么此函数内部的参数需要重新调试 void sys_delay_about_ms(u16 ms) { u16 i,j; for(i=0;i<ms;i++) for(j=0;j<3000;j++); }
//软件大致延时,单位us //如果修改了优化等级,那么此函数内部的参数需要重新调试 void sys_delay_about_us(u8 us) { u8 i,j; for(i=0;i<us;i++) for(j=0;j<5;j++); }
//利用定时器2进行精确延时,单位ms void sys_delay_ms(u16 ms) { delay_tick = ms; while(delay_tick); }
//读DGUS中的VP变量数据 //addr:就是直接传入DGUS中的地址 //buf:缓冲区 //len:读取的字数,一个字等于2个字节 void sys_read_vp(u16 addr,u8* buf,u16 len) { u8 i;
i = (u8)(addr&0x01); addr >>= 1; ADR_H = 0x00; ADR_M = (u8)(addr>>8); ADR_L = (u8)addr; ADR_INC = 0x01; RAMMODE = 0xAF; while(APP_ACK==0); while(len>0) { APP_EN=1; while(APP_EN==1); if((i==0)&&(len>0)) { *buf++ = DATA3; *buf++ = DATA2; i = 1; len--; } if((i==1)&&(len>0)) { *buf++ = DATA1; *buf++ = DATA0; i = 0; len--; } } RAMMODE = 0x00; }
//写DGUS中的VP变量数据 //addr:就是直接传入DGUS中的地址 //buf:缓冲区 //len:被发送数据的字数,一个字等于2个字节 void sys_write_vp(u16 addr,u8* buf,u16 len) { u8 i;
i = (u8)(addr&0x01); addr >>= 1; ADR_H = 0x00; ADR_M = (u8)(addr>>8); ADR_L = (u8)addr; ADR_INC = 0x01; RAMMODE = 0x8F; while(APP_ACK==0); if(i && len>0) { RAMMODE = 0x83; DATA1 = *buf++; DATA0 = *buf++; APP_EN = 1; while(APP_EN==1); len--; } RAMMODE = 0x8F; while(len>=2) { DATA3 = *buf++; DATA2 = *buf++; DATA1 = *buf++; DATA0 = *buf++; APP_EN = 1; while(APP_EN==1); len -= 2; } if(len) { RAMMODE = 0x8C; DATA3 = *buf++; DATA2 = *buf++; APP_EN = 1; while(APP_EN==1); } RAMMODE = 0x00; }
//定时器2中断服务程序 void sys_timer2_isr() interrupt 5 { TF2=0;//清除定时器2的中断标志位
//精准延时处理 if(delay_tick) delay_tick--; } Sys.h #ifndef __SYS_H__ #define __SYS_H__ #include "t5los8051.h"
//类型重定义 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; typedef signed char s8; typedef signed short s16; typedef signed long s32;
//看门狗宏定义 #define WDT_ON() MUX_SEL|=0x02 //开启看门狗 #define WDT_OFF() MUX_SEL&=0xFD //关闭看门狗 #define WDT_RST() MUX_SEL|=0x01 //喂狗
//系统主频和1ms定时数值定义 #define FOSC 206438400UL #define T1MS (65536-FOSC/12/1000)
//函数申明 void sys_init(void); void sys_delay_about_ms(u16 ms); void sys_delay_about_us(u8 us); void sys_delay_ms(u16 ms); void sys_read_vp(u16 addr,u8* buf,u16 len); void sys_write_vp(u16 addr,u8* buf,u16 len);
#endif T5l #ifndef __T5LOS8051_H__ #define __T5LOS8051_H__
sfr P0 = 0x80; /********PO口*******/ sfr SP = 0x81; /********堆栈指针*******/ sfr DPL = 0x82; /********DPTR数据指针*******/ sfr DPH = 0x83; /********DPTR数据指针*******/ sfr PCON = 0x87; /********.7 UART2波特率设置*******/ sfr TCON = 0x88; /********T0 T1控制寄存器*******/
sbit TF1 = TCON^7; /********T1中断触发*******/ sbit TR1 = TCON^6; sbit TF0 = TCON^5; /********T0中断触发*******/ sbit TR0 = TCON^4; sbit IE1 = TCON^3; /********外部中断1*******/ sbit IT1 = TCON^2; /********外部中断1触发方式 0:低电平触发 1:下降沿触发*******/ sbit IE0 = TCON^1; /********外部中断0*******/ sbit IT0 = TCON^0; /********外部中断0触发方式 0:低电平触发 1:下降沿触发*******/
sfr TMOD = 0x89; /********T0 T1模式选择,同8051*******/ sfr TH0 = 0x8C; sfr TL0 = 0x8A; sfr TH1 = 0x8D; sfr TL1 = 0x8B;
sfr CKCON = 0x8E; /********CPU运行*******/ sfr P1 = 0x90; sfr DPC = 0x93; /********MOVX指令后,DPTR的变化模式 0:不变 1:+1 2:-1*******/ sfr PAGESEL = 0x94; /********必须是0x01*******/ sfr D_PAGESEL = 0x95; /********必须是0x02*******/
sfr SCON0 = 0x98; /********UART2控制接口,同8051*******/ sbit TI0 = SCON0^1; sbit RI0 = SCON0^0; sfr SBUF0 = 0x99; /********UART2收发数据接口*******/ sfr SREL0H = 0xBA; /********设置波特率,当ADCON为0x80时*******/ sfr SREL0L = 0xAA;
sfr SCON1 = 0x9B; /********UART3控制接口*******/ sfr SBUF1 = 0x9C; sfr SREL1H = 0xBB; sfr SREL1L = 0x9D;
sfr IEN2 = 0x9A; /********中断使能控制器SFR .7~.1必须写0 .0 UART3中断使能控制位*******/ sfr P2 = 0xA0; sfr IEN0 = 0xA8; /********中断使能控制器0*******/ sbit EA = IEN0^7; /********中断总控制位*******/ sbit ET2 = IEN0^5; /********定时器2中断控制位*******/ sbit ES0 = IEN0^4; /********UART2*******/ sbit ET1 = IEN0^3; /********T1*******/ sbit EX1 = IEN0^2; /********外部中断1*******/ sbit ET0 = IEN0^1; /********T0*******/ sbit EX0 = IEN0^0; /********外部中断0*******/
sfr IP0 = 0xA9; /********中断优先级控制器0*******/ sfr P3 = 0xB0; sfr IEN1 = 0xB8; /********中断使能接受控制器******/ sbit ES3R = IEN1^5; /*****UART5接受中断使能控制位****/ sbit ES3T = IEN1^4; /*****UART5接受中断使能控制位****/ sbit ES2R = IEN1^3; /*****UART4接受中断使能控制位****/ sbit ES2T = IEN1^2; /*****UART4接受中断使能控制位****/ sbit ECAN = IEN1^1; /********CAN中断使能控制位******/
sfr IP1 = 0xB9; /********中断优先级控制器0*******/ sfr IRCON2 = 0xBF; sfr IRCON = 0xC0; sbit TF2 = IRCON^6; /********T2中断触发标志*******/ sfr T2CON = 0xC8; /********T2控制寄存器********/ sbit TR2 = T2CON^0; /***********T2使能***********/ sfr TRL2H = 0xCB; sfr TRL2L = 0xCA; sfr TH2 = 0xCD; sfr TL2 = 0xCC;
sfr PSW = 0xD0; sbit CY = PSW^7; sbit AC = PSW^6; sbit F0 = PSW^5; sbit RS1 = PSW^4; sbit RS0 = PSW^3; sbit OV = PSW^2; sbit F1 = PSW^1; sbit P = PSW^0; sfr ADCON = 0xD8; sfr ACC = 0xE0; sfr B = 0xF0;
/******硬件扩展定义*********/ /******DGUS变量存储器访问*********/ sfr RAMMODE = 0xF8; /******DGUS变量存储器访问接口控制寄存器*********/ sbit APP_REQ = RAMMODE^7; sbit APP_EN = RAMMODE^6; sbit APP_RW = RAMMODE^5; sbit APP_ACK = RAMMODE^4; sfr ADR_H = 0xF1; sfr ADR_M = 0xF2; sfr ADR_L = 0xF3; sfr ADR_INC = 0xF4; sfr DATA3 = 0xFA; sfr DATA2 = 0xFB; sfr DATA1 = 0xFC; sfr DATA0 = 0xFD;
//UART4 sfr SCON2T = 0x96; /******UART4发送控制********/ sfr SCON2R = 0x97; /******UART4接收控制*********/ sfr BODE2_DIV_H = 0xD9; /******波特率设置********/ sfr BODE2_DIV_L = 0xE7; sfr SBUF2_TX = 0x9E; /******UART4发送数据接口********/ sfr SBUF2_RX = 0x9F; /******UART4接收数据接口*********/
//UART5 sfr SCON3T = 0xA7; sfr SCON3R = 0xAB; sfr BODE3_DIV_H = 0xAE; sfr BODE3_DIV_L = 0xAF; sfr SBUF3_TX = 0xAC; sfr SBUF3_RX = 0xAD;
//CAN通信 sfr CAN_CR = 0x8F; sfr CAN_IR = 0x91; sfr CAN_ET = 0xE8;
//GPIO sfr P0MDOUT = 0xB7; sfr P1MDOUT = 0xBC; sfr P2MDOUT = 0xBD; sfr P3MDOUT = 0xBE; sfr MUX_SEL = 0xC9; sfr PORTDRV = 0xF9; /******输出驱动强度*********/
//MAC&DIV sfr MAC_MODE = 0xE5; sfr DIV_MODE = 0xE6;
//SFR扩展接口 sfr EXADR = 0xFE; sfr EXDATA = 0xFF;
#endif 接口连接 将超声波测距模块与STM32F103C8T6单片机结合起来,可以实现测距功能,并将结果显示在OLED屏幕上。 实现步骤如下: 连接硬件:将超声波测距模块的Trig引脚连接到STM32F103C8T6的一个GPIO引脚,将Echo引脚连接到另一个GPIO引脚。 同时,将OLED屏幕连接到STM32F103C8T6的I2C接口。 配置GPIO:在STM32F103C8T6上配置Trig和Echo引脚为输入输出模式,并设置相应的中断和触发方式。 系统实现与测试
超声波测距系统是利用超声波的反射原理来测量物体距离的一种非接触式传感器技术。它的工作原理大致分为以下几个步骤: 发射:系统会发送一个短促的超声脉冲波,通常由一个小型晶体发出,比如压电陶瓷或晶片。 接收:当声波遇到物体(如墙壁、地面或其他物体表面)时,会被反射回来。部分时间被用来测量声波从发射到接收到回波的时间。 计算:通过计算声波来回传播的总时间(考虑到声速),然后将这个时间除以声速的一半,可以得出两个物体之间的距离。因为声波速度在空气中大约是每秒343米,所以距离公式通常是:(距离 = \frac{声波往返时间}{2} \times 声速 )。 数据处理:测距系统通常会将测量结果转换为电子信号,然后进行滤波和补偿,以减小误差并处理非线性影响。 测试:测试超声波测距系统的准确性和稳定性至关重要。这包括静态测试(在固定环境条件下测量不同距离),动态测试(观察系统在运动中的性能),以及抗干扰测试(评估系统在噪声或反射物干扰下的表现)。
|