打印
[AVR单片机]

gy-86陀螺仪模块

[复制链接]
4126|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
沙发
南方孩子95|  楼主 | 2014-8-17 12:20 | 只看该作者
#include <avr/io.h>
//#include "IIC.h"
/***********模拟IIC IO **************/
#define AT_SCL_H PORTC|=(1<<0) //PC0
#define AT_SCL_L PORTC&=~(1<<0)
#define AT_SDA_H PORTC|=(1<<1) //PC1
#define AT_SDA_L PORTC&=~(1<<1)
#define SDA_IN  DDRC&=~(1<<1);PORTC |=0x02//上拉电阻
#define SDA_OUT DDRC|=(1<<1)
#define SDA_DATA (PINC&0x02)
#define SCL_OUT DDRC|=(1<<1)

/***************** Address ******************/
#define WD_DEVICE_ADDR 0xD0//0xA6   MPU6050地址为0x68
#define RD_DEVICE_ADDR 0XD1//0xA7   //看手册即可知道
//unsigned char WD_DEVICE_ADDR=0xD0,RD_DEVICE_ADDR=0XD1;      //为了改变IIC写入读出地址方便
       
unsigned char BUF[16],Data[6];

void delay_us(unsigned int us)//1us   
{
while(us--);   
        asm("nop");
/*                unsigned int i;
        for (i=0;i<40;i++)asm ("nop");*/
}
void delay_1ms(void)                 //1ms延时函数
{
        unsigned int i;
        for (i=0;i<1140;i++)asm ("nop");  
}

void delay_nms(unsigned int n)       //N ms延时函数
{
        unsigned int i=0;
        for (i=0;i<n;i++)
        delay_1ms();
}

/**************************************
起始信号
**************************************/
void AT24C04_Start()
{
        SDA_OUT;
        SCL_OUT;
        AT_SDA_H;                    //拉高数据线
        AT_SCL_H;                    //拉高时钟线
        delay_us(5);                 //延时
        AT_SDA_L;                    //产生下降沿
        delay_us(5);                 //延时
        AT_SCL_L;                    //拉低时钟线
}
/**/
/**************************************
停止信号
**************************************/
void AT24C04_Stop()
{
        SDA_OUT;
        SCL_OUT;
        AT_SDA_L;                    //拉低数据线
        AT_SCL_H;                    //拉高时钟线
        delay_us(5);                 //延时
        AT_SDA_H;                    //产生上升沿
        delay_us(5);                 //延时
}
/**/
/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void AT24C04_SendACK(unsigned char ack)
{
        SCL_OUT;
        SDA_OUT;
        if(ack==1)AT_SDA_H;
        else AT_SDA_L;                 //写应答信号
        AT_SCL_H;                   //拉高时钟线
        delay_us(5);                 //延时
        AT_SCL_L;                    //拉低时钟线
        delay_us(5);                 //延时
}
/**/
/**************************************
接收应答信号
**************************************/
unsigned char AT24C04_RecvACK()
{
        SCL_OUT;
        unsigned char i=0;
        SDA_IN;
        AT_SCL_H;                    //拉高时钟线
        delay_us(5);                 //延时
        //i = SDA_DATA;             //读应答信号
        if(SDA_DATA) i=1;
        AT_SCL_L;                    //拉低时钟线
        delay_us(5);                 //延时
        SDA_OUT;
        return i;
}
/**/
/**************************************
向IIC总线发送一个字节数据
**************************************/
void AT24C04_SendByte(unsigned char dat)
{
        unsigned char i;
       
        SDA_OUT;
        SCL_OUT;
        for (i=0; i<8; i++)         //8位计数器
        {
               
                if(dat&0x80)AT_SDA_H;else AT_SDA_L;
               
                dat <<= 1;              //移出数据的最高位
                //送数据口
                AT_SCL_H;                //拉高时钟线
                delay_us(5);             //延时
                AT_SCL_L;                //拉低时钟线
                delay_us(4);             //延时    此处延时长了点
        }
        AT24C04_RecvACK();
}
/**/
/**************************************
从IIC总线接收一个字节数据    注意 SDA SCL IO 改变
**************************************/
unsigned char AT24C04_RecvByte()
{
        unsigned char i;
        unsigned char dat = 0;
    SDA_IN;
        SCL_OUT;
        AT_SDA_H;
        //DDRC&=0xFD;                   //使能内部上拉,准备读取数据
        for (i=0; i<8; i++)         //8位计数器
        {
                dat <<= 1;
                AT_SCL_H;                //拉高时钟线
                delay_us(5);             //延时
               
                if(SDA_DATA)
                dat |=0x01;
                //dat |= (SDA_DATA>>4);             //读数据                 /////////////////////////////////////???????
                AT_SCL_L;                //拉低时钟线
                delay_us(5);             //延时   ///////
        }
        //DDRC|=0x02;
        SDA_OUT;
        return dat;
}/**/

//***************************************************

void WriteByte(unsigned char REG_Address,unsigned char REG_data)
{
    AT24C04_Start();                  //起始信号
    AT24C04_SendByte(WD_DEVICE_ADDR);   //发送设备地址+写信号
    AT24C04_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf
    AT24C04_SendByte(REG_data);       //内部寄存器数据,请参考中文pdf
    AT24C04_Stop();                   //发送停止信号
}

//********单字节读取内部寄存器*************************
unsigned char Single_Read(unsigned char REG_Address)
{  unsigned char REG_data;
    AT24C04_Start();                          //起始信号
    AT24C04_SendByte(WD_DEVICE_ADDR);           //发送设备地址+写信号
    AT24C04_SendByte(REG_Address);                   //发送存储单元地址,从0开始       
    AT24C04_Start();                          //起始信号
    AT24C04_SendByte(WD_DEVICE_ADDR+1);         //发送设备地址+读信号
    REG_data=AT24C04_RecvByte();              //读出寄存器数据
        AT24C04_SendACK(1);   
        AT24C04_Stop();                           //停止信号
    return REG_data;
}
/**************************************
向AT24C04写1页(16字节)数据
将TESTDATA开始的16个测试数据写如设备的00~0F地址中
**************************************/
/*void AT24C04_WritePage()
{
        unsigned char i;

        AT24C04_Start();            //起始信号
        AT24C04_SendByte(0xa0);     //发送设备地址+写信号
        AT24C04_SendByte(0x00);     //发送存储单元地址
        for (i=0; i<16; i++)
        {
                AT24C04_SendByte(TESTDATA[i]);
        }
        AT24C04_Stop();             //停止信号
}
*/
/**************************************
从 ADXL345 读取0x32~0x37数据 并存放 Data[6]

**************************************/
void ADXL345_ReadPage()
{
        unsigned char i;

        AT24C04_Start();            //起始信号
        AT24C04_SendByte(WD_DEVICE_ADDR);     //发送设备地址+写信号
        AT24C04_SendByte(0x32);     //发送存储单元地址,从0x32开始       
        AT24C04_Start();            //起始信号
        AT24C04_SendByte(WD_DEVICE_ADDR+1);     //发送设备地址+读信号
        for (i=0; i<6; i++)
        {
                Data[i] = AT24C04_RecvByte();
                //send_date(BUF[i]);
                if (i == 5)
                {
                        AT24C04_SendACK(1); //最后一个数据需要会NAK
                }
                else
                {
                        AT24C04_SendACK(0); //回应ACK
                }
        }
        AT24C04_Stop();             //停止信号
        delay_nms(5);
}
//#include "IIC.h"
#include<avr/interrupt.h>

//#define CLK 7372800
#define CLK 8000000
//****************************************
// 定义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
#define        PWR_MGMT_1                0x6B        //电源管理,典型值:0x00(正常启用)
#define        WHO_AM_I                        0x75        //IIC地址寄存器(默认数值0x68,只读)
#define        SlaveAddress        0xD0        //IIC写入时的地址字节数据,+1为读取

#define L_on PORTD |=0x80//
#define L_off PORTD &=0x7F
#define Key (PIND&0x01)

unsigned char value;


void init_uart(unsigned int baud)
{
        UCSRB=0x00;
        UCSRA=0x00;                     //控制寄存器清零
        UCSRC=(1<<URSEL)|(0<<UPM0)|(3<<UCSZ0);    //选择UCSRC,异步模式,禁止校验,1位停止位,8位数据位
       
        UBRRL=(CLK/16/baud-1)%256;
        UBRRH=(CLK/16/baud-1)/256;                    //设置波特率
        UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE);     //接收、发送使能,接收中断使能
       
        sei();                        //全局中断开放
        DDRD|=0X02;                        //配置TX为输出(很重要)TX--PD1,RX--PD0

}

