阿修k:Arduino控制IIC转GPIO模块读写操作

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 14:19:20
  • Arduino控制IIC转GPIO模块读写操作
  • 2008-12-10 23:35:51   分类: Arduino教程    浏览(96)    评论(0)
  •       我们在用Arduino制作机器人或互动媒体时,本已经设计好一个系统,却发现少一个数字口,而不得不放弃这种方案时,怎么办?有2种方案可以解决。第一,用2个Arduino处理在用串口或IIC通讯完成;第二,用74HC595数字IO扩展模块。这2种方案都各有优缺点,第一种优点是不但扩展了数字口,而且还扩展了模拟口,缺点是成本高;第二种优点是模块可以提供8个IO口,成本低,缺点是采用3线SPI通讯,IO口只能写不能读,如果级联使用的话程序复杂。

           现在我们推出第三种方案,那就是IIC转GPIO模块,该模块使用2线IIC总线通讯,每个模块可以扩展出16个IO口,IIC总线上最多可以并接8个模块,每个模块采用跳线设置硬件地址,主机控制器程序也不复杂。模块IO口不但可以写还可以读,真正的双向IO口。模块IO口都具有内部上拉,可提供最大50mA漏电流和20mA灌电流。

    A:大电流外部5v输入

    B:双向数字IO口

    C:IIC总线和电源输入端

    D:地址跳线

    模块内部命令寄存器:

    寄存器地址                       功能

    0x00                       P0口输入,端口高阻态,默认为高电平

    0x01                       P1口输入,端口高阻态,默认为高电平

    0x02                       P0口输出寄存器,8位分别表示8个IO口状态

    0x03                       P1口输出寄存器,8位分别表示8个IO口状态

    0x04                       P0口输入电平反转,高有效

    0x05                       P1口输入电平反转,高有效

    0x06                       P0口配置寄存器,置高输入,置低输出,默认为高

    0x07                       P1口配置寄存器,置高输入,置低输出,默认为高

    模块的写输出寄存器时序:

    模块地址的设置:

           从上面的时序图看,模块地址是8位,包括一位R/W读写位,但我们在操作模块时,地址只需要7位,即地址范围0x20~0x27,R/W读写位Wire库会根据你操作的方向自动添加进去(PS:模块上的地址错写为40~47,正确应是20~27)。A2~A0地址跳线都用短路帽接地,默认地址就是为0x20。如果需要在IIC总线上并联模块,那么每个模块都需要设置一个地址,不可重复。如果只用一个模块,那么模块地址就设置为0x20。地址的设置方法是,A2~A0三个地址位表示地址的低3位,从000到111,用短路帽接地表示0,用杜邦线接电源5V表示1。

          模块还有一个中断输出口(INT),当模块IO口被设置为输入时,IO口上输入只要有变化,中断就会输出,低电平有效。

    模块的使用

           我们还是用实例来说明比较直观一点。

           如图所示,Arduino使用4根线(5V,GND,SCL模拟口5,SDA模拟口4)与模块B相连接,模块A又并接在模块B的IIC接口上。模块A地址设为0x27,A2~A0用杜邦线接5V,模块B地址设为0x20,A2~A0用短路帽接GND。

           实例的功能是,模块A做输出,P1口高4位驱动4个LED,模块B做输入,P0口低4位接键盘(图上用一根杜邦线代替键盘功能)。当模块B的P0口低4位有1位接地时,模块A的P1口高4位相反IO点亮一个LED。

    实例代码:

    #include


    //  地址            0 1 0 0   A2 A1 A0
    #define KEY_ADDRESS 0x20 //模块B地址
    #define LED_ADDRESS 0x27 //模块A地址

    #define REGISTER_INPUT 0x00 //寄存器0 设置P0输入
    #define REGISTER_OUTPUT 0x02 //寄存器2 设置P0输出参数
    #define REGISTER_CONFIG 0x06 //寄存器6 设置P0状态

    void setup() 
    {
      Wire.begin();
      gpio_write(LED_ADDRESS, 0xffff);//设置模块A  IO口输出为高
      gpio_dir(LED_ADDRESS, 0x0000);//设置模块A  IO口为输出
    }


    void loop() 
    {
      int bits;
      bits = gpio_read(KEY_ADDRESS) & 0x0f;//读模块B,因为输入寄存器
      
      gpio_write(LED_ADDRESS,
          (
            ((bits & 1) << 3) | ((bits & 2) << 1) |
            ((bits & 4) >> 1) | ((bits & 8) >> 3)
          ) << 12);//  将模块B的值镜像输出到模块A
          
      delay(200);
    }

    int gpio_read(int address)//读函数
    {
      int data = 0;
      
      //  发送输入寄存器地址
      Wire.beginTransmission(address);//模块地址
      Wire.send(REGISTER_INPUT);//寄存器地址
      Wire.endTransmission();
      
      //  连接模块并接收2字节数据
      Wire.beginTransmission(address);
      Wire.requestFrom(address, 2);
      
      if (Wire.available()) //读P0
      {
        data = Wire.receive();//读P0口8位
      }
      if (Wire.available())
      {
        data |= Wire.receive() << 8;//读P1口8位
      }
      
      Wire.endTransmission();
      
      return data;
    }

    void gpio_dir(int address, int dir) //配置函数
    {
      //  发送配置寄存器地址
      Wire.beginTransmission(address);
      Wire.send(REGISTER_CONFIG);
      
      //  连接模块并发送2字节数据
      Wire.send(0xff & dir);  //  写P0配置寄存器8位
      Wire.send(dir >> 8);    //  写P1配置寄存器8位

      Wire.endTransmission();
    }

    void gpio_write(int address, int data) //写函数
    {
      //  发送输出寄存器地址
      Wire.beginTransmission(address);
      Wire.send(REGISTER_OUTPUT);
      
      //  连接模块并发送2字节数据
      Wire.send(0xff & data);  //  写P0输出寄存器8位
      Wire.send(data >> 8);    //  写P1输出寄存器8位

      Wire.endTransmission();
    }

    实例视频:


    原地址:http://www.roboticfan.com/blog/user_2005/1229/cmd.shtml?uid=1229&do=blogs&id=636&page=1