标题: 基于51单片机的无线蓝牙小车-ADXL345手势遥控 碉堡了 [打印本页]
作者: 84533243 时间: 2015-4-12 22:55
标题: 基于51单片机的无线蓝牙小车-ADXL345手势遥控 碉堡了
本制作以STC89C52RC单片机和ADXL345加速度模块。加速度模块固定在手上时,当手向左倾斜,小车左转;手向右倾斜,小车右转;手向前倾斜,小车前进;手向后倾斜,小车倒退;手水平不动,小车停止任何动作。有效控制范围 10米(开阔地)。小车视频可以见教程附件。
原理:ADXL345加速度模块可以测量X Y Z三轴的加速度和倾角。人的手做动作时,势必会改变模块的加速度大小和倾角。由于测量加速度叫繁琐,所以测量的是倾角数据。当倾角数据满足一定范围时,通过蓝牙模块传输控制指令到小车,实现小车的动作。
制作教程(配图见附于文章结尾):
本制作除了单片机最小系统需要焊接外,其他的组件都是模块(单片机系统可以自己焊接,也可以使用模块。最小系统图看最后面附图),直接和单片机的IO口连线就可以了,单片机最小系统原理图我已经上传,本教程主要是讲解模块的说明和接线方式。
一 小车系统:
可以是四驱型的,也可以是万向型的,只要你会改程序,就无需局限于小车制动类型。当然,如果你不会改程序,那就使用四驱,小车的套件在淘宝上的价格都很便宜,几十块的也有,根据自己的经济能力决定。购买时注意电机的额定电压和转速就可以了。
小车电机接线:
1号轮红线接L293D输出端:8
1号轮黑线接L293D输出端:7
2号轮红线接L293D输出端:6
2号轮黑线接L293D输出端:5
3号轮红线接L293D输出端:4
3号轮黑线接L293D输出端:3
4号轮红线接L293D输出端:2
4号轮黑线接L293D输出端:1
注:必须确定小车的方向,本例为1号轮为小车前进轮;实际的接线可以完全相反,只需要改变输入端线序即可!
二 电机驱动模块
我使用的是成品模块,型号为L293D,模块省去了焊接调试工作,直接使用即可。此类模块还有一个优点,就是当你的供电电源大于6V时,模块可以当5V的电源使用,可以给单片机系统和蓝牙系统供电, 模块的供电电压是5v到16V,当你需要外接5V电源时,可用6V至16V电源供电。最大可提供1A驱动电流。
模块接线:
P1.0接IN8
P1.1接IN7
P1.2接IN6
P1.3接IN5
P1.4接IN4
P1.5接IN3
P1.6接IN2
P1.7接IN1
注:若组装好后,小车运动与预设完全相反,只需要单片机端口线序倒置即可:如P1.7接IN8,P1.6接IN7以此类推。
三 供电系统
我使用的是12V铅酸蓄电池。注意,你使用的电池电压必须在你电机的额定电压工作范围内。驱动模块的控制信号是0到5V(单片机电压),但驱动模块给电机供电是,就是电源电压,所以一定要注意电机的额定工作范围。
供电接线:
蓄电池正极——L293D Vcc
蓄电池负极——L293D Gnd
L293D 5V ——单片机系统Vcc
L293D Gnd——单片机Gnd
四 无线传输模块
我使用的是UART蓝牙模块,这种模块自动配对,且无需额外编程,价格在30元左右(一只),虽然网上有很多几块钱的模块,性价比较高,但是我的程序重点在于加速度模块程序的设计,所以没有过多精力来搞无限通信。如果你有良好的程序基础,那么建议你购买价格便宜的无线模块。蓝牙模块分主从模式,我使用的是主从一体的蓝牙模块,通过管脚可以切换主从,但有些是需要AT指令切换主从的,购买的时候需要注意。蓝牙模块工作时必须一主一从才能配对成功。
蓝牙模块连接:
1主模块连接:
SET与3V3脚短接
VCC接可接3.3或5V
RX接单片机TX
TX接单片机RX
GND接地
2从模块连接
SET脚与地短接
VCC接可接3.3或5V
RX接单片机TX
TX接单片机RX
GND接地
注:不管是主模块还是从模块,只要配对好,是可以互相通信的。所以不管是哪个连接到小车都可以。
五 加速度ADXL345模块
此模块的程序设计是整个制作的核心。模块的详细参数见模块官方手册说明。
模块接线:
VCC接5V
GND接地
SCL接P1.0
DAT接P1.1
-
-
遥控小车.zip
889.42 KB, 下载次数: 172, 下载积分: 黑币 -5
作者: 84533243 时间: 2015-4-12 22:56
程序在下一楼
作者: 84533243 时间: 2015-4-12 22:57
#include <REG52.H>
#include <basic.h>
#include <math.h> //Keil library
#include <stdio.h> //Keil library
#include <INTRINS.H>
sbit SCL=P1^0; //IIC时钟引脚定义
sbit SDA=P1^1; //IIC数据引脚定义
#define SlaveAddress 0xA6 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
//ALT ADDRESS引脚接地时地址为0xA6,接电源时地
#define JudgeP_M 0x8000 //正负数判断
#define Left_cmp 0x006e //方向数据比较值,数值越小,越灵敏
#define Right_cmp 0x006e
#define Go_cmp 0x006e
#define Back_cmp 0x006e
#define Go 0xaa //小车实际动作控制字符,以实物为准
#define Back 0x55
#define Left 0xa0
#define Right 0x0a
#define Stop 0x00 //停止控制字符
Byte BUF[8]; //接收数据缓存区
Byte Sbuf[8];
Word Wbuf[2];
int dis_data; //变量
void delay(unsigned int k);
void Init_ADXL345(void); //初始化ADXL345
void WriteDataLCM(Byte dataW);
void WriteCommandLCM(Byte CMD,Byte Attribc);
void DisplayOneChar(Byte X,Byte Y,Byte DData);
void conversion(Word temp_data);
void Single_Write_ADXL345(Byte REG_Address,Byte REG_data); //单个写入数据
Byte Single_Read_ADXL345(Byte REG_Address); //单个读取内部寄存器数据
void Multiple_Read_ADXL345(); //连续的读取内部寄存器数据
//------------------------------------
void Delay5us();
void Delay5ms();
void Delay20ms();
void ADXL345_Start();
void ADXL345_Stop();
void ADXL345_SendACK(bit ack);
bit ADXL345_RecvACK();
void ADXL345_SendByte(Byte dat);
Byte ADXL345_RecvByte();
void ADXL345_ReadPage();
void ADXL345_WritePage();
void send();
void uart();
void Data_Convert();
void Data_Process();
void direction_judge();
//******主程序********
void main()
{
void Delay20ms(); //上电延时
uart();
Init_ADXL345(); //初始化ADXL345
while(1) //循环
{
Multiple_Read_ADXL345(); //连续读出数据,存储在BUF中
Data_Convert();
Data_Process();
direction_judge();
Delay20ms(); //延时
}
}
/*******************************/
void Delay20ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 1;
j = 216;
k = 35;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
/*******************************/
/**************************************
延时5微秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数,注意时钟过快时需要修改
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5us()
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}
/**************************************
延时5毫秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5ms()
{
Word n = 560;
while (n--);
}
/**************************************
起始信号
**************************************/
void ADXL345_Start()
{
SDA = 1; //拉高数据线
SCL = 1; //拉高时钟线
Delay5us(); //延时
SDA = 0; //产生下降沿
Delay5us(); //延时
SCL = 0; //拉低时钟线
}
/**************************************
停止信号
**************************************/
void ADXL345_Stop()
{
SDA = 0; //拉低数据线
SCL = 1; //拉高时钟线
Delay5us(); //延时
SDA = 1; //产生上升沿
Delay5us(); //延时
}
/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void ADXL345_SendACK(bit ack)
{
SDA = ack; //写应答信号
SCL = 1; //拉高时钟线
Delay5us(); //延时
SCL = 0; //拉低时钟线
Delay5us(); //延时
}
/**************************************
接收应答信号
**************************************/
bit ADXL345_RecvACK()
{
SCL = 1; //拉高时钟线
Delay5us(); //延时
CY = SDA; //读应答信号
SCL = 0; //拉低时钟线
Delay5us(); //延时
return CY;
}
/**************************************
向IIC总线发送一个字节数据
**************************************/
void ADXL345_SendByte(Byte dat)
{
Byte i;
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1; //移出数据的最高位
SDA = CY; //送数据口
SCL = 1; //拉高时钟线
Delay5us(); //延时
SCL = 0; //拉低时钟线
Delay5us(); //延时
}
ADXL345_RecvACK();
}
//从IIC总线接收一个字节数据
Byte ADXL345_RecvByte()
{
Byte i;
Byte dat = 0;
SDA = 1; //使能内部上拉,准备读取数据,
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
SCL = 1; //拉高时钟线
Delay5us(); //延时
dat |= SDA; //读数据
SCL = 0; //拉低时钟线
Delay5us(); //延时
}
return dat;
}
//******单字节写入*******************************************
void Single_Write_ADXL345(Byte REG_Address,Byte REG_data)
{
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(REG_Address); //内部寄存器地址,请参考中文pdf22页
ADXL345_SendByte(REG_data); //内部寄存器数据,请参考中文pdf22页
ADXL345_Stop(); //发送停止信号
}
//********单字节读取*****************************************
Byte Single_Read_ADXL345(Byte REG_Address)
{ Byte REG_data;
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(REG_Address); //发送存储单元地址,从0开始
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress+1); //发送设备地址+读信号
REG_data=ADXL345_RecvByte(); //读出寄存器数据
ADXL345_SendACK(1);
ADXL345_Stop(); //停止信号
return REG_data;
}
//连续读出ADXL345内部加速度数据,地址范围0x32~0x37
void Multiple_read_ADXL345(void)
{ Byte i;
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(0x32); //发送存储单元地址,从0x32开始
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress+1); //发送设备地址+读信号
for (i=0; i<6; i++) //连续读取6个地址数据,存储中BUF
{
BUF[i] = ADXL345_RecvByte(); //BUF[0]存储0x32地址中的数据
if (i == 5)
{
ADXL345_SendACK(1); //最后一个数据需要回NOACK
}
else
{
ADXL345_SendACK(0); //回应ACK
}
}
ADXL345_Stop(); //停止信号
Delay5ms();
}
//初始化ADXL345,根据需要请参考pdf进行修改************************
void Init_ADXL345()
{
Single_Write_ADXL345(0x31,0x0B); //测量范围,正负16g,13位模式
Single_Write_ADXL345(0x2C,0x08); //速率设定为12.5 参考pdf13页
Single_Write_ADXL345(0x2D,0x08); //选择电源模式 参考pdf24页
Single_Write_ADXL345(0x2E,0x80); //使能 DATA_READY 中断
Single_Write_ADXL345(0x1E,0x00); //X 偏移量 根据测试传感器的状态写入pdf29页
Single_Write_ADXL345(0x1F,0x00); //Y 偏移量 根据测试传感器的状态写入pdf29页
Single_Write_ADXL345(0x20,0x05); //Z 偏移量 根据测试传感器的状态写入pdf29页
}
void uart()
{
SCON=0x50;
TMOD=0x20;
PCON=0x00;
TH1=0xfd;
TL1=0xfd;
IE=0x90;
TR1=1;
}
void send(unsigned char ch)
{
ES=0;
SBUF=ch;
while (TI==0);
TI=0 ;
ES=1;
}
void Data_Convert() //将两个八位数据合成为一个16位数据
{
Wbuf[0]=BUF[1]<<8|BUF[0];
Wbuf[1]=BUF[3]<<8|BUF[2];
Wbuf[2]=BUF[5]<<8|BUF[4];
}
void Data_Process()
{
Word i=0;
i=Wbuf[0]&JudgeP_M; //X轴数据处理
if(i==0x8000) //当结果为负数时
{
Wbuf[0]=~Wbuf[0]+1;
Wbuf[0]=Wbuf[0]&0x7fff;
if(Wbuf[0]>Left_cmp)
{
Sbuf[0]=Left;
}
else
{
Sbuf[0]=Stop;
}
}
else //当结果为正数时
{
if(Wbuf[0]>Right_cmp)
{
Sbuf[0]=Right;
}
else
{
Sbuf[0]=Stop;
}
}
i=Wbuf[1]&JudgeP_M; //Y轴数据处理
if(i==0x8000) //当结果为负数时
{
Wbuf[1]=~Wbuf[1]+1;
Wbuf[1]=Wbuf[1]&0x7fff;
if(Wbuf[1]>Back_cmp)
{
Sbuf[1]=Back;
}
else
{
Sbuf[1]=Stop;
}
}
else //当结果为正数时
{
if(Wbuf[1]>Go_cmp)
{
Sbuf[1]=Go;
}
else
{
Sbuf[1]=Stop;
}
}
}
void direction_judge()
{
if(Sbuf[0]==Left|Sbuf[0]==Right)
{
send(Sbuf[0]);
}
else
{
send(Sbuf[1]);
}
}
作者: 84533243 时间: 2015-4-12 23:16
刚才我发错代码格式了,你们就看下面的就行了
作者: 茂茂耶 时间: 2015-4-15 18:44
谢谢分享
作者: 1719199337 时间: 2016-9-8 10:40
给力谢谢分享
作者: dxa572862121 时间: 2016-12-13 17:33
大神,收藏一下
作者: Gesir123 时间: 2017-10-25 02:19
我现在也要搞类似的东西,我负责adxl345的蓝牙数据传输部分,如果不懂再来问楼主,楼主写的很好
作者: Gesir123 时间: 2017-10-25 02:25
你说蓝牙模块URAT进行无线数据传输,发送端的adxl345接什么? 我在淘宝上看的貌似都是连接再单片机上的,都是再接收端。
作者: niqi 时间: 2022-4-19 14:09
接单片机啊 单片机再通过蓝牙发送数据
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |