Chinaunix首页 | 论坛 | 博客
  • 博客访问: 72359
  • 博文数量: 63
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 14
  • 用 户 组: 普通用户
  • 注册时间: 2018-09-15 14:26
文章分类

全部博文(63)

文章存档

2018年(63)

我的朋友

分类: C/C++

2018-09-15 14:31:13

原文地址:Cortex_A9----I2C 作者:小米拍客光

IIC
1. 概念,IIC是由PHILIPS公司推出的两线式串行总线,通过串行数据线(SDA)和串行时钟线(SCL)在连接到总线上的设备间进行
   传递消息,每一个设备都有自己唯一的地址识别
2. 看原理图,找到从机设备(三轴加速度传感器)所接的IIC引脚 -- I2C_SCL5 I2C_SDA5
   配置相关引脚为IIC功能  -- XspiMISO0/I2C_5_SDA/GPB_2   XspiMOSI0/I2C_5_SCL/GPB_3
   1. GPBCON
      GPBCON[2]   [11:8]:0x3 = I2C_5_SDA
      GPBCON[3]  [15:12]:0x3 = I2C_5_SCL
   2. GPBPUD
      GPBPUD[n] [2n + 1:2n]:0x0 = Disables Pull-up/Pull-down
   
3. 看芯片手册上的IIC概述
   1. 当IIC被闲置的时候,SDA和SCL都处于高电平,在SCL处于高电平的时候,SDA的一个下降沿表示一个start信号
                                                                      SDA的一个上升沿表示一个stop信号
   2. 我们的start和stop信号都是有主机设备产生的
   3. 主机发送start信号后接着通过SDA发送一个7bits的地址,这个地址决定主机要通信的从机设备,第八位决定主机是要读
      从机设备还是写从机设备
      从SDA发送的数据只能是八位八位的,在接收到一个字节后会立马发出一个响应信号(ACK)
      主机通过判断中断挂起位来判断是否接受到数据或者ACK应答信号


   4. IIC的四种操作模式
      主机发送、主机接收、从机发送、从机接收
   5. 分析时序图
      
   6. 寄存器  - 看原理图发现我们的三轴加速度传感器接I2C_SCL5
      1. I2CCON5
         Acknowledge generation     [7]: 1 = Enables
                                         In Tx mode, the I2CSDA is idle in the ACK time.
                                         In Rx mode, the I2CSDA is low in the ACK time
         注意: ACK generation is disabled before Reading the last data to generate the STOP condition in Rx mode.
         Tx clock source selection  [6]: 0 = I2CCLK = fPCLK/16
                                         1 = I2CCLK = fPCLK/512
         Tx/Rx Interrupt  (5)       [5]: 1 = Enables
         Interrupt pending flag     [4]: 0 = 1) No interrupt is pending (If Read).
                                             2) Clears pending condition and resumes the operation (if Write).
                                         1 = 1) Interrupt is pending (If Read)
                                             2) N/A (If Write)
         Transmit clock value (4) [3:0]: Tx clock = I2CCLK/(I2CCON[3:0] + 1)
      2. I2CSTAT5
         Mode selection  [7:6]: 00 = Slave receive mode
                                01 = Slave transmit mode
                                10 = Master receive mode
                                11 = Master transmit mode
         Busy signal status/START STOP condition [5]: 0 = (Read) Not busy (If Read)
                                                          (write) STOP signal generation
                                                      1 = (Read) Busy (If Read)
                                                          (write) START signal generation.
                                                      Transfers the data in I2CDS automatically just after the start signal.
         Serial output    [4]: 1 = Enables Rx/Tx
         Last-received bit status flag [0]:1 = Last-received bit is set to 1 (does not receive ACK).
      3. I2CADD5                               //用来读从机地址的
         Slave address  [7:0]: Slave address: [7:1]
      4. I2CDS5
         Data shift     [7:0]: 8-bit data shift register for I2C-bus Tx/Rx operation


4. 看MPU6050的数据手册(Datasheet)
   1. The slave address of the MPU-60X0 is b110100X which is 7 bits long. The LSB bit of the 7 bit address is
      determined by the logic level on pin AD0
      经查看三轴加速度的原理图发现AD0为0,所以从机地址是0x68  ==》  slave_addr = 0x68
   2. To read the internal MPU-60X0 registers, the master sends a start condition, followed by the IIC address and
      a write bit, and then the register address that is going to be read
      当要对MPU6050内部的寄存器进行操作时,在发送完IIC从机地址收到ACk后还要接着发送6050内部寄存器地址
   2. 分析主发从(MPU6050)收的时序


