蓝牙测距单片机

2018-05-19 22:38:41 Prediction_185 阅读数 912

引语:本篇将介绍如何用51单片机的蓝牙舵机控制超声波模块测距,并将距离在开发板的数码管上显示

你通过学习上两篇的文章,应该可以实现这些功能了,那么下面我们要做的就是将他们组装起来。

2014-01-10 16:59:49 silveryhand 阅读数 11433
今天到了第一批制作四旋翼飞行器用的开发板和传感器,实现了最简单的ArduinoUNO和Android手机间的蓝牙串口通讯和超声测距传感器的试用。

Arduino <wbr>UNO连接蓝牙模块与安卓手机通讯教程

最左边的是HC-06蓝牙模块,中间的一对金属圆柱是超声测距的传感器,最右是ArduinoUNO开发板。然后操作者点按手机中串口调试助手上的按钮发送信号,并接收发回的传感器数据。下图键盘左上角的测量按键会通过蓝牙串口向ArduinoUNO发送一个信号,单片机收到信号激活超声传感器,并读回数据,再通过蓝牙传回手机显示。图中前一部分数据是传感器测得的桌面到屋顶的距离,最后一个是桌面到地面的距离。

Arduino <wbr>UNO连接蓝牙模块与安卓手机通讯教程

1 蓝牙模块的调试

我选择的蓝牙模块是HC-06,相关资料下载:百度云下载
第一步,连线:
  RXD--------TX->1
  TXD--------RX<-0
蓝牙模块  GND--------GND   Arduino UNO
  VCC--------3.3V

第二步,修改蓝牙模块的名字、密码和波特率,因为我的应用中对带宽要求不高,所以波特率还是选择默认的9600。修改名字和密码用蓝牙模块的AT指令,因为没有USB转串口的片子,我是用单片机执行这段代码,更多代码可以在手册里查看:
void setup()
{
  
Serial.begin(9600);
Serial.print("AT");
delay(2000);
Serial.print("AT+NAMERon_bluetooth");
delay(2000);
Serial.print("AT+PIN5274");
}
void loop()
{
delay(1000);
}
注意:上传代码的时候必须先拔掉接蓝牙模块接在串口上的两条线,程序写入之后按下板上的reset键使代码执行一遍。
第三步,在手机上下载蓝牙串口助手,搜索先前设置的蓝牙设备,这个app的使用很简单,不多做介绍。




至此,蓝牙模块配置完成,用法与串口完全一样,基本上属于即插即用。


2 超声模块HC-SR04

主要参数:1 使用电压:5V 2 静态电流:小于2mA 3 电平输出:0-5V
        4 感应角度:不大于15度 5 探测距离:2cm-450cm
使用方法:控制口Trig发一个10US以上的高电平,就可以在接收口等待高电平输出.一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,就可以得到测量的距离了。

第一步,接线
  TRIG--------PIN 2

  ECHO--------PIN4

超声模块 GND---------GND   Arduino UNO

  VCC---------5V



第二步,烧写入以下代码,



#define TRIG_PIN 
#define ECHO_PIN 
char val; 
int cm; 
void setup()
{
   Serial.begin(9600);
   pinMode(TRIG_PIN,OUTPUT);
   pinMode(ECHO_PIN,INPUT);
}
void loop()
{
   if((val = Serial.read()) == 'c')
   {
    
     digitalWrite(TRIG_PIN, LOW);
     delayMicroseconds(2);
     digitalWrite(TRIG_PIN,HIGH);
     delayMicroseconds(10);
     digitalWrite(TRIG_PIN, LOW);
     cm pulseIn(ECHO_PIN,HIGH) / 60;
     Serial.print(cm);
     Serial.println(" cm");
   }
}
这时候手机与蓝牙模块完成配对,如代码中所写,手机端串口发送'c',获得超声测距的数值。
2018-01-06 22:16:55 lipeng08 阅读数 28988

1. 简介

这是2016年底两周时间做的一个蓝牙小车,它分为上下两篇,本文是上篇。原本是发在了http://bbs.elecfans.com/ 的,不过由于我的博客都在CSDN上,因此我就把它们重新复制到这里来了。

1.1 相关的博客和代码

原文地址
源代码地址
小车手机端代码 — 下篇博客,此为后续版本,实现了手机端的蓝牙程序控制小车运动以及接收小车状态并展示。

