單片機源碼:
- #include <STC15.H> //引用STC15系列頭文件,百度上搜索下載
- #include <INTRINS.H>
- #include <MATH.H>
- #define I2C_SCL P14 //時鐘信號線
- #define I2C_SDA P15 //數據信號線
- #define PWR_MGMT_1 0x6B //電源管理,典型值:0x00(正常啟用)
- #define WHO_AM_I 0x75 //IIC地址寄存器(默認數值0x68,只讀)
- #define SlaveAddress 0xD0 //IIC寫入時的地址字節數據,+1為讀取
- #define NOP1() nop_()
- #define NOP2() NOP1(),NOP1()
- #define MAIN_Fosc 24000000L //主時鐘,不同的晶振頻率可以直接修改
- #define serial_one_read_max 16 //接收緩存區長度
- #define serial_one_baud_rate 115200L //波特率,波特率可以直接修改
- #define Timer1_Reload_Usart (65536UL -(MAIN_Fosc / 4 / serial_one_baud_rate)) //Timer1重裝值,定時器1產生波特率
- //****************************************
- // 定義MPU6050內部地址
- //****************************************
- #define SMPLRT_DIV 0x19 //陀螺儀采樣率,典型值:0x07(125Hz)
- #define CONFIG 0x1A //低通濾波頻率,典型值:0x06(5Hz)
- #define GYRO_CONFIG 0x1B //陀螺儀自檢及測量范圍,典型值:0x18(不自檢,2000deg/s)
- #define ACCEL_CONFIG 0x1C //加速計自檢、測量范圍及高通濾波頻率,典型值:0x01(不自檢,2G,5Hz)
- #define ACCEL_XOUT_H 0x3B
- #define ACCEL_XOUT_L 0x3C
- #define ACCEL_YOUT_H 0x3D
- #define ACCEL_YOUT_L 0x3E
- #define ACCEL_ZOUT_H 0x3F
- #define ACCEL_ZOUT_L 0x40
- #define TEMP_OUT_H 0x41
- #define TEMP_OUT_L 0x42
- #define GYRO_XOUT_H 0x43
- #define GYRO_XOUT_L 0x44
- #define GYRO_YOUT_H 0x45
- #define GYRO_YOUT_L 0x46
- #define GYRO_ZOUT_H 0x47
- #define GYRO_ZOUT_L 0x48
- void Delay1000ms() //延時函數1秒
- {
- unsigned char i, j, k;
- _nop_();
- _nop_();
- i = 85;
- j = 12;
- k = 155;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
- //========================================================================
- // 函數: void I2C_Start()
- // 描述: I2C起始信號.
- // 參數: none.
- // 返回: none.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- void I2C_Start()
- {
- I2C_SDA = 1; //拉高數據線
- I2C_SCL = 1; //拉高時鐘線
- NOP2(); //等待機器反應
- I2C_SDA = 0; //產生下降沿
- I2C_SCL = 0; //拉低時鐘線
- }
- //========================================================================
- // 函數: void I2C_Stop()
- // 描述: I2C停止信號.
- // 參數: none.
- // 返回: none.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- void I2C_Stop()
- {
- I2C_SDA = 0; //拉低數據線
- I2C_SCL = 1; //拉高時鐘線
- NOP2(); //等待機器反應
- I2C_SDA = 1; //產生上升沿
- NOP1(); //等待機器反應
- }
- //========================================================================
- // 函數: void I2C_SendACK(bit ack)
- // 描述: I2C發送應答信號.
- // 參數: ack (0:ACK 1:NAK).
- // 返回: none.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- void I2C_SendACK(bit ack)
- {
- I2C_SDA = ack; //寫應答信號
- I2C_SCL = 1; //拉高時鐘線
- NOP2(); //等待機器反應
- I2C_SCL = 0; //拉低時鐘線
- NOP1(); //等待機器反應
- }
- //========================================================================
- // 函數: bit I2C_RecvACK()
- // 描述: I2C接收應答信號.
- // 參數: none.
- // 返回: 1:成功,0:失敗.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- bit I2C_RecvACK()
- {
- I2C_SCL = 1; //拉高時鐘線
- NOP2(); //等待機器反應
- CY = I2C_SDA; //讀應答信號
- I2C_SCL = 0; //拉低時鐘線
- return CY;
- }
- //========================================================================
- // 函數: void I2C_SendByte(u8 dat)
- // 描述: 向I2C總線發送一個字節數據.
- // 參數: dat:要發送的數據.
- // 返回: none.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- void I2C_SendByte(unsigned char dat)
- {
- unsigned char i;
- for (i=0; i<8; i++) //8位計數器
- {
- dat <<= 1; //移出數據的最高位
- I2C_SDA = CY; //送數據口
- I2C_SCL = 1; //拉高時鐘線
- NOP2(); //等待機器反應
- I2C_SCL = 0; //拉低時鐘線
- }
- I2C_RecvACK();
- }
- //========================================================================
- // 函數: unsigned char I2C_RecvByte()
- // 描述: 從I2C總線接收一個字節數據.
- // 參數: none.
- // 返回: 接收到的數據.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- unsigned char I2C_RecvByte()
- {
- unsigned char i;
- unsigned char dat = 0;
- I2C_SDA = 1; //使能內部上拉,準備讀取數據,
- for (i=0; i<8; i++) //8位計數器
- {
- dat <<= 1;
- I2C_SCL = 1; //拉高時鐘線
- NOP2(); //等待機器反應
- dat |= I2C_SDA; //讀數據
- I2C_SCL = 0; //拉低時鐘線
- }
- return dat;
- }
- //========================================================================
- // 函數: void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
- // 描述: 向I2C設備寫入一個字節數據.
- // 參數: REG_Address:地址.
- // REG_data:要寫入的數據.
- // 返回: none.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
- {
- I2C_Start(); //起始信號
- I2C_SendByte(SlaveAddress); //發送設備地址+寫信號
- I2C_SendByte(REG_Address); //內部寄存器地址,
- I2C_SendByte(REG_data); //內部寄存器數據,
- I2C_Stop(); //發送停止信號
- }
- //========================================================================
- // 函數: unsigned char Single_ReadI2C(unsigned char REG_Address)
- // 描述: 從I2C設備讀取一個字節數據.
- // 參數: REG_Address:地址.
- // 返回: 讀取到的數據.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- unsigned char Single_ReadI2C(unsigned char REG_Address)
- {
- unsigned char REG_data;
- I2C_Start(); //起始信號
- I2C_SendByte(SlaveAddress); //發送設備地址+寫信號
- I2C_SendByte(REG_Address); //發送存儲單元地址,從0開始
- I2C_Start(); //起始信號
- I2C_SendByte(SlaveAddress+1); //發送設備地址+讀信號
- REG_data=I2C_RecvByte(); //讀出寄存器數據
- I2C_SendACK(1); //接收應答信號
- I2C_Stop(); //停止信號
- return REG_data;
- }
- //========================================================================
- // 函數: void MPU6050_init()
- // 描述: 初始化MPU6050.
- // 參數: none.
- // 返回: none.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- void MPU6050_Init()
- {
- Single_WriteI2C(PWR_MGMT_1, 0x00); //解除休眠狀態
- Single_WriteI2C(SMPLRT_DIV, 0x07);
- Single_WriteI2C(CONFIG, 0x06);
- Single_WriteI2C(GYRO_CONFIG, 0x18);
- Single_WriteI2C(ACCEL_CONFIG, 0x01);
- }
- //========================================================================
- // 函數: int GetData(u8 REG_Address)
- // 描述: 讀取數據并合成為int型數據.
- // 參數: REG_Address:地址.
- // 返回: 讀取到的數據.
- // 版本: V1.0, 2017-06-23
- //========================================================================
- int GetData(unsigned char REG_Address)
- {
- unsigned char H,L;
- H = Single_ReadI2C(REG_Address);
- L = Single_ReadI2C(REG_Address + 1);
- return (H << 8) + L; //合成數據
- }
- ////========================================================================
- //// 函數: int get_x_angle()
- //// 描述: 獲取三軸角速度,三軸加速度
- //// 參數: gyro_id:數據ID,1:x角速度,2:y角速度,3:z角速度,4:x加速度,5:y加速度,6:z加速度.
- //// 返回: 陀螺儀值.
- //// 版本: V2.0, 2017-07-15
- ////========================================================================
- int Get_Gyro_Data(unsigned char gyro_id)
- {
- switch(gyro_id)
- {
- case 1: return GetData(ACCEL_XOUT_H); break;
- case 2: return GetData(ACCEL_YOUT_H); break;
- case 3: return GetData(ACCEL_ZOUT_H); break;
- case 4: return GetData(GYRO_XOUT_H) ; break;
- case 5: return GetData(GYRO_YOUT_H) ; break;
- case 6: return GetData(GYRO_ZOUT_H) ; break;
- }
- return 0;
- }
- //========================================================================
- // 函數: int MPU6050_Get_Angle(float x,float y,float z,u8 dir)
- // 描述: 轉化成與三個方向的夾角.
- // 參數: x:x方向數據.
- // y:y方向數據.
- // z:z方向數據.
- // dir:方向ID.
- // 返回: 夾角角度值(放大10倍).
- // 版本: V1.0, 2017-06-23
- //========================================================================
- int MPU6050_Get_Angle(int x,int y,int z,unsigned char dir)
- {
- float xdata temp;
- float xdata res = 0;
- switch(dir)
- {
- case 0://與z軸的夾角
- temp = sqrt(((float)x*(float)x+(float)y*(float)y))/(float)z;
- res = atan(temp);
- break;
- case 1://與x軸的夾角
- temp = (float)x/sqrt(((float)y*(float)y+(float)z*(float)z));
- res = atan(temp);
- break;
- case 2://與y軸的夾角
- temp = (float)y/sqrt(((float)x*(float)x+(float)z*(float)z));
- res = atan(temp);
- break;
- }
- return (int)(res*1800/3.1416);//弧度轉換為角度,擴大10倍
- }
- //========================================================================
- // int get_included_angle(unsigned dat)
- // 描述: 獲取角度或加速度
- // 參數: angle_id:方向指示變量(1:X軸角度,2:Y軸角度,3:Z軸角度,4:X軸加速度,5:Y軸加速度,6:Z軸加速度).
- // 返回: 夾角角度值(放大10倍).
- // 版本: V1.0, 2017-06-23
- //========================================================================
- int MPU6050_Get_Data(unsigned angle_id)
- {
- switch(angle_id)
- {
- case 1:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 1);break;
- case 2:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 2);break;
- case 3:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 0);break;
- case 4:return (int)((float)((float)Get_Gyro_Data(4)/16384)*9.8*100);
- case 5:return (int)((float)((float)Get_Gyro_Data(5)/16384)*9.8*100);
- case 6:return (int)((float)((float)Get_Gyro_Data(6)/16384)*9.8*100);
- }
- return 0;
- }
- //串口初始化
- void Uart_Init()
- {
- SCON |= 0x40; //8位數據
- P_SW1 &= ~0xc0; //UART1 使用P30 P31口 默認
- TR1 = 0; //關閉定時器1
- AUXR &= ~0x01; //串口1波特率使用定時器1
- TMOD &= ~(1<<6); //Timer1 set As Timer
- TMOD &= ~0x30; //16位自動重裝
- AUXR |= (1<<6); //定時器使用1T模式
- TH1 = (unsigned char)(Timer1_Reload_Usart >> 8);
- TL1 = (unsigned char)Timer1_Reload_Usart;
- TR1 = 1; //打開定時器1
- PS = 1; //高優先級中斷
- REN = 1; //允許接收
- ES = 1; //允許中斷
- EA = 1; //允許全局中斷
- }
- //========================================================================
- // 函數: serial_one_send_byte(unsigned char dat)
- // 描述: 串口1發送一個字節.
- // 參數: dat:字符(無符號八位整型數據).
- // 返回: none.
- // 版本: V1.0, 2017-06-22
- //========================================================================
- void serial_one_send_byte(unsigned char dat)
- {
- SBUF = dat;
- while(!TI);
- TI = 0;
- }
- //========================================================================
- // 函數: serial_one_send_string(u8 *dat)
- // 描述: 串口1發送字符串.
- // 參數: dat:字符串.
- // 返回: none.
- // 版本: V1.0, 2017-06-22
- //========================================================================
- void serial_one_send_string(unsigned char *dat)
- {
- while(*dat)
- serial_one_send_byte(*dat++);
- }
- //========================================================================
- // 函數: void serial_one_send_number(long num)
- // 描述: 串口1發送整型數據.
- // 參數: num:整型數值.
- // 返回: none.
- // 版本: V1.0, 2017-06-22
- //========================================================================
- void serial_one_send_number(long num)
- {
- long dat = 0;
- unsigned char length = 0;
- if(num < 0) //當數值為負數時
- {
- serial_one_send_byte('-'); //輸出負號
- num = -num; //將數值取相反數
- }
- if(num == 0) //當數值為0時
- serial_one_send_byte('0'); //輸出字符0
- else //當數值不為0時
- {
- while(num) //將數值倒過來
- {
- dat = dat * 10;
- dat = dat + num % 10;
- num = num / 10;
- length++;
- }
- while(length--) //從第一位開始輸出倒過來的數值
- {
- serial_one_send_byte(dat % 10 + '0');
- dat = dat / 10;
- }
- }
- }
- void serial_one_send_float(double float_val, char bit_val)
- {
- long xdata value_int = 0;
- long xdata value_flt = 0;
- if(float_val < 0)
- {
- serial_one_send_byte('-');
- float_val = -float_val;
- }
- value_int = (long)float_val;
- float_val = float_val - (double)value_int;
- for(;bit_val;bit_val--)
- float_val = float_val * 10;
- serial_one_send_number(value_int);
- serial_one_send_byte('.');
- serial_one_send_number((long)float_val);
- }
- float value = 0;
- //主函數
- void main()
- {
- Delay1000ms();
- Uart_Init(); //串口初始化
- MPU6050_Init(); //初始化MPU6505
- while(1)
- {
- value = MPU6050_Get_Data(1); //獲取與x軸的夾角,角度被放大10倍
- serial_one_send_string("模塊與x軸的夾角為:");
- serial_one_send_float(value / 10,1); //角度除以10,并從串口發出,第二個參數為保留一位小數
- serial_one_send_string("\r\n"); //換行
- value = MPU6050_Get_Data(2); //獲取與y軸的夾角,角度被放大10倍
- serial_one_send_string("模塊與y軸的夾角為:");
- serial_one_send_float(value / 10,1); //角度除以10,并從串口發出
- serial_one_send_string("\r\n"); //換行
- value = MPU6050_Get_Data(3); //獲取與z軸的夾角,角度被放大10倍
- serial_one_send_string("模塊與z軸的夾角為:");
- serial_one_send_float(value / 10,1); //角度除以10,并從串口發出
- serial_one_send_string("\r\n"); //換行
- value = MPU6050_Get_Data(4); //獲取與x軸加速度,數值被放大100倍
- serial_one_send_string("x軸加速度為:");
- serial_one_send_float(value/100,1); //角度除以100,并從串口發出,第二個參數為保留一位小數
- serial_one_send_string(" M/S2\r\n"); //換行
- value = MPU6050_Get_Data(4); //獲取與y軸加速度,數值被放大100倍
- serial_one_send_string("y軸加速度為:");
- serial_one_send_float(value / 100,1); //角度除以100,并從串口發出
- serial_one_send_string(" M/S2\r\n"); //換行
- value = MPU6050_Get_Data(4); //獲取與z軸加速度,數值被放大100倍
- serial_one_send_string("z軸加速度為:");
- serial_one_send_float(value / 100,1); //角度除以100,并從串口發出
- serial_one_send_string(" M/S2\r\n\r\n"); //換行
- Delay1000ms();
- Delay1000ms();
- }
- }
- //串口中斷
- void Uart1_Int (void) interrupt 4
- {
- if(RI)
- RI = 0;
- }
復制代碼
- /*
- * ADXL345模塊
- *
- * 用途:ADXL345模塊IIC測試程序
- *
- * 作者 日期 備注
- *
- */
- #include "uart3.h"
- #include <stc15.H>
- #include <math.h> //Keil library
- #include <stdio.h> //Keil library
- #include <INTRINS.H>
- #define uchar unsigned char
- #define uint unsigned int
- sbit SCL=P0^6; //IIC時鐘引腳定義
- sbit SDA=P0^7; //IIC數據引腳定義
- sbit P_PWM = P2^5; //定義PWM輸出引腳。
- sbit O_PWM = P2^1;
- #define SlaveAddress 0xa6 //定義器件在IIC總線中的從地址,根據ALT ADDRESS地址引腳不同修改
- //ALT ADDRESS引腳接地時地址為0xA6,接電源時地址為0x3A
- #define PWM_HIGH_MIN 32 //限制PWM輸出的最小占空比。用戶請勿修改。
- #define PWM_HIGH_MAX (PWM_DUTY-PWM_HIGH_MIN) //限制PWM輸出的最大占空比。用戶請勿修改。
- long PWM_DUTY=20200;
- unsigned int duty;
- unsigned char fu_flag=0;
- unsigned int pwm; //定義PWM輸出高電平的時間的變量。用戶操作PWM的變量。
- //BYTE BUF[8]; //接收數據緩存區
- uchar ge,shi,bai,qian,wan; //顯示變量
- int dis_data; //變量
- int x_value=0;
- void delay(unsigned int k);
- void Init_ADXL345(void); //初始化ADXL345
- void conversion(uint temp_data);
- void Single_Write_ADXL345(uchar REG_Address,uchar REG_data); //單個寫入數據
- uchar Single_Read_ADXL345(uchar REG_Address); //單個讀取內部寄存器數據
- void Multiple_Read_ADXL345(); //連續的讀取內部寄存器數據
- //sbit P_PWM = P1^4; //定義PWM輸出引腳。STC15W204S
- unsigned int PWM_high,PWM_low; //中間變量,用戶請勿修改。
- void change_pwm(int i);
- void LoadPWM(int i);
- void pwm_init();
- //------------------------------------
- void PID_Operation();
- void PID_Output(void);
- void Delay5us();
- void Delay5ms();
- void ADXL345_Start();
- void ADXL345_Stop();
- void ADXL345_SendACK(bit ack);
- bit ADXL345_RecvACK();
- void ADXL345_SendByte(BYTE dat);
- BYTE ADXL345_RecvByte();
- void ADXL345_ReadPage();
- void ADXL345_WritePage();
- //-----------------------------------
- //*********************************************************
- //void conversion(uint temp_data)
- //{
- // wan=temp_data/10000+0x30 ;
- // temp_data=temp_data%10000; //取余運算
- // qian=temp_data/1000+0x30 ;
- // temp_data=temp_data%1000; //取余運算
- // bai=temp_data/100+0x30 ;
- // temp_data=temp_data%100; //取余運算
- // shi=temp_data/10+0x30 ;
- // temp_data=temp_data%10; //取余運算
- // ge=temp_data+0x30;
- //}
- /*******************************/
- void delay(unsigned int k)
- {
- unsigned int i,j;
- for(i=0;i<k;i++)
- {
- for(j=0;j<121;j++)
- {;}}
- }
- /**************************************
- 延時5微秒(STC90C52RC---12MHz---12T)
- 不同的工作環境,需要調整此函數,注意時鐘過快時需要修改
- 當改用1T的MCU時,請調整此延時函數
- **************************************/
- void Delay5us()
- {
- unsigned char i;
- _nop_();
- _nop_();
- i = 27;
- while (--i);
- }
- ///**************************************
- //延時5毫秒(STC90C52RC@12M)
- //不同的工作環境,需要調整此函數
- //當改用1T的MCU時,請調整此延時函數
- //**************************************/
- //void Delay5ms()
- //{
- // unsigned char i, j;
- // i = 117;
- // j = 184;
- // do
- // {
- // while (--j);
- // } while (--i);
- //}
- /**************************************
- 起始信號
- **************************************/
- void ADXL345_Start()
- {
- SDA = 1; //拉高數據線
- SCL = 1; //拉高時鐘線
- Delay5us(); //延時
- SDA = 0; //產生下降沿
- Delay5us(); //延時
- SCL = 0; //拉低時鐘線
- }
- /**************************************
- 停止信號
- **************************************/
- void ADXL345_Stop()
- {
- SDA = 0; //拉低數據線
- SCL = 1; //拉高時鐘線
- Delay5us(); //延時
- SDA = 1; //產生上升沿
- Delay5us(); //延時
- }
- /**************************************
- 發送應答信號
- 入口參數:ack (0:ACK 1:NAK)
- **************************************/
- void ADXL345_SendACK(bit ack)
- {
- SDA = ack; //寫應答信號
- SCL = 1; //拉高時鐘線
- Delay5us(); //延時
- SCL = 0; //拉低時鐘線
- Delay5us(); //延時
- }
- /**************************************
- 接收應答信號
- **************************************/
- bit ADXL345_RecvACK()
- {
- SCL = 1; //拉高時鐘線
- Delay5us(); //延時
- CY = SDA; //讀應答信號
- SCL = 0; //拉低時鐘線
- Delay5us(); //延時
- return CY;
- }
- /**************************************
- 向IIC總線發送一個字節數據
- **************************************/
- void ADXL345_SendByte(BYTE dat)
- {
- BYTE i;
- for (i=0; i<8; i++) //8位計數器
- {
- dat <<= 1; //移出數據的最高位
- SDA = CY; //送數據口
- SCL = 1; //拉高時鐘線
- Delay5us(); //延時
- SCL = 0; //拉低時鐘線
- Delay5us(); //延時
- }
- ADXL345_RecvACK();
- }
- /**************************************
- 從IIC總線接收一個字節數據
- **************************************/
- BYTE ADXL345_RecvByte()
- {
- BYTE i;
- BYTE dat = 0;
- SDA = 1; //使能內部上拉,準備讀取數據,
- for (i=0; i<8; i++) //8位計數器
- {
- dat <<= 1;
- SCL = 1; //拉高時鐘線
- Delay5us(); //延時
- dat |= SDA; //讀數據
- SCL = 0; //拉低時鐘線
- Delay5us(); //延時
- }
- return dat;
- }
- //******單字節寫入*******************************************
- void Single_Write_ADXL345(uchar REG_Address,uchar REG_data)
- {
- ADXL345_Start(); //起始信號
- ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
- ADXL345_SendByte(REG_Address); //內部寄存器地址,請參考中文pdf22頁
- ADXL345_SendByte(REG_data); //內部寄存器數據,請參考中文pdf22頁
- ADXL345_Stop(); //發送停止信號
- }
- //********單字節讀取*****************************************
- uchar Single_Read_ADXL345(uchar REG_Address)
- { uchar REG_data;
- ADXL345_Start(); //起始信號
- ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
- ADXL345_SendByte(REG_Address); //發送存儲單元地址,從0開始
- ADXL345_Start(); //起始信號
- ADXL345_SendByte(SlaveAddress+1); //發送設備地址+讀信號
- REG_data=ADXL345_RecvByte(); //讀出寄存器數據
- ADXL345_SendACK(1);
- ADXL345_Stop(); //停止信號
- return REG_data;
- }
- //*********************************************************
- //
- //連續讀出ADXL345內部加速度數據,地址范圍0x32~0x37
- //
- //*********************************************************
- void Multiple_read_ADXL345(void)
- { uchar i;
- ADXL345_Start(); //起始信號
- ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
- ADXL345_SendByte(0x32); //發送存儲單元地址,從0x32開始
- ADXL345_Start(); //起始信號
- ADXL345_SendByte(SlaveAddress+1); //發送設備地址+讀信號
- for (i=0; i<6; i++) //連續讀取6個地址數據,存儲中BUF
- {
- BUF[i] = ADXL345_RecvByte(); //BUF[0]存儲0x32地址中的數據
- if (i == 5)
- {
- ADXL345_SendACK(1); //最后一個數據需要回NOACK
- }
- else
- {
- ADXL345_SendACK(0); //回應ACK
- }
- }
- ADXL345_Stop(); //停止信號
- }
- //void send0ff()
- //{
- // SendData(0xff);
- // SendData(0xff);
- // SendData(0xff);
- //}
- //*****************************************************************
- //初始化ADXL345,根據需要請參考pdf進行修改************************
- void Init_ADXL345()
- {
- Single_Write_ADXL345(0x31,0x08); //測量范圍,正負16g,13位模式
- Single_Write_ADXL345(0x2C,0x0a); //速率設定為12.5 參考pdf13頁
- Single_Write_ADXL345(0x2D,0x08); //選擇電源模式 參考pdf24頁
- Single_Write_ADXL345(0x2E,0x80); //使能 DATA_READY 中斷
- Single_Write_ADXL345(0x1E,0x00); //X 偏移量 根據測試傳感器的狀態寫入pdf29頁
- Single_Write_ADXL345(0x1F,0x00); //Y 偏移量 根據測試傳感器的狀態寫入pdf29頁
- Single_Write_ADXL345(0x20,0x05); //Z 偏移量 根據測試傳感器的狀態寫入pdf29頁
- }
- ////***********************************************************************
- ////顯示x軸
- //void display_x()
- //{ float temp;
- // unsigned char dis_t[16]="n0.val=0000";
- // dis_data=(BUF[1]<<8)+BUF[0]; //合成數據
- // if(dis_data<0){
- // dis_data=-dis_data;
- // SendString("t3.txt=\"-\"");
- // send0ff();
- // }
- // else{
- // SendString("t3.txt=\" \"");
- // send0ff();}
- // temp=(float)dis_data*3.9; //計算數據和顯示,查考ADXL345快速入門第4頁
- // conversion(temp); //轉換出顯示需要的數據
- // dis_t[7]=qian;
- // dis_t[8]=bai;
- // dis_t[9]=shi;
- // dis_t[10]=ge;
- // dis_t[11]=0xff;
- // dis_t[12]=0xff;
- // dis_t[13]=0xff;
- // SendString(dis_t);
- //}
- //***********************************************************************
- //顯示y軸
- //void display_y()
- //{ float temp;
- // unsigned char dis_t[16]="n1.val=";
- // dis_data=(BUF[3]<<8)+BUF[2]; //合成數據
- // if(dis_data<0){
- // dis_data=-dis_data;
- // SendString("t4.txt=\"-\"");
- // send0ff();
- // }
- // else{
- // SendString("t4.txt=\" \"");
- // send0ff();}
- // temp=(float)dis_data*3.9; //計算數據和顯示,查考ADXL345快速入門第4頁
- // conversion(temp); //轉換出顯示需要的數據
- // dis_t[7]=qian;
- // dis_t[8]=bai;
- // dis_t[9]=shi;
- // dis_t[10]=ge;
- // dis_t[11]=0xff;
- // dis_t[12]=0xff;
- // dis_t[13]=0xff;
- // SendString(dis_t);
- //}
- //***********************************************************************
- //顯示z軸
- //void display_z()
- //{
- // float temp;
- // unsigned char dis_t[16]="n2.val=";
- // dis_data=(BUF[5]<<8)+BUF[4]; //合成數據
- // if(dis_data<0){
- // dis_data=-dis_data;
- // SendString("t5.txt=\"-\"");
- // send0ff();
- // }
- // else{
- // SendString("t5.txt=\" \"");
- // send0ff();
- //}
- // temp=(float)dis_data*3.9; //計算數據和顯示,查考ADXL345快速入門第4頁
- // conversion(temp); //轉換出顯示需要的數據
- // dis_t[7]=qian;
- // dis_t[8]=bai;
- // dis_t[9]=shi;
- // dis_t[10]=ge;
- // dis_t[11]=0xff;
- // dis_t[12]=0xff;
- // dis_t[13]=0xff;
- // SendString(dis_t);
- //}
- void io_init()
- {
- P0M0 = 0x00;
- P0M1 = 0x00;
- P1M0 = 0x00;
- P1M1 = 0x00;
- P2M0 = 0x00;
- P2M1 = 0x00;
- P3M0 = 0x00;
- P3M1 = 0x00;
- P4M0 = 0x00;
- P4M1 = 0x00;
- P5M0 = 0x00;
- P5M1 = 0x00;
- P6M0 = 0x00;
- P6M1 = 0x00;
- P7M0 = 0x00;
- P7M1 = 0x00;
- }
- //*********************************************************
- //******主程序********
- //*********************************************************
- void main()
- {
- uchar temp[5];
- uchar devid;
- delay(500); //上電延時
- io_init();
- pwm_init();
- uart3_init();
- PID.iSetVal=16;
- PID.uKP_Coe=3;
- PID.uKI_Coe=0.1;
- PID.uKD_Coe=5;
- Init_ADXL345(); //初始化ADXL345
- devid=Single_Read_ADXL345(0X00); //讀出的數據為0XE5,表示正確
- while(1) //循環
- {
- Multiple_Read_ADXL345(); //連續讀出數據,存儲在BUF中
- x_value=(BUF[1]<<8)+BUF[0]; //合成數據
-
- if(x_value<=0)
- {
- fu_flag=1;
- x_value=-x_value;
- }
- else
- fu_flag=0;
- temp[0]=x_value/10000+'0';
- temp[1]=x_value/1000%10+'0';
- temp[2]=x_value/100%10+'0';
- temp[3]=x_value/10%10+'0';
- temp[4]=x_value%10+'0';
-
-
-
-
- SendString(temp);
- PID.iCurVal=x_value;
- PID_Operation();
- PID_Output();
- // if(x_value>0)
- // {
- // fu_flag=0;
- // if(x_value>=300)
- // {
- // x_value=300;
- //
- // }
- // change_pwm(x_value);
- // }
- // else if(x_value<0)
- // {
- // x_value=-x_value;
- // fu_flag=1;
- // if(x_value>=300)
- // {
- // x_value=300;
- //
- // }
- // change_pwm(x_value);
- // }
-
- }
- }
- void pwm_init()
- {
- P_PWM = 0;
- P2M1 &= ~(1 << 5); //P2.5 設置為推挽輸出
- P2M0 |= (1 << 5);
- P2M1 &= ~(1 << 1); //P2.1 設置為推挽輸出
- P2M0 |= (1 << 1);
- // P1M1 &= ~(1 << 4); //P1.4 設置為推挽輸出 STC15W204S
- // P1M0 |= (1 << 4);
- TR0 = 0; //停止計數
- ET0 = 1; //允許中斷
- PT0 = 1; //高優先級中斷
- TMOD &= ~0x03; //工作模式,0: 16位自動重裝
- AUXR |= 0x80; //1T
- TMOD &= ~0x04; //定時
- INT_CLKO |= 0x01; //輸出時鐘
- TH0 = 0;
- TL0 = 0;
- TR0 = 1; //開始運行
- EA = 1;
- }
- //========================================================================
- // 函數: void delay_ms(unsigned char ms)
- // 描述: 延時函數。
- // 參數: ms,要延時的ms數, 這里只支持1~255ms. 自動適應主時鐘.
- // 返回: none.
- // 版本: VER1.0
- // 日期: 2013-4-1
- // 備注:
- //========================================================================
- void change_pwm(int i)
- {
- LoadPWM(PWM_DUTY * i / 300);
- }
- /**************** 計算PWM重裝值函數 *******************/
- void LoadPWM(int i)
- {
- int j;
- if(i > PWM_HIGH_MAX) i = PWM_HIGH_MAX; //如果寫入大于最大占空比數據,則強制為最大占空比。
- if(i < PWM_HIGH_MIN) i = PWM_HIGH_MIN; //如果寫入小于最小占空比數據,則強制為最小占空比。
- j = 65536UL - PWM_DUTY + i; //計算PWM低電平時間
- i = 65536UL - i; //計算PWM高電平時間
- EA = 0;
- PWM_high = i; //裝載PWM高電平時間
- PWM_low = j; //裝載PWM低電平時間
- EA = 1;
- }
- /********************* Timer0中斷函數************************/
- void timer0_int (void) interrupt 1
- {
- if(P_PWM&&fu_flag==0)
- {
- TH0 = (unsigned char)(PWM_low >> 8); //如果是輸出高電平,則裝載低電平時間。
- TL0 = (unsigned char)PWM_low;
- P_PWM=0;
- O_PWM=0;
- }
- else if(!P_PWM&&fu_flag==0)
- {
- TH0 = (unsigned char)(PWM_high >> 8); //如果是輸出低電平,則裝載高電平時間。
- TL0 = (unsigned char)PWM_high;
- O_PWM=0;
- P_PWM=1;
- }
- if(O_PWM&&fu_flag==1)
- {
- TH0 = (unsigned char)(PWM_low >> 8); //如果是輸出高電平,則裝載低電平時間。
- TL0 = (unsigned char)PWM_low;
- O_PWM=0;
- P_PWM=0;
- }
- else if(!O_PWM&&fu_flag==1)
- {
- TH0 = (unsigned char)(PWM_high >> 8); //如果是輸出低電平,則裝載高電平時間。
- TL0 = (unsigned char)PWM_high;
- O_PWM=1;
- P_PWM=0;
- }
- }
- /*
- ********************************************************
- /*
- 函數名稱:PID_Operation() void PID_Output(void)
- /*
- 函數功能:PID運算
- /*
- 入口參數:無(隱形輸入,系數、設定值等)
- /*
- 出口參數:無(隱形輸出,U(k))
- /*
- 函數說明:U(k)=KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]
- ********************************************************
- */
- void PID_Operation(void)
- {
- uInt32 Temp[3] = {0}; //中間臨時變量
- uInt32 PostSum = 0; //正數和
- uInt32 NegSum = 0; //負數和
- if(PID.iSetVal > PID.iCurVal) //設定值大于實際值否?
- {
- if(PID.iSetVal - PID.iCurVal > 300) //偏差大于10否?
- PID.iPriVal = 300; //偏差大于10為上限幅值輸出(全速加熱)
- else
- //否則慢慢來
- {
- Temp[0] = PID.iSetVal - PID.iCurVal; //偏差<=10,計算E(k)
- PID.uEkFlag[1] = 0; //E(k)為正數,因為設定值大于實際值
- /*
- 數值進行移位,注意順序,否則會覆蓋掉前面的數值 */
- PID.liEkVal[2] = PID.liEkVal[1];
- PID.liEkVal[1] = PID.liEkVal[0];
- PID.liEkVal[0] = Temp[0];
- /*
- =================================================================== */
- if(PID.liEkVal[0] > PID.liEkVal[1]) //E(k)>E(k-1)否?
- {
- Temp[0] = PID.liEkVal[0] - PID.liEkVal[1]; //E(k)>E(k-1)
- PID.uEkFlag[0] = 0; //E(k)-E(k-1)為正數
- }
- else
- {
- Temp[0] = PID.liEkVal[1] - PID.liEkVal[0]; //E(k)<E(k-1)
- PID.uEkFlag[0] = 1; //E(k)-E(k-1)為負數
- }
- /*
- =================================================================== */
- Temp[2] = PID.liEkVal[1] * 2; //2E(k-1)
- if((PID.liEkVal[0] + PID.liEkVal[2]) > Temp[2]) //E(k-2)+E(k)>2E(k-1)否?
- {
- Temp[2] = (PID.liEkVal[0] + PID.liEkVal[2]) - Temp[2];
- PID.uEkFlag[2]=0; //E(k-2)+E(k)-2E(k-1)為正數
- }
- else //E(k-2)+E(k)<2E(k-1)
- {
- Temp[2] = Temp[2] - (PID.liEkVal[0] + PID.liEkVal[2]);
- PID.uEkFlag[2] = 1; //E(k-2)+E(k)-2E(k-1)為負數
- }
- /*
- =================================================================== */
- Temp[0] = (uInt32)PID.uKP_Coe * Temp[0]; //KP*[E(k)-E(k-1)]
- Temp[1] = (uInt32)PID.uKI_Coe * PID.liEkVal[0]; //KI*E(k)
- Temp[2] = (uInt32)PID.uKD_Coe * Temp[2]; //KD*[E(k-2)+E(k)-2E(k-1)]
- /*
- 以下部分代碼是講所有的正數項疊加,負數項疊加 */
- /*
- ========= 計算KP*[E(k)-E(k-1)]的值 ========= */
- if(PID.uEkFlag[0] == 0)
- PostSum += Temp[0]; //正數和
- else
- NegSum += Temp[0]; //負數和
- /*
- ========= 計算KI*E(k)的值 ========= */
- if(PID.uEkFlag[1] == 0)
- PostSum += Temp[1]; //正數和
- else
- ;
- /*
- 空操作。就是因為PID.iSetVal > PID.iCurVal(即E(K)>0)才進入if的,
- 那么就沒可能為負,所以打個轉回去就是了
- */
- /*
- ========= 計算KD*[E(k-2)+E(k)-2E(k-1)]的值 ========= */
- if(PID.uEkFlag[2]==0)
- PostSum += Temp[2]; //正數和
- else
- NegSum += Temp[2]; //負數和
- /*
- ========= 計算U(k) ========= */
- PostSum += (uInt32)PID.iPriVal;
- if(PostSum > NegSum) //是否控制量為正數
- {
- Temp[0] = PostSum - NegSum;
- if(Temp[0] < 300 ) //小于上限幅值則為計算值輸出
- PID.iPriVal = (uInt16)Temp[0];
- else
- PID.iPriVal = 300; //否則為上限幅值輸出
- }
- else
- //控制量輸出為負數,則輸出0(下限幅值輸出)
- PID.iPriVal = 0;
- }
- }
- else
- PID.iPriVal = 0;
- }
- /*
- ********************************************************
- /*
- 函數名稱:PID_Output()
- /*
- 函數功能:PID輸出控制
- /*
- 入口參數:無(隱形輸入,U(k))
- /*
- 出口參數:無(控制端)
- ********************************************************
- */
- void PID_Output(void)
- {
- static uInt16 iTemp;
- iTemp = PID.iPriVal;
- change_pwm(iTemp);
- }
復制代碼
所有資料51hei提供下載:
PCA捕獲 帶串口通信.zip
(80.33 KB, 下載次數: 40)
2018-7-20 08:49 上傳
點擊文件名下載附件
|