您当前的位置:首页 VR硬件 增益设备 正文

模拟VR中的风-设计一个蓝牙控制的调频风扇

查看: 3424| 评论: 0 2016-9-10 10:16 PM| 发布者: administrator |原作者: beautifulzzzz

设计一个蓝牙控制的调频风扇

小编一直想整理一篇模拟VR场景中的风的文章,大家应该见过,当你处在VR中的悬崖时,突然感到有风刮过来,当你在VR中进行雪橇滑雪时,风的模拟是一个不得不考虑的事情,所以,接下来 我们假定了一个需求:

1)可调速变频风扇,通过调制pwm波形来驱动电机变速

2)使用蓝牙模块进行控制

3)使用51单片机就可以做风扇的主控cpu了,因为需求不复杂。 

      在本教程中,为了使教程完整,我们直接设计了一个android app 来进行蓝牙控制的演示。

      需要说明的是,如果要进行220V的风扇控制,则需要用到继电器了,52VR.COM正在约稿中,下期会发布上来。


1 预期效果构思

  简单起见我们实现一个可以通过手机App遥控的可调速小风扇。如图1_1,左边手机应用部分主要包括:

1) 1、2、3三个按钮和4用于显示风扇速度的文本框;

2)右边小风扇部分主要包括7风扇模块和8用于显示风扇速度的显示模块;

3)中间的5、6表示双方通过蓝牙进行无线通信实现遥控功能。

             图1_1 预期效果构思

 

2 硬件轮廓勾勒

      其实整个硬件部分都是要我们自己DIY的。如图2_1所示:

1号为51最小系统模块,起总控作用;

2号为电源模块,用于向整个系统供电;

3号为蓝牙模块,用于单片机和智能手机进行蓝牙通信;

4号为电机模块(包括电机驱动电路),用于将电能转换为机械能提供风;

5号为数码管显示模块,用于显示小风扇的当前转速。

    

              图 2_1 硬件轮廓勾勒

 

3 硬件整体电路图设计

  既然轮廓已经勾勒出,接下来要看看我们具体需要哪些元件。首先对于51最小系统模块(如图3_1所示)包括晶振电路和89C52单片机(其实为了简单笔者偷偷地将复位电路去掉了,这样带来的直接后果是程序烧不进去。如果大家也一样学着偷懒,不妨把该最小系统的电源引脚和串口引脚用杜邦线连接到你买来的开发板对应的引脚处,同时把开发板上的单片机拿掉。这样就可以利用开发板上的复位电路模块来实现程序的有效烧写。)

 

             图 3_1 51最小系统

  对于电源模块,我们可以使用可充电的5V锂电池或者用3节1.5V的普通电池凑合。蓝牙模块是HC-05或HC-06。这里电机模块要特别说明下:如图3_2需要用一个ULN2003做驱动,这样控制信号要从4号引脚输入以实现对马达的控制。另外马达可以选择玩具四驱车上的那种。

    

            图 3_2 电机模块

  最后显示模块采用的是四位八段共阴数码管3461AS。如图3_3每个3461AS有4个数码管,每个数码管中有8个LED灯。这样当我们想使某一个数码管显示相应的数字时,只要给4路位选信号和8路段选信号相应的组合电平就能实现功能。需要另外说明的是:3461AS属于共阴数码管,如图3_4,其中6、8、9、12为位选引脚,3、5、10、1、2、4、7、11为段选引脚。如果我们想让第二个数码管显示2时,要让9号引脚置低电平其余位选引脚置高电平,同时要让11、7、5、1、2置高电平其余段选置低电平。

            图 3_3 3461AS封装图

            图 3_4 3461AS内部电路图

  因此在实际电路中(如图3_5)将P0口作段选信号引脚,同时用P2.3、P2.4、P2.5、P2.6作为位选信号引脚,通过单片机直接驱动即可。此外R1~R8八个上拉电阻不能忽视,起初笔者没有注意结果烧坏了2个3461AS。

  

            图3_5 显示模块实际驱动电路

  最终我们设计的电路图如下,其中RXD和TXD引脚接HC-05或HC-06的TXD和RXD(要交错相连)。因为HC-05/06是蓝牙串口模块,也就是说只要单片机采用串口驱动程序并且相应的引脚连接正确,单片机-蓝牙模块通信完全和单片机-串口设备通信一样。所以图中的串口模块也就相当于我们的蓝牙模块,唯一需要注意的是单片机和蓝牙模块的RXD和TXD是交错相连。

                            图 3_6 整体电路图

 

