不知不觉中,已经到了8月,时间过的好快好快,好像写上一篇EDN博客时,还是不久的事,但却已是上月1号的事了!
7月,一直在学着单片机,零零星星的又学懂了一些东西,程序写得慢慢的有点个人风格和习惯了,一切都在悄无声息的慢慢地变化着,当然,我也一直在成长的路上,,慢慢的爬行着,,,
其中,最令本人幸福的,当属于用IAP15F2K61S2单片机写出超声波测距了!
接触IAP15F2K61S2也就一个月吧,以前一直都在用着STC或者AT的51,都不太知道单片机内各个周期的问题,也不太注意,例如机器周期,时钟周期,指令周期啊,也就是在郭天祥的单片机书上看几下而已,当然,也不知道单片机分频等的问题,而IAP15F2K61S2刚接触时,还是按一般的51延时,然后发现,例如像写DS18B20测温时,在一般51上能显示的,在IAP15上显示不了了,直到某天,孤岛圆梦点醒了我,才开始对IAP15F2K61S2有所感觉!才明白:
1T 单片机中,一个机器周期=1个时钟周期
12T单片机中,一个机器周期=12个时钟周期
以下为个人学习过程中一些认识,如有不对,欢迎指点和批评!
-----------------------------------------------------------------------------------------------------------------
本人用的超声波模块(上图),本人查了下,发现淘宝上卖的,这类型的超声波模块的使用都基本相同
模块有5个端口,分别为 VCC:供5V电源;GND:为地线; Trig:触发控制信号 输入端; Echo: 回收信号输出端; OUT: 开关量输出(可不接)
超声波模块工作原理:
超声波模块至少需要单片机提供一个10us以上的脉冲,(也就是给Ttig口)才能触发其工作,然后,模块内部将发出8个40KHZ周期电平,并检测回波,若有回波,信号则输出回响信号(也就是Echo输出信号)
回响信号的脉冲宽度与所测的距离成正比,由此通过发射信号到收到回响信号时间间隔可以算出距离
距离=高电平时间*声速(340M/S)/2;
说起给Ttig口提供的至少10us以上脉冲,我深有体会,当初对IAP15F时序的不了解,始终给不对延时时间,当然,也不懂算出具体的时序,直到后来突然想起STC-ISP烧录软件可以自动生成延时C程序,才解决了微妙延时的问题,同时也发现,宏晶这个烧录还是蛮方便的呀!
以下为生成的微妙延时C程序,这延时的准确性,太重要了,绝对了,能否正确使用模块
/**************************************************************
函数功能: 延时 1乘于x 微妙
函数入口: x
函数出口: void
**************************************************************/
void delay1us(uint x) // 12.000MHz晶振
{
while(x--) // x*1 us
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
解决了微妙延时的问题了,离正确超声波已经算是成功一半了吧
下面说超声波初始化本人遇到的一些小问题,以下为C程序
/**************************************************************
函数功能: 超声波初始化函数
函数入口: void
函数出口: void
**************************************************************/
void Init_distance()
{
TMOD = 0x01; // 定时器0为工作方式1
ET0 = 1; // 开定时器0中断
IT1 = 1; // 启动外部中断0
Trig = 0; // 输入端
// Echo = 0;
}
此处Echo给0,是不对的, Echo是不需要人为去操作的,超声波内部自动去处理,也就是说,如有信号返回,则Echo自动给0,这里当时本人使用时并不懂,同时掉程序时也很郁闷,明明程序都全对了,使用时序也对了,可为什么还是不能测距呢?直到最后的最后,本人才发现,才想明白啊!
以下是超声波获取距离程序及注释:
/***********************************************************
函数功能: 获取距离函数
函数入口: void
函数出口: distance(距离)
***********************************************************/
bit flag; //标志位
float get_distance()
{
float distance;
flag = 0;
Trig = 1; // 输入端拉高
delay1us(20); // 给20us延时触发信号
Trig = 0; // 输入端拉低,拉高—延时—拉低:启动超声波,发出超声波信号
while(Echo==0); // 等待超声波的自动检测返回信号,有信号echo输出一个高电平
EA = 1; // 开总中断
TR0 = 1; // 启动定时器0
EX1 = 1; // 开外部中断1
delayms(30); // 延时等待结果(20—100适合)
if(flag==1) // 计算完成后,置标志位为1,证明超声波信号已经返回完成
{
time=timeH*256+timeL; // 计算距离的公式
distance=time*0.0180;
}
else
distance=0;
return distance; //返回计算所得的距离,用于主函数处理后1602显示
}
void T0_time(void) interrupt 1 // 定时器0
{
TH0 = 0; // 重装初值
TL0 = 0;
flag = 0; // 还未完成 所以给标志位置0
}
void external_1(void) interrupt 2 //外部中断1
{
EX1 =0; // 关闭外部中断1
TR0 =0; // 关闭定时器0
EA =0; // 关总中断
timeH=TH0;
timeL=TL0;
TH0 = 0; //再次给定时器0重装初值
TL0 = 0;
flag = 1; //完成了,给标志位置1
}
计算距离公式中,乘于0.0180这个值,本人测量过,误差为1cm左右,但很奇怪,有时候同样条件下,误差却为1cm--5cm之间,同时本人也试过 0.0130—0.0200之间的值,都不如0.0180 理想,在此,如有大师知道此现象原因,望指点一下吧!
算出距离将由get_distance()函数值distance返回主函数,同时调用1602子函数
主函数和1602函数摘要如下:
uchar distance_buf[17]; //定义一个数组
void main()
{
float distance;
Init_lcd();
Init_distance();
while(1)
{
distance=get_distance();
sprintf(distance_buf,"Distance:%3.1fcm",distance);
Lcd_showstring(0,0,distance_buf); // 显示温度
}
}
以下为主函数调用1602程序
/***********************************************
函数功能: 在LCD指点位置显示字符串
入口参数: hang lie string
出口参数: void
***********************************************/
void Lcd_showstring(uchar hang,uchar lie,uchar *string)
{
uchar i;
Write_command(0x80+hang*0x40+lie); // 显示第几行第几列
for(i=0; string!='\0'; i++) // '\0'为字符串结束符号,如果字符串string没有结束,继续for循环
Write_data(string);
}
最后:非常希望路过的朋友们,大师们,如有发现本人有 写错的地方,或者程序写得不规范处,真诚恳请您的指点和批评,我坚信,您的批评将是我成长的推力!!!谢谢!!!
用户377235 2014-5-11 21:32
用户377235 2013-10-1 17:45
能开源吗?
644398774_263592779 2013-8-31 00:21
644398774_263592779 2013-8-31 00:20
用户377235 2013-8-29 19:50
用户444575 2013-8-21 18:57
644398774_263592779 2013-8-21 18:53
用户444575 2013-8-20 18:44
644398774_263592779 2013-8-14 22:58
飞言走笔 2013-8-14 22:44