1.2 想法来源

最初的想法是做一个红外遥控的装置,链接地址。只需要前进和停止,二路遥控,想使用模拟电路搭建,但最后也没能完成,这个想法依然在,现在只能留带以后是否有想法再做了。

第二个想法是想做一个小车,小车的功能如下: 前进,后退,转弯,遥控控制,自主智能运转。 上某宝买了一个小车的底座(4驱动的,带电机), 买了两个L298N驱动模块用来驱动小车,买了蓝牙模块(HC05)用来充当遥控。

2. 实践篇

2.1 电路焊接

首先根据51单片机的最小系统的电路图,焊接了一个最小系统板,使用的STC89c52的单片机(晶振6Mhz,带复位电路,复位指示灯显示),为了便于测试,又焊接了一个发光二极管连接一个I/O口,用于测试最小系统。

2.2 最小系统测试

开始测试最小系统,不过我很多年没有用过keil和下载器了,就上网寻找了一下关于这方面的帖子,并作了总结。要测试最小系统,首先需要编译代码的工具(我用的keil),下载代码到单片机的工具(stc-isp),usb转ttl硬件设备(某宝上2块多钱买的),串口调试助手(使用的是单片机多功能调试助手PortHelper.exe),于是从网上下载了keil4破解版本,stc-isp下载软件,单片机多功能调试助手三个软件。

注意:
下面的步骤2.2.1和2.2.2是用于测试USB转TTL设备,而2.2.3-2.2.5是用于单纯的最小系统测试。那为何需要用USB转TTL设备呢?在解释之前,先介绍我们的小车总体控制路径:

空气
手机端按下方向按钮
手机发送命令到手机蓝牙
单片机串口蓝牙设备
从蓝牙串口读取
单片机串口
单片机处理程序接收到串口命令
单片机处理命令

可以看出,上述的路径无需USB转TTL的参与,我们之所以要使用USB转TTL是出于测试蓝牙的需要。考虑一种情况:蓝牙和单片机的串口连接之后,若单片机的控制程序无法驱动蓝牙正常工作,我们将无法判断是单片机方面的问题(例如代码或者连线等),还是蓝牙本身的问题。 因此,为了尽可能隔离错误域,我们可使用这个神奇的USB转TTL设备,使其直连蓝牙模块,并使用电脑的串口调试助手,驱动USB转TTL,进而驱动蓝牙模块,从而可确定蓝牙模块的好坏。其测试流程:

USB口连接
导线相连接
电脑
串口调试助手
USB转TTL
蓝牙串口模块

不过要使用以上的方案,我们首先要测试USB转TTL模块是不是好的,好绕口。

2.2.1 USB转TTL设备连接电脑端是否可识别

测试usb转ttl是否可用(就44个引脚,5VGNDTXRX)
打开串口调试助手,设置波特率,打开,发现打开失败,比较郁闷,为何呢? 极有可能是串口号不对,于是打开我的电脑-》管理-》设备管理器,找到串口的条目,查看它的串口号,我的串口号竟然是12,在串口调试助手中压根没有1212。于是电脑给设备重新设置串口号,重新打开,OK。 如何测试usb转ttl呢? 我的想法是如果发送数据的话,对应的tx引脚应该有信号,如果将TX和RX连接到一起,那么发送出去的应该自己可以接收到。我没有示波器,就简单的使用万用表量它的TX引脚的电压,点击发送按钮,发现TX引脚的电压有波动即可。

2.2.2 USB转TTL与单片机连接

将usb转ttl的四个引脚接入到单片机的对应引脚即可(其实就是VCC接VCC,GND接GND,TX接RX,RX接TX)。没有采用外部供电,直接利用usb转ttl进行的5v供电

2.2.3 在keil中写代码,对单片机的某一个I/O进行翻转电平的操作

代码如下

sbit LED=P0^0;
while(1){
    LED = !LED
    Delay10ms(100);
}

2.2.4 编译程序,生成HEX文件

使用keil创建相应的51工程,加入上述代码以及头文件,并对程序进行编译,生成相应的hex文件。

2.2.5 烧录程序

打开stc-isp下载工具,选择单片机型号,hex程序位置,点击下载即可,如果识别了单片机的话,会出现给MCU重新上电的字样,这个时候只需要关闭再打开MCU的电源开关即可,就会出现烧写程序的过程。

