zoukankan      html  css  js  c++  java
  • GPIO软件模拟IIC时序

    一、MPU6050中的IIC时序

    1.1 START和STOP



    SDA和SCL在高电平时,SDA拉低表示START。SCL拉低,表示可以传输数据。
    SDA和SCL在低电平时,SDA拉高表示STOP。 SCL拉高,表示传输数据结束。
    1. /******************************************
    2. *函数原型: void IIC_Start(void)
    3. *功能: 产生IIC起始信号
    4. ******************************************/
    5. void IIC_Start(void)
    6. {
    7.     SDA_OUT();
    8.     IIC_SDA=1;
    9.     IIC_SCL=1;
    10.     delay_us(4);
    11.     IIC_SDA=0; //START:when CLK is high,SDA change from hig to low
    12.     delay_us(4);
    13.     IIC_SCL=0; //Ready Transmit or Receive
    14. }

    15. /******************************************
    16. *函数原型: void IIC_Start(void)
    17. *功能: 产生IIC结束信号
    18. ******************************************/
    19. void IIC_Stop(void)
    20. {
    21.     SDA_OUT();
    22.     IIC_SDA=0;
    23.     IIC_SCL=0;
    24.     delay_us(4);
    25.     IIC_SDA=1; //STOP:when CLK is low,SDA change from low to high
    26.     IIC_SCL=1; //发送I2C总线结束信号
    27.     delay_us(4);
    28. }
    一些的宏定义:
    1. #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
    2. #define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
    3. #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))

    4. #define GPIOB_ODR_Addr (GPIOB_BASE+12)
    5. #define GPIOB_IDR_Addr (GPIOB_BASE+8)


    6. #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
    7. #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入

    8. //驱动接口,GPIO模拟IIC
    9. //PB7->I2C_SDA
    10. //PB6->I2C_SCL
    11. #define SDA_IN() {GPIOB->CRL&=0x0FFFFFFF;GPIOB->CRL|=0x80000000;} //上拉输入
    12. #define SDA_OUT() {GPIOB->CRL&=0x0FFFFFFF;GPIOB->CRL|=0x30000000;} //通用推挽输出,不用硬件IIC


    13. //IO操作函数
    14. #define IIC_SCL PBout(6)
    15. #define IIC_SDA PBout(7)
    16. #define READ_SDA PBin(7)

    1.2 ACK和NACK时序图


    在START信号后,读取8位的数据,STM32需要对MPU6050发出响应以同步。
    第九个SCL时,SCL从低电平变成高电平后,SDA如果是低电平则是ACK,如果是高电平则是NACK。
    1. /******************************************
    2. *函数原型: void IIC_Wait_Ack(void)
    3. *功能: 等待应答信号到来
    4. *输出; 1,接收应答失败
    5.        0,接收应答成功
    6. ******************************************/
    7. u8 IIC_Wait_Ack(void)
    8. {
    9.     u8 ucErrTime = 0;
    10.     SDA_IN();
    11.     IIC_SDA=1;
    12.     delay_us(1);
    13.     IIC_SCL=1;
    14.     delay_us(1);
    15.     while(IIC_SDA) //最多等待50us
    16.     {
    17.         ucErrTime++;
    18.         if(ucErrTime>50)
    19.         {
    20.             IIC_Stop();
    21.             return 1;
    22.         }
    23.         delay_us(1);
    24.     }
    25.     IIC_SCL=0; //时钟输出0
    26.     return 0;
    27. }

    28. /******************************************
    29. *函数原型: void IIC_Ack(void)
    30. *功能: 产生ACK应答信号SDA=0
    31. ******************************************/
    32. void IIC_Ack(void)
    33. {
    34.     IIC_SCL=0;
    35.     SDA_OUT();
    36.     IIC_SDA=0;
    37.     delay_us(1);
    38.     IIC_SCL=1;
    39.     delay_us(1);
    40.     IIC_SCL=0;
    41. }

    42. /******************************************
    43. *函数原型: void IIC_Ack(void)
    44. *功能: 产生ACK应答信号SDA=0
    45. ******************************************/
    46. void IIC_NAck(void)
    47. {
    48.     IIC_SCL=0;
    49.     SDA_OUT();
    50.     IIC_SDA=1;
    51.     delay_us(1);
    52.     IIC_SCL=1;
    53.     delay_us(1);
    54.     IIC_SCL=0;
    55. }

    1.3 MPU6050写入时序



    写时序的步骤:START+(MPU6050地址+W)+等待ACK+寄存器地址+等待ACK+写入的数据+等待ACK+STOP。
    读时序的步骤:START+(MPU6050地址+W)+等待ACK+寄存器地址+START+读取数据+ACK响应+STOP。

    1. /****************************************************
    2. *函数原型: u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8 *data)
    3. *功能: 将多个字节写入指定设备 指定寄存器
    4. *输入: dev 目标设备地址
    5. * reg 寄存器地址
    6. * length 要写的字节数
    7. * *data 将要写的数据的首地址
    8. *返回: 返回是否成功,1成功
    9. ****************************************************/
    10. u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8 *data)
    11. {
    12.     u8 count = 0;
    13.     IIC_Start();
    14.     IIC_Send_Byte(dev); //发送写命令
    15.     IIC_Wait_Ack();
    16.     IIC_Send_Byte(reg); //发送写入的地址
    17.     IIC_Wait_Ack();
    18.     for(count=0;count<length;count++)
    19.     {
    20.         IIC_Send_Byte(data[count]);
    21.         IIC_Wait_Ack();
    22.     }
    23.     IIC_Stop(); //发送停止信号
    24.     
    25.     return 1;
    26. }

    27. /******************************************
    28. *函数原型: u8 IIC_Read_Byte(unsigned char ack)
    29. *功能: 读取一个Byte的字节
    30. *输入: 读取一个字节,ack=1,发送ACK,ack=0,发送nACK
    31. *返回: 读取到的Byte
    32. ******************************************/
    33. u8 IIC_Read_Byte(unsigned char ack)
    34. {
    35.     unsigned char i, receive = 0;
    36.     SDA_IN(); //设置为输入
    37.     for(i=0;i<8;i++)
    38.     {
    39.         IIC_SCL=0;
    40.         delay_us(1);
    41.         IIC_SCL=1;
    42.         receive<<=1;
    43.         if(READ_SDA) receive++;
    44.         delay_us(1);
    45.     }
    46.     if(ack)
    47.         IIC_Ack(); //发送ACK
    48.     else
    49.         IIC_NAck(); //发送NACK
    50.     
    51.     return receive;    
    52. }

    留下了一个不太清楚的内容,按位,位长度写数据:

    1. /****************************************************
    2. *函数原型: u8 IICwriteBits(u8 dev, u8 reg, u8 bitStart, u8 length, u8 data)
    3. *功能: 读、修改、写指定设备、指定寄存器一个字节中的多个位
    4. *输入: dev 目标设备地址
    5. * reg 寄存器地址
    6. * bitStart 目标字节的起始位,自左向右?
    7. * length 位长度
    8. * data 存放改变目标字节位的值
    9. *返回: 返回是否成功,1成功
    10. ****************************************************/
    11. u8 IICwriteBits(u8 dev, u8 reg, u8 bitStart, u8 length, u8 data)
    12. {
    13.     u8 b;
    14.     u8 mask;
    15.     if(IICreadByte(dev, reg, &b) != 0)
    16.     {
    17.         mask = (0xFF << (bitStart +1))| 0xFF >> ((8 - bitStart) + length -1);
    18.         data >>= (7 - bitStart);
    19.         b &= mask;
    20.         b |= data;
    21.         return IICwriteByte(dev, reg, b);
    22.     } else {
    23.         return 0;
    24.     }
    25. }



    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    常用的长度单位
    HTML常用的列表标签
    html常用文本标签
    CSS选择器及优先级
    块级元素与内联元素
    移动端app打包
    内联框架
    Leetcode303.区域和检索-数组不可变
    Leetcode107.二叉树的层次遍历||
    Leetcode784.字母大小写全排列
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363260.html
Copyright © 2011-2022 走看看