zjm19860703 发表于 2008-8-19 11:13:01

想请教PCA9555的用法,不知道坛子里面有没有用过的人。

小弟现在在做一个用AVR单片机用PCA9555的I2C接口来扩展I/O的实验,可是我就是通不起来,搞了好几次了还没能有结果,我想论坛里面谁又这个经验能帮小弟一把,指点一下,小弟不胜感激,下面是我的程序,麻烦帮忙看一下


#include <iom16v.h>
#include <macros.h>
#include <delay.h>
#include "I2Ctest.h"

/* I2C 通信错误标志,默认为0,出错时为1*/
unsigned char g_ucErrFlg = {0};


/*清除中断标志位,使能TWI功能,开放TWI中断,在主控接收状态下不对SDA线作应答*/
#define Twi_NoAcK()          {TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);}


void twi_master_init(void)
{
        TWCR= 0x00; /*disable twi*/
        TWBR= 0x64; /*set bit rate = 100,实际SCL 频率=37K*/
        TWSR= 0x00; /*set prescale=1*/
        TWAR= 0x00; /*set slave address*/
        TWCR= (1<<TWEN); /*enable twi*/
}

/*操作步骤: 启动,发送地址,发送数据,关闭总线*/
char i2c_maste_transt(unsigned char addr, unsigned char data0,unsigned char data1,unsigned char comdata)
{
        if(OK != i2c_start())
        {
                return ERROR;
        }

        if(i2c_write_addr(addr, TW_WRITE) == TW_MT_SLA_ACK) /*发送地址成功并收到ACK*/
        {
                if(i2c_write_command(comdata) == OK)
                {
                        if(i2c_write_data(data0) == OK);
                        {
                                i2c_write_data(data1);
                        }
                }
        }
       
        i2c_stop();
}
/*发送控制数据,控制pca9555是还是写,是哪个IO口*/
char i2c_write_command(unsigned char comdata)
{
        unsigned int iCnt = 0;
        TWDR = comdata;   /*写如控制寄存器*/
        TWCR = (1<<TWINT)|(1<<TWEN);
        while (!(TWCR & (1<<TWINT)))
        {
                _NOP();

                if (iCnt++ > 100)
                {
                        g_ucErrFlg++;

                        return ERROR;
                }
        }

        /*TWSR高五位为I2C工作状态。*/
        if ((TWSR & 0xF8) != TW_MT_SLA_ACK)
        {
                return ERROR;
        }
       
        return OK;
}


/*总线上起动开始条件*/
char i2c_start(void)
{
        unsigned int iCnt = 0;
        TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
       
        while (!(TWCR & (1<<TWINT))) /*等待START 信号成功发送*/
        {
                if (iCnt++ > 10)
                {
                        g_ucErrFlg++;
                        return ERROR;
                }
        }

        if ((TWSR & 0xF8) != TW_START)
        {
                return ERROR;
        }

        return OK;
}

/*发送地址,r_w:1为读,0为写*/
unsigned char i2c_write_addr(unsigned char addr,unsigned char r_w)
{
        unsigned int iCnt = 0;

        if(TW_READ == r_w)
        {
                TWDR = addr | r_w;    /*RW 为1:读操作*/
        }
        else
        {
                TWDR = addr & 0xFE;   /*RW 为0: 写操作*/
        }

        TWCR = (1<<TWINT)|(1<<TWEN);
        while (!(TWCR & (1<<TWINT)))
        {
                _NOP();

                if (iCnt++ > 100)
                {
                        g_ucErrFlg++;

                        return ERROR;
                }
        }

        /*TWSR高五位为I2C工作状态。*/
        if ((TWSR & 0xF8) != TW_MT_SLA_ACK)
        {
                return ERROR;
        }
       
        return(OK);
}

/*发送数据*/
unsigned char i2c_write_data(unsigned char data)
{
        unsigned int iCnt = 0;

        TWDR = data;
       
        TWCR = (1<<TWINT)|(1<<TWEN);
       
        while (!(TWCR & (1<<TWINT)))
        {
                _NOP();
       
                if (iCnt++ > 100)
                {
                        g_ucErrFlg++;
       
                        return ERROR;
                }
        }

        /*TWSR高五位为I2C工作状态。*/
        if ((TWSR & 0xF8) != TW_MT_DATA_ACK)
        {
                return ERROR;
        }

        return OK;
}

/*总线上起动停止条件 */
void i2c_stop(void)
{
        TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);

        return;
}

/*操作步骤,启动,发送地址,读数据,关闭总线*/
unsigned char i2c_maste_read(unsigned char addr)
{
        unsigned char tmp=0;
        i2c_start();
        if(i2c_write_addr(addr, 1)==TW_MR_SLA_ACK) /*发送地址成功并收到ACK*/
        {
                tmp=i2c_read();
        }
        i2c_stop();
        return tmp;
}

