Fork me on GitHub

Microcontrolandos

O Blog está passando por uma fase de mudanças. Todos os posts estão sendo atualizados, códigos, links e imagens estão sendo arrumados. Conteúdos novos ainda estão por vir.

PIC: MCP23008

Share:

PIC: MCP23008



O MCP23008 é um dispositivo I2C escravo que fornece 8 saídas bi-direcionais.

Os quatro bits mais significativos do endereço do escravo são fixos (0100) e outros três bits são bits do endereço de hardware definidos pelo usuário (pinos A2, A1 e A0). Isso nos permite conectar até oito dispositivos MCP23008 em um mesmo barramento I2C.


Os bits individuais da porta GPIO de 8 bits pode ser configurado como entrada ou de saída. Os pinos da porta também pode ser habilitado o resistor pull-up interno e interrupção por mudança de estado. Estas operações são controladas através de um conjunto de configuração e controle de registros.


IODIR: Controla a direção dos pinos: 1 é entrada; 0 é saída.

IPOL: Controla a polaridade dos bits correspondentes de GPIO. Se definido com 1, o bit do registro GPIO irá armazenar o valor invertido do pino.

GPINTER: Controla o recurso de interrupção por mudança de estado. Se o bit é definido com 1, o pino correspondente estará habilitado para interrupção.

INTCON: Controla como o valor do pino associado é comparado com o recurso de interrupção. Se o bit é definido com 1, o pino I/O correspondente é comparado com o bit associado no registro DEFVAL. Se o bit é definido com 0, o pino I/O correspondente é comparado com o seu valor anterior.

DEFVAL: O valor de comparação padrão é configurado no registo DEFVAL. Se ativado (via GPINTEN e INTCON) para comparar com o registo DEFVAL, um valor oposto no pino associado irá causar uma interrupção. Por exemplo, se os bits GPINT6 (em GPINTEN), IOC6 (em INTCON) e DEF6 (em DEFVAL)  = 1, então uma interrupção será gerada quando o pino GP6 é puxado para o nível baixo. A direção do pino GP6 deve ser definido como entrada.

IOCON: Ele contém vários bits para controlar o dispositivo:

  • SEQOP controla a função de incremento do ponteiro de endereço. Se for definido com 0, ele estará ativado. O ponteiro do endereço dentro do MCP23008 será incrementada em 1 após cada byte de dados recebidos, se você começar a escrever um byte de registo 0x00 (que é IODIR), o segundo byte você enviar irá para o registro IPOL, terceiro byte vai para GPINTEN, e assim por diante. Isso é útil quando você tem que configurar diversos registros.
  • DISSLW controla a taxa de variação no pino SDA.
  • ODR configura o pino INT como uma saída em dreno aberto ou saída ativa. Se definido com 1, configura como dreno aberto.
  • INTPOL configura a polaridade do pino INT. Esse bit é funcional somente quando o bit ODR = 0.


GPPU: Este registo controla os resistores pull-up para cada pino da porta. Se um bit é definido com 1 e o pino correspondente é configurado como uma entrada, o pino da porta correspondente é puxado internamente com um resistor.

INTF: Flag de interrupção. Se o bit estiver setado indica que o pino associado causou a interrupção. Este registro é "somente leitura".

INTCAP: Ele captura o valor da porta GPIO no momento que ocorreu a interrupção. O registo é atualizado apenas quando ocorre uma interrupção. O registo permanecerá inalterado até que a interrupção é eliminado através de uma leitura de INTCAP ou GPIO.

GPIO: Valor da porta. A leitura deste registro lê a porta. A escrita neste registro modifica o registro OLAT e o valor da porta.

OLAT: Fornece acesso as travas de saídas. Uma leitura resulta na leitura de OLAT e não da à própria porta. A escrita neste registro modifica o valor da saída dos pinos.

BIBLIOTECA
MikroC PRO PIC
//Registros
#define MCP23008_IORDIR  0x00
#define MCP23008_IPOL  0x01
#define MCP23008_GPINTEN 0x02
#define MCP23008_DEFVAL  0x03
#define MCP23008_INTCON  0x04
#define MCP23008_IOCON  0x05
#define MCP23008_GPPU  0x06
#define MCP23008_INTF  0x07 //Read-only
#define MCP23008_INTCAP  0x08 //Read-only
#define MCP23008_GPIO  0x09
#define MCP23008_OLAT  0x0A

#define MCP23008_ADDR  64

void MCP23008_WriteByte( char Address, char RegAddress, char _data )
{
    I2C1_Start();
    I2C1_Wr( MCP23008_ADDR | ( Address << 1 ) );
    I2C1_Wr( RegAddress );
    I2C1_Wr( _data );
    I2C1_Stop();
}

char MCP23008_ReadByte( char Address, char RegAddress )
{
char read;
    I2C1_Start();
    I2C1_Wr( MCP23008_ADDR | ( Address << 1 ) );
    I2C1_Wr( RegAddress );
    I2C1_Repeated_Start();
    I2C1_Wr( MCP23008_ADDR | 1 | ( Address << 1 ) );
    Delay_ms( 1 );
    read = I2C1_Rd(0);
    I2C1_Stop();
    return(read);
}

