C52单片机的应用(连接、编程、测试)

控制/MCU

1883人已加入

描述

一、连接单片机板

MPU6050 威廉希尔官方网站 图,参看:MPU6050开发 -- 初识

从威廉希尔官方网站 图上看了引出四根线:电源、GND、SCL、SDA. 连接单片机板。

单片机部分威廉希尔官方网站 图:

 

思考:SCL、SDA应该接在单片机的哪个I/O口呢?

STC89C52 没有集成 I2C 控制器,只能通过软件模拟方法实现 I2C 功能,因此,普通I/O口都可以实现,不需要固定。你可以任意使用 STC89C52 单片机两个引脚,作为数据和时钟,然后自己编写模块 I2C 代码。

那么我们就定义51单片机端口:
//****************************************
sbit    SCL=P1^5;//IIC时钟引脚定义
sbit    SDA=P1^4;//IIC数据引脚定义

//****************************************

二、测试程序

 

//****************************************

// Update to MPU6050 by shinetop

// MCU: STC89C52

// 2012.3.1

// 功能: 显示加速度计和陀螺仪的10位原始数据

//****************************************

// 使用单片机STC89C52

// 晶振:11.0592M

// 显示:串口

// 编译环境 Keil uVision2

//****************************************

#include

#include    //Keil library  

#include   //Keil library

#include

typedef unsigned char  uchar;

typedef unsigned short ushort;

typedef unsigned int   uint;

//****************************************

// 定义51单片机端口

//****************************************

sbit    SCL=P1^5; //IIC时钟引脚定义

sbit    SDA=P1^4; //IIC数据引脚定义

//****************************************

// 定义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

#define ACCEL_YOUT_H 0x3D

#define ACCEL_YOUT_L 0x3E

#define ACCEL_ZOUT_H 0x3F

#define ACCEL_ZOUT_L 0x40

#define TEMP_OUT_H 0x41

#define TEMP_OUT_L 0x42

#define GYRO_XOUT_H 0x43

#define GYRO_XOUT_L 0x44

#define GYRO_YOUT_H 0x45

#define GYRO_YOUT_L 0x46

#define GYRO_ZOUT_H 0x47

#define GYRO_ZOUT_L 0x48

#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)

#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)

#define SlaveAddress 0xD0 //IIC写入时的地址字节数据,+1为读取

//**************************************************************************************************

//定义类型及变量

//**************************************************************************************************

uchar dis[6]; //显示数字(-511至512)的字符数组

int dis_data; //变量

//**************************************************************************************************

//函数声明

//**************************************************************************************************

void  Delay5us();

void  delay(unsigned int k); //延时

void  lcd_printf(uchar *s,int temp_data);

//********************************MPU6050操作函数***************************************************

void  InitMPU6050(); //初始化MPU6050

void  I2C_Start();

void  I2C_Stop();

void  I2C_SendACK(bit ack);

bit   I2C_RecvACK();

void  I2C_SendByte(uchar dat);

uchar I2C_RecvByte();

void  I2C_ReadPage();

void  I2C_WritePage();

void  display_ACCEL_x();

void  display_ACCEL_y();

void  display_ACCEL_z();

uchar Single_ReadI2C(uchar REG_Address); //读取I2C数据

void  Single_WriteI2C(uchar REG_Address,uchar REG_data);    //向I2C写入数据

//********************************************************************************

//整数转字符串

//********************************************************************************

void lcd_printf(uchar *s,int temp_data)

{

if(temp_data<0)

{

temp_data=-temp_data;

*s='-';

}

else *s=' ';

*++s =temp_data/10000+0x30;

temp_data=temp_data%10000;     //取余运算

*++s =temp_data/1000+0x30;

temp_data=temp_data%1000;     //取余运算

*++s =temp_data/100+0x30;

temp_data=temp_data%100;     //取余运算

*++s =temp_data/10+0x30;

temp_data=temp_data%10;      //取余运算

*++s =temp_data+0x30;

}

//******************************************************************************************************

//串口初始化

//*******************************************************************************************************

void init_uart()

{

TMOD=0x21;

TH1=0xfd; //实现波特率9600(系统时钟11.0592MHZ)

TL1=0xfd;

SCON=0x50;

PS=1;      //串口中断设为高优先级别

TR0=1;   //启动定时器

TR1=1;

ET0=1;     //打开定时器0中断

ES=1;

EA=1;

}

//*************************************************************************************************

//串口发送函数

//*************************************************************************************************

void  SeriPushSend(uchar send_data)

{

SBUF=send_data;  

while(!TI);TI=0;

}

//*************************************************************************************************

//************************************延时*********************************************************

//*************************************************************************************************

void delay(unsigned int k)

{

unsigned int i,j;

for(i=0;i

{

for(j=0;j<121;j++);

}

}

//************************************************************************************************

//延时5微秒(STC90C52RC@12M)

//不同的工作环境,需要调整此函数

//注意当改用1T的MCU时,请调整此延时函数

//************************************************************************************************

void Delay5us()

{

_nop_();_nop_();_nop_();_nop_();

_nop_();_nop_();_nop_();_nop_();

_nop_();_nop_();_nop_();_nop_();

_nop_();_nop_();_nop_();_nop_();

_nop_();_nop_();_nop_();_nop_();

_nop_();_nop_();_nop_();_nop_();

}

//*************************************************************************************************

//I2C起始信号

//*************************************************************************************************

void I2C_Start()

{

SDA = 1;                    //拉高数据线

SCL = 1;                    //拉高时钟线

Delay5us();                 //延时

SDA = 0;                    //产生下降沿

Delay5us();                 //延时

SCL = 0;                    //拉低时钟线

}

//*************************************************************************************************

//I2C停止信号

//*************************************************************************************************

void I2C_Stop()

{

SDA = 0;                    //拉低数据线

SCL = 1;                    //拉高时钟线

Delay5us();                 //延时

SDA = 1;                    //产生上升沿

Delay5us();                 //延时

}

//**************************************************************************************************

//I2C发送应答信号

//入口参数:ack (0:ACK 1:NAK)

//**************************************************************************************************

void I2C_SendACK(bit ack)

{

SDA = ack;                  //写应答信号

SCL = 1;                    //拉高时钟线

Delay5us();                 //延时

SCL = 0;                    //拉低时钟线

Delay5us();                 //延时

}

//****************************************************************************************************

//I2C接收应答信号

//****************************************************************************************************

bit I2C_RecvACK()

{

SCL = 1;                    //拉高时钟线

Delay5us();                 //延时

CY = SDA;                   //读应答信号

SCL = 0;                    //拉低时钟线

Delay5us();                 //延时

return CY;

}

//*****************************************************************************************************

//向I2C总线发送一个字节数据

//*****************************************************************************************************

void I2C_SendByte(uchar dat)

{

uchar i;

for (i=0; i<8; i++)         //8位计数器

{

dat <<= 1;              //移出数据的最高位

SDA = CY;               //送数据口

SCL = 1;                //拉高时钟线

Delay5us();             //延时

SCL = 0;                //拉低时钟线

Delay5us();             //延时

}

I2C_RecvACK();

}

//*****************************************************************************************************

//从I2C总线接收一个字节数据

//******************************************************************************************************

uchar I2C_RecvByte()

{

uchar i;

uchar dat = 0;

SDA = 1;                    //使能内部上拉,准备读取数据,

for (i=0; i<8; i++)         //8位计数器

{

dat <<= 1;

SCL = 1;                //拉高时钟线

Delay5us();             //延时

dat |= SDA;             //读数据               

SCL = 0;                //拉低时钟线

Delay5us();             //延时

}

return dat;

}

//*****************************************************************************************************

//向I2C设备写入一个字节数据

//*****************************************************************************************************

void Single_WriteI2C(uchar REG_Address,uchar REG_data)

{

I2C_Start();                  //起始信号

I2C_SendByte(SlaveAddress);   //发送设备地址+写信号

I2C_SendByte(REG_Address);    //内部寄存器地址,

I2C_SendByte(REG_data);       //内部寄存器数据,

I2C_Stop();                   //发送停止信号

}

//*******************************************************************************************************

//从I2C设备读取一个字节数据

//*******************************************************************************************************

uchar Single_ReadI2C(uchar REG_Address)

{

uchar REG_data;

I2C_Start();                   //起始信号

I2C_SendByte(SlaveAddress);    //发送设备地址+写信号

I2C_SendByte(REG_Address);     //发送存储单元地址,从0开始

I2C_Start();                   //起始信号

I2C_SendByte(SlaveAddress+1);  //发送设备地址+读信号

REG_data=I2C_RecvByte();       //读出寄存器数据

I2C_SendACK(1);                //接收应答信号

I2C_Stop();                    //停止信号

return REG_data;

}

//******************************************************************************************************

//初始化MPU6050

//******************************************************************************************************

void InitMPU6050()

{

Single_WriteI2C(PWR_MGMT_1, 0x00); //解除休眠状态

Single_WriteI2C(SMPLRT_DIV, 0x07);

Single_WriteI2C(CONFIG, 0x06);

Single_WriteI2C(GYRO_CONFIG, 0x18);

Single_WriteI2C(ACCEL_CONFIG, 0x01);

}

//******************************************************************************************************

//合成数据

//******************************************************************************************************

int GetData(uchar REG_Address)

{

uchar H,L;

H=Single_ReadI2C(REG_Address);

L=Single_ReadI2C(REG_Address+1);

return ((H<<8)+L);   //合成数据

}

//******************************************************************************************************

//超级终端(串口调试助手)上显示10位数据

//******************************************************************************************************

void Display10BitData(int value)

{  uchar i;

// value/=64; //转换为10位数据

lcd_printf(dis, value); //转换数据显示

for(i=0;i<6;i++)

{

SeriPushSend(dis[i]);

}

// DisplayListChar(x,y,dis,4); //启始列,行,显示数组,显示长度

}

//*******************************************************************************************************

//主程序

//*******************************************************************************************************

void main()

delay(500); //上电延时

init_uart();

InitMPU6050(); //初始化MPU6050

delay(150);

while(1)

{

SeriPushSend('A');  

SeriPushSend(0x20);SeriPushSend('X'); SeriPushSend(':'); 

Display10BitData(GetData(ACCEL_XOUT_H)); //显示X轴加速度

SeriPushSend(0x20);SeriPushSend('Y'); SeriPushSend(':');

Display10BitData(GetData(ACCEL_YOUT_H)); //显示Y轴加速度

SeriPushSend(0x20);SeriPushSend('Z'); SeriPushSend(':');

Display10BitData(GetData(ACCEL_ZOUT_H)); //显示Z轴加速度

SeriPushSend(0x20); 

SeriPushSend('G');  

SeriPushSend(0x20);SeriPushSend('X'); SeriPushSend(':');

Display10BitData(GetData(GYRO_XOUT_H)); //显示X轴角速度

SeriPushSend(0x20);SeriPushSend('Y'); SeriPushSend(':');

Display10BitData(GetData(GYRO_YOUT_H)); //显示Y轴角速度

SeriPushSend(0x20);SeriPushSend('Z'); SeriPushSend(':');

Display10BitData(GetData(GYRO_ZOUT_H)); //显示Z轴角速度     

SeriPushSend(0x0d); 

SeriPushSend(0x0a);//换行,回车

delay(2000);

}

}

三、使用keil烧写程序

四、测试

打开串口调试工具进行测试。

如果引脚接错会打印 -00001,正确打印信息如下图。

A 为三轴MEMS加速度计,G为三轴MEMS陀螺仪。挪动MPU6050模块,则数据变化。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分