一般而言,在单片机组的比赛中只有在国赛的时候才会出现超声波测距模块。但是在第十届蓝桥杯比赛的时候却意外出现了频率计模块,导致很多选手因为没有充分准备相应的模块而摔跟头。所以我认为,超声波模块还是有可能出现在省赛当中的,毕竟蓝桥杯的题目正在变得越来越灵活多变了。下面我来介绍一下超声波模块的代码编写!
- 超声波模块硬件电路
我们看到有2个电路分别控制JS1和JS2,就是接收和发射模块JS1由N B1控制JS2由N A1控制
然后这2个口由JUMP6跳线组控制,所以要把跳线帽接到13&24所以我们只要控制P1^0 P1^1。
- 代码设计
由单片机产生12个40KHZ的脉冲信号,加到超声波探头的引脚上,使内部的压电晶片产生共振,向外发射超声波。 因此程序方面,需要有超声波发生程序。
接收原理:当接收到38k的发射信号后,接收引脚将由高电平变为低电平,因此程序的设计可以启用一个定时器,在发射的时候清空定时器的初值,然后开始发送超声波并且开启计时,当引脚电平变为低电平的时候则结束计时,并通过定时器来计算发射到接收的时间,用测试距离=(高电平时间*声速(340M/S))/2;即可计算出距离!
大家可以先参考一下标准程序模板(独立按键)的代码块:
http://blog.csdn.net/qq_44629819/article/details/107937826
接下来以上述代码块为蓝本,写下超声波模块的实现程序。
#include <STC15F2K60S2.H>
#include "intrins.h"
#define u8 unsigned char
#define u16 unsigned int
#define NO_KEY 0xF0
#define KEY_STATE0 0
#define KEY_STATE1 1
#define KEY_STATE2 2
#define LED0 0x00
#define LED1 0x01
#define LED2 0x01<<1
#define LED3 0x01<<2
#define LED4 0x01<<3
#define LED5 0x01<<4
#define LED6 0x01<<5
#define LED7 0x01<<6
#define LED8 0x01<<7
#define NO_THING 0x00
#define BUZZER 0x40
#define RELAY 0x10
#define BU_RE 0x50
/*********added*********/
sbit TX=P1^0;//定义反射脚
sbit RX=P1^1;//定义接收脚
/*********added*********/
/***************************************本地常量声明**********************************/
u8 code smg_du[]={//标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e};
u8 code smg_point[]={0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};//0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//位码
u8 code led_du[]={LED0,LED1,LED2,LED3,LED4,LED5,LED6,LED7,LED8};
u8 code bure_du[]={NO_THING,RELAY,BUZZER,BU_RE};
void Timer0Init(void) //1毫秒中断@12.0MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初值
TH0 = 0xD1; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
}
/*********added*********/
//定时器1;16位自动重装载;12T模式;12.000MHz//
void Timer1Init(void) //该定时器用来记录时间,没有进入中断
{
AUXR &= 0xBF; //12T
TMOD |= 0x00; //设置定时器模式//特别注意,需要自己写TMOD |= 0x00;
TL1 = 0; //设置定时初值//特别注意,需要自己写0
TH1 = 0; //设置定时初值//特别注意,需要自己写0
TF1 = 0; //清除TF1标志
TR1 = 0; //定时器1开始计时//特别注意,需要自己写0
}
/*********added*********/
unsigned char key_scan()
{
static u8 key_state=KEY_STATE0;//设置按键状态为全局变量,方便函数外读取。
u8 key1,key_temp,key_val;
P30=1;P31=1;P32=1;P33=1;P44=0;
if(P30==0) key1=0x10;
if(P31==0) key1=0x20;
if(P32==0) key1=0x30;
if(P33==0) key1=0x40;
if((P30==1)&&(P31==1)&&(P32==1)&&(P33==1)) key1=0xf0;
key_temp=key1;
switch(key_state)
{
case KEY_STATE0:
if(key_temp!=NO_KEY)
{
key_state=KEY_STATE1;
}
break;
case KEY_STATE1:
if(key_temp==NO_KEY)
{
key_state=KEY_STATE0;
}
else
{
key_state=KEY_STATE2;
switch(key_temp)
{
case 0x10:key_val=7;break;
case 0x20:key_val=6;break;
case 0x30:key_val=5;break;
case 0x40:key_val=4;break;
}
}
break;
case KEY_STATE2:
if(key_temp==NO_KEY)
{
key_state=KEY_STATE0;
}
break;
}
return key_val;
}
/*********added*********/
void Delay12us() //@12.0MHz(进行一个12微秒的延时)
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
/*********added*********/
/*********added*********/
void send_wave(void)//发射2个方波
{
u8 i;
for(i=0;i<2;i++)
{
TX=1;
Delay12us();
TX=0;
Delay12us();
}
}
/*********added*********/
bit key_flag=0;//按键读取标志位
u8 key_value;//按键键值
u8 led_choose=0;//LED1灯选择
u8 bure_choose=0;//ULN2003选择
/*********added*********/
bit sonic_flag=0;//超声波发送标志位
unsigned int distance;//存储超声波检测到的距离数值
u8 smg_sonic[8];//数码管显示距离
/*********added*********/
void main()
{
Timer0Init();
Timer1Init();
while(1)
{
if(key_flag)
{
key_flag=0;
key_value=key_scan();
switch(key_value)
{
case 4: break;
case 5: break;
case 6: break;
case 7: break;
}
}
/*********added*********/
if(sonic_flag)
{
sonic_flag=0;
send_wave();
TR1=1;//定时器1打开
while((TF1==0)&&(RX==1));//满足接收到了信号并且定时器1计数值未溢出
TR1=0;//定时器1关闭
if(TF1==1)//若程序是因为定时器1计数值溢出,那么将对应标志位置为0
{
TF1=0;
distance=999;
}
else//正常情况下
{
distance=(unsigned int)(((TH1<<8)|TL1)*0.017);//将定时器1中的计数值转换为十进制的距离数值
}
TH1=0;//清空寄存器数值
TL1=0;//清空寄存器数值
}
smg_sonic[0]=smg_du[distance/100];
smg_sonic[1]=smg_du[distance/10%10];
smg_sonic[2]=smg_du[distance%10];
/*********added*********/
}
}
void timer0() interrupt 1 using 1
{
static u16 key_count=0,display_count=0,i=0,sonic_count=0;
/***************************************按键定时器中断**********************************/
key_count++;
if(key_count==10)
{
key_count=0;
key_flag=1;
}
/***************************************显示定时器中断**********************************/
display_count++;
if(display_count==1)
{
P0=~led_du[led_choose];P2=0x80;P2=0x00;
}
if(display_count==2)
{
P0=bure_du[bure_choose];P2=0xA0;P2=0x00;
}
if(display_count==3)
{
display_count=0;
P2=0XE0;P0=~0X00;P2=0X00;
P2=0XC0;P0=smg_wei[i];P2=0X00;
P2=0XE0;P0=~smg_sonic[i];P2=0X00;//显示距离
i++;
if(i==8) i=0;
}
/*********added*********/
sonic_count++;
if(sonic_count==50)//每50ms进行一次超声波发送·
{
sonic_count=0;
sonic_flag=1;
}
/*********added*********/
}
定时器0:定时器0的作用是为固定的时间间隔进行超声波测量;因为如果两次间隔时间太短会影响测量的;定时器1:定时器寄存器TMOD 的复位值为0x00;所以定时器1工作在计时 方式0(16位自动重装)而且 TCON的复位值也是0x00;即TH1==TL1=0;所以定时1不用配置也能用;因为我的代码没有配置定时器1;所以我啰嗦的写了这一条;当然自己可以配置定时器1的完全不影响使用的;