/*从器件读出一个字节*/
unsigned char i2c_read(void)
{
        unsigned int iCnt = 0;
        TWCR = (1<<TWINT)|(1<<TWEN);
        Twi_NoAcK();
        while (!(TWCR & (1<<TWINT)))
        {
                _NOP();
       
                if (iCnt++ > 100)
                {
                        g_ucErrFlg++;
       
                        return ERROR;
                }
        }
        return(TWDR);
}



void main(void)
{
        unsigned char i=0,tmp=0;
       
        /*re-enable interrupts*/
        DDRC=0X00;
        PORTC=0x03; /*使能内部上拉电阻*/

        twi_master_init();

        while(1)
        {
                DDRD = 0XFF;
                PORTD = 0x00;
                i2c_maste_transt(0x4e,0x02,0x01,0x02);
                i++;
                delay(10);
                DDRD = 0XFF;
                PORTD = 0xff;
                tmp=i2c_maste_read(0x4f); /*读一个数*/
                delay(10);
                DDRA = 0XFF;
                PORTA = tmp;
                if(tmp==0x10)
                {
                        i=0;
                }
        }
}

有哪里错误的希望能够直接指出或者帮我改一下,谢谢!

zjm19860703 发表于 2008-8-19 12:06:45

为什么没人回答我啊,难道都没人用过,用过的告诉我下啊

sinc_mark 发表于 2013-6-25 15:58:53

zjm19860703 发表于 2008-8-19 12:06 static/image/common/back.gif
为什么没人回答我啊,难道都没人用过,用过的告诉我下啊

楼主,程序调通了吗?

yuyu87 发表于 2013-6-25 16:22:01

PCA9555简单的狠,做过1个项目,扩展32个输入,16个输出

sinc_mark 发表于 2013-6-27 10:38:50

yuyu87 发表于 2013-6-25 16:22 static/image/common/back.gif
PCA9555简单的狠,做过1个项目,扩展32个输入,16个输出

想问问,9555的用法。是不是当主控设定好了16个IO的输入输出后,如果这16个IO中有一个改变,就会产生中断,主控接收到中断之后就通过IIC去读这16个IO现在的状态,从而知道是哪一个键按下了?

yuyu87 发表于 2013-6-27 13:46:15

是这样的,有任意按键变化就会触发中断脚,然后主机读取IIC,就知道哪个有输入了,

我读取的是气缸传感器,没有读取它的中断脚,是定时读取,每隔10ms读取一次

图图2014 发表于 2015-11-19 22:34:53

yuyu87 发表于 2013-6-27 13:46
是这样的,有任意按键变化就会触发中断脚,然后主机读取IIC,就知道哪个有输入了,

我读取的是气缸传感器 ...

最近在写PCA9555的驱动,但是没弄好。想问下配置成输出口的话,配置寄存器已经配置好了作为输出口,那么直接往Output register寄存器对应的位写“1”就输出为高电平吗?

mekin0626 发表于 2015-11-19 23:13:32

图图2014 发表于 2015-11-19 22:34
最近在写PCA9555的驱动,但是没弄好。想问下配置成输出口的话,配置寄存器已经配置好了作为输出口,那么 ...

是的,写1为高电平

yuyu87 发表于 2015-11-20 08:58:55

图图2014 发表于 2015-11-19 22:34
最近在写PCA9555的驱动,但是没弄好。想问下配置成输出口的话,配置寄存器已经配置好了作为输出口,那么 ...

认真看下手册吧,很简单的

LVmcu 发表于 2015-11-20 09:19:33

PCA9555多少钱?

图图2014 发表于 2015-11-20 09:45:39

yuyu87 发表于 2015-11-20 08:58
认真看下手册吧,很简单的

搞了两天了,也没弄出来啊,项目急呢,麻烦您给指点下吧,这个芯片的IIC读取时可以单个寄存器的读写是吧?
例如:PCA9555_WriteReg(0x40,0x06,0xf0);//配置P0.0~P0.4为输出,P0.5~P0.7为输入
        PCA9555_WriteReg(0x40,0x02,0x0f);//将输出口P0.0~P0.4置高电平
不知道这样子对不对啊,但是不出高电平啊

图图2014 发表于 2015-11-20 10:17:06

LVmcu 发表于 2015-11-20 09:19
PCA9555多少钱?

我也不晓得多钱,公司硬件工程师买的。去淘宝上搜一下吧,就知道了。

dengxiaofeng 发表于 2015-11-20 10:28:37