5. 查看MPU6050的寄存器手册(Register Map)  寄存器都是8位的
   SMPLRT_DIV      0x19 //陀螺仪采样率,典型值:0x07(125Hz)                                 
   CONFIG          0x1A //低通滤波频率,典型值:0x06(5Hz)                                   
   GYRO_CONFIG     0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)             
   ACCEL_CONFIG    0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x18(不自检,2G,5Hz)                                                                                                                                          
   GYRO_ZOUT_H     0x47 //获取MPU6050-Z轴角速度高字节                                                                   
   GYRO_ZOUT_L     0x48 //获取MPU6050-Z轴角速度低字节                                                                   
   PWR_MGMT_1      0x6B //电源管理,典型值:0x00(正常启用)  用来设置6050内部时钟                                


6. 写程序
   iic_init
   /* 1. 初始化GPIO引脚为IIC相关功能 */
   GPBCON = GPBCON & (~(0xf<<8))  | (0x3<<8);      //配置GPB_2引脚为IIC_SDA
   GPBCON = GPBCON & (~(0xf<<12)) | (0x3<<12);     //配置GPB_3引脚为IIC_SCL
   
   /* 2. 设置IIC的工作时钟,使能IIC中断,使能ACK */
   I2CCON5 |= (0x7<<5);
   
   /* 3. 使能IIC串口输出 */
   I2CSTAT5 |= (1<<4);


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


   iic_write  -- 参数:addr_slave(从机地址)   addr_slave_reg(从机寄存器地址)  data
   /* 1. 发送start信号 */
   I2CSTAT5 |= (1<<5);
   
   /* 2. 设置主发模式 */
   I2CSTAT5 |= (3<<6);
   
   /* 3. 发送IIC从机设备地址 */
   I2CDS5 = (0x68<<1);
   while(!(I2CCON5 & (1<<4)));     //等待,直到中断被挂起(收到ACK)
   
   /* 4. 发送从设备内部寄存器地址,发送后先清中断挂起(从新开始发送),然后再等待中断被挂起(收到ACK) */
   I2CDS5 = addr_slave_reg;
   I2CCON5 &= ~(1<<4);             //清中断挂起位
   while(!(I2CCON5 & (1<<4)));     //等待,直到中断被挂起(收到ACK)
   
   /* 5. 发送数据,发送前先等待中断被挂起(收到ACK),然后清中断挂起,最后再发送 */
   I2CDS5 = data;
   I2CCON5 &= ~(1<<4);
   while(!(I2CCON5 & (1<<4)));
   
   /* 6. 发送stop信号,禁止接受ACK */
   I2CSTAT5 = 0xd0;
   
   /* 请中断挂起 */
   I2CCON5 &= ~(1<<4);
   
   delay_ms(10);
   
   /*********************************************************************************************************/
   
   iic_read  -- 参数:addr_slave(从机地址)   addr_slave_reg(从机寄存器地址)
   /* 1. 发送start信号 */
   I2CSTAT5 |= (1<<5)|(1<<4);
   
   /* 2. 设置主发模式 */
   I2CSTAT5 |= (3<<6);
   
   /* 3. 发送IIC从机设备地址+写0 */
   I2CDS5 = (0x68<<1);
   while(!(I2CCON5 & (1<<4)));     //等待,直到中断被挂起(收到ACK)
   
   /* 4. 发送从设备内部寄存器地址,发送后先清中断挂起(从新开始发送),然后再等待中断被挂起(收到ACK) */
   I2CDS5 = addr_slave_reg;
   I2CCON5 &= ~(1<<4);             //清中断挂起位
   while(!(I2CCON5 & (1<<4)));     //等待,直到中断被挂起(收到ACK)
   
   /* 5. 清中断,发stop信号 */
   I2CCON5 &= ~(1<<4);
   I2CSTAT5 = 0xd0;
   
   /* 6. 设置主机接收模式 */
   I2CSTAT5 = I2CSTAT5& (~(3<<6)) | (2<<6);
   
   /* 7. 发送start信号,发从机地址+读1位 */
   I2CSTAT5 |= (1<<5);
   I2CDS5 = (0x68<<1) | 0x1;
   while(!(I2CCON5 & (1<<4)));
   
   /* 5. 发送数据,发送前先等待中断被挂起(收到ACK),然后清中断挂起,最后再发送 */
   I2CDS5 = data;
   I2CCON5 &= ~(1<<4);
   while(!(I2CCON5 & (1<<4)));
   
   /* 6. 发送stop信号 */
   I2CSTAT5 = 0xd0;
   
   /* 清中断挂起位 */
   I2CCON5 &= ~(1<<4);
   
   delay_ms(10);
   
   /*********************************************************************************************************/
   
   init_mpu6050
   iic_write(SlaveAddress, PWR_MGMT_1, 0x00);  //设置使用内部时钟8M
   iic_write(SlaveAddress, SMPLRT_DIV, 0x07);  //设置陀螺仪采样率
   iic_write(SlaveAddress, CONFIG, 0x06);  //设置数字低通滤波器
   iic_write(SlaveAddress, GYRO_CONFIG, 0x18);  //设置陀螺仪量程+-2000度/s
   iic_write(SlaveAddress, ACCEL_CONFIG, 0x0);  //设置加速度量程+-2g


   最后一步,在main中读Z轴的加速度
   zvalue_h = iic_read(SlaveAddress, GYRO_ZOUT_H); //获取MPU6050-Z轴角速度高字节
   zvalue_l = iic_read(SlaveAddress, GYRO_ZOUT_L); //获取MPU6050-Z轴角速度低字节
   zvalue  =  (zvalue_h<<8)|zvalue_l; //获取MPU6050-Z轴角速度




