找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3810|回复: 0
收起左侧

51单片机驱动MPU6050+ADXL345带详细注释的源程序

[复制链接]
ID:375307 发表于 2018-7-20 08:50 | 显示全部楼层 |阅读模式
0.png
单片机源码:
  1. #include <STC15.H>   //引用STC15系列头文件,百度上搜索下载
  2. #include <INTRINS.H>
  3. #include <MATH.H>

  4. #define     I2C_SCL     P14      //时钟信号线
  5. #define     I2C_SDA     P15      //数据信号线

  6. #define PWR_MGMT_1      0x6B      //电源管理,典型值:0x00(正常启用)
  7. #define WHO_AM_I        0x75      //IIC地址寄存器(默认数值0x68,只读)
  8. #define SlaveAddress    0xD0      //IIC写入时的地址字节数据,+1为读取

  9. #define NOP1() nop_()
  10. #define NOP2() NOP1(),NOP1()

  11. #define MAIN_Fosc                   24000000L               //主时钟,不同的晶振频率可以直接修改
  12. #define serial_one_read_max         16                      //接收缓存区长度
  13. #define serial_one_baud_rate        115200L                 //波特率,波特率可以直接修改
  14. #define Timer1_Reload_Usart         (65536UL -(MAIN_Fosc / 4 / serial_one_baud_rate))       //Timer1重装值,定时器1产生波特率


  15. //****************************************
  16. // 定义MPU6050内部地址
  17. //****************************************
  18. #define SMPLRT_DIV      0x19    //陀螺仪采样率,典型值:0x07(125Hz)
  19. #define CONFIG          0x1A    //低通滤波频率,典型值:0x06(5Hz)
  20. #define GYRO_CONFIG     0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
  21. #define ACCEL_CONFIG    0x1C    //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
  22. #define ACCEL_XOUT_H    0x3B
  23. #define ACCEL_XOUT_L    0x3C
  24. #define ACCEL_YOUT_H    0x3D
  25. #define ACCEL_YOUT_L    0x3E
  26. #define ACCEL_ZOUT_H    0x3F
  27. #define ACCEL_ZOUT_L    0x40
  28. #define TEMP_OUT_H      0x41
  29. #define TEMP_OUT_L      0x42
  30. #define GYRO_XOUT_H     0x43
  31. #define GYRO_XOUT_L     0x44   
  32. #define GYRO_YOUT_H     0x45
  33. #define GYRO_YOUT_L     0x46
  34. #define GYRO_ZOUT_H     0x47
  35. #define GYRO_ZOUT_L     0x48


  36. void Delay1000ms()      //延时函数1秒
  37. {
  38.     unsigned char i, j, k;

  39.     _nop_();
  40.     _nop_();
  41.     i = 85;
  42.     j = 12;
  43.     k = 155;
  44.     do
  45.     {
  46.         do
  47.         {
  48.             while (--k);
  49.         } while (--j);
  50.     } while (--i);
  51. }


  52. //========================================================================
  53. // 函数: void I2C_Start()
  54. // 描述: I2C起始信号.
  55. // 参数: none.
  56. // 返回: none.
  57. // 版本: V1.0, 2017-06-23
  58. //========================================================================
  59. void I2C_Start()
  60. {
  61.     I2C_SDA = 1;                    //拉高数据线
  62.     I2C_SCL = 1;                    //拉高时钟线
  63.     NOP2();                         //等待机器反应
  64.     I2C_SDA = 0;                    //产生下降沿
  65.     I2C_SCL = 0;                    //拉低时钟线
  66. }

  67. //========================================================================
  68. // 函数: void I2C_Stop()
  69. // 描述: I2C停止信号.
  70. // 参数: none.
  71. // 返回: none.
  72. // 版本: V1.0, 2017-06-23
  73. //========================================================================
  74. void I2C_Stop()
  75. {
  76.     I2C_SDA = 0;                    //拉低数据线
  77.     I2C_SCL = 1;                    //拉高时钟线
  78.     NOP2();                         //等待机器反应
  79.     I2C_SDA = 1;                    //产生上升沿
  80.     NOP1();                         //等待机器反应
  81. }

  82. //========================================================================
  83. // 函数: void I2C_SendACK(bit ack)
  84. // 描述: I2C发送应答信号.
  85. // 参数: ack (0:ACK 1:NAK).
  86. // 返回: none.
  87. // 版本: V1.0, 2017-06-23
  88. //========================================================================
  89. void I2C_SendACK(bit ack)
  90. {
  91.     I2C_SDA = ack;                  //写应答信号
  92.     I2C_SCL = 1;                    //拉高时钟线
  93.     NOP2();                                         //等待机器反应
  94.     I2C_SCL = 0;                    //拉低时钟线
  95.     NOP1();                                         //等待机器反应
  96. }

  97. //========================================================================
  98. // 函数: bit I2C_RecvACK()
  99. // 描述: I2C接收应答信号.
  100. // 参数: none.
  101. // 返回: 1:成功,0:失败.
  102. // 版本: V1.0, 2017-06-23
  103. //========================================================================
  104. bit I2C_RecvACK()
  105. {
  106.     I2C_SCL = 1;            //拉高时钟线
  107.     NOP2();                         //等待机器反应
  108.     CY = I2C_SDA;           //读应答信号
  109.     I2C_SCL = 0;            //拉低时钟线
  110.     return CY;
  111. }

  112. //========================================================================
  113. // 函数: void I2C_SendByte(u8 dat)
  114. // 描述: 向I2C总线发送一个字节数据.
  115. // 参数: dat:要发送的数据.
  116. // 返回: none.
  117. // 版本: V1.0, 2017-06-23
  118. //========================================================================
  119. void I2C_SendByte(unsigned char dat)
  120. {
  121.     unsigned char i;
  122.     for (i=0; i<8; i++)         //8位计数器
  123.     {
  124.         dat <<= 1;              //移出数据的最高位
  125.         I2C_SDA = CY;           //送数据口
  126.         I2C_SCL = 1;                //拉高时钟线
  127.         NOP2();                                 //等待机器反应
  128.         I2C_SCL = 0;                //拉低时钟线
  129.     }
  130.     I2C_RecvACK();
  131. }

  132. //========================================================================
  133. // 函数: unsigned char I2C_RecvByte()
  134. // 描述: 从I2C总线接收一个字节数据.
  135. // 参数: none.
  136. // 返回: 接收到的数据.
  137. // 版本: V1.0, 2017-06-23
  138. //========================================================================
  139. unsigned char I2C_RecvByte()
  140. {
  141.     unsigned char i;
  142.     unsigned char dat = 0;
  143.     I2C_SDA = 1;                    //使能内部上拉,准备读取数据,
  144.     for (i=0; i<8; i++)                       //8位计数器
  145.     {
  146.         dat <<= 1;
  147.         I2C_SCL = 1;                //拉高时钟线
  148.         NOP2();                                 //等待机器反应
  149.         dat |= I2C_SDA;             //读数据               
  150.         I2C_SCL = 0;                //拉低时钟线
  151.     }
  152.     return dat;
  153. }

  154. //========================================================================
  155. // 函数: void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
  156. // 描述: 向I2C设备写入一个字节数据.
  157. // 参数: REG_Address:地址.
  158. //           REG_data:要写入的数据.
  159. // 返回: none.
  160. // 版本: V1.0, 2017-06-23
  161. //========================================================================
  162. void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
  163. {
  164.     I2C_Start();                  //起始信号
  165.     I2C_SendByte(SlaveAddress);   //发送设备地址+写信号
  166.     I2C_SendByte(REG_Address);    //内部寄存器地址,
  167.     I2C_SendByte(REG_data);       //内部寄存器数据,
  168.     I2C_Stop();                   //发送停止信号
  169. }

  170. //========================================================================
  171. // 函数: unsigned char Single_ReadI2C(unsigned char REG_Address)
  172. // 描述: 从I2C设备读取一个字节数据.
  173. // 参数: REG_Address:地址.
  174. // 返回: 读取到的数据.
  175. // 版本: V1.0, 2017-06-23
  176. //========================================================================
  177. unsigned char Single_ReadI2C(unsigned char REG_Address)
  178. {
  179.     unsigned char REG_data;
  180.     I2C_Start();                   //起始信号
  181.     I2C_SendByte(SlaveAddress);    //发送设备地址+写信号
  182.     I2C_SendByte(REG_Address);     //发送存储单元地址,从0开始  
  183.     I2C_Start();                   //起始信号
  184.     I2C_SendByte(SlaveAddress+1);  //发送设备地址+读信号
  185.     REG_data=I2C_RecvByte();       //读出寄存器数据
  186.     I2C_SendACK(1);                //接收应答信号
  187.     I2C_Stop();                    //停止信号
  188.     return REG_data;
  189. }

  190. //========================================================================
  191. // 函数: void MPU6050_init()
  192. // 描述: 初始化MPU6050.
  193. // 参数: none.
  194. // 返回: none.
  195. // 版本: V1.0, 2017-06-23
  196. //========================================================================
  197. void MPU6050_Init()
  198. {
  199.     Single_WriteI2C(PWR_MGMT_1, 0x00);  //解除休眠状态
  200.     Single_WriteI2C(SMPLRT_DIV, 0x07);
  201.     Single_WriteI2C(CONFIG, 0x06);
  202.     Single_WriteI2C(GYRO_CONFIG, 0x18);
  203.     Single_WriteI2C(ACCEL_CONFIG, 0x01);
  204. }

  205. //========================================================================
  206. // 函数: int GetData(u8 REG_Address)
  207. // 描述: 读取数据并合成为int型数据.
  208. // 参数: REG_Address:地址.
  209. // 返回: 读取到的数据.
  210. // 版本: V1.0, 2017-06-23
  211. //========================================================================
  212. int GetData(unsigned char REG_Address)
  213. {
  214.     unsigned char H,L;
  215.     H = Single_ReadI2C(REG_Address);
  216.     L = Single_ReadI2C(REG_Address + 1);
  217.     return (H << 8) + L;   //合成数据
  218. }

  219. ////========================================================================
  220. //// 函数: int get_x_angle()
  221. //// 描述: 获取三轴角速度,三轴加速度
  222. //// 参数: gyro_id:数据ID,1:x角速度,2:y角速度,3:z角速度,4:x加速度,5:y加速度,6:z加速度.
  223. //// 返回: 陀螺仪值.
  224. //// 版本: V2.0, 2017-07-15
  225. ////========================================================================
  226. int Get_Gyro_Data(unsigned char gyro_id)
  227. {
  228.     switch(gyro_id)
  229.     {
  230.         case 1: return GetData(ACCEL_XOUT_H);   break;
  231.         case 2: return GetData(ACCEL_YOUT_H);   break;
  232.         case 3: return GetData(ACCEL_ZOUT_H);   break;
  233.         case 4: return GetData(GYRO_XOUT_H) ;   break;
  234.         case 5: return GetData(GYRO_YOUT_H) ;   break;
  235.         case 6: return GetData(GYRO_ZOUT_H) ;   break;
  236.     }
  237.     return 0;
  238. }

  239. //========================================================================
  240. // 函数: int MPU6050_Get_Angle(float x,float y,float z,u8 dir)
  241. // 描述: 转化成与三个方向的夹角.
  242. // 参数: x:x方向数据.
  243. //       y:y方向数据.
  244. //       z:z方向数据.
  245. //       dir:方向ID.
  246. // 返回: 夹角角度值(放大10倍).
  247. // 版本: V1.0, 2017-06-23
  248. //========================================================================
  249. int MPU6050_Get_Angle(int x,int y,int z,unsigned char dir)
  250. {
  251.     float xdata temp;
  252.     float xdata res = 0;
  253.     switch(dir)
  254.     {
  255.         case 0://与z轴的夹角
  256.                 temp = sqrt(((float)x*(float)x+(float)y*(float)y))/(float)z;
  257.                 res  = atan(temp);
  258.         break;
  259.         case 1://与x轴的夹角
  260.                 temp = (float)x/sqrt(((float)y*(float)y+(float)z*(float)z));
  261.                 res  = atan(temp);
  262.         break;
  263.         case 2://与y轴的夹角
  264.                 temp = (float)y/sqrt(((float)x*(float)x+(float)z*(float)z));
  265.                 res  = atan(temp);
  266.         break;
  267.     }
  268.     return (int)(res*1800/3.1416);//弧度转换为角度,扩大10倍
  269. }

  270. //========================================================================
  271. // int get_included_angle(unsigned dat)
  272. // 描述: 获取角度或加速度
  273. // 参数: angle_id:方向指示变量(1:X轴角度,2:Y轴角度,3:Z轴角度,4:X轴加速度,5:Y轴加速度,6:Z轴加速度).
  274. // 返回: 夹角角度值(放大10倍).
  275. // 版本: V1.0, 2017-06-23
  276. //========================================================================
  277. int MPU6050_Get_Data(unsigned angle_id)
  278. {
  279.     switch(angle_id)
  280.     {
  281.         case 1:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 1);break;
  282.         case 2:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 2);break;
  283.         case 3:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 0);break;
  284.         case 4:return (int)((float)((float)Get_Gyro_Data(4)/16384)*9.8*100);
  285.         case 5:return (int)((float)((float)Get_Gyro_Data(5)/16384)*9.8*100);
  286.         case 6:return (int)((float)((float)Get_Gyro_Data(6)/16384)*9.8*100);
  287.     }
  288.     return 0;
  289. }

  290. //串口初始化
  291. void Uart_Init()
  292. {
  293.     SCON |= 0x40;               //8位数据
  294.     P_SW1 &=  ~0xc0;       //UART1 使用P30 P31口  默认
  295.     TR1 = 0;                        //关闭定时器1
  296.     AUXR &= ~0x01;         //串口1波特率使用定时器1
  297.     TMOD &= ~(1<<6);       //Timer1 set As Timer
  298.     TMOD &= ~0x30;         //16位自动重装
  299.     AUXR |=  (1<<6);        //定时器使用1T模式
  300.     TH1 = (unsigned char)(Timer1_Reload_Usart >> 8);
  301.     TL1 = (unsigned char)Timer1_Reload_Usart;
  302.     TR1 = 1;                        //打开定时器1
  303.     PS  = 1;                        //高优先级中断
  304.     REN = 1;                        //允许接收
  305.     ES  = 1;                        //允许中断
  306.     EA  = 1;                        //允许全局中断
  307. }

  308. //========================================================================
  309. // 函数: serial_one_send_byte(unsigned char dat)
  310. // 描述: 串口1发送一个字节.
  311. // 参数: dat:字符(无符号八位整型数据).
  312. // 返回: none.
  313. // 版本: V1.0, 2017-06-22
  314. //========================================================================
  315. void serial_one_send_byte(unsigned char dat)
  316. {
  317.     SBUF = dat;
  318.     while(!TI);
  319.     TI = 0;
  320. }

  321. //========================================================================
  322. // 函数: serial_one_send_string(u8 *dat)
  323. // 描述: 串口1发送字符串.
  324. // 参数: dat:字符串.
  325. // 返回: none.
  326. // 版本: V1.0, 2017-06-22
  327. //========================================================================
  328. void serial_one_send_string(unsigned char *dat)
  329. {
  330.     while(*dat)
  331.         serial_one_send_byte(*dat++);
  332. }

  333. //========================================================================
  334. // 函数: void serial_one_send_number(long num)
  335. // 描述: 串口1发送整型数据.
  336. // 参数: num:整型数值.
  337. // 返回: none.
  338. // 版本: V1.0, 2017-06-22
  339. //========================================================================
  340. void serial_one_send_number(long num)
  341. {
  342.     long dat = 0;
  343.     unsigned char  length = 0;
  344.     if(num < 0)                                     //当数值为负数时
  345.     {
  346.         serial_one_send_byte('-');  //输出负号
  347.         num = -num;                                 //将数值取相反数
  348.     }

  349.     if(num == 0)                                    //当数值为0时
  350.         serial_one_send_byte('0');  //输出字符0
  351.     else                                            //当数值不为0时
  352.     {
  353.         while(num)                                  //将数值倒过来
  354.         {
  355.             dat = dat * 10;
  356.             dat = dat + num % 10;
  357.             num = num / 10;
  358.             length++;
  359.         }

  360.         while(length--)                         //从第一位开始输出倒过来的数值
  361.         {
  362.             serial_one_send_byte(dat % 10 + '0');
  363.             dat = dat / 10;
  364.         }
  365.     }
  366. }

  367. void serial_one_send_float(double float_val, char bit_val)
  368. {
  369.     long xdata value_int = 0;
  370.     long xdata value_flt = 0;

  371.     if(float_val < 0)
  372.     {
  373.         serial_one_send_byte('-');
  374.         float_val = -float_val;
  375.     }

  376.     value_int = (long)float_val;

  377.     float_val = float_val - (double)value_int;

  378.     for(;bit_val;bit_val--)
  379.         float_val = float_val * 10;

  380.     serial_one_send_number(value_int);
  381.     serial_one_send_byte('.');
  382.     serial_one_send_number((long)float_val);
  383. }

  384. float value = 0;

  385. //主函数
  386. void main()
  387. {
  388.     Delay1000ms();
  389.     Uart_Init();            //串口初始化
  390.     MPU6050_Init();         //初始化MPU6505
  391.     while(1)
  392.     {
  393.         value = MPU6050_Get_Data(1);                    //获取与x轴的夹角,角度被放大10倍
  394.         serial_one_send_string("模块与x轴的夹角为:");
  395.         serial_one_send_float(value / 10,1);            //角度除以10,并从串口发出,第二个参数为保留一位小数
  396.         serial_one_send_string("\r\n");                 //换行

  397.         value = MPU6050_Get_Data(2);                    //获取与y轴的夹角,角度被放大10倍
  398.         serial_one_send_string("模块与y轴的夹角为:");
  399.         serial_one_send_float(value / 10,1);            //角度除以10,并从串口发出
  400.         serial_one_send_string("\r\n");                 //换行

  401.         value = MPU6050_Get_Data(3);                    //获取与z轴的夹角,角度被放大10倍
  402.         serial_one_send_string("模块与z轴的夹角为:");
  403.         serial_one_send_float(value / 10,1);            //角度除以10,并从串口发出
  404.         serial_one_send_string("\r\n");                 //换行

  405.         value = MPU6050_Get_Data(4);                    //获取与x轴加速度,数值被放大100倍
  406.         serial_one_send_string("x轴加速度为:");
  407.         serial_one_send_float(value/100,1);         //角度除以100,并从串口发出,第二个参数为保留一位小数
  408.         serial_one_send_string(" M/S2\r\n");                    //换行

  409.         value = MPU6050_Get_Data(4);                    //获取与y轴加速度,数值被放大100倍
  410.         serial_one_send_string("y轴加速度为:");
  411.         serial_one_send_float(value / 100,1);           //角度除以100,并从串口发出
  412.         serial_one_send_string(" M/S2\r\n");                    //换行

  413.         value = MPU6050_Get_Data(4);                    //获取与z轴加速度,数值被放大100倍
  414.         serial_one_send_string("z轴加速度为:");
  415.         serial_one_send_float(value / 100,1);           //角度除以100,并从串口发出
  416.         serial_one_send_string(" M/S2\r\n\r\n");                    //换行

  417.         Delay1000ms();
  418.         Delay1000ms();
  419.     }
  420. }

  421. //串口中断
  422. void Uart1_Int (void) interrupt 4
  423. {
  424.     if(RI)
  425.         RI = 0;
  426. }
