搜索
bottom↓
回复: 15

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

[复制链接]

出0入0汤圆

发表于 2008-8-19 11:13:01 | 显示全部楼层 |阅读模式
小弟现在在做一个用AVR单片机用PCA9555的I2C接口来扩展I/O的实验,可是我就是通不起来,搞了好几次了还没能有结果,我想论坛里面谁又这个经验能帮小弟一把,指点一下,小弟不胜感激,下面是我的程序,麻烦帮忙看一下


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

/* I2C 通信错误标志,默认为0,出错时为1*/
unsigned char g_ucErrFlg[8] = {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[1]++;

                        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[0]++;
                        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[1]++;

                        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[2]++;
       
                        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[3]++;
       
                        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;
                }
        }
}

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

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2008-8-19 12:06:45 | 显示全部楼层
为什么没人回答我啊,难道都没人用过,用过的告诉我下啊

出0入0汤圆

发表于 2013-6-25 15:58:53 | 显示全部楼层
zjm19860703 发表于 2008-8-19 12:06
为什么没人回答我啊,难道都没人用过,用过的告诉我下啊

楼主,程序调通了吗?

出20入186汤圆

发表于 2013-6-25 16:22:01 | 显示全部楼层
PCA9555简单的狠,做过1个项目,扩展32个输入,16个输出

出0入0汤圆

发表于 2013-6-27 10:38:50 | 显示全部楼层
yuyu87 发表于 2013-6-25 16:22
PCA9555简单的狠,做过1个项目,扩展32个输入,16个输出

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

出20入186汤圆

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

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

出0入0汤圆

发表于 2015-11-19 22:34:53 | 显示全部楼层
yuyu87 发表于 2013-6-27 13:46
是这样的,有任意按键变化就会触发中断脚,然后主机读取IIC,就知道哪个有输入了,

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

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

出0入0汤圆

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

是的,写1为高电平

出20入186汤圆

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

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

出0入0汤圆

发表于 2015-11-20 09:19:33 | 显示全部楼层
PCA9555多少钱?

出0入0汤圆

发表于 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置高电平
不知道这样子对不对啊,但是不出高电平啊

出0入0汤圆

发表于 2015-11-20 10:17:06 | 显示全部楼层

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

出0入18汤圆

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

出0入0汤圆

发表于 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->SCL1  PC3->SDA1  PCA9555 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;         
}

出0入18汤圆

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

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

出0入0汤圆

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

PCA9555淘宝上看3-4块,还不如果个单片机来的方便。不知道你们这样选择的原因是什么?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-3 22:29

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表