单片机源码:
- #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)
|