标题:
51单片机驱动MPU6050+ADXL345带详细注释的源程序
[打印本页]
作者:
lllllllu
时间:
2018-7-20 08:50
标题:
51单片机驱动MPU6050+ADXL345带详细注释的源程序
0.png
(46.92 KB, 下载次数: 42)
下载附件
2018-7-21 02:32 上传
单片机源码:
#include <STC15.H> //引用STC15系列头文件,百度上搜索下载
#include <INTRINS.H>
#include <MATH.H>
#define I2C_SCL P14 //时钟信号线
#define I2C_SDA P15 //数据信号线
#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)
#define SlaveAddress 0xD0 //IIC写入时的地址字节数据,+1为读取
#define NOP1() nop_()
#define NOP2() NOP1(),NOP1()
#define MAIN_Fosc 24000000L //主时钟,不同的晶振频率可以直接修改
#define serial_one_read_max 16 //接收缓存区长度
#define serial_one_baud_rate 115200L //波特率,波特率可以直接修改
#define Timer1_Reload_Usart (65536UL -(MAIN_Fosc / 4 / serial_one_baud_rate)) //Timer1重装值,定时器1产生波特率
//****************************************
// 定义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
void Delay1000ms() //延时函数1秒
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 85;
j = 12;
k = 155;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//========================================================================
// 函数: void I2C_Start()
// 描述: I2C起始信号.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_Start()
{
I2C_SDA = 1; //拉高数据线
I2C_SCL = 1; //拉高时钟线
NOP2(); //等待机器反应
I2C_SDA = 0; //产生下降沿
I2C_SCL = 0; //拉低时钟线
}
//========================================================================
// 函数: void I2C_Stop()
// 描述: I2C停止信号.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_Stop()
{
I2C_SDA = 0; //拉低数据线
I2C_SCL = 1; //拉高时钟线
NOP2(); //等待机器反应
I2C_SDA = 1; //产生上升沿
NOP1(); //等待机器反应
}
//========================================================================
// 函数: void I2C_SendACK(bit ack)
// 描述: I2C发送应答信号.
// 参数: ack (0:ACK 1:NAK).
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_SendACK(bit ack)
{
I2C_SDA = ack; //写应答信号
I2C_SCL = 1; //拉高时钟线
NOP2(); //等待机器反应
I2C_SCL = 0; //拉低时钟线
NOP1(); //等待机器反应
}
//========================================================================
// 函数: bit I2C_RecvACK()
// 描述: I2C接收应答信号.
// 参数: none.
// 返回: 1:成功,0:失败.
// 版本: V1.0, 2017-06-23
//========================================================================
bit I2C_RecvACK()
{
I2C_SCL = 1; //拉高时钟线
NOP2(); //等待机器反应
CY = I2C_SDA; //读应答信号
I2C_SCL = 0; //拉低时钟线
return CY;
}
//========================================================================
// 函数: void I2C_SendByte(u8 dat)
// 描述: 向I2C总线发送一个字节数据.
// 参数: dat:要发送的数据.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_SendByte(unsigned char dat)
{
unsigned char i;
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1; //移出数据的最高位
I2C_SDA = CY; //送数据口
I2C_SCL = 1; //拉高时钟线
NOP2(); //等待机器反应
I2C_SCL = 0; //拉低时钟线
}
I2C_RecvACK();
}
//========================================================================
// 函数: unsigned char I2C_RecvByte()
// 描述: 从I2C总线接收一个字节数据.
// 参数: none.
// 返回: 接收到的数据.
// 版本: V1.0, 2017-06-23
//========================================================================
unsigned char I2C_RecvByte()
{
unsigned char i;
unsigned char dat = 0;
I2C_SDA = 1; //使能内部上拉,准备读取数据,
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
I2C_SCL = 1; //拉高时钟线
NOP2(); //等待机器反应
dat |= I2C_SDA; //读数据
I2C_SCL = 0; //拉低时钟线
}
return dat;
}
//========================================================================
// 函数: void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
// 描述: 向I2C设备写入一个字节数据.
// 参数: REG_Address:地址.
// REG_data:要写入的数据.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
{
I2C_Start(); //起始信号
I2C_SendByte(SlaveAddress); //发送设备地址+写信号
I2C_SendByte(REG_Address); //内部寄存器地址,
I2C_SendByte(REG_data); //内部寄存器数据,
I2C_Stop(); //发送停止信号
}
//========================================================================
// 函数: unsigned char Single_ReadI2C(unsigned char REG_Address)
// 描述: 从I2C设备读取一个字节数据.
// 参数: REG_Address:地址.
// 返回: 读取到的数据.
// 版本: V1.0, 2017-06-23
//========================================================================
unsigned char Single_ReadI2C(unsigned char REG_Address)
{
unsigned char 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;
}
//========================================================================
// 函数: void MPU6050_init()
// 描述: 初始化MPU6050.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void MPU6050_Init()
{
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(u8 REG_Address)
// 描述: 读取数据并合成为int型数据.
// 参数: REG_Address:地址.
// 返回: 读取到的数据.
// 版本: V1.0, 2017-06-23
//========================================================================
int GetData(unsigned char REG_Address)
{
unsigned char H,L;
H = Single_ReadI2C(REG_Address);
L = Single_ReadI2C(REG_Address + 1);
return (H << 8) + L; //合成数据
}
////========================================================================
//// 函数: int get_x_angle()
//// 描述: 获取三轴角速度,三轴加速度
//// 参数: gyro_id:数据ID,1:x角速度,2:y角速度,3:z角速度,4:x加速度,5:y加速度,6:z加速度.
//// 返回: 陀螺仪值.
//// 版本: V2.0, 2017-07-15
////========================================================================
int Get_Gyro_Data(unsigned char gyro_id)
{
switch(gyro_id)
{
case 1: return GetData(ACCEL_XOUT_H); break;
case 2: return GetData(ACCEL_YOUT_H); break;
case 3: return GetData(ACCEL_ZOUT_H); break;
case 4: return GetData(GYRO_XOUT_H) ; break;
case 5: return GetData(GYRO_YOUT_H) ; break;
case 6: return GetData(GYRO_ZOUT_H) ; break;
}
return 0;
}
//========================================================================
// 函数: int MPU6050_Get_Angle(float x,float y,float z,u8 dir)
// 描述: 转化成与三个方向的夹角.
// 参数: x:x方向数据.
// y:y方向数据.
// z:z方向数据.
// dir:方向ID.
// 返回: 夹角角度值(放大10倍).
// 版本: V1.0, 2017-06-23
//========================================================================
int MPU6050_Get_Angle(int x,int y,int z,unsigned char dir)
{
float xdata temp;
float xdata res = 0;
switch(dir)
{
case 0://与z轴的夹角
temp = sqrt(((float)x*(float)x+(float)y*(float)y))/(float)z;
res = atan(temp);
break;
case 1://与x轴的夹角
temp = (float)x/sqrt(((float)y*(float)y+(float)z*(float)z));
res = atan(temp);
break;
case 2://与y轴的夹角
temp = (float)y/sqrt(((float)x*(float)x+(float)z*(float)z));
res = atan(temp);
break;
}
return (int)(res*1800/3.1416);//弧度转换为角度,扩大10倍
}
//========================================================================
// int get_included_angle(unsigned dat)
// 描述: 获取角度或加速度
// 参数: angle_id:方向指示变量(1:X轴角度,2:Y轴角度,3:Z轴角度,4:X轴加速度,5:Y轴加速度,6:Z轴加速度).
// 返回: 夹角角度值(放大10倍).
// 版本: V1.0, 2017-06-23
//========================================================================
int MPU6050_Get_Data(unsigned angle_id)
{
switch(angle_id)
{
case 1:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 1);break;
case 2:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 2);break;
case 3:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 0);break;
case 4:return (int)((float)((float)Get_Gyro_Data(4)/16384)*9.8*100);
case 5:return (int)((float)((float)Get_Gyro_Data(5)/16384)*9.8*100);
case 6:return (int)((float)((float)Get_Gyro_Data(6)/16384)*9.8*100);
}
return 0;
}
//串口初始化
void Uart_Init()
{
SCON |= 0x40; //8位数据
P_SW1 &= ~0xc0; //UART1 使用P30 P31口 默认
TR1 = 0; //关闭定时器1
AUXR &= ~0x01; //串口1波特率使用定时器1
TMOD &= ~(1<<6); //Timer1 set As Timer
TMOD &= ~0x30; //16位自动重装
AUXR |= (1<<6); //定时器使用1T模式
TH1 = (unsigned char)(Timer1_Reload_Usart >> 8);
TL1 = (unsigned char)Timer1_Reload_Usart;
TR1 = 1; //打开定时器1
PS = 1; //高优先级中断
REN = 1; //允许接收
ES = 1; //允许中断
EA = 1; //允许全局中断
}
//========================================================================
// 函数: serial_one_send_byte(unsigned char dat)
// 描述: 串口1发送一个字节.
// 参数: dat:字符(无符号八位整型数据).
// 返回: none.
// 版本: V1.0, 2017-06-22
//========================================================================
void serial_one_send_byte(unsigned char dat)
{
SBUF = dat;
while(!TI);
TI = 0;
}
//========================================================================
// 函数: serial_one_send_string(u8 *dat)
// 描述: 串口1发送字符串.
// 参数: dat:字符串.
// 返回: none.
// 版本: V1.0, 2017-06-22
//========================================================================
void serial_one_send_string(unsigned char *dat)
{
while(*dat)
serial_one_send_byte(*dat++);
}
//========================================================================
// 函数: void serial_one_send_number(long num)
// 描述: 串口1发送整型数据.
// 参数: num:整型数值.
// 返回: none.
// 版本: V1.0, 2017-06-22
//========================================================================
void serial_one_send_number(long num)
{
long dat = 0;
unsigned char length = 0;
if(num < 0) //当数值为负数时
{
serial_one_send_byte('-'); //输出负号
num = -num; //将数值取相反数
}
if(num == 0) //当数值为0时
serial_one_send_byte('0'); //输出字符0
else //当数值不为0时
{
while(num) //将数值倒过来
{
dat = dat * 10;
dat = dat + num % 10;
num = num / 10;
length++;
}
while(length--) //从第一位开始输出倒过来的数值
{
serial_one_send_byte(dat % 10 + '0');
dat = dat / 10;
}
}
}
void serial_one_send_float(double float_val, char bit_val)
{
long xdata value_int = 0;
long xdata value_flt = 0;
if(float_val < 0)
{
serial_one_send_byte('-');
float_val = -float_val;
}
value_int = (long)float_val;
float_val = float_val - (double)value_int;
for(;bit_val;bit_val--)
float_val = float_val * 10;
serial_one_send_number(value_int);
serial_one_send_byte('.');
serial_one_send_number((long)float_val);
}
float value = 0;
//主函数
void main()
{
Delay1000ms();
Uart_Init(); //串口初始化
MPU6050_Init(); //初始化MPU6505
while(1)
{
value = MPU6050_Get_Data(1); //获取与x轴的夹角,角度被放大10倍
serial_one_send_string("模块与x轴的夹角为:");
serial_one_send_float(value / 10,1); //角度除以10,并从串口发出,第二个参数为保留一位小数
serial_one_send_string("\r\n"); //换行
value = MPU6050_Get_Data(2); //获取与y轴的夹角,角度被放大10倍
serial_one_send_string("模块与y轴的夹角为:");
serial_one_send_float(value / 10,1); //角度除以10,并从串口发出
serial_one_send_string("\r\n"); //换行
value = MPU6050_Get_Data(3); //获取与z轴的夹角,角度被放大10倍
serial_one_send_string("模块与z轴的夹角为:");
serial_one_send_float(value / 10,1); //角度除以10,并从串口发出
serial_one_send_string("\r\n"); //换行
value = MPU6050_Get_Data(4); //获取与x轴加速度,数值被放大100倍
serial_one_send_string("x轴加速度为:");
serial_one_send_float(value/100,1); //角度除以100,并从串口发出,第二个参数为保留一位小数
serial_one_send_string(" M/S2\r\n"); //换行
value = MPU6050_Get_Data(4); //获取与y轴加速度,数值被放大100倍
serial_one_send_string("y轴加速度为:");
serial_one_send_float(value / 100,1); //角度除以100,并从串口发出
serial_one_send_string(" M/S2\r\n"); //换行
value = MPU6050_Get_Data(4); //获取与z轴加速度,数值被放大100倍
serial_one_send_string("z轴加速度为:");
serial_one_send_float(value / 100,1); //角度除以100,并从串口发出
serial_one_send_string(" M/S2\r\n\r\n"); //换行
Delay1000ms();
Delay1000ms();
}
}
//串口中断
void Uart1_Int (void) interrupt 4
{
if(RI)
RI = 0;
}
复制代码
/*
* ADXL345模块
*
* 用途:ADXL345模块IIC测试程序
*
* 作者 日期 备注
*
*/
#include "uart3.h"
#include <stc15.H>
#include <math.h> //Keil library
#include <stdio.h> //Keil library
#include <INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
sbit SCL=P0^6; //IIC时钟引脚定义
sbit SDA=P0^7; //IIC数据引脚定义
sbit P_PWM = P2^5; //定义PWM输出引脚。
sbit O_PWM = P2^1;
#define SlaveAddress 0xa6 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
//ALT ADDRESS引脚接地时地址为0xA6,接电源时地址为0x3A
#define PWM_HIGH_MIN 32 //限制PWM输出的最小占空比。用户请勿修改。
#define PWM_HIGH_MAX (PWM_DUTY-PWM_HIGH_MIN) //限制PWM输出的最大占空比。用户请勿修改。
long PWM_DUTY=20200;
unsigned int duty;
unsigned char fu_flag=0;
unsigned int pwm; //定义PWM输出高电平的时间的变量。用户操作PWM的变量。
//BYTE BUF[8]; //接收数据缓存区
uchar ge,shi,bai,qian,wan; //显示变量
int dis_data; //变量
int x_value=0;
void delay(unsigned int k);
void Init_ADXL345(void); //初始化ADXL345
void conversion(uint temp_data);
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data); //单个写入数据
uchar Single_Read_ADXL345(uchar REG_Address); //单个读取内部寄存器数据
void Multiple_Read_ADXL345(); //连续的读取内部寄存器数据
//sbit P_PWM = P1^4; //定义PWM输出引脚。STC15W204S
unsigned int PWM_high,PWM_low; //中间变量,用户请勿修改。
void change_pwm(int i);
void LoadPWM(int i);
void pwm_init();
//------------------------------------
void PID_Operation();
void PID_Output(void);
void Delay5us();
void Delay5ms();
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 conversion(uint temp_data)
//{
// wan=temp_data/10000+0x30 ;
// temp_data=temp_data%10000; //取余运算
// qian=temp_data/1000+0x30 ;
// temp_data=temp_data%1000; //取余运算
// bai=temp_data/100+0x30 ;
// temp_data=temp_data%100; //取余运算
// shi=temp_data/10+0x30 ;
// temp_data=temp_data%10; //取余运算
// ge=temp_data+0x30;
//}
/*******************************/
void delay(unsigned int k)
{
unsigned int i,j;
for(i=0;i<k;i++)
{
for(j=0;j<121;j++)
{;}}
}
/**************************************
延时5微秒(STC90C52RC---12MHz---12T)
不同的工作环境,需要调整此函数,注意时钟过快时需要修改
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5us()
{
unsigned char i;
_nop_();
_nop_();
i = 27;
while (--i);
}
///**************************************
//延时5毫秒(STC90C52RC@12M)
//不同的工作环境,需要调整此函数
//当改用1T的MCU时,请调整此延时函数
//**************************************/
//void Delay5ms()
//{
// unsigned char i, j;
// i = 117;
// j = 184;
// do
// {
// while (--j);
// } while (--i);
//}
/**************************************
起始信号
**************************************/
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(uchar REG_Address,uchar REG_data)
{
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(REG_Address); //内部寄存器地址,请参考中文pdf22页
ADXL345_SendByte(REG_data); //内部寄存器数据,请参考中文pdf22页
ADXL345_Stop(); //发送停止信号
}
//********单字节读取*****************************************
uchar Single_Read_ADXL345(uchar REG_Address)
{ uchar 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)
{ uchar 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(); //停止信号
}
//void send0ff()
//{
// SendData(0xff);
// SendData(0xff);
// SendData(0xff);
//}
//*****************************************************************
//初始化ADXL345,根据需要请参考pdf进行修改************************
void Init_ADXL345()
{
Single_Write_ADXL345(0x31,0x08); //测量范围,正负16g,13位模式
Single_Write_ADXL345(0x2C,0x0a); //速率设定为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页
}
////***********************************************************************
////显示x轴
//void display_x()
//{ float temp;
// unsigned char dis_t[16]="n0.val=0000";
// dis_data=(BUF[1]<<8)+BUF[0]; //合成数据
// if(dis_data<0){
// dis_data=-dis_data;
// SendString("t3.txt=\"-\"");
// send0ff();
// }
// else{
// SendString("t3.txt=\" \"");
// send0ff();}
// temp=(float)dis_data*3.9; //计算数据和显示,查考ADXL345快速入门第4页
// conversion(temp); //转换出显示需要的数据
// dis_t[7]=qian;
// dis_t[8]=bai;
// dis_t[9]=shi;
// dis_t[10]=ge;
// dis_t[11]=0xff;
// dis_t[12]=0xff;
// dis_t[13]=0xff;
// SendString(dis_t);
//}
//***********************************************************************
//显示y轴
//void display_y()
//{ float temp;
// unsigned char dis_t[16]="n1.val=";
// dis_data=(BUF[3]<<8)+BUF[2]; //合成数据
// if(dis_data<0){
// dis_data=-dis_data;
// SendString("t4.txt=\"-\"");
// send0ff();
// }
// else{
// SendString("t4.txt=\" \"");
// send0ff();}
// temp=(float)dis_data*3.9; //计算数据和显示,查考ADXL345快速入门第4页
// conversion(temp); //转换出显示需要的数据
// dis_t[7]=qian;
// dis_t[8]=bai;
// dis_t[9]=shi;
// dis_t[10]=ge;
// dis_t[11]=0xff;
// dis_t[12]=0xff;
// dis_t[13]=0xff;
// SendString(dis_t);
//}
//***********************************************************************
//显示z轴
//void display_z()
//{
// float temp;
// unsigned char dis_t[16]="n2.val=";
// dis_data=(BUF[5]<<8)+BUF[4]; //合成数据
// if(dis_data<0){
// dis_data=-dis_data;
// SendString("t5.txt=\"-\"");
// send0ff();
// }
// else{
// SendString("t5.txt=\" \"");
// send0ff();
//}
// temp=(float)dis_data*3.9; //计算数据和显示,查考ADXL345快速入门第4页
// conversion(temp); //转换出显示需要的数据
// dis_t[7]=qian;
// dis_t[8]=bai;
// dis_t[9]=shi;
// dis_t[10]=ge;
// dis_t[11]=0xff;
// dis_t[12]=0xff;
// dis_t[13]=0xff;
// SendString(dis_t);
//}
void io_init()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
}
//*********************************************************
//******主程序********
//*********************************************************
void main()
{
uchar temp[5];
uchar devid;
delay(500); //上电延时
io_init();
pwm_init();
uart3_init();
PID.iSetVal=16;
PID.uKP_Coe=3;
PID.uKI_Coe=0.1;
PID.uKD_Coe=5;
Init_ADXL345(); //初始化ADXL345
devid=Single_Read_ADXL345(0X00); //读出的数据为0XE5,表示正确
while(1) //循环
{
Multiple_Read_ADXL345(); //连续读出数据,存储在BUF中
x_value=(BUF[1]<<8)+BUF[0]; //合成数据
if(x_value<=0)
{
fu_flag=1;
x_value=-x_value;
}
else
fu_flag=0;
temp[0]=x_value/10000+'0';
temp[1]=x_value/1000%10+'0';
temp[2]=x_value/100%10+'0';
temp[3]=x_value/10%10+'0';
temp[4]=x_value%10+'0';
SendString(temp);
PID.iCurVal=x_value;
PID_Operation();
PID_Output();
// if(x_value>0)
// {
// fu_flag=0;
// if(x_value>=300)
// {
// x_value=300;
//
// }
// change_pwm(x_value);
// }
// else if(x_value<0)
// {
// x_value=-x_value;
// fu_flag=1;
// if(x_value>=300)
// {
// x_value=300;
//
// }
// change_pwm(x_value);
// }
}
}
void pwm_init()
{
P_PWM = 0;
P2M1 &= ~(1 << 5); //P2.5 设置为推挽输出
P2M0 |= (1 << 5);
P2M1 &= ~(1 << 1); //P2.1 设置为推挽输出
P2M0 |= (1 << 1);
// P1M1 &= ~(1 << 4); //P1.4 设置为推挽输出 STC15W204S
// P1M0 |= (1 << 4);
TR0 = 0; //停止计数
ET0 = 1; //允许中断
PT0 = 1; //高优先级中断
TMOD &= ~0x03; //工作模式,0: 16位自动重装
AUXR |= 0x80; //1T
TMOD &= ~0x04; //定时
INT_CLKO |= 0x01; //输出时钟
TH0 = 0;
TL0 = 0;
TR0 = 1; //开始运行
EA = 1;
}
//========================================================================
// 函数: void delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void change_pwm(int i)
{
LoadPWM(PWM_DUTY * i / 300);
}
/**************** 计算PWM重装值函数 *******************/
void LoadPWM(int i)
{
int j;
if(i > PWM_HIGH_MAX) i = PWM_HIGH_MAX; //如果写入大于最大占空比数据,则强制为最大占空比。
if(i < PWM_HIGH_MIN) i = PWM_HIGH_MIN; //如果写入小于最小占空比数据,则强制为最小占空比。
j = 65536UL - PWM_DUTY + i; //计算PWM低电平时间
i = 65536UL - i; //计算PWM高电平时间
EA = 0;
PWM_high = i; //装载PWM高电平时间
PWM_low = j; //装载PWM低电平时间
EA = 1;
}
/********************* Timer0中断函数************************/
void timer0_int (void) interrupt 1
{
if(P_PWM&&fu_flag==0)
{
TH0 = (unsigned char)(PWM_low >> 8); //如果是输出高电平,则装载低电平时间。
TL0 = (unsigned char)PWM_low;
P_PWM=0;
O_PWM=0;
}
else if(!P_PWM&&fu_flag==0)
{
TH0 = (unsigned char)(PWM_high >> 8); //如果是输出低电平,则装载高电平时间。
TL0 = (unsigned char)PWM_high;
O_PWM=0;
P_PWM=1;
}
if(O_PWM&&fu_flag==1)
{
TH0 = (unsigned char)(PWM_low >> 8); //如果是输出高电平,则装载低电平时间。
TL0 = (unsigned char)PWM_low;
O_PWM=0;
P_PWM=0;
}
else if(!O_PWM&&fu_flag==1)
{
TH0 = (unsigned char)(PWM_high >> 8); //如果是输出低电平,则装载高电平时间。
TL0 = (unsigned char)PWM_high;
O_PWM=1;
P_PWM=0;
}
}
/*
********************************************************
/*
函数名称:PID_Operation() void PID_Output(void)
/*
函数功能:PID运算
/*
入口参数:无(隐形输入,系数、设定值等)
/*
出口参数:无(隐形输出,U(k))
/*
函数说明:U(k)=KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]
********************************************************
*/
void PID_Operation(void)
{
uInt32 Temp[3] = {0}; //中间临时变量
uInt32 PostSum = 0; //正数和
uInt32 NegSum = 0; //负数和
if(PID.iSetVal > PID.iCurVal) //设定值大于实际值否?
{
if(PID.iSetVal - PID.iCurVal > 300) //偏差大于10否?
PID.iPriVal = 300; //偏差大于10为上限幅值输出(全速加热)
else
//否则慢慢来
{
Temp[0] = PID.iSetVal - PID.iCurVal; //偏差<=10,计算E(k)
PID.uEkFlag[1] = 0; //E(k)为正数,因为设定值大于实际值
/*
数值进行移位,注意顺序,否则会覆盖掉前面的数值 */
PID.liEkVal[2] = PID.liEkVal[1];
PID.liEkVal[1] = PID.liEkVal[0];
PID.liEkVal[0] = Temp[0];
/*
=================================================================== */
if(PID.liEkVal[0] > PID.liEkVal[1]) //E(k)>E(k-1)否?
{
Temp[0] = PID.liEkVal[0] - PID.liEkVal[1]; //E(k)>E(k-1)
PID.uEkFlag[0] = 0; //E(k)-E(k-1)为正数
}
else
{
Temp[0] = PID.liEkVal[1] - PID.liEkVal[0]; //E(k)<E(k-1)
PID.uEkFlag[0] = 1; //E(k)-E(k-1)为负数
}
/*
=================================================================== */
Temp[2] = PID.liEkVal[1] * 2; //2E(k-1)
if((PID.liEkVal[0] + PID.liEkVal[2]) > Temp[2]) //E(k-2)+E(k)>2E(k-1)否?
{
Temp[2] = (PID.liEkVal[0] + PID.liEkVal[2]) - Temp[2];
PID.uEkFlag[2]=0; //E(k-2)+E(k)-2E(k-1)为正数
}
else //E(k-2)+E(k)<2E(k-1)
{
Temp[2] = Temp[2] - (PID.liEkVal[0] + PID.liEkVal[2]);
PID.uEkFlag[2] = 1; //E(k-2)+E(k)-2E(k-1)为负数
}
/*
=================================================================== */
Temp[0] = (uInt32)PID.uKP_Coe * Temp[0]; //KP*[E(k)-E(k-1)]
Temp[1] = (uInt32)PID.uKI_Coe * PID.liEkVal[0]; //KI*E(k)
Temp[2] = (uInt32)PID.uKD_Coe * Temp[2]; //KD*[E(k-2)+E(k)-2E(k-1)]
/*
以下部分代码是讲所有的正数项叠加,负数项叠加 */
/*
========= 计算KP*[E(k)-E(k-1)]的值 ========= */
if(PID.uEkFlag[0] == 0)
PostSum += Temp[0]; //正数和
else
NegSum += Temp[0]; //负数和
/*
========= 计算KI*E(k)的值 ========= */
if(PID.uEkFlag[1] == 0)
PostSum += Temp[1]; //正数和
else
;
/*
空操作。就是因为PID.iSetVal > PID.iCurVal(即E(K)>0)才进入if的,
那么就没可能为负,所以打个转回去就是了
*/
/*
========= 计算KD*[E(k-2)+E(k)-2E(k-1)]的值 ========= */
if(PID.uEkFlag[2]==0)
PostSum += Temp[2]; //正数和
else
NegSum += Temp[2]; //负数和
/*
========= 计算U(k) ========= */
PostSum += (uInt32)PID.iPriVal;
if(PostSum > NegSum) //是否控制量为正数
{
Temp[0] = PostSum - NegSum;
if(Temp[0] < 300 ) //小于上限幅值则为计算值输出
PID.iPriVal = (uInt16)Temp[0];
else
PID.iPriVal = 300; //否则为上限幅值输出
}
else
//控制量输出为负数,则输出0(下限幅值输出)
PID.iPriVal = 0;
}
}
else
PID.iPriVal = 0;
}
/*
********************************************************
/*
函数名称:PID_Output()
/*
函数功能:PID输出控制
/*
入口参数:无(隐形输入,U(k))
/*
出口参数:无(控制端)
********************************************************
*/
void PID_Output(void)
{
static uInt16 iTemp;
iTemp = PID.iPriVal;
change_pwm(iTemp);
}
复制代码
所有资料51hei提供下载:
PCA捕获 带串口通信.zip
(80.33 KB, 下载次数: 40)
2018-7-20 08:49 上传
点击文件名下载附件
下载积分: 黑币 -5
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1