2.2.6 用万用表量P0^0口

查看电压是否1秒一次变化即可

2.3 最小系统测试篇遇到的问题,回忆篇

51单片机的电源供电问题,忘了接单片机的VCC引脚了(如果是这方面的问题,就检查几个关键地方,vcc和地接好了吗,tx和rx接好了吗,晶振接好了吗,复位电路先不用管,我是使用的万用表一个个的量的)
晶振的电路没焊好(万用表搞定)
usb转ttl找不到串口(软件问题的话,容易解决,也有可能是usb转ttl硬件有问题,驱动没有安装成功,导致识别不了硬件)

3. 蓝牙模块工作篇

从某宝上花了17大洋买了一个HC05蓝牙主从模块,有6个引脚(VCC,GND,TX,RX,AT,STATUS),前4个引脚与usb转ttl的接法相同(注意RX,TX交叉接线接入到单片机),AT和STatus引脚是我自己命的名字。 AT引脚高电平有效,用于蓝牙模块进入AT状态(所谓AT状态,即是其他程序可以通过它的引脚向蓝牙模块发送AT控制命令,例如设置波特率,查看版本号,设置主从模式),AT引脚悬空默认为低电平。Status引脚用于显示配对的状态(配对成功输出高电平,未配对输出低电平)

3.1 蓝牙模块测试篇

第一步:蓝牙模块既然包含串口,那么它应该可以跟usb转ttl直接连接,使用电脑向蓝牙模块发送命令。于是连接蓝牙模块与usb转ttl的对应引脚。
第二步:将AT引脚悬空,使用手机搜索周围的蓝牙设备,发现有HC05的蓝牙(因为这个蓝牙模块默认是从模块,可以被收到)
第三步:将AT引脚拉高电平,使其进入AT状态(按照文档描述,如果上电之后再置位AT,指示灯无变化,依旧是,如果上电之前拉高AT,指示灯转为1秒一次),然后通过电脑串口发送AT+VERSION?(注意需要换行)查看版本号,使用AT+UART?查看波特率(默认9600,不带校验)
此文档有用: ATK-HC05-V11用户手册_V1.0.pdf (请自行搜索)
第四步:实验了一下,我的模块有问题,就是上电之前拉高AT,模块不接受AT命令,只有上电后拉高AT才有用,不过不影响使用。
第五步:将蓝牙模块和usb转ttl连接后,AT保持悬空,即蓝牙模块为从模块,手机安装蓝牙串口助手,打开手机蓝牙,然后搜索HC05,配对,然后打开手机端的蓝牙串口助手软件,向HC05发送消息,如果蓝牙模块工作正常,那么电脑端的串口调试助手应该收到手机发送的消息。同样的也可以通过电脑端发送消息,到手机端。

消息传递流程如下:
手机端蓝牙串口助手 -> 手机蓝牙 ->空气 -> HC05蓝牙模块 -> USB转ttl模块 -> 电脑的串口调试助手,反过来也是可行的(注意线路连接方式都是RX与TX交叉连接)

3.2 蓝牙模块与单片机集成调试篇

上面的测试已经证明了蓝牙模块是可以发送接收手机端消息的,现在开始将蓝牙模块与单片机的TX,RX接口连接起来,通过程序控制蓝牙模块与手机蓝牙进行沟通,从而达到利用手机蓝牙进行遥控的目的。

main函数如下,主要设置串口波特率,以及开启串口中断

//PCON:SMOD位默认为0,串行口波特率加倍位
PCON = 0x80;                //SMOD=1;

TMOD=0x20;          //8位自动加载计数器
//TH1=0xfd;  TL1=0xfd;   for 11.0592MHZ and SMOD=0, 
TH1 = 0xf3;//2400bps
TL1 = 0xf3;
TR1=1;    // T1
//SCON: 0x50=SM0=0, SM1=1,REN=1
REN=1;   
SM0=0;
SM1=1; //串口
EA=1; //中断
ES=1; 

串口中断函数
void serial() interrupt 4
{
         char sbuf;
         sbuf=SBUF;
         switch (sbuf)
         {
                 case 'f': direc=4; break;
                 case 'b': direc=5; break;
                 case 'l': direc=6; break;
                 case 'r': direc=7; break;
                 case 's': direc=-1; break;
                 default : LED = !LED; //LED为一个I/O引脚,控制发光二极管
         }
         RI=0;
} 

