阿修k:Arduino控制IIC转GPIO模块读写操作
来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 14:19:20
- 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