本帖最后由 he07413 于 2017-4-24 10:45 编辑
平衡车的陀螺仪部件,我使用的MPU6050模块。左侧那个洞洞板上,上方红色的是电机驱动。中间蓝色的小模块就是MPU6050。连线如图,可能看不清,下面会详细介绍。
查看麒麟座 开发板的原理图可以看到,有一些没有用到的引脚。之所以不占用板子上其他资源的IO口,主要是考虑到,小车跑起来之后 还要用板子上的传感器采集信息。所以只能用剩下的引脚东拼西凑了。
决定用PB3引脚做IIC通讯的SCK时钟线,PB4引脚做SDA数据线。右侧 PA8-PA11为定时器1的4个通道,后面可以用来做PWM输出作为直流电机驱动的输入信号。或者给电机编码器使用。左侧的PC0-PC3被1602占用了。可以说如果不放弃板子原本就带的一些传感器的话,可用的引脚资源非常少 - -
IIC通讯采用软件模拟的方式,下面是IIC底层驱动程序。
/**************************ʵÏÖº¯Êý********************************************
复制代码
MPU6050初始化,数据读取。
- /**************************ʵÏÖº¯Êý********************************************
- 将新的ADC数据更新到FIFO数组,做滤波处理
- *******************************************************************************/
- void MPU6050_newValues(int16_t ax,int16_t ay,int16_t az,int16_t gx,int16_t gy,int16_t gz)
- {
- unsigned char i ;
- int32_t sum=0;
- for(i=1;i<10;i++){ //FIFO ²Ù×÷
- MPU6050_FIFO[0][i-1]=MPU6050_FIFO[0][i];
- MPU6050_FIFO[1][i-1]=MPU6050_FIFO[1][i];
- MPU6050_FIFO[2][i-1]=MPU6050_FIFO[2][i];
- MPU6050_FIFO[3][i-1]=MPU6050_FIFO[3][i];
- MPU6050_FIFO[4][i-1]=MPU6050_FIFO[4][i];
- MPU6050_FIFO[5][i-1]=MPU6050_FIFO[5][i];
- }
- MPU6050_FIFO[0][9]=ax;//½«ÐµÄÊý¾Ý·ÅÖõ½ Êý¾ÝµÄ×îºóÃæ
- MPU6050_FIFO[1][9]=ay;
- MPU6050_FIFO[2][9]=az;
- MPU6050_FIFO[3][9]=gx;
- MPU6050_FIFO[4][9]=gy;
- MPU6050_FIFO[5][9]=gz;
- sum=0;
- for(i=0;i<10;i++){ //Çóµ±Ç°Êý×éµÄºÏ£¬ÔÙȡƽ¾ùÖµ
- sum+=MPU6050_FIFO[0][i];
- }
- MPU6050_FIFO[0][10]=sum/10;
- sum=0;
- for(i=0;i<10;i++){
- sum+=MPU6050_FIFO[1][i];
- }
- MPU6050_FIFO[1][10]=sum/10;
- sum=0;
- for(i=0;i<10;i++){
- sum+=MPU6050_FIFO[2][i];
- }
- MPU6050_FIFO[2][10]=sum/10;
- sum=0;
- for(i=0;i<10;i++){
- sum+=MPU6050_FIFO[3][i];
- }
- MPU6050_FIFO[3][10]=sum/10;
- sum=0;
- for(i=0;i<10;i++){
- sum+=MPU6050_FIFO[4][i];
- }
- MPU6050_FIFO[4][10]=sum/10;
- sum=0;
- for(i=0;i<10;i++){
- sum+=MPU6050_FIFO[5][i];
- }
- MPU6050_FIFO[5][10]=sum/10;
- }
- /**************************ʵÏÖº¯Êý********************************************
- 设置MPU6050的时钟源
- * CLK_SEL | Clock Source
- * --------+--------------------------------------
- * 0 | Internal oscillator
- * 1 | PLL with X Gyro reference
- * 2 | PLL with Y Gyro reference
- * 3 | PLL with Z Gyro reference
- * 4 | PLL with external 32.768kHz reference
- * 5 | PLL with external 19.2MHz reference
- * 6 | Reserved
- * 7 | Stops the clock and keeps the timing generator in reset
- *******************************************************************************/
- void MPU6050_setClockSource(uint8_t source){
- IICwriteBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_CLKSEL_BIT, MPU6050_PWR1_CLKSEL_LENGTH, source);
- }
- /** Set full-scale gyroscope range.
- * @param range New full-scale gyroscope range value
- * [url=home.php?mod=space&uid=1466806]@SEE[/url] getFullScaleRange()
- * @see MPU6050_GYRO_FS_250
- * @see MPU6050_RA_GYRO_CONFIG
- * @see MPU6050_GCONFIG_FS_SEL_BIT
- * @see MPU6050_GCONFIG_FS_SEL_LENGTH
- */
- void MPU6050_setFullScaleGyroRange(uint8_t range) {
- IICwriteBits(devAddr, MPU6050_RA_GYRO_CONFIG, MPU6050_GCONFIG_FS_SEL_BIT, MPU6050_GCONFIG_FS_SEL_LENGTH, range);
- }
- /**************************ʵÏÖº¯Êý********************************************
- 设置加速度计的最大量程
- *******************************************************************************/
- void MPU6050_setFullScaleAccelRange(uint8_t range) {
- IICwriteBits(devAddr, MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, range);
- }
- /**************************ʵÏÖº¯Êý********************************************
- 设置是否进入睡眠模式
- *******************************************************************************/
- void MPU6050_setSleepEnabled(uint8_t enabled) {
- IICwriteBit(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, enabled);
- }
- /**************************ʵÏÖº¯Êý********************************************
- 读取芯片ID
- *******************************************************************************/
- uint8_t MPU6050_getDeviceID(void) {
- IICreadBytes(devAddr, MPU6050_RA_WHO_AM_I, 1, buffer);
- return buffer[0];
- }
- /**************************ʵÏÖº¯Êý********************************************
- 检测是否已连接
- *******************************************************************************/
- uint8_t MPU6050_testConnection(void) {
- if(MPU6050_getDeviceID() == 0x68) //0b01101000;
- return 1;
- else return 0;
- }
- /**************************ʵÏÖº¯Êý********************************************
- 设置MPU6050是否做AUX IIC主机
- *******************************************************************************/
- void MPU6050_setI2CMasterModeEnabled(uint8_t enabled) {
- IICwriteBit(devAddr, MPU6050_RA_USER_CTRL, MPU6050_USERCTRL_I2C_MST_EN_BIT, enabled);
- }
- /**************************ʵÏÖº¯Êý********************************************
- *******************************************************************************/
- void MPU6050_setI2CBypassEnabled(uint8_t enabled) {
- IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_I2C_BYPASS_EN_BIT, enabled);
- }
- /**************************ʵÏÖº¯Êý********************************************
- 初始化
- *******************************************************************************/
- void MPU6050_initialize(void) {
- MPU6050_setClockSource(MPU6050_CLOCK_PLL_YGYRO); //ÉèÖÃʱÖÓ
- MPU6050_setFullScaleGyroRange(MPU6050_GYRO_FS_2000);//ÍÓÂÝÒÇ×î´óÁ¿³Ì +-1000¶ÈÿÃë
- MPU6050_setFullScaleAccelRange(MPU6050_ACCEL_FS_2); //¼ÓËٶȶÈ×î´óÁ¿³Ì +-2G
- MPU6050_setSleepEnabled(0); //½øÈ빤×÷״̬
- MPU6050_setI2CMasterModeEnabled(0); //²»ÈÃMPU6050 ¿ØÖÆAUXI2C
- MPU6050_setI2CBypassEnabled(0); //Ö÷¿ØÖÆÆ÷µÄI2CÓë MPU6050µÄAUXI2C ֱͨ¡£¿ØÖÆÆ÷¿ÉÒÔÖ±½Ó·ÃÎÊHMC5883L
- }
复制代码
获取姿态信息
- /**************************************************************************
- 获取姿态信息
- **************************************************************************/
- void Get_Angle(u8 way)
- {
- float Accel_Y,Accel_X,Accel_Z,Gyro_Y,Gyro_Z;
- Temperature=Read_Temperature(); //===¶ÁÈ¡MPU6050ÄÚÖÃζȴ«¸ÐÆ÷Êý¾Ý£¬½üËƱíʾÖ÷°åζȡ£
- if(way==1) //===DMPµÄ¶ÁÈ¡ÔÚÊý¾Ý²É¼¯ÖжÏÌáÐѵÄʱºò£¬Ñϸñ×ñÑʱÐòÒªÇó
- {
- Read_DMP(); //===¶ÁÈ¡¼ÓËٶȡ¢½ÇËٶȡ¢Çã½Ç
- Angle_Balance=Pitch; //===¸üÐÂƽºâÇã½Ç
- Gyro_Balance=gyro[1]; //===¸üÐÂƽºâ½ÇËÙ¶È
- Gyro_Turn=gyro[2]; //===¸üÐÂתÏò½ÇËÙ¶È
- Acceleration_Z=accel[2]; //===¸üÐÂZÖá¼ÓËٶȼÆ
- }
- else
- {
- Gyro_Y=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_L); //¶ÁÈ¡YÖáÍÓÂÝÒÇ
- Gyro_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L); //¶ÁÈ¡ZÖáÍÓÂÝÒÇ
- Accel_X=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_L); //¶ÁÈ¡XÖá¼ÓËٶȼÆ
- Accel_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_L); //¶ÁÈ¡ZÖá¼ÓËٶȼÆ
- if(Gyro_Y>32768) Gyro_Y-=65536; //Êý¾ÝÀàÐÍת»» Ò²¿Éͨ¹ýshortÇ¿ÖÆÀàÐÍת»»
- if(Gyro_Z>32768) Gyro_Z-=65536; //Êý¾ÝÀàÐÍת»»
- if(Accel_X>32768) Accel_X-=65536; //Êý¾ÝÀàÐÍת»»
- if(Accel_Z>32768) Accel_Z-=65536; //Êý¾ÝÀàÐÍת»»
- Gyro_Balance=-Gyro_Y; //¸üÐÂƽºâ½ÇËÙ¶È
- Accel_Y=atan2(Accel_X,Accel_Z)*180/PI; //¼ÆËãÇã½Ç
- Gyro_Y=Gyro_Y/16.4; //ÍÓÂÝÒÇÁ¿³Ìת»»
- if(Way_Angle==2) Kalman_Filter(Accel_Y,-Gyro_Y);//¿¨¶ûÂüÂ˲¨
- else if(Way_Angle==3) Yijielvbo(Accel_Y,-Gyro_Y); //»¥²¹Â˲¨
- Angle_Balance=angle; //¸üÐÂƽºâÇã½Ç
- Gyro_Turn=Gyro_Z; //¸üÐÂתÏò½ÇËÙ¶È
- Acceleration_Z=Accel_Z; //===¸üÐÂZÖá¼ÓËٶȼÆ
- }
- }
复制代码
通过IO引脚模拟I2C程序,读取MPU6050的ADC转换结果。进行姿态解算。麒麟座的PA9 PA10两个IO引脚虽然作为USRAT1串口,可以打印姿态到电脑上,但是由于资源有限,这两个引脚打算作为PWM输出信号给直流电机驱动板。暂时把姿态信息显示在1602液晶屏上看看效果。
|