3.3 遇到的问题:

利用手机给蓝牙HC05发送消息,如果不是switch中的几个case的话,那么LED灯会明暗变化,但是刚开始的测试却始终不如意。而后仔细查看了代码,并没有发现什么错误,后来怀疑是波特率的问题,因为我的晶振是6Mhz的,蓝牙模块的波特率是96009600

采用波特率倍频,我手动计算了一下: 610000002/12/32/9600=3.2556*1000000*2 / 12 / 32 / 9600 = 3.255若对其取整为33. 然后使用3反代入到此式子中,我们有
610000002/12/32/3=10416.7 6*1000000*2 / 12 / 32 /3 = 10416.7 它与96009600的波特率相差14001400多,这个似乎差距太大了。我又尝试了其他几个参数,像48004800, 1920019200, 3840038400都相差挺大的,估计就是这个原因。于是继续尝试,发现24002400的话,相差不多。
610000002/12/32/2400=13.026*1000000*2/12/32/2400 = 13.02 ,然后使用1313代入进去,其波特率结果为2403.82403.8,与24002400的波特率相差很小,估计是可以用的,但是看蓝牙模块的文档,发现它说不支持24002400的,我不甘心,就使用usb转ttl模块(有没有发现此模块是不是很有用?)设置了一下24002400,没想到AT命令还真的返回OK了,单片机程序也可以正常工作了。

4. 小车驱动篇

将两个L298N模块与单片机的P2口直接相连(小车4轮驱动,每个电机需要两个输入引脚,以及一个使能引脚,那就是12个引脚,我刚开始并不想支持调速的功能,因此使能引脚直接高电平了,就连接了8个I/O口)。注意L298N的GND引脚一定要和单片机的GND共地。

关于L298N: 它的EN引脚用于使能,EN为高电平,才使能。另外两个输入引脚IN1,IN2根据电平的组合变化会有4种情况(00,10,01,11),电机相应的在00和11停止(这个停止是带电的,类似于锁死的感觉),在10正转,01反转。可以直接使用单片机的VCC和GND连接L298N的IN1和IN2,同时将EN端接VCC,看电机转不转就可以测试L298N模块了。

编写程序,控制轮子的正转,翻转,停止等。基本上就是以下的这种代码

void wheelForward(uchar which)
{
        switch(which)
        {
                case 1:
                {        
                        wheel_1_1 = 0;
                        wheel_1_2 = 1;
                        break;
                }
                case 2:
                {
                        wheel_2_1 = 0;
                        wheel_2_2 = 1;
                        break;
                }
                case 3:
                {
                        wheel_3_1 = 0;
                        wheel_3_2 = 1;
                        break;                
                }
                case 4:
                {
                        wheel_4_1 = 0;
                        wheel_4_2 = 1;
                        break;
                }
        }
}

4.2 遇到的问题

问题1: 刚开始L298N直接连接P0口,死活不转,而直接引出高低电平到某一个电机的IN1,IN2口,电机正常运转。于是猜测是I/O有问题,使用万用表测量,发现P0的I/O在输出高电平的时候,根本不是高电平,而后发了帖子,询问了一下才知道P0口在高电平是呈现高阻态的,需要外部焊接电路加上拉电阻才可工作。我不想焊接过多的电路,就将其I/O换到P2口,可以正常工作,帖子链接地址

问题2: 我使用的是路由器的9v直流电源,使用其带动两个L298N,同时将L298N的输出的一个5V高电平接到单片机上给单片机供电,启动4轮驱动,电机只会翁的一声,然后啥也没有,二轮驱动也不转。 上网查看了不少资料,基本上都是电源功率过低,需要将单片机与L298N分别供电才可以。 于是使用笔记本的usb口给单片机供电,使用9v直流电源给电机供电,比刚才好了一些,两轮可以转,但是4个轮子还是转不了。没办法,想到自己有一个小的卡片相机,有镍氢电池8节,然后上网买了一个电池盒,装上去,电机转的吼吼叫,同时L298N给单片机供电也没问题。

问题3:关于L298N同时给单片机供电的问题,大家可以在启动轮子转动的时候量一量单片机的电源电压,会发现在电机启动的一刹那,单片机的电压有一个瞬时的拉低,这样单片机就会复位了。