4 四位八段共阴数码管3461AS的驱动程序设计

  由上面分析我们知道通过位选信号和段选信号的组合可以实现数码管显示功能。如果采用图3_6所示电路图,上面想让第二个数码管显示2时,则P0等于0x5b(01011101),P2等于0xdf(11011111)。采用同样的分析方法我们可以计算出让八段数码管显示从0~F的所有P0对应的赋值:0x3f 0x06 0x5b 0x4f 0x66 0x6d 0x7d 0x07 0x7f 0x6f 0x77 0x7c 0x39 0x5e 0x79 0x71,以及单独选通第1位到第4位P2的所有赋值:0xbf 0xdf 0xef 0xf7。这样当我们想让第3位显示9只需要给P0、P2分别赋值0x6f和0xef即可。

  这时大家可能会有这样的疑惑:“按照上面的说法似乎每次只能让某一位显示一个数字”。其实有这样的疑惑说明大家学的比较认真,其实生活中很多数码管的显示案例中都是每次只显示一位的!之所以我们看到的情况是一次显示多个,就在于数码管驱动程序设计了!而这其中的秘诀则是采用了高频刷新(也即动态扫描)这一技巧。如果大家对动态扫描没有感觉,可以想象一下挥舞荧光棒时的样子——本来只是一根荧光棒,由于挥舞速度比较快而在空中划出一道美丽的弧线。

下面结合驱动程序和大家详细介绍:

 1 #include"display_4X8.h"
 2 
 3 unsigned char code DuanMa[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
 4       0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};// 显示段码值0~F
 5 unsigned char code WeiMa[]={0xbf,0xdf,0xef,0xf7};//分别对应相应的数码管点亮,即位码
 6 unsigned char TempData[4]; //存储显示值的全局变量
 7 
 8 //------------------------------------------------
 9 //4位8段共阴数码管显示函数
10 //第一个参数为0表示从第一个数码管开始显示num个数
11 //提前要显示的数要存在TempData中(TempData[0]表示要显示的第一个数)
12 //------------------------------------------------
13 void Display(unsigned char FirstBit,unsigned char Num)
14 {
15     static unsigned char i=0;
16 
17     DataPort=0x00;   //清空数据,防止有交替重影
18     DataControl=0x00;
19 
20     DataPort=TempData[i]; //取显示数据,段码
21     DataControl=WeiMa[i+FirstBit];
22 
23     i++;
24     if(i==Num)
25         i=0;
26 }

这里的DuanMa[]和WeiMa[]不再说明,TempData[4]用来存储要显示数据。在该驱动中只有一个Display函数,正如第10行提示所述:第一个参数用来表明从哪一个数码管开始显示数据,第二个参数表明一共要显示多少位数据。这样如果要在数码管的后两位显示一个两位数则可以用Display(2,2)。这里要特别说明下TempData数组,该数组用于存放数码管要显示的数据,千万不要把该数组和数码管直接对应。例如同样是在数码管后两位显示一个两位数num可以采用下列两种方案:

   ① TempData[0]=DuanMa[num/10]; 
   TempData[1]=DuanMa[num%10]; 
   Display(2,2); 
  ② TempData[2]=DuanMa[num/10]; 
    TempData[3]=DuanMa[num%10]; 
    Display(0,4);

  其中方案一直接把要显示的两位数据存储在TempData的前两位,然后调用Display函数从第3个数码管开始显示2位来实现功能。方案二其实是把要显示的数据存放在TempData的后两位(前两位默认为0),然后调用Display函数从第1个数码管开始显示4位来实现功能。

  对于动态扫描这里用了一个很巧妙的方法:注意到第15行定义了一个静态变量i,其功能在于实现一个周期内实现对需要点亮的数码管顺序点亮。这样如果Display(0,4)显示1234,则数码管的慢动作则为:第一个数码管显示1、接着第二个数码管显示2、然后第三个数码管显示3……由于刷新频率很高,所以人眼看上去就是4个数码管同时显示1234的效果。

 