点击(此处)折叠或打开

  1. #include "exynos_4412.h"
  2. #include "uart.h"


  3. //****************************************
  4. //    MPU6050内部地址
  5. //****************************************
  6. #define    SMPLRT_DIV        0x19    //陀螺仪采样率,典型值:0x07(125Hz)
  7. #define    CONFIG             0x1A    //低通滤波频率,典型值:0x06(5Hz)
  8. #define    GYRO_CONFIG        0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
  9. #define    ACCEL_CONFIG    0x1C    //加速计自检、测量范围及高通滤波频率,典型值:0x18(不自检,2G,5Hz)
  10. #define    ACCEL_XOUT_H    0x3B
  11. #define    ACCEL_XOUT_L    0x3C
  12. #define    ACCEL_YOUT_H    0x3D
  13. #define    ACCEL_YOUT_L    0x3E
  14. #define    ACCEL_ZOUT_H    0x3F
  15. #define    ACCEL_ZOUT_L    0x40
  16. #define    TEMP_OUT_H        0x41
  17. #define    TEMP_OUT_L        0x42
  18. #define    GYRO_XOUT_H        0x43
  19. #define    GYRO_XOUT_L        0x44
  20. #define    GYRO_YOUT_H        0x45
  21. #define    GYRO_YOUT_L        0x46
  22. #define    GYRO_ZOUT_H        0x47
  23. #define    GYRO_ZOUT_L        0x48
  24. #define    PWR_MGMT_1        0x6B    //电源管理,典型值:0x00(正常启用)
  25. #define    WHO_AM_I        0x75    //IIC地址寄存器(默认数值0x68,只读)
  26. #define    SlaveAddress    0x68    //MPU6050-I2C地址



  27. /**********************************************************************
  28.  *函数功能:延时函数
  29.  **********************************************************************/
  30. void mydelay_ms(int time)
  31. {
  32.     int i, j;
  33.     while(time--)
  34.     {
  35.         for (i = 0; i < 5; i++)
  36.             for (j = 0; j < 514; j++);
  37.     }
  38. }


  39. /**********************************************************************
  40.  * 函数功能:I2C向特定地址写一个字节
  41.  * 输入参数:
  42.  *         slave_addr: I2C从机地址
  43.  *              addr: 芯片内部特定地址
  44.  *              data:写入的数据
  45. **********************************************************************/

  46. void iic_write (unsigned char slave_addr, unsigned char addr, unsigned char data)
  47. {

  48.     I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);    //设置I2C时钟预分配512、使能I2C中断
  49.     I2C5.I2CSTAT |= 0x1<<4;                         //使能I2C串口输出

  50.     I2C5.I2CDS = slave_addr<<1 ;                 //MPU6050-I2C地址+写位0
  51.     I2C5.I2CSTAT = 0xf0;                         //主机发送模式 、使能I2C的发送和接受、发出开始信号
  52.     while(!(I2C5.I2CCON & (1<<4)));                 //等待ACK周期后,中断挂起

  53.     I2C5.I2CDS = addr;                                //数据写入地址(MPU6050芯片内部地址)
  54.     I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));            //清除中断标志位
  55.     while(!(I2C5.I2CCON & (1<<4)));                    //等待ACK周期后,中断挂起

  56.     I2C5.I2CDS = data;                                //要写入的数据
  57.     I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));            //清除中断标志位
  58.     while(!(I2C5.I2CCON & (1<<4)));                    //等待ACK周期后,中断挂起

  59.     I2C5.I2CSTAT = 0xD0;                             //发出停止信号
  60.      //1101 0000
  61.     I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));            //清除中断标志位
  62.     mydelay_ms(10);                                    //延时等待I2C停止信号生效
  63. }


  64. /**********************************************************************
  65.  * 函数功能:I2C从特定地址读取1个字节的数据
  66.  * 输入参数:    slave_addr: I2C从机地址
  67.  *                       addr: 芯片内部特定地址
  68.  * 返回参数: unsigned char: 读取的数值
  69. **********************************************************************/

  70. unsigned char iic_read(unsigned char slave_addr, unsigned char addr)
  71. {

  72.     unsigned char data = 0;

  73.     I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);    //设置I2C时钟预分配512、使能I2C中断
  74.     I2C5.I2CSTAT |= 0x1<<4;                         //使能I2C串口输出

  75.     I2C5.I2CDS = slave_addr<<1;                        //MPU6050-I2C地址+写位0
  76.     I2C5.I2CSTAT = 0xf0;                         //主机发送模式 、使能I2C的发送和接受、发出开始信号
  77.     while(!(I2C5.I2CCON & (1<<4)));                    //等待ACK周期后,中断挂起

  78.     I2C5.I2CDS = addr;                                //读取数据的地址(MPU6050芯片内部地址)
  79.     I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));            //清除中断标志位
  80.     while(!(I2C5.I2CCON & (1<<4)));                    //等待ACK周期后,中断挂起


  81.     I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));            //清除中断标志位

  82.     I2C5.I2CDS = slave_addr << 1 | 0x01;            //MPU6050-I2C地址+读位1
  83.     I2C5.I2CSTAT = 0xb0;                         //主机接受模式 、使能I2C的发送和接受、发出开始信号
  84.     while(!(I2C5.I2CCON & (1<<4)));                    //等待ACK周期后,中断挂起



  85.     I2C5.I2CCON = I2C5.I2CCON & (~(1<<7))&(~(1<<4));//禁止ACK信号、清除中断标志位
  86.     while(!(I2C5.I2CCON & (1<<4)));                    //等待ACK周期后,中断挂起
  87.     data = I2C5.I2CDS;                                //读取数据


  88.     I2C5.I2CSTAT = 0x90;                            //发出停止信号
  89.     I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));            //清除中断标志位
  90.     mydelay_ms(10);                                    //延时等待I2C停止信号生效

  91.     return data;                                    //返回读取的数值

  92. }


  93. /**********************************************************************
  94.  * 函数功能:MPU6050初始化
  95. **********************************************************************/

  96. void MPU6050_Init ()
  97. {
  98.     iic_write(SlaveAddress, PWR_MGMT_1, 0x00);         //设置使用内部时钟8M
  99.     iic_write(SlaveAddress, SMPLRT_DIV, 0x07);        //设置陀螺仪采样率
  100.     iic_write(SlaveAddress, CONFIG, 0x06);            //设置数字低通滤波器
  101.     iic_write(SlaveAddress, GYRO_CONFIG, 0x18);        //设置陀螺仪量程+-2000度/s
  102.     iic_write(SlaveAddress, ACCEL_CONFIG, 0x0);        //设置加速度量程+-2g
  103. }



  104. /**********************************************************************
  105.  * 函数功能:主函数
  106.  **********************************************************************/

  107. int main(void)
  108. {

  109.     unsigned char zvalue_h,zvalue_l;                        //存储读取结果
  110.     short int zvalue;

  111.     /*设置GPB_2引脚和GPB_3引脚功能为I2C传输引脚*/
  112.     GPB.CON = (GPB.CON & ~(0xF<<12)) | 0x3<<12;                 //设置GPB_3引脚功能为I2C_5_SCL
  113.     GPB.CON = (GPB.CON & ~(0xF<<8)) | 0x3<<8;                //设置GPB_2引脚功能为I2C_5_SDA

  114.     uart_init();                                             //初始化串口
  115.     MPU6050_Init();                                            //初始化MPU6050

  116.     printf("\n********** I2C test!! ***********\n");
  117.     while(1)
  118.     {
  119.         zvalue_h = iic_read(SlaveAddress, GYRO_ZOUT_H);        //获取MPU6050-Z轴角速度高字节
  120.         zvalue_l = iic_read(SlaveAddress, GYRO_ZOUT_L);        //获取MPU6050-Z轴角速度低字节
  121.         zvalue = (zvalue_h<<8)|zvalue_l;                    //获取MPU6050-Z轴角速度

  122.         printf(" GYRO--Z :Hex: %d    \n", zvalue);            //打印MPU6050-Z轴角速度
  123.         mydelay_ms(100);
  124.     }
  125.     return 0;
  126. }


































阅读(563) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~