简单 I2C 读写 寄存器 就好,用过 这个芯片,不过这芯片 不咋的。 有时候不如数字芯片 来的直接

图图2014 发表于 2015-11-20 17:02:58

本帖最后由 图图2014 于 2015-11-20 17:09 编辑

dengxiaofeng 发表于 2015-11-20 10:28
简单 I2C 读写 寄存器 就好,用过 这个芯片,不过这芯片 不咋的。 有时候不如数字芯片 来的直接 ...

我把代码贴出来,大家帮我看下吧,到底是哪里出了问题。还是PCA9555这个芯片有问题,是假的之类的。
我等级不够,发不了新帖,就借这个帖子发一下吧,就麻烦大家给我看一下吧。非常感谢!
单片机是STM32F407VGT6

////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define PCA9555_WR      0x40    //PCA9555写地址
#define PCA9555_RD      0x41    //PCA9555读地址

//PC2->SCL1PC3->SDA1PCA9555 IIC I/O口定义
//这部分的IO口输入/输出电平PCout(x)没有贴出来,也都是复用别人的代码,经过验证了,而且拿这个IIC驱动,修改了IO口,去驱动QN8035,读写都没问题。
#define SDA1_IN(){GPIOC->MODER&=~(3<<(3*2));GPIOC->MODER|=0<<3*2;}
#define SDA1_OUT() {GPIOC->MODER&=~(3<<(3*2));GPIOC->MODER|=1<<3*2;}
#define IIC1_SCL    PCout(2) //IIC1_SCL
#define IIC1_SDA    PCout(3) //IIC1_SDA       
#define READ_SDA1   PCin(3)//读取IIC1_SDA



//-------------------------------IIC1驱动-------------------------------//
/*************************************************************
//函数名称:IIC1_Start
//函数功能:IIC起始信号
//入口参数:无
//出口参数:无
**************************************************************/
void IIC1_Start(void)
{
SDA1_OUT();   //sda输出
IIC1_SDA=1;                    
IIC1_SCL=1;
delay_us(2);
IIC1_SDA=0;    //START:when CLK is high,DATA change form high to low
delay_us(2);
IIC1_SCL=0;
}          


/*************************************************************
//函数名称:IIC1_Stop
//函数功能:IIC结束信号
//入口参数:无
//出口参数:无
**************************************************************/
void IIC1_Stop(void)
{         
SDA1_OUT();//sda输出
IIC1_SCL=0;
IIC1_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(2);
IIC1_SCL=1;
IIC1_SDA=1;//发送IIC总线结束信号
delay_us(2);                                                                  
         
}

/*************************************************************
//函数名称:IIC1_Wait_Ack
//函数功能:等待应答信号
//入口参数:无
//出口参数:1:接收应答失败,0:接收应答成功
**************************************************************/
u8 IIC1_Wait_Ack(void)
{
u8 ucErrTime=0;

SDA1_IN();      //SDA设置为输入
IIC1_SDA=1;
    delay_us(1);          
IIC1_SCL=1;
   
while(READ_SDA1)
{
    ucErrTime++;
    if(ucErrTime>250)//超过250次,失败
      {
          IIC1_Stop();
          return 1;
      }
    }
IIC1_SCL=0;//SCL拉低          
return 0; //应答成功
}

/*************************************************************
//函数名称:IIC1_Ack
//函数功能:产生应答信号
//入口参数:无
//出口参数:无
**************************************************************/
void IIC1_Ack(void)
{
IIC1_SCL=0;
SDA1_OUT();
IIC1_SDA=0;
    delay_us(2);
IIC1_SCL=1;
    delay_us(2);
IIC1_SCL=0;
}

/*************************************************************
//函数名称:IIC_NAck
//函数功能:不产生应答信号
//入口参数:无
//出口参数:无
**************************************************************/
void IIC1_NAck(void)
{
    IIC1_SCL=0;
    SDA1_OUT();
    IIC1_SDA=1;
      delay_us(2);
    IIC1_SCL=1;
      delay_us(2);
    IIC1_SCL=0;
}       

/*************************************************************
//函数名称:IIC_Send_Byte
//函数功能:发送1byte
//入口参数: 发送1byte数据
//出口参数:无
**************************************************************/
void IIC1_Send_Byte(u8 SendByte)
{                        
    u8 t;
   
    SDA1_OUT(); //SDA设置输出
    IIC1_SCL=0;//拉低时钟,开始传输数据
         
    for(t=0;t<8;t++)
    {            
       if((SendByte&0x80)>>7)
          IIC1_SDA=1;
      else
          IIC1_SDA=0;
      
      SendByte<<=1;           
          delay_us(1);
        IIC1_SCL=1;
          delay_us(2);
        IIC1_SCL=0;       
          delay_us(2);
    }       
   
}           