5. 蓝牙遥控小车汇总篇

第一步:部署小车,L298N,镍氢电池盒,蓝牙模块组装到一起
第二步:编写代码,本来可以使用EN口进行调速控制的,但是考虑到还需要使用额外的I/O口,就先不打算做了。

代码完成的功能:

小车前进,后退,停止,左转,右转
小车单个轮子的转动(用于测试)
小车当前状态的获取(用于后期给小车增加其他模块的时候,例如温度模块,就可以读取温度了)
小车命令帮助

代码思路:

首先完成单个轮子的控制
再完成小车的控制
再加入串口接收中断,收到不同命令,设置方向变量
main程序读取方向变量控制不同的方向

6. 思路篇

一些比较有特点的思路:
思路1:一个棘手的问题想实现这样的功能: 用户按键,小车才走,用户松开按键,小车停止。
我的想法如下: 小车使用一个定时器T0,控制定时器的延时时间为100ms,用户每发送一个前进信号,小车会前进100ms,但是这100ms内小车还需要能够响应外部的命令。例如如果用户在t=0ms发送前进命令,然后在t=50ms发送左转命令,小车能够立刻左转,而不是继续前进100ms,然后才执行左转的命令。基本的代码思路是用户的每一个命令,都会重置timer0,timer0的超时中断函数会将小车停止。这样用户只要以连续的小于100ms间隔发送前进命令,小车就会一直前进,也就是说timer0的中断没有执行,如果用户间隔100ms还没有发送命令,那么小车停止。 当前我使用的蓝牙串口助手它的按键不支持连续发送,只能按下松开手,才会发送消息,这样我现在就把时间间隔设置为1000ms,用户只要以小于1000ms的间隔连续按键,小车就会一直前进,如果不按键,小车会继续前进1000ms才会停止。 后期打算找到蓝牙串口调试助手的源代码,修改它的源代码,设置成如果用户按下不丢,小车前进命令能够一直发送。

思路2: 既然有了手机蓝牙,那么小车再想展示一些状态信息,就没必要使用像1602,12864之类的东东了,直接定时发给手机蓝牙模块就OK了。我现在并没有实现定时发送,不过支持了命令获取的功能。 当用户发送命令h到单片机,单片机会返回一个帮助界面,告知如何控制小车,例如"f"控制小车前进,"b"控制小车后退,当用户发送命令i到单片机,单片机会返回小车的一些状态信息,我当前只返回了一些简单的变量状态(后面想加入距离,温度,光敏都是可行的)。

思路3:有了蓝牙,这个小车就可以被我们随心所欲的控制了。你既可以推命令到单片机,控制它,你又可以把单片机内部的当前状态拉出来。单片机本身又可以定期将它的状态向你的手机进行推送。这个我感觉还是很好玩的,有了这个代码的基本框架,后面有可能的话像实现一个小车的扩展功能,加上红外对管让它不撞墙,加上超声波让它测距,加上麦克风让它向着声音跑,加上人体感应让它做一个跟屁虫,甚至于加上一个智能化点的程序,让它能够在一个屋子里随便的转悠,然后记录屋里的情况。还想做的是加入一个wifi模块,能将它的状态信息上传到路由器里面(手里有一个坏的路由器华为hg255d,正在修理中,还没有摸清楚如何修),这样远在千里之外都可以访问小车上面传感器的情况了。还想加的是一个摄像头模块,不过单片机的处理能力有限,摄像头的解码对它是个大问题,估计很难办到(手头有优龙fs2401开发板,刚修好它的电源模块,正在研究中,不过前天它突然bios引导不起来了,也不知道是什么问题,关于这种arm的东西,还没有接触过,完全不懂刷bios,uboot等等的东西,看情况是要重新刷bios了)。

后记:
修改于2018年12月24日午饭后。此博客原本是直接从电子爱好者中把自己写过的内容粘贴过来,也没使用markdown,文章内容显得很乱,今天突然看到了,就花了会简单调整一下,希望能给大家一些更好的阅读体验。

2018-05-19 22:38:02 Prediction_185 阅读数 1241

                                                    超声波模块篇

