MPU6050为3轴加速度3轴陀螺仪传感器,可以测量三方向位置信息以及加速度信息。但MPU6050采用IIC总线传输,于是操作起来比其他的位移传感器复杂了不少。
此篇以89C51单片机为主,实现MPU6050的应用。
89C51+LCD1602+IIC
1.LCD1602液晶显示屏。
由名称可知,此种显示屏有2行,每行可显示16个字符。
对于LCD1602液晶显示屏的详细操作请参考有关文档及程序,这里不再赘述。
为了使代码简介清晰,我对LCD1602的代码进行了封装,方便调用。下面贴出LCD1602.H:
sbit RS = P1^0; //定义端口
sbit RW = P1^1;
sbit EN = P2^5;
sbit DU = P2^0;
sbit WE = P2^1;
#define RS_CLR RS=0
#define RS_SET RS=1
#define RW_CLR RW=0
#define RW_SET RW=1
#define EN_CLR EN=0
#define EN_SET EN=1
#define DataPort P0
//****************************************
//整数转字符串
//转换结果保存在uchar型的字符数组里
//函数只是负责转换三位数的整数,要是实现更多位的转换可以修改代码
//****************************************
void lcd_printf(uchar *s,int temp_data)
{
if(temp_data<0)
{
temp_data=-temp_data; //temp_data为负数则转化为正数运算
*s='-'; //此时字符串应该由‘-’负号开始
}
else *s=' '; //正数的话由空白字符开始 此时s[0]='-'或者‘ ’
*++s =temp_data/100+0x30; //百位数字转为ASCII码形式 s[1]为千位数字的ASCII码
temp_data=temp_data%100; //取余运算
*++s =temp_data/10+0x30; //同样,此处得到十位数字的ASCII码,赋给s[2]
temp_data=temp_data%10; //取余运算
*++s =temp_data+0x30; //得到个位数字的ASCII码,赋给s[3]
}
void cmg88()//关数码管,点阵函数
{
DU=1;
P0=0X00;
DU=0;
}
/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
/*------------------------------------------------
判忙函数
------------------------------------------------*/
bit LCD_Check_Busy(void)
{
DataPort= 0xFF;
RS_CLR;
RW_SET;
EN_CLR;
_nop_();
EN_SET;
return (bit)(DataPort & 0x80);
}
/*------------------------------------------------
写入命令函数
------------------------------------------------*/
void LCD_Write_Com(unsigned char com)
{
while(LCD_Check_Busy()); //忙则等待
RS_CLR;
RW_CLR;
EN_SET;
DataPort= com;
_nop_();
EN_CLR;
}
/*------------------------------------------------
写入数据函数
------------------------------------------------*/
void LCD_Write_Data(unsigned char Data)
{
while(LCD_Check_Busy()); //忙则等待
RS_SET;
RW_CLR;
EN_SET;
DataPort= Data;
_nop_();
EN_CLR;
}
/*------------------------------------------------
清屏函数
------------------------------------------------*/
void LCD_Clear(void)
{
LCD_Write_Com(0x01);
DelayMs(5);
}
/*------------------------------------------------
写入字符串函数
------------------------------------------------*/
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0)
{
LCD_Write_Com(0x80 + x); //表示第一行
}
else
{
LCD_Write_Com(0xC0 + x); //表示第二行
}
while (*s)
{
LCD_Write_Data( *s);
s ++;
}
}
/*------------------------------------------------
写入字符函数
------------------------------------------------*/
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{
if (y == 0)
{
LCD_Write_Com(0x80 + x);
}
else
{
LCD_Write_Com(0xC0 + x);
}
LCD_Write_Data( Data);
}
/*------------------------------------------------
初始化函数
------------------------------------------------*/
void LCD_Init(void)
{
LCD_Write_Com(0x38); /*显示模式设置*/
DelayMs(5);
LCD_Write_Com(0x38);
DelayMs(5);
LCD_Write_Com(0x38);
DelayMs(5);
LCD_Write_Com(0x38);
LCD_Write_Com(0x08); /*显示关闭*/
LCD_Write_Com(0x01); /*显示清屏*/
LCD_Write_Com(0x06); /*显示光标移动设置*/
DelayMs(5);
LCD_Write_Com(0x0C); /*显示开及光标设置*/
}
该头文件使用时需要
cmg88();//关数码管,
LCD_Init();//液晶初始化
LCD_Clear();//清屏
之后就可以利用LCD_Write_Char函数写一个字符,或者利用LCD_Write_String写一个字符串。
2.IIC总线
常见总线有IIC总线,SPI总线等。IIC采用双线控制,接入设备简单,SPI采用4线(3线也可以),全双工工作。
有关IIC的知识可以参考上篇文章:http://blog.csdn.net/yibu_refresh/article/details/23354245
这里也贴出IIC.H
/*********************************************
*IIC总线程序
void init()初始化
void write_add(uchar address,uchar date)写
uchar read_add(uchar address) 读
***********************************************/
#define uchar unsigned char
sbit sda=P2^0;
sbit scl=P2^1;
uchar a;
void delay1()
{ ;; }
void start() //开始信号
{
sda=1;
delay1();
scl=1;
delay1();
sda=0;
delay1();
}
void stop() //停止
{
sda=0;
delay1();
scl=1;
delay1();
sda=1;
delay1();
}
void respons() //应答
{
uchar i;
scl=1;
delay1();
while((sda==1)&&(i<250))i++;
scl=0;
delay1();
}
void init()
{
sda=1;
delay1();
scl=1;
delay1();
}
void write_byte(uchar date)
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delay1();
sda=CY;
delay1();
scl=1;
delay1();
// scl=0;
// delay();
}
scl=0;
delay1();
sda=1;
delay1();
}
uchar read_byte()
{
uchar i,k;
scl=0;
delay1();
sda=1;
delay1();
for(i=0;i<8;i++)
{
scl=1;
delay1();
k=(k<<1)|sda;
scl=0;
delay1();
}
return k;
}
void write_add(uchar address,uchar date)
{
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
}
uchar read_add(uchar address)
{
uchar date;
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
return date;
}
3.MPU6050某些参数定义:
MPU6050.H:
//****************************************
// 定义MPU6050内部地址
//****************************************
#define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C //x轴加速度
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E //y轴加速度
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40 //z轴加速度
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44 //x轴角速度
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46 //y轴角速度
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48 //z轴角速度
#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)
//**************************************
//初始化MPU6050
//**************************************
void InitMPU6050()
{
write_add(PWR_MGMT_1, 0x00); //解除休眠状态
write_add(SMPLRT_DIV, 0x07);
write_add(CONFIG, 0x06);
write_add(GYRO_CONFIG, 0x18);
write_add(ACCEL_CONFIG, 0x01);
}
4.主程序:
/*
* MPU6050模块测试程序
* MCU: STC89C52
* OSCILLATOR:11.0592M
* LCD:LCD1602
*
*/
#include <REG52.H>
#include <math.h>
#include <stdio.h>
#include <INTRINS.H>
#include "IIC.h"
#include "LCD1602.h"
#include "MPU6050.h"
//****************************************
//定义类型及变量
//****************************************
uchar dis[4]; //显示数字(-511至512)的字符数组
//**************************************
//合成数据:从IIC总线上读取两次,合成16位数据
//**************************************
int GetData(uchar REG_Address)
{
char H,L;
H=read_add(REG_Address);
L=read_add(REG_Address+1);
return (H<<8)+L; //合成数据
}
//**************************************
//在1602上显示10位数据
//**************************************
void Display10BitData(int value,uchar x,uchar y)
{
value/=64; //转换为10位数据
lcd_printf(dis, value); //转换数据显示
LCD_Write_String(x,y,dis); //启始列,行,显示数组,显示长度
}
//*********************************************************
//主程序
//*********************************************************
void delay(uchar x)
{
uchar i,j;
for(i=x;i>0;i--)
for(j=110;j>0;j--);
}
void main()
{
delay(500); //上电延时
LCD_Init(); //液晶初始化
init(); //IIC总线初始化
InitMPU6050(); //初始化MPU6050
delay(150);
while(1)
{
Display10BitData(GetData(ACCEL_XOUT_H),2,0); //显示X轴加速度
Display10BitData(GetData(ACCEL_YOUT_H),7,0); //显示Y轴加速度
Display10BitData(GetData(ACCEL_ZOUT_H),12,0); //显示Z轴加速度
Display10BitData(GetData(GYRO_XOUT_H),2,1); //显示X轴角速度
Display10BitData(GetData(GYRO_YOUT_H),7,1); //显示Y轴角速度
Display10BitData(GetData(GYRO_ZOUT_H),12,1); //显示Z轴角速度
delay(500);
}
}
这样程序看起来就简单了许多,也方便了很多。