5 PWM实现变速小马达

  欲实现直流小马达的速度控制这里必须先讲解下PWM。所谓PWM是“Pulse Width Modulation”的缩写,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。这里举个通俗的例子来解释PWM:假设你是某公司的老板,手下有个奇葩的员工喜欢周期性的在一个小时内干一会休息一会,如果你想多压榨一下他就会督促让他在一个周期内多干活少休息。同样的利用微处理器在一个比较短的周期内设置某个引脚输出高电平比低电平的持续时间多一点,从宏观上看则呈现出输出功率升高的效果,反之输出功率变低。

          图 5_1不同占空比的输出脉冲

 

6 串口驱动程序设计

  上面已经介绍过单片机和蓝牙模块的通信方式是采用串口通信,其重要特别注意的是单片机和HC-05/06的RXD引脚和TXD引脚要交错相连。既然HC-05/06采用的是串口通信方式,所以在给单片机编程时只要按照串口驱动来设计就可以了。

 1 #include"uart.h"              
 2 
 3 #define Length 8
 4 
 5 unsigned char getByte[Length];  //定义临时变量
 6 unsigned char flag;             //接收标记
 7 unsigned char point;            //指针
 8 
 9 //------------------------------------------------
10 //串口初始化
11 //------------------------------------------------
12 void InitUART  (void)
13 {
14     flag=0;
15     point=0;
16     SCON  = 0x50;                // SCON: 模式 1, 8-bit UART, 使能接收  
17     TMOD |= 0x20;               // TMOD: timer 1, mode 2, 8-bit 重装
18     TH1   = 0xFD;               // TH1:  重装值 9600 波特率 晶振 11.0592MHz  
19     TL1   = 0xFD;   
20     TR1   = 1;                  // TR1:  timer 1 打开                         
21     EA    = 1;                  //打开总中断
22     ES    = 1;                  //打开串口中断
23 }       
24                      
25 //------------------------------------------------
26 //发送一个字节
27 //------------------------------------------------
28 void SendByte(unsigned char dat)
29 {
30     SBUF = dat;
31     while(!TI);
32     TI = 0;
33 }
34 
35 //------------------------------------------------
36 //发送一个字符串
37 //------------------------------------------------
38 void SendStr(unsigned char *s)
39 {
40     while(*s!='\0')// \0 表示字符串结束标志,通过检测是否字符串末尾
41     {
42         SendByte(*s);
43         s++;
44     }
45 }
46 
47 //------------------------------------------------
48 //串口中断程序
49 //------------------------------------------------
50 void UART_SER (void) interrupt 4 //串行中断服务程序
51 {
52     if(RI)                                  //检测接收完成标志位置1
53     {
54         RI=0;                            //清零接收完成标志位
55         getByte[point]=SBUF;               //读取接收到的数据
56 
57         if(getByte[point++]==0xAA)        //遇到可能的结束标志则发送flag
58             flag=1;                        //再主函数再进行判断是否为有效帧
59 
60         if(point==8)                    //防止数组越界
61             point=0;
62     }
63 }


在该串口驱动文件里主要包括串口初始化函数InitUART,用来设置串口通信的波特率和接收中断等。接下来分别是发送一字节函数和发送一个字符串函数。这里单片机向串口设备发送信息采用直接发送,即在程序中用到要发送信息的地方直接调用发送函数发送;但是数据接收则采用中断的方式,因为在顺序执行的程序中不容易处理随时都可能传输过来的信息。在中断函数中把每次接收来的数据保存在getByte数组中。由于这里采用了数据帧,所以包含了对数据有效性的验证,这个将在下面详细分析。

 


1234下一页
52VR.COM微信扫一扫
52vr公众号
专注于VR的学习、开发和人才交流

52VR开发交流

已有 0 人参与

发表评论

您需要登录才可以回帖 登录 | 立即注册

手机版|VR开发网 ( 津ICP备18009691号 ) 统计 网安备12019202000257

GMT+8, 2020-7-14 04:08 AM

返回顶部