引语:本篇将介绍如何使用超声波模块。
最终目的:将51开发板与超声波模块相连,超声波模块的echo引脚将电信号返回给单片机,通过程序判断距离,然后将距离显示在数码管上。
实现效果需要达到的目标:
1.了解SR-04超声波模块的工作原理,并会编写相应程序。

2.将距离显示到数码管上。

材料:51单片机开发板,SR-04超声波模块,杜邦线若干。

51单片机开发板 

我使用的是宋雪松的51开发板,如图。


他的数码管工作原理,我这里就不做过多解释了。

SR-04超声波模块 


接线方式:vcc接5v

                trig接P2^0口

                echo接P2^1口

                GND接单片机上的GND

如图是SR-04超声波模块

#include"reg51.h"
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

sbit RX=P2^1;
sbit TX=P2^0;
unsigned int  time=0;
unsigned int  timer=0;
unsigned char posit=0;
unsigned char i=0; 
unsigned long S=0;
bit      flag =0;
//--定义使用的IO--//



//--定义全局变量--//
unsigned char code DIG_CODE[17]={
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
unsigned char disbuff[4]	   ={ 0,0,0,0,};
void delay20us(void)   //?? -0.46875us
{
    unsigned char a,b; 
    for(b=3;b>0;b--)
        for(a=1;a>0;a--);
}

/*******************************************************************************
* 函 数 名         : DigDisplay
* 函数功能		   : 使用数码管显示
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

/********************************************************/
    void Conut(void)
	{
	 time=TH0*256+TL0;
	 TH0=0;
	 TL0=0;
	
	 S= (long)(time*0.17);     //算出来是CM
	 if((S>=4000)||flag==1) //超出测量范围显示“ERR0”
	 {	 
	  flag=0;
	  disbuff[0]=0x7b;	   //“-”
	  disbuff[1]=0x72;	   //“-”
	  disbuff[2]=0x72;	   //“-”
	  disbuff[3]=0x3f;	   //“-”
	 }
	 else
	 {
	  disbuff[3]=DIG_CODE[S%10000/1000];
	  disbuff[2]=DIG_CODE[S%1000/100];
	  disbuff[1]=DIG_CODE[S%100/10];
	  disbuff[0]=DIG_CODE[S%10/1];//个位
	 }
	}
/********************************************************/
     void zd0() interrupt 1 		 //T0中断用来计数器溢出,超过测距范围
  {
    flag=1;							 //中断溢出标志
  }
/********************************************************/
   void  zd3()  interrupt 3 		 //T1中断用来扫描数码管和计800MS启动模块
  {	
	static unsigned char i=0;
	 TH1=0xf8;
	 TL1=0xCD;
	  P0 = 0xFF;   //显示消隐
    switch (i)
    {
        case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=disbuff[0]; break;
        case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=disbuff[1]; break;
        case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=disbuff[2]; break;
        case 3: ADDR2=0; ADDR1=1; ADDR0=1; i=0; P0=disbuff[3]; break;
       /* case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=disbuff[4]; break;
        case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=disbuff[5]; break;*/
        default: break;
    }
	 timer++;
	 if(timer>=100)
	 {
	  timer=0;
	  TX=1;			                //800MS  启动一次模块
		delay20us();
	  TX=0;
	 } 
  }
/*********************************************************/

	void  main(void)

  { 
	ENLED=0;
	ADDR3=1;
  TMOD=0x11;		   //设T0为方式1,GATE=1;
	TH0=0;
	TL0=0;          
	TH1=0xf8;		   //2MS定时
	TL1=0xCD;
	ET0=1;             //允许T0中断
	ET1=1;			   //允许T1中断
	TR1=1;			   //开启定时器
	EA=1;			   //开启总中断

	while(1)
	{
	 while(!RX);		//当RX为零时等待
	 TR0=1;			    //开启计数
	 while(RX);			//当RX为1计数并等待
	 TR0=0;				//关闭计数
     Conut();			//计算
	}

  }





2018-05-19 22:37:03 Prediction_185 阅读数 3639

蓝牙舵机篇  

引语  本系列博客将分为三篇来讲解,第一篇讲解如何通过HC-05蓝牙模块控制舵机,第二篇会介绍HC-SR04超声波模块的测距程序,第三篇会将两者组装在一起。


最终目的:通过手机连接蓝牙向单片机发送信号,单片机收到信号后向舵机发送pwm信号,让舵机达到相应的角度。

实现效果需要达到的目标:

1.会使用HC-05蓝牙模块,了解51单片机的串口通信。

2.会用51单片机输出pwm波控制舵机,并校正舵机的误差。

材料:51单片机最小系统、HC-05蓝牙模块、舵机、杜邦线、数据传输线。

51单片机最小系统:如图:


HC-05


如上图所示为蓝牙模块与51单片机的连接方式

那么如何让手机控制单片机呢?

这里我们需要下载一个app,如图


我们可以在聊天栏中,向单片机发送信息,手机将信息分解为ASCII码发给单片机。单片机接受到的也是ASCII码,因此在下面的程序中的case语句中是以16进制来分情况的。

舵机:我们这里所使用的是SG-90舵机 如图


将舵机的橙线连接到P1.2接口

              红线连接到VCC口

              棕色连接到GND

想要控制舵机,那么我们就需要一个周期T = 20ms,高电平的时间(t)等于0.5ms-2.5ms之间的这样一个信号。 
以下是高电平持续的时间(t)与舵机的关系。


t = 0.5ms——————-舵机会转动 0 ° 
t = 1.0ms——————-舵机会转动 45° 
t = 1.5ms——————-舵机会转动 90° 
t = 2.0ms——————-舵机会转动 135° 

t = 2.5ms——————-舵机会转动180° 

但是在实际的应用中,我发现每一个舵机都存在误差,也就是说输出对应空占比的pwm信号,舵机不会精确地转动到相应的度数。因此我将在下面的程序中加以校正。

以下是代码

#include <AT89x51.H>//注意这里的头文件为 <AT89x51.H>

#define SEH_PWM P1_2//舵机PWM口定义

unsigned char SEH_count=5;
unsigned char count=0;


unsigned char T0RH = 0xff;  //T0重载值的高字节
unsigned char T0RL = 0xa3;  //T0重载值的低字节
unsigned char RxdByte = 0;  //串口接收到的字节

void ConfigTimer0();
void ConfigUART(unsigned int baud);

void PWM(unsigned char x)
{
	SEH_count=x;
}

void main()
{
    EA = 1;       //使能总中断
;
    ConfigTimer0();   //配置T0定时1ms
    ConfigUART(9600);  //配置波特率为9600
    
    while (1)
    {  
					switch(RxdByte)
				{
					case 0x31:{
											PWM(5);//手机向单片机发送‘0’,舵机转到0度    
										};break;
					case 0x32:{
										PWM(10);//手机向单片机发送‘1’,舵机转到45度  
										};break;
					case 0x33:{
										PWM(15);//手机向单片机发送‘2’,舵机转到90度  
										};break;
					case 0x34:{
										PWM(20);//手机向单片机发送‘3’,舵机转到135度  
										};break;
					case 0x35:{
										PWM(25);//手机向单片机发送‘4’,舵机转到180度  
										};break;
					case 0x36:{
										;//														
										};break;
					case 0x37:{
									   ;//																
										};break;
					case 0x38:;break;
				}
    }
}
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0()
{
  


    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
    SCON  = 0x50;  //配置串口为模式1
    TMOD &= 0x0F;  //清零T1的控制位
    TMOD |= 0x20;  //配置T1为模式2
    TH1 = 256 - (11059200/12/32)/baud;  //计算T1重载值
    TL1 = TH1;     //初值等于重载值
    ET1 = 0;       //禁止T1中断
    ES  = 1;       //使能串口中断
    TR1 = 1;       //启动T1
}

/* T0中断服务函数,完成LED扫描 */
void InterruptTimer0() interrupt 1
{
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;
	  if(count <= SEH_count) 
    {
     
        SEH_PWM = 1;
    }
    else
    {
        SEH_PWM = 0;
    }

    
    count++;
    if (count >= 200) 
    {
        count = 0;
			
    }
	
}
/* UART中断服务函数 */
void InterruptUART() interrupt 4
{
    if (RI)  //接收到字节
    {
        RI = 0;  //手动清零接收中断标志位
        RxdByte = SBUF;  //接收到的数据保存到接收字节变量中
        SBUF = RxdByte;  //接收到的数据又直接发回,叫作-"echo",
                         //用以提示用户输入的信息是否已正确接收
    }
    if (TI)  //字节发送完毕
    {
        TI = 0;  //手动清零发送中断标志位
    }
}