void send_date(unsigned char date)
{
        while(!(UCSRA&(1<<UDRE)));     //等待数据寄存器空
        UDR=date;
        while(!(UCSRA&(1<<TXC)));      //等待发送结束
        UCSRA|=(1<<TXC);               //写1清零
}

//初始化ADXL345,根据需要请参考pdf进行修改************************
void Init_ADXL345()
{
        WriteByte(0x31,0x0B);   //测量范围,正负16g,13位模式
        WriteByte(0x2C,0x08);   //速率设定为12.5 参考pdf13页
        WriteByte(0x2D,0x08);   //选择电源模式   参考pdf24页
        WriteByte(0x2E,0x80);   //使能 DATA_READY 中断
        WriteByte(0x1E,0x00);   //X 偏移量 根据测试传感器的状态写入pdf29页
        WriteByte(0x1F,0x00);   //Y 偏移量 根据测试传感器的状态写入pdf29页
        WriteByte(0x20,0x05);   //Z 偏移量 根据测试传感器的状态写入pdf29页
}
/***************** 等待延时 12000≈80S********************/
unsigned char waitkey ( unsigned int i1 )
{
        while ( i1-- )
        {
                if ( !Key)
        {return 1;}
                delay_nms ( 5 );
        }
        return 0;
}
void n_to_c(int i)//数值转为字符并通过串口输出
{
        float i1;
        unsigned char temp1;
       
//        i=i/64;
        if(i<0){i=-i;send_date('-');}
           else send_date(' ');
          
        i1=(float)i/64;  //for 加速度测量 1 LSB 代表3.9 mg
        i=(int)i1;
       
        temp1=i/10000;
        if(temp1==0)send_date(' '); else send_date(temp1+'0');
        i %=10000;
        send_date(i/1000+'0');
        send_date('.');
        i %=1000;
        send_date(i/100+'0');
        i %=100;
        send_date(i/10+'0');
        send_date(i%10+'0');
        //小数点
        send_date('g');
}

//**************************************
//初始化MPU6050
//**************************************
void InitMPU6050()
{       
        WriteByte(PWR_MGMT_1, 0x00);        //解除休眠状态
        WriteByte(SMPLRT_DIV, 0x07);
        WriteByte(CONFIG, 0x06);
        WriteByte(GYRO_CONFIG, 0x18);
        WriteByte(ACCEL_CONFIG, 0x01);
}

