久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4086|回復: 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 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美精产国品一二三区 | 成人一区二区三区 | 特级黄一级播放 | www国产亚洲精品久久网站 | 亚洲精品大片 | 亚洲一区二区三区高清 | 日韩欧美中文字幕在线观看 | 91av在线影院 | 国产精品毛片无码 | 亚洲福利网 | 一区二区伦理电影 | 羞羞视频免费观 | 99视频在线免费观看 | 日韩有码一区 | 中文字幕亚洲一区二区三区 | 欧美精品久久 | 国产一区二区电影 | 精品国产乱码久久久久久蜜柚 | 日本一本视频 | 国产激情网 | 久久9久 | 在线播放国产一区二区三区 | 久久久久久亚洲 | 伊人网综合在线观看 | 国产重口老太伦 | 亚洲h视频| 欧美成人精品一区二区男人看 | 免费一级欧美在线观看视频 | 精品伊人| 久久精品亚洲精品国产欧美 | 最新国产在线 | 欧美一级欧美一级在线播放 | 青娱乐av| 免费毛片网站在线观看 | 精品国产乱码久久久久久闺蜜 | 成人三级视频在线观看 | 日韩中文字幕免费在线观看 | 国产成人av免费看 | 国产成人精品一区二区三区四区 | 97国产精品视频人人做人人爱 | 色呦呦在线 |