/*************************************************************
//函数名称:IIC_Read_Byte
//函数功能:读取1byte
//入口参数: 是否要求应答,0:应答 1:不应答
//出口参数: 读到的1byte数据
**************************************************************/
u8 IIC1_Read_Byte(u8 ack)
{
    u8 i;
    u8 ReceiveByte=0;
   
    SDA1_IN(); //SDA输入
      
    for(i=0;i<8;i++)
    {   
           IIC1_SCL=0;
      delay_us(2);
        IIC1_SCL=1;
      ReceiveByte<<=1;
      if(READ_SDA1)
          ReceiveByte++;
      delay_us(1);
    }
   
   // SDA_OUT(); //SDA设置输出
      
    if (ack)
    {
      IIC1_NAck(); //不应答
    }
    else
    {
      IIC1_Ack();//发送ACK
    }
   return ReceiveByte;
}


//-------------------------------PCA9555驱动-------------------------------//
/*************************************************************
//函数名称:PCA9555_Init
//函数功能:PCA9555初始化
//入口参数: 无
//出口参数: 无
**************************************************************/
void PCA9555_Init(void)
{
//PCA9555_WriteOneByte(0x02,0xff);//所有P0输出置为高电平
//PCA9555_WriteOneByte(0x03,0xff);//所有P1输出置为高电平

//PCA9555_WriteOneByte(0x04, 0x00);//所有P0输入均不反转
//PCA9555_WriteOneByte(0x05, 0x00);//所有P1输入均不反转

PCA9555_WriteOneByte(0x06,0x7f);//配置IO口方向,P0.1/1/2/3/4/5/6输入,P0.7输出
PCA9555_WriteOneByte(0x07,0xc7);//配置IO口方向,P1.0/1/2/6/7输入,P1.3/4/5输出
delay_ms(20);


}


/*************************************************************
//函数名称:PCA9555_ReadOneByte
//函数功能:PCA9555读取1byte数据
//入口参数: 数据地址
//出口参数: 读到的1byte数据
**************************************************************/
u8 PCA9555_ReadOneByte(u8 Addr)
{   
    u8 temp = 0;
    IIC1_Start();
   
    IIC1_Send_Byte(PCA9555_WR); //写操作
    IIC1_Wait_Ack();
   
    IIC1_Send_Byte(Addr); //送地址
    IIC1_Wait_Ack();
   
    IIC1_Start();
    IIC1_Send_Byte(PCA9555_RD); //读操作
    IIC1_Wait_Ack();
   
    temp = IIC1_Read_Byte(1);//读数据,NACK
    IIC1_Stop();
    return temp;
}
/*************************************************************
//函数名称:PCA9555_WriteOneByte
//函数功能:PCA9555写入1byte数据
//入口参数: 要写入的地址,数据
//出口参数: 无
**************************************************************/
void PCA9555_WriteOneByte(u8 Addr, u8 Data)
{

IIC1_Start();
IIC1_Send_Byte(PCA9555_WR);//写操作
IIC1_Wait_Ack();
   
IIC1_Send_Byte(Addr); //送地址
IIC1_Wait_Ack();

IIC1_Send_Byte(Data);//送数据
IIC1_Wait_Ack();
IIC1_Stop();
}

/---------------------------------------------------主函数--------------------------------------------------------------------------------/
//主函数,就是测试下PCA9555的P0.7口输出高、低电平,但是并不是我想要的结果,移植都高电平,不出低电平
int main(void)
{
   RCC_Init();
delay_init(SystemClock);
GPIO_Init();

delay_ms(100);
IWDG_Feed();
PCA9555_Init();

while(1)
{
    delay_ms(1000);
   PCA9555_WriteOneByte(0x02,0x7f);//P0.7输出低
   delay_ms(1000);
    PCA9555_WriteOneByte(0x02,0x8f);//P0.7输出高
      delay_ms(1000);
}
return 1;       
}

dengxiaofeng 发表于 2015-11-20 17:13:15

图图2014 发表于 2015-11-20 17:02
我把代码贴出来,大家帮我看下吧,到底是哪里出了问题。还是PCA9555这个芯片有问题,是假的之类的。
我等 ...

上 逻辑分析仪or 示波器看波形 立马就能找到问题

LVmcu 发表于 2015-11-20 19:15:48

图图2014 发表于 2015-11-20 10:17
我也不晓得多钱,公司硬件工程师买的。去淘宝上搜一下吧,就知道了。

PCA9555淘宝上看3-4块,还不如果个单片机来的方便。不知道你们这样选择的原因是什么?
页: [1]
查看完整版本: 想请教PCA9555的用法,不知道坛子里面有没有用过的人。