/*******************通过MPU6050辅助IIC接口写数据到 从机0***********************/
/***********本函数针对 从机0编写,若要操作从机 1-4请查阅6050寄存器数据手册,注意从机4叫特殊只能读取一个字节的值*********/
void Auxiliary_I2C_Write(unsigned char add,unsigned char da)
{
                WriteByte(0x25,0x53);//写入从机0地址 写模式
                WriteByte(0x26,add);//数据从 I2C_SLV0_REG指定的地址
               
                WriteByte(0x27,0x81);//使能数据传输 字节长度1
                WriteByte(0x63,da);  //要写入的值 注意先使能数据传输 后写值到I2C_SLV0_DO !
}
int main(void)
{
    unsigned char i=0,i1=0;
        int temp=0;
//        DDRD |=0xC0;//??????
//  PORTD &=0xBF;
       
        DDRD|=(1<<1);
        PORTD |=(1<<1);
//        DDRC |=0x30;//IIC port init  要改成PC0--SCL,PC1--SDA!!!!
        init_uart(9600);
       
        InitMPU6050();        //初始化MPU6050
        Init_ADXL345();       
        WriteByte(0x6A,0x20);//I2C_MST_EN 使能I2C主机模式  0x20


        //WriteByte(0x37,0x02);//I2C_BYPASS_EN 为了直接接到辅助IIC接口,此时可不要   
        /// Pass-Through Mode:I2C_MST_EN=0  I2C_BYPASS_EN =1即可直接接到旁路IIC,注意修改IIC读/写的从机地址
       
   //通过 auxiliary I2C Interface 初始化ADXl345
   /*
   Auxiliary_I2C_Write(0x31,0x0B);
   Auxiliary_I2C_Write(0x2C,0x08);
   Auxiliary_I2C_Write(0x2D,0x08);
   Auxiliary_I2C_Write(0x2E,0x80);
   Auxiliary_I2C_Write(0x1E,0);
   Auxiliary_I2C_Write(0x1F,0);
   Auxiliary_I2C_Write(0x20,0x05);
*/       
   
   //MPU6050 读取并显示,由于本程序以介绍MPU6050辅助IIC接口为主,所以屏蔽了此部分
   while(1)
        {
                ADXL345_ReadPage();
                 waitkey(400);
                 Data[0]=Single_Read(ACCEL_XOUT_H);
                 Data[1]=Single_Read(ACCEL_XOUT_L);
                 Data[2]=Single_Read(ACCEL_YOUT_H);
                 Data[3]=Single_Read(ACCEL_YOUT_L);
                 Data[4]=Single_Read(ACCEL_ZOUT_H);
                 Data[5]=Single_Read(ACCEL_ZOUT_L);
                 temp=(Data[0]<<8)+Data[1];
                 send_date('X');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
                 
                 temp=(Data[2]<<8)+Data[3];
                 send_date('Y');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
                 
                 temp=(Data[4]<<8)+Data[5];
                 send_date('Z');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');send_date(' ');send_date(' ');
                 
                 Data[0]=Single_Read(GYRO_XOUT_H);
                 Data[1]=Single_Read(GYRO_XOUT_L);
                 Data[2]=Single_Read(GYRO_YOUT_H);
                 Data[3]=Single_Read(GYRO_YOUT_L);
                 Data[4]=Single_Read(GYRO_ZOUT_H);
                 Data[5]=Single_Read(GYRO_ZOUT_L);
                 temp=(Data[0]<<8)+Data[1];
                 send_date('X');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
                 
                 temp=(Data[2]<<8)+Data[3];
                 send_date('Y');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
                 
                 temp=(Data[4]<<8)+Data[5];
                 send_date('Z');send_date(':');n_to_c(temp);
                 send_date(0x0d);send_date(0x0a);//换行
                 
        }
       
/*        while(1)
        {*/
        /*****************6050 master mode 下从从机0(0x53)读取起始位置0x32的6字节数据******************/
/*                        WriteByte(0x25,0xD3);//读出从机地址 读模式
                        WriteByte(0x26,0x32);//数据从 I2C_SLV0_REG指定的地址
                        WriteByte(0x27,0x86);//使能数据传输 字节长度6(bit 3-0 为字节数)                                          
               
               
                L_on;
                waitkey(100);
*/
                /***  在MPU6050 master mode 下读取 ADXL345 EXT_SENS_DATA_00~EXT_SENS_DATA_05***/
/*                Data[0]=Single_Read(0x49);delay_nms(10);
                Data[1]=Single_Read(0x4A);delay_nms(10);
                Data[2]=Single_Read(0x4B);delay_nms(10);
                Data[3]=Single_Read(0x4C);delay_nms(10);
                Data[4]=Single_Read(0x4D);delay_nms(10);
                Data[5]=Single_Read(0x4E);

        //显示输出部分
                temp=(Data[1]<<8)+Data[0];//1 LSB 代表3.9 mg
                send_date('X');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
       
                temp=(Data[3]<<8)+Data[2];//1 LSB 代表3.9 mg
                send_date('Y');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');

                temp=(Data[5]<<8)+Data[4];//1 LSB 代表3.9 mg
                send_date('Z');send_date(':');n_to_c(temp);
             
            send_date(0x0d);send_date(0x0a);
       L_off;
          
       waitkey(100);
               
    }
*/
}

/***************串口接收中断***************/
/********捕捉同步字,接收1000字节内结束*******/
SIGNAL ( USART_RXC_vect )
{
        UCSRB&=~ ( 1<<RXCIE );      //关接受结束中断使能
        value=UDR;
        //send_date(value);/////////////////
       
        UCSRB|= ( 1<<RXCIE );                         // 开接受结束中断使能
}

使用特权

评论回复
板凳
bzd_111| | 2014-8-24 19:03 | 只看该作者
我也在研究这个问题,我们可以交流一下,,我QQ2192029272

使用特权

评论回复
地板
单片机学习0| | 2014-8-29 17:32 | 只看该作者
读出来的是0说明你的IIC不正确,接线只需要接电源、地、SCL、SDA,这四根线就可以读出有效数据

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

3

帖子

0

粉丝