void MCP23008_Init( char Address )
{
    I2C1_Start();
    I2C1_Wr( MCP23008_ADDR | ( Address << 1 ) );
    I2C1_Wr(0x00); // IODIR
    I2C1_Wr(0x00); // GP0-GP7 como saída
    I2C1_Wr(0x00); // IPOL
    I2C1_Wr(0x00);
    I2C1_Wr(0x00);
    I2C1_Wr(0x00);
    I2C1_Wr(0x22); // Desabilita escrita sequencial
    I2C1_Stop();
}

//Faz a leitura da porta
char MCP23008_Read_Port( char Address )
{
     return MCP23008_ReadByte( Address, MCP23008_GPIO );
}

//Escreve um valor para a porta
void MCP23008_Write_Port( char Address, char _data )
{
     MCP23008_WriteByte( Address, MCP23008_GPIO, _data );
}

//Define a direção dos pinos( entrada ou saída )
void MCP23008_Set_DirectionPort( char Address, char direction )
{
     MCP23008_WriteByte( Address, MCP23008_IORDIR, direction );
}

//Configura os resistores de Pull-up
void MCP23008_Set_PullUp( char Address, char _data )
{
     MCP23008_WriteByte( Address, MCP23008_GPPU, _data );
}


EXEMPLO
MikroC PRO PIC
//Habilitar as seguintes bibliotecas:
// - I2C

//PIC16F876A
//CLOCK: 4MHz

//Copie e cole o código da biblioteca aqui!!!

void main()
{
char i = 0;
     
     //configura o pino RB0/INT como entrada
     TRISB0_Bit = 1;
     
     //interrupção por borda de subida
     INTEDG_Bit = 1;
     
     I2C1_Init( 100000 );
     
     MCP23008_Init( 7 );
     
     //GP0-GP6 são saidas, GP7 Entrada
     MCP23008_Set_DirectionPort( 7, 0x80 );
     //Habilita int. GP7
     MCP23008_WriteByte( 7, MCP23008_GPINTEN, 0x80 );
     //Configura interrupção do pino GP7 por borda de descida
     MCP23008_WriteByte( 7, MCP23008_DEFVAL, 0x80 );
     //Configura a int. do pino GP7 para comparar com o registro DEFVAL
     MCP23008_WriteByte( 7, MCP23008_INTCON, 0x80 );
     //Habilita resistor de pull-up do pino GP7
     MCP23008_Set_PullUp( 7, 0x80 );

     
     while(1)
     {
          //Espera a interrupção ocorrer
          while( !INTF_Bit );
          INTF_Bit = 0;  //limpa a flag de interrupção
          
          //Poderia ler o registro INTF, verificar se ocorreu a interrupção
          //e verificar qual pino disparou o evento. Exemplo abaixo.

          //Faz a leitura de GPIO para limpar a interrupção
          MCP23008_ReadByte( 7, MCP23008_GPIO );
          //Escreve para o dispositivo
          MCP23008_Write_Port( 7, ++i & 0x7F );
     }
}

EXEMPLO
MikroC PRO PIC
//Habilitar as seguintes bibliotecas:
// - I2C

//PIC16F876A
//CLOCK: 4MHz

//Copie e cole o código da biblioteca aqui!!!

void main()
{
char i = 0;
     
     Uart1_Init( 9600 );
     
     I2C1_Init( 100000 );
     
     MCP23008_Init( 7 );
     
     //GP0-GP3 são saidas, GP4-GP7 Entrada
     MCP23008_Set_DirectionPort( 7, 0xF0 );
     //Habilita int. GP7-GP4
     MCP23008_WriteByte( 7, MCP23008_GPINTEN, 0xF0 );
     //Configura interrupção dos pinos GP4-GP7 por borda de descida
     MCP23008_WriteByte( 7, MCP23008_DEFVAL, 0xF0 );
     //Configura a int. dos pinos GP4-GP7 para comparar com o registro DEFVAL
     MCP23008_WriteByte( 7, MCP23008_INTCON, 0xF0 );
     //Habilita resistor de pull-up dos pinos GP4-GP7
     MCP23008_Set_PullUp( 7, 0xF0 );

     
     while(1)
     {
     char port;
          
          Delay_ms( 200 );

          port = MCP23008_ReadByte( 7, MCP23008_INTF );

          if( port == 0 )  //Nao houve nehuma interrupção
             continue; //retorna ao inicio do loop

          if( port.B7 )
          {
              Uart1_Write_Text( "GP7" );
          }
          
          if( port.B6 )
          {
              Uart1_Write_Text( "GP6" );
          }
          
          if( port.B5 )
          {
              Uart1_Write_Text( "GP5" );
          }
          
          if( port.B4 )
          {
              Uart1_Write_Text( "GP4" );
          }
     }
}


Nenhum comentário