复制代码

  1. /*
  2. * ADXL345模块
  3. *
  4. * 用途:ADXL345模块IIC测试程序
  5. *
  6. * 作者                                        日期                                备注
  7. *
  8. */
  9. #include "uart3.h"
  10. #include  <stc15.H>        
  11. #include  <math.h>    //Keil library  
  12. #include  <stdio.h>   //Keil library        
  13. #include  <INTRINS.H>
  14. #define   uchar unsigned char
  15. #define   uint unsigned int


  16. sbit          SCL=P0^6;      //IIC时钟引脚定义
  17. sbit           SDA=P0^7;      //IIC数据引脚定义
  18. sbit    P_PWM = P2^5;       //定义PWM输出引脚。
  19. sbit                O_PWM = P2^1;
  20. #define        SlaveAddress   0xa6          //定义器件在IIC总线中的从地址,根据ALT  ADDRESS地址引脚不同修改
  21.                               //ALT  ADDRESS引脚接地时地址为0xA6,接电源时地址为0x3A
  22. #define     PWM_HIGH_MIN    32              //限制PWM输出的最小占空比。用户请勿修改。
  23. #define     PWM_HIGH_MAX    (PWM_DUTY-PWM_HIGH_MIN) //限制PWM输出的最大占空比。用户请勿修改。
  24. long  PWM_DUTY=20200;
  25. unsigned int duty;
  26. unsigned char fu_flag=0;

  27. unsigned int     pwm;                //定义PWM输出高电平的时间的变量。用户操作PWM的变量。
  28. //BYTE BUF[8];                         //接收数据缓存区              
  29. uchar ge,shi,bai,qian,wan;           //显示变量
  30. int  dis_data;                       //变量
  31. int  x_value=0;
  32. void delay(unsigned int k);
  33. void Init_ADXL345(void);             //初始化ADXL345

  34. void conversion(uint temp_data);

  35. void  Single_Write_ADXL345(uchar REG_Address,uchar REG_data);   //单个写入数据
  36. uchar Single_Read_ADXL345(uchar REG_Address);                   //单个读取内部寄存器数据
  37. void  Multiple_Read_ADXL345();                                  //连续的读取内部寄存器数据






  38. //sbit  P_PWM = P1^4;       //定义PWM输出引脚。STC15W204S



  39. unsigned int     PWM_high,PWM_low;   //中间变量,用户请勿修改。
  40. void         change_pwm(int i);
  41. void  LoadPWM(int i);
  42. void        pwm_init();
  43. //------------------------------------
  44. void PID_Operation();  
  45. void PID_Output(void);
  46. void Delay5us();
  47. void Delay5ms();
  48. void ADXL345_Start();
  49. void ADXL345_Stop();
  50. void ADXL345_SendACK(bit ack);
  51. bit  ADXL345_RecvACK();
  52. void ADXL345_SendByte(BYTE dat);
  53. BYTE ADXL345_RecvByte();
  54. void ADXL345_ReadPage();
  55. void ADXL345_WritePage();
  56. //-----------------------------------

  57. //*********************************************************
  58. //void conversion(uint temp_data)  
  59. //{  
  60. //    wan=temp_data/10000+0x30 ;
  61. //    temp_data=temp_data%10000;   //取余运算
  62. //                qian=temp_data/1000+0x30 ;
  63. //    temp_data=temp_data%1000;    //取余运算
  64. //    bai=temp_data/100+0x30   ;
  65. //    temp_data=temp_data%100;     //取余运算
  66. //    shi=temp_data/10+0x30    ;
  67. //    temp_data=temp_data%10;      //取余运算
  68. //    ge=temp_data+0x30;         
  69. //}

  70. /*******************************/
  71. void delay(unsigned int k)        
  72. {                                                
  73. unsigned int i,j;                                
  74.         for(i=0;i<k;i++)
  75.         {                        
  76.         for(j=0;j<121;j++)                        
  77.         {;}}                                                
  78. }
  79. /**************************************
  80. 延时5微秒(STC90C52RC---12MHz---12T)
  81. 不同的工作环境,需要调整此函数,注意时钟过快时需要修改
  82. 当改用1T的MCU时,请调整此延时函数
  83. **************************************/
  84. void Delay5us()
  85. {
  86. unsigned char i;

  87.         _nop_();
  88.         _nop_();
  89.         i = 27;
  90.         while (--i);
  91. }

  92. ///**************************************
  93. //延时5毫秒(STC90C52RC@12M)
  94. //不同的工作环境,需要调整此函数
  95. //当改用1T的MCU时,请调整此延时函数
  96. //**************************************/
  97. //void Delay5ms()
  98. //{
  99. //        unsigned char i, j;

  100. //        i = 117;
  101. //        j = 184;
  102. //        do
  103. //        {
  104. //                while (--j);
  105. //        } while (--i);
  106. //}

  107. /**************************************
  108. 起始信号
  109. **************************************/
  110. void ADXL345_Start()
  111. {
  112.     SDA = 1;                    //拉高数据线
  113.     SCL = 1;                    //拉高时钟线
  114.     Delay5us();                 //延时
  115.     SDA = 0;                    //产生下降沿
  116.     Delay5us();                 //延时
  117.     SCL = 0;                    //拉低时钟线
  118. }

  119. /**************************************
  120. 停止信号
  121. **************************************/
  122. void ADXL345_Stop()
  123. {
  124.     SDA = 0;                    //拉低数据线
  125.     SCL = 1;                    //拉高时钟线
  126.     Delay5us();                 //延时
  127.     SDA = 1;                    //产生上升沿
  128.     Delay5us();                 //延时
  129. }

  130. /**************************************
  131. 发送应答信号
  132. 入口参数:ack (0:ACK 1:NAK)
  133. **************************************/
  134. void ADXL345_SendACK(bit ack)
  135. {
  136.     SDA = ack;                  //写应答信号
  137.     SCL = 1;                    //拉高时钟线
  138.     Delay5us();                 //延时
  139.     SCL = 0;                    //拉低时钟线
  140.     Delay5us();                 //延时
  141. }

  142. /**************************************
  143. 接收应答信号
  144. **************************************/
  145. bit ADXL345_RecvACK()
  146. {
  147.     SCL = 1;                    //拉高时钟线
  148.     Delay5us();                 //延时
  149.     CY = SDA;                   //读应答信号
  150.     SCL = 0;                    //拉低时钟线
  151.     Delay5us();                 //延时

  152.     return CY;
  153. }

  154. /**************************************
  155. 向IIC总线发送一个字节数据
  156. **************************************/
  157. void ADXL345_SendByte(BYTE dat)
  158. {
  159.     BYTE i;

  160.     for (i=0; i<8; i++)         //8位计数器
  161.     {
  162.         dat <<= 1;              //移出数据的最高位
  163.         SDA = CY;               //送数据口
  164.         SCL = 1;                //拉高时钟线
  165.         Delay5us();             //延时
  166.         SCL = 0;                //拉低时钟线
  167.         Delay5us();             //延时
  168.     }
  169.     ADXL345_RecvACK();
  170. }

  171. /**************************************
  172. 从IIC总线接收一个字节数据
  173. **************************************/
  174. BYTE ADXL345_RecvByte()
  175. {
  176.     BYTE i;
  177.     BYTE dat = 0;

  178.     SDA = 1;                    //使能内部上拉,准备读取数据,
  179.     for (i=0; i<8; i++)         //8位计数器
  180.     {
  181.         dat <<= 1;
  182.         SCL = 1;                //拉高时钟线
  183.         Delay5us();             //延时
  184.         dat |= SDA;             //读数据               
  185.         SCL = 0;                //拉低时钟线
  186.         Delay5us();             //延时
  187.     }
  188.     return dat;
  189. }

  190. //******单字节写入*******************************************

  191. void Single_Write_ADXL345(uchar REG_Address,uchar REG_data)
  192. {
  193.     ADXL345_Start();                  //起始信号
  194.     ADXL345_SendByte(SlaveAddress);   //发送设备地址+写信号
  195.     ADXL345_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf22页
  196.     ADXL345_SendByte(REG_data);       //内部寄存器数据,请参考中文pdf22页
  197.     ADXL345_Stop();                   //发送停止信号
  198. }

  199. //********单字节读取*****************************************
  200. uchar Single_Read_ADXL345(uchar REG_Address)
  201. {  uchar REG_data;
  202.     ADXL345_Start();                          //起始信号
  203.     ADXL345_SendByte(SlaveAddress);           //发送设备地址+写信号
  204.     ADXL345_SendByte(REG_Address);            //发送存储单元地址,从0开始        
  205.     ADXL345_Start();                          //起始信号
  206.     ADXL345_SendByte(SlaveAddress+1);         //发送设备地址+读信号
  207.     REG_data=ADXL345_RecvByte();              //读出寄存器数据
  208.         ADXL345_SendACK(1);   
  209.         ADXL345_Stop();                           //停止信号
  210.     return REG_data;
  211. }
  212. //*********************************************************
  213. //
  214. //连续读出ADXL345内部加速度数据,地址范围0x32~0x37
  215. //
  216. //*********************************************************
  217. void Multiple_read_ADXL345(void)
  218. {   uchar i;
  219.     ADXL345_Start();                          //起始信号
  220.     ADXL345_SendByte(SlaveAddress);           //发送设备地址+写信号
  221.     ADXL345_SendByte(0x32);                   //发送存储单元地址,从0x32开始        
  222.     ADXL345_Start();                          //起始信号
  223.     ADXL345_SendByte(SlaveAddress+1);         //发送设备地址+读信号
  224.          for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中BUF
  225.     {
  226.         BUF[i] = ADXL345_RecvByte();          //BUF[0]存储0x32地址中的数据
  227.         if (i == 5)
  228.         {
  229.            ADXL345_SendACK(1);                //最后一个数据需要回NOACK
  230.         }
  231.         else
  232.         {
  233.           ADXL345_SendACK(0);                //回应ACK
  234.        }
  235.    }
  236.     ADXL345_Stop();                          //停止信号

  237. }
  238. //void send0ff()

  239. //{
  240. //        SendData(0xff);
  241. //        SendData(0xff);
  242. //        SendData(0xff);
  243. //}

  244. //*****************************************************************

  245. //初始化ADXL345,根据需要请参考pdf进行修改************************
  246. void Init_ADXL345()
  247. {
  248.    Single_Write_ADXL345(0x31,0x08);   //测量范围,正负16g,13位模式
  249.    Single_Write_ADXL345(0x2C,0x0a);   //速率设定为12.5 参考pdf13页
  250.    Single_Write_ADXL345(0x2D,0x08);   //选择电源模式   参考pdf24页
  251.    Single_Write_ADXL345(0x2E,0x80);   //使能 DATA_READY 中断
  252.    Single_Write_ADXL345(0x1E,0x00);   //X 偏移量 根据测试传感器的状态写入pdf29页
  253.    Single_Write_ADXL345(0x1F,0x00);   //Y 偏移量 根据测试传感器的状态写入pdf29页
  254.    Single_Write_ADXL345(0x20,0x05);   //Z 偏移量 根据测试传感器的状态写入pdf29页
  255. }
  256. ////***********************************************************************
  257. ////显示x轴
  258. //void display_x()
  259. //{   float temp;
  260. //                unsigned char dis_t[16]="n0.val=0000";
  261. //    dis_data=(BUF[1]<<8)+BUF[0];  //合成数据   
  262. //        if(dis_data<0){
  263. //        dis_data=-dis_data;
  264. //   SendString("t3.txt=\"-\"");
  265. //                send0ff();
  266. //        }
  267. //                else{
  268. //                SendString("t3.txt=\" \"");
  269. //                        send0ff();}

  270. //    temp=(float)dis_data*3.9;  //计算数据和显示,查考ADXL345快速入门第4页
  271. //    conversion(temp);          //转换出显示需要的数据
  272. //                dis_t[7]=qian;
  273. //                dis_t[8]=bai;
  274. //                dis_t[9]=shi;
  275. //                dis_t[10]=ge;
  276. //                dis_t[11]=0xff;
  277. //        dis_t[12]=0xff;
  278. //        dis_t[13]=0xff;
  279. //        SendString(dis_t);
  280. //}

  281. //***********************************************************************
  282. //显示y轴
  283. //void display_y()
  284. //{     float temp;
  285. //        unsigned char dis_t[16]="n1.val=";
  286. //    dis_data=(BUF[3]<<8)+BUF[2];  //合成数据   
  287. //        if(dis_data<0){
  288. //        dis_data=-dis_data;
  289. //   SendString("t4.txt=\"-\"");
  290. //                send0ff();
  291. //        }
  292. //                else{
  293. //                SendString("t4.txt=\" \"");
  294. //                        send0ff();}

  295. //    temp=(float)dis_data*3.9;  //计算数据和显示,查考ADXL345快速入门第4页
  296. //    conversion(temp);          //转换出显示需要的数据
  297. //                dis_t[7]=qian;
  298. //                dis_t[8]=bai;
  299. //                dis_t[9]=shi;
  300. //                dis_t[10]=ge;
  301. //                dis_t[11]=0xff;
  302. //        dis_t[12]=0xff;
  303. //        dis_t[13]=0xff;
  304. //        SendString(dis_t);
  305. //}

  306. //***********************************************************************
  307. //显示z轴
  308. //void display_z()
  309. //{
  310. //    float temp;
  311. //        unsigned char dis_t[16]="n2.val=";
  312. //    dis_data=(BUF[5]<<8)+BUF[4];    //合成数据   
  313. //        if(dis_data<0){
  314. //        dis_data=-dis_data;
  315. //   SendString("t5.txt=\"-\"");
  316. //                send0ff();
  317. //        }
  318. //        else{
  319. //                SendString("t5.txt=\" \"");
  320. //                        send0ff();
  321. //}

  322. //    temp=(float)dis_data*3.9;  //计算数据和显示,查考ADXL345快速入门第4页
  323. //    conversion(temp);          //转换出显示需要的数据
  324. //                dis_t[7]=qian;
  325. //                dis_t[8]=bai;
  326. //                dis_t[9]=shi;
  327. //                dis_t[10]=ge;
  328. //        dis_t[11]=0xff;
  329. //        dis_t[12]=0xff;
  330. //        dis_t[13]=0xff;
  331. //        SendString(dis_t);
  332. //}
  333. void io_init()
  334. {
  335.           P0M0 = 0x00;
  336.     P0M1 = 0x00;
  337.     P1M0 = 0x00;
  338.     P1M1 = 0x00;
  339.     P2M0 = 0x00;
  340.     P2M1 = 0x00;
  341.     P3M0 = 0x00;
  342.     P3M1 = 0x00;
  343.     P4M0 = 0x00;
  344.     P4M1 = 0x00;
  345.     P5M0 = 0x00;
  346.     P5M1 = 0x00;
  347.     P6M0 = 0x00;
  348.     P6M1 = 0x00;
  349.     P7M0 = 0x00;
  350.     P7M1 = 0x00;
  351. }

  352. //*********************************************************
  353. //******主程序********
  354. //*********************************************************
  355. void main()
  356. {
  357.         uchar temp[5];
  358.         uchar devid;
  359.         delay(500);                                   //上电延时               
  360.         io_init();
  361.         pwm_init();
  362.         uart3_init();
  363.         PID.iSetVal=16;        
  364.         PID.uKP_Coe=3;
  365.         PID.uKI_Coe=0.1;
  366.         PID.uKD_Coe=5;
  367.         Init_ADXL345();                         //初始化ADXL345
  368.         devid=Single_Read_ADXL345(0X00);        //读出的数据为0XE5,表示正确
  369.         while(1)                                 //循环
  370.         {
  371.                 Multiple_Read_ADXL345();               //连续读出数据,存储在BUF中         
  372.                 x_value=(BUF[1]<<8)+BUF[0];  //合成数据  
  373.                
  374.                 if(x_value<=0)
  375.                 {
  376.                         fu_flag=1;
  377.                         x_value=-x_value;
  378.                 }
  379.                 else
  380.                         fu_flag=0;
  381.                 temp[0]=x_value/10000+'0';
  382.                 temp[1]=x_value/1000%10+'0';
  383.                 temp[2]=x_value/100%10+'0';
  384.                 temp[3]=x_value/10%10+'0';
  385.                 temp[4]=x_value%10+'0';
  386.                
  387.                
  388.                
  389.                
  390.                 SendString(temp);
  391.                 PID.iCurVal=x_value;
  392.                 PID_Operation();
  393.                 PID_Output();
  394. //                if(x_value>0)
  395. //                {
  396. //                        fu_flag=0;
  397. //                        if(x_value>=300)
  398. //                        {
  399. //                                x_value=300;
  400. //                                
  401. //                        }
  402. //                        change_pwm(x_value);
  403. //                }
  404. //                else if(x_value<0)
  405. //                {
  406. //                        x_value=-x_value;
  407. //                        fu_flag=1;
  408. //                        if(x_value>=300)
  409. //                        {
  410. //                                x_value=300;
  411. //                                
  412. //                        }
  413. //                        change_pwm(x_value);
  414. //                }
  415.                         
  416.         }
  417. }
  418. void pwm_init()
  419. {
  420.                 P_PWM = 0;
  421.     P2M1 &= ~(1 << 5);  //P2.5 设置为推挽输出
  422.     P2M0 |=  (1 << 5);
  423.                 P2M1 &= ~(1 << 1);  //P2.1 设置为推挽输出
  424.     P2M0 |=  (1 << 1);

  425. //  P1M1 &= ~(1 << 4);  //P1.4 设置为推挽输出   STC15W204S
  426. //  P1M0 |=  (1 << 4);

  427.     TR0 = 0;        //停止计数
  428.     ET0 = 1;        //允许中断
  429.     PT0 = 1;        //高优先级中断
  430.     TMOD &= ~0x03;  //工作模式,0: 16位自动重装
  431.     AUXR |=  0x80;  //1T
  432.     TMOD &= ~0x04;  //定时
  433.     INT_CLKO |=  0x01;  //输出时钟

  434.     TH0 = 0;
  435.     TL0 = 0;
  436.     TR0 = 1;    //开始运行

  437.     EA = 1;
  438. }


  439. //========================================================================
  440. // 函数: void  delay_ms(unsigned char ms)
  441. // 描述: 延时函数。
  442. // 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
  443. // 返回: none.
  444. // 版本: VER1.0
  445. // 日期: 2013-4-1
  446. // 备注:
  447. //========================================================================
  448. void         change_pwm(int i)
  449. {
  450.         LoadPWM(PWM_DUTY * i / 300);
  451. }

  452. /**************** 计算PWM重装值函数 *******************/
  453. void    LoadPWM(int i)
  454. {
  455.     int j;

  456.     if(i > PWM_HIGH_MAX)        i = PWM_HIGH_MAX;   //如果写入大于最大占空比数据,则强制为最大占空比。
  457.     if(i < PWM_HIGH_MIN)        i = PWM_HIGH_MIN;   //如果写入小于最小占空比数据,则强制为最小占空比。
  458.     j = 65536UL - PWM_DUTY + i; //计算PWM低电平时间
  459.     i = 65536UL - i;            //计算PWM高电平时间
  460.     EA = 0;
  461.     PWM_high = i;   //装载PWM高电平时间
  462.     PWM_low  = j;   //装载PWM低电平时间
  463.     EA = 1;
  464. }

  465. /********************* Timer0中断函数************************/
  466. void timer0_int (void) interrupt 1
  467. {
  468.     if(P_PWM&&fu_flag==0)
  469.     {
  470.         TH0 = (unsigned char)(PWM_low >> 8);   //如果是输出高电平,则装载低电平时间。
  471.         TL0 = (unsigned char)PWM_low;
  472.                                 P_PWM=0;
  473.                                 O_PWM=0;
  474.     }
  475.     else if(!P_PWM&&fu_flag==0)
  476.     {
  477.         TH0 = (unsigned char)(PWM_high >> 8);  //如果是输出低电平,则装载高电平时间。
  478.         TL0 = (unsigned char)PWM_high;
  479.                                 O_PWM=0;
  480.                                 P_PWM=1;
  481.     }
  482.                 if(O_PWM&&fu_flag==1)
  483.                 {
  484.         TH0 = (unsigned char)(PWM_low >> 8);   //如果是输出高电平,则装载低电平时间。
  485.         TL0 = (unsigned char)PWM_low;
  486.                                 O_PWM=0;
  487.                                 P_PWM=0;
  488.     }
  489.     else if(!O_PWM&&fu_flag==1)
  490.     {
  491.         TH0 = (unsigned char)(PWM_high >> 8);  //如果是输出低电平,则装载高电平时间。
  492.         TL0 = (unsigned char)PWM_high;
  493.                                 O_PWM=1;
  494.                                 P_PWM=0;
  495.     }
  496. }
  497. /*
  498. ********************************************************

  499. /*
  500. 函数名称:PID_Operation()  void PID_Output(void)                                

  501. /*
  502. 函数功能:PID运算                    

  503. /*
  504. 入口参数:无(隐形输入,系数、设定值等)                     

  505. /*
  506. 出口参数:无(隐形输出,U(k))

  507. /*
  508. 函数说明:U(k)=KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]                                    

  509. ********************************************************
  510. */

  511. void        PID_Operation(void)

  512. {

  513.     uInt32        Temp[3] = {0};   //中间临时变量

  514.     uInt32        PostSum = 0;     //正数和

  515.     uInt32        NegSum = 0;      //负数和

  516.     if(PID.iSetVal > PID.iCurVal)                //设定值大于实际值否?

  517.     {

  518.         if(PID.iSetVal - PID.iCurVal > 300)      //偏差大于10否?

  519.             PID.iPriVal = 300;                  //偏差大于10为上限幅值输出(全速加热)

  520.         else                                   

  521. //否则慢慢来

  522.         {

  523.             Temp[0] = PID.iSetVal - PID.iCurVal;    //偏差<=10,计算E(k)

  524.             PID.uEkFlag[1] = 0;                     //E(k)为正数,因为设定值大于实际值

  525.             /*
  526. 数值进行移位,注意顺序,否则会覆盖掉前面的数值 */

  527.             PID.liEkVal[2] = PID.liEkVal[1];

  528.             PID.liEkVal[1] = PID.liEkVal[0];

  529.             PID.liEkVal[0] = Temp[0];

  530.             /*
  531. =================================================================== */

  532.             if(PID.liEkVal[0] > PID.liEkVal[1])              //E(k)>E(k-1)否?

  533.             {

  534.                 Temp[0] = PID.liEkVal[0] - PID.liEkVal[1];  //E(k)>E(k-1)

  535.                 PID.uEkFlag[0] = 0;                         //E(k)-E(k-1)为正数

  536.             }                                      

  537.             else

  538.             {

  539.                 Temp[0] = PID.liEkVal[1] - PID.liEkVal[0];  //E(k)<E(k-1)

  540.                 PID.uEkFlag[0] = 1;                         //E(k)-E(k-1)为负数

  541.             }                       

  542.             /*
  543. =================================================================== */

  544.             Temp[2] = PID.liEkVal[1] * 2;                   //2E(k-1)

  545.             if((PID.liEkVal[0] + PID.liEkVal[2]) > Temp[2]) //E(k-2)+E(k)>2E(k-1)否?

  546.             {

  547.                 Temp[2] = (PID.liEkVal[0] + PID.liEkVal[2]) - Temp[2];

  548.                 PID.uEkFlag[2]=0;                          //E(k-2)+E(k)-2E(k-1)为正数

  549.             }                                             

  550.             else                                           //E(k-2)+E(k)<2E(k-1)

  551.             {

  552.                 Temp[2] = Temp[2] - (PID.liEkVal[0] + PID.liEkVal[2]);

  553.                 PID.uEkFlag[2] = 1;                         //E(k-2)+E(k)-2E(k-1)为负数

  554.             }                                 

  555.             /*
  556. =================================================================== */

  557.             Temp[0] = (uInt32)PID.uKP_Coe * Temp[0];        //KP*[E(k)-E(k-1)]

  558.             Temp[1] = (uInt32)PID.uKI_Coe * PID.liEkVal[0]; //KI*E(k)

  559.             Temp[2] = (uInt32)PID.uKD_Coe * Temp[2];        //KD*[E(k-2)+E(k)-2E(k-1)]

  560.             /*
  561. 以下部分代码是讲所有的正数项叠加,负数项叠加 */

  562.             /*
  563. ========= 计算KP*[E(k)-E(k-1)]的值 ========= */

  564.             if(PID.uEkFlag[0] == 0)

  565.                 PostSum += Temp[0];                         //正数和

  566.             else                                            

  567.                 NegSum += Temp[0];                          //负数和

  568.             /*
  569. ========= 计算KI*E(k)的值 ========= */

  570.             if(PID.uEkFlag[1] == 0)     

  571.                 PostSum += Temp[1];                         //正数和

  572.             else
  573.                                                         ;  
  574. /*
  575. 空操作。就是因为PID.iSetVal > PID.iCurVal(即E(K)>0)才进入if的,

  576.                     那么就没可能为负,所以打个转回去就是了
  577. */

  578.             /*
  579. ========= 计算KD*[E(k-2)+E(k)-2E(k-1)]的值 ========= */

  580.             if(PID.uEkFlag[2]==0)

  581.                 PostSum += Temp[2];             //正数和

  582.             else

  583.                 NegSum += Temp[2];              //负数和

  584.             /*
  585. ========= 计算U(k) ========= */                        

  586.             PostSum += (uInt32)PID.iPriVal;         

  587.             if(PostSum > NegSum)                 //是否控制量为正数

  588.             {

  589.                 Temp[0] = PostSum - NegSum;

  590.                 if(Temp[0] < 300 )               //小于上限幅值则为计算值输出

  591.                     PID.iPriVal = (uInt16)Temp[0];

  592.                 else
  593.                                                                                 PID.iPriVal = 300;         //否则为上限幅值输出

  594.             }

  595.             else                              

  596. //控制量输出为负数,则输出0(下限幅值输出)

  597.                 PID.iPriVal = 0;

  598.         }

  599.     }

  600.     else

  601. PID.iPriVal = 0;                       

  602. }

  603. /*
  604. ********************************************************

  605. /*
  606. 函数名称:PID_Output()                                    

  607. /*
  608. 函数功能:PID输出控制                  

  609. /*
  610. 入口参数:无(隐形输入,U(k))                        

  611. /*
  612. 出口参数:无(控制端)                                      

  613. ********************************************************
  614. */

  615. void PID_Output(void)

  616. {

  617.     static uInt16 iTemp;

  618.     iTemp = PID.iPriVal;

  619.                 change_pwm(iTemp);

  620. }
复制代码

所有资料51hei提供下载:
PCA捕获 带串口通信.zip (80.33 KB, 下载次数: 40)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表