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

一、连接单片机板
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模块,则数据变化。

智能康辅,为创新赋能
“千言”机器人开始引入知识图谱,强化机器人的知识构建能力
如何在WINCC中使用报警声音
OpenHarmony创新赛 | 您有一份创新激励奖待领取 请查收!
自动驾驶商业化落地再提速,激光雷达传感器蓄势待发
C52单片机的应用(连接、编程、测试)
ITF 指控多家中企涉嫌侵权 中国已经成为美国“337调查”的最大受害国
DSM™ 算法如何提供更响亮、更丰富的声音
搭建FTP服务器并登录,抓包验证的实验笔记
2022年Q2全球手机运营利润同比增长6%
基于软件测试技术的FPGA测试研究[图]
苹果持续招聘汽车行业的相关岗位
50W晶体管制作的功放电路,Simple power amplifier
谷歌推出Visual Core芯片,将优化头显摄像头,量产仍是问题
QBotix推出双轴太阳能跟踪系统
排针排母电子连接器的选购和质量这五点很重要
2018年中国移动财报公布,全年营运收入达到7368亿元
Vishay超薄IGBT/MOSFET驱动器在小尺寸逆变器中有效节省空间
高压分立Si MOSFET (≥ 2 kV)及其应用
力士乐柱塞泵的清洗需要注意哪些问题