- O que é o protocolo de comunicação I2C?
- Como funciona a comunicação I2C?
- Onde usar a comunicação I2C?
- I2C com PIC16F877a usando Compilador XC8
- Programação usando os arquivos de cabeçalho I2C:
- Simulação Proteus:
Os microcontroladores PIC são uma plataforma poderosa fornecida por microchip para projetos embarcados, sua natureza versátil fez com que encontrassem maneiras em muitas aplicações e a fase ainda está acontecendo. Se você tem seguido nossos tutoriais PIC, então deve ter notado que já cobrimos uma ampla variedade de tutoriais sobre microcontroladores PIC, começando desde o básico. Desde agora, cobrimos o básico para que possamos entrar em coisas mais interessantes como o portal de comunicação.
No vasto sistema de aplicativos embarcados, nenhum microcontrolador pode realizar todas as atividades sozinho. Em algum momento ele precisa se comunicar com outros dispositivos para compartilhar informações, existem muitos tipos diferentes de protocolos de comunicação para compartilhar essas informações, mas os mais usados são USART, IIC, SPI e CAN. Cada protocolo de comunicação tem suas próprias vantagens e desvantagens. Vamos nos concentrar na parte da IIC por enquanto, pois é isso que aprenderemos neste tutorial.
O que é o protocolo de comunicação I2C?
O termo IIC significa “ Inter Integrated Circuits ”. Normalmente é denotado como I2C ou I ao quadrado C ou mesmo como protocolo de interface de 2 fios (TWI) em alguns lugares, mas significa o mesmo. I2C é um protocolo de comunicação síncrona, o que significa que ambos os dispositivos que estão compartilhando as informações devem compartilhar um sinal de relógio comum. Ele tem apenas dois fios para compartilhar informações, dos quais um é usado para o sinal do galo e o outro é usado para enviar e receber dados.
Como funciona a comunicação I2C?
A comunicação I2C foi introduzida pela primeira vez por Phillips. Como disse anteriormente, ele tem dois fios, esses dois fios serão conectados em dois dispositivos. Aqui, um dispositivo é chamado de mestre e o outro dispositivo é chamado de escravo. A comunicação deve e sempre ocorrerá entre um Mestre e um Escravo. A vantagem da comunicação I2C é que mais de um escravo pode ser conectado a um mestre.
A comunicação completa ocorre por meio desses dois fios, a saber, Serial Clock (SCL) e Serial Data (SDA).
Serial Clock (SCL): Compartilha o sinal de clock gerado pelo mestre com o escravo
Serial Data (SDA): Envia os dados de e para o mestre e o escravo.
A qualquer momento, apenas o mestre será capaz de iniciar a comunicação. Como há mais de um escravo no barramento, o mestre deve referir-se a cada escravo usando um endereço diferente. Quando endereçado, apenas o bálsamo com aquele endereço específico responderá de volta com a informação enquanto os outros continuam desistindo. Dessa forma, podemos usar o mesmo barramento para nos comunicarmos com vários dispositivos.
Onde usar a comunicação I2C?
A comunicação I2C é usada apenas para comunicação de curta distância. É certamente confiável até certo ponto, pois tem um pulso de relógio sincronizado para torná-lo inteligente. Este protocolo é usado principalmente para se comunicar com o sensor ou outros dispositivos que precisam enviar informações a um mestre. É muito útil quando um microcontrolador precisa se comunicar com muitos outros módulos escravos usando, no mínimo, fios. Se você está procurando uma comunicação de longo alcance, você deve tentar o RS232 e se estiver procurando uma comunicação mais confiável, você deve tentar o protocolo SPI.
I2C com PIC16F877a usando Compilador XC8
Chega de introduções, vamos entrar e aprender como podemos usar um microcontrolador para realizar a comunicação I2C. Antes de começarmos, deixe claro que este tutorial fala apenas sobre I2C em PIC16F877a usando o compilador XC8, o processo será o mesmo para outros microcontroladores, mas pequenas alterações podem ser necessárias. Lembre-se também de que para microcontroladores avançados como a série PIC18F, o próprio compilador pode ter alguma biblioteca embutida para usar os recursos I2C, mas para PIC16F877A nada disso existe, então vamos construir um por conta própria. A biblioteca explicada aqui será fornecida como um arquivo de cabeçalho para download na parte inferior, que pode ser usado para que o PIC16F877A se comunique com outros dispositivos I2C.
Como sempre, o melhor lugar para começar qualquer coisa é nossa folha de dados. Procure detalhes sobre I2C na ficha técnica e verifique quais registros devem ser configurados. Não vou explicar em detalhes, pois a folha de dados já fez isso para você. Mais abaixo irei explicar as diferentes funções presentes no arquivo de cabeçalho e sua responsabilidade no programa.
void I2C_Initialize ()
A função de inicialização é usada para informar ao microcontrolador que vamos usar o protocolo I2C. Isso pode ser feito definindo os bits necessários no registro SSPCON e SSPCON2. O primeiro passo seria declarar os pinos IIC como pinos de entrada, aqui os pinos RC3 e RC4 devem ser usados para comunicação I2C, portanto, nós os declaramos como pinos de entrada. Em seguida, devemos definir o SSPCON e o SSPCON2, que é um registrador de controle MSSP. Estamos operando o PIC no modo mestre IIC com uma frequência de clock de FOSC / (4 * (SSPADD + 1)). Consulte os números das páginas da folha de dados mencionada nas linhas de comentários abaixo para entender por que esse registro específico é definido dessa forma.
Em seguida, temos que definir a frequência do relógio, a frequência do relógio para diferentes aplicativos pode variar, portanto, obtemos a escolha do usuário por meio da variável feq_k e a usamos em nossas fórmulas para definir o registro SSPADD.
void I2C_Initialize (const unsigned long feq_K) // Começar IIC como master { TRISC3 = 1; TRISC4 = 1; // Defina os pinos SDA e SCL como pinos de entrada SSPCON = 0b00101000; // pg84 / 234 SSPCON2 = 0b00000000; // pg85 / 234 SSPADD = (_XTAL_FREQ / (4 * feq_K * 100)) - 1; // Configurando a velocidade do relógio pg99 / 234 SSPSTAT = 0b00000000; // pág83 / 234 }
Vazio I2C_Hold ()
A próxima função importante é a função I2C_hold , que é usada para manter a execução do dispositivo até que a operação I2C atual seja concluída. Teríamos que verificar se as operações I2C devem ser realizadas antes de iniciar qualquer nova operação. Isso pode ser feito verificando o registro SSPSTAT e SSPCON2. O SSPSTAT contém as informações sobre o status do barramento I2C.
O programa pode parecer um pouco complicado, pois envolve um operador “e” e um “ou”. Quando você o quebra como
SSPSTAT e 0b00000100 SSPCON2 e 0b00011111
Isso significa que estamos nos certificando de que o 2º bit em SSPSTAT é zero e, da mesma forma, os bits de 0 a 4 são zero em SSPCON2. Então combinamos tudo isso para verificar se o resultado é zero. Se o resultado for zero, o programa prosseguirá se não ele vai segurar lá até que ele recebe de zero, uma vez que é usado em um enquanto loop.
void I2C_Hold () { enquanto ((SSPCON2 & 0b00011111) - (SSPSTAT & 0b00000100)); // verifique os registros para ter certeza de que o IIC não está em andamento }
Void I2C_Begin () e void I2C_End ()
Cada vez que escrever ou ler qualquer dado usando o barramento I2C , devemos começar e terminar a conexão I2C. Para iniciar uma comunicação I2C, temos que definir o bit SEN e, para encerrar a comunicação, temos que definir o bit de status PEN. Antes de alternar qualquer um desses bits, também devemos verificar se o barramento I2C está ocupado usando a função I2C_Hold conforme discutido acima.
void I2C_Begin () { I2C_Hold (); // Mantenha o programa I2C ocupado SEN = 1; // Comece IIC pg85 / 234 } void I2C_End () { I2C_Hold (); // Segure o programa se I2C está ocupado PEN = 1; // Fim da IIC pág 85/234 }
Nulo I2C_Write ()
A função de gravação é usada para enviar quaisquer dados do módulo mestre para o módulo salve. Esta função é normalmente usada após uma função inicial I2C e é seguida por uma função I2C End. Os dados que devem ser gravados no barramento IIC são transmitidos pelos dados variáveis. Esses dados são carregados no registrador de buffer SSPBUF para enviá-los pelo barramento I2C.
Normalmente, antes de escrever um dado, um endereço é escrito, portanto, você teria que usar a função de escrita duas vezes, uma para definir o endereço e a outra para enviar os dados reais.
void I2C_Write (dados não assinados) { I2C_Hold (); // Segure o programa se I2C está ocupado SSPBUF = dados; // pág82 / 234 }
curto sem sinal I2C_Read ()
A função final que precisamos conhecer é a função I2C_Read . Esta função é usada para ler os dados que estão atualmente no barramento I2C. É usado após solicitar a um escravo que escreva algum valor no barramento. O valor que for recebido estará no SSPBUF , podemos transferir esse valor para qualquer variável do nosso funcionamento.
Durante uma comunicação I2C, o escravo após enviar os dados solicitados pelo Mestre enviará um outro bit que é o bit de reconhecimento, este bit também deve ser verificado pelo mestre para garantir que a comunicação foi bem-sucedida. Após verificar o bit ACKDT para confirmação, ele deve ser habilitado configurando o bit ACKEN.
curto sem sinal I2C_Read (ack curto sem sinal) { recebimento curto sem sinal; I2C_Hold (); RCEN = 1; I2C_Hold (); entrada = SSPBUF; // obtém os dados salvos em SSPBUF I2C_Hold (); ACKDT = (ack)? 0: 1; // verifique se o bit de reconhecimento foi recebido ACKEN = 1; // página 85/234 retorno de entrada; }
Ou seja, essas funções devem ser suficientes para configurar uma comunicação I2C e escrever ou ler dados de um dispositivo. Observe também que há muitas outras funcionalidades que a comunicação I2C pode executar, mas por uma questão de simplicidade, não as discutiremos aqui. Você sempre pode consultar a ficha técnica para saber o funcionamento completo do
O código completo com arquivo de cabeçalho para comunicação PIC16F877A I2C pode ser baixado do link.
Programação usando os arquivos de cabeçalho I2C:
Agora que aprendemos como funciona uma comunicação I2C e como podemos usar o arquivo de cabeçalho criado para ela, vamos fazer um programa simples no qual usaremos o arquivo de cabeçalho e escreveremos alguns valores nas linhas I2C. Em seguida, simularemos este programa e verificaremos se esses valores estão sendo escritos no barramento.
Como sempre, o programa começa com a configuração dos bits de configuração e a definição da frequência do relógio para 20 MHz, conforme mostrado abaixo
#pragma config FOSC = HS // Bits de seleção do oscilador (oscilador HS) #pragma config WDTE = OFF // Bit de ativação do temporizador Watchdog (WDT desativado) #pragma config PWRTE = ON // Bit de ativação do temporizador de inicialização (PWRT ativado) # pragma config BOREN = LIGADO // Bit de habilitação de redefinição de Brown-out (BOR habilitado) #pragma config LVP = DESLIGADO // Bit de habilitação de programação serial de baixa tensão (fonte única) (RB3 é E / S digital, HV ligado MCLR deve ser usado para programação) #pragma config CPD = OFF // Bit de proteção de código de memória EEPROM de dados (proteção de código EEPROM de dados desativada) #pragma config WRT = OFF // Flash de memória de programa habilitar bits de habilitação (proteção de gravação desativada; toda a memória de programa pode ser escrito pelo controle EECON) #pragma config CP = OFF // Bit de proteção de código de memória de programa Flash (proteção de código desativada) #define _XTAL_FREQ 20000000
A próxima etapa seria adicionar o arquivo de cabeçalho que acabamos de discutir. O arquivo de cabeçalho é denominado PIC16F877a_I2C.h e pode ser baixado do link que discutimos acima. Certifique-se de que o arquivo de cabeçalho seja adicionado ao arquivo de cabeçalho de sua lista de projetos, sua estrutura de arquivos de projeto deve ser semelhante a esta
Depois de certificar-se de que o arquivo de cabeçalho foi adicionado ao seu arquivo de projeto, inclua o arquivo de cabeçalho no arquivo C principal
#incluir
Dentro da enquanto ciclo que começará a comunicação I2C alguns valores aleatórios de gravação para o bus I2C e depois Terminar a comunicação I2C. Os valores aleatórios que escolhi são D0, 88 e FF. Você pode inserir os valores que desejar. Mas lembre-se desses valores, pois iremos verificá-los em nossa simulação.
enquanto (1) { I2C_Begin (); I2C_Write (0xD0); I2C_Write (0x88); I2C_Write (0xFF); I2C_End (); __delay_ms (1000); }
O programa completo pode ser encontrado no final da página, você pode usar ou baixar o arquivo zip completo do programa aqui. Depois de obter o programa, compile-o e prepare-se para a simulação.
Simulação Proteus:
Proteus tem um bom instrumento chamado depurador I2C que pode ser usado para ler os dados em um barramento I2C, então vamos construir um circuito usando ele e verificar se os dados estão sendo escritos com sucesso. O diagrama completo do circuito é mostrado abaixo
Carregue o arquivo hex que foi gerado pelo nosso programa clicando duas vezes no Microcontrolador. Em seguida, simule o programa. Você notará uma janela pop-up que exibirá todas as informações sobre o barramento I2C. A janela do nosso programa é mostrada abaixo.
Se você observar atentamente os dados que estão sendo gravados, poderá notar que eles são os mesmos que escrevemos em nosso programa. Os valores são D0, 88 e FF. Os valores são gravados a cada 1 segundo, portanto, o tempo também é atualizado conforme mostrado abaixo. A seta azul indica que está escrito de mestre para escravo, caso contrário, estaria apontando na direção oposta. Uma visão mais detalhada dos dados enviados é mostrada abaixo.
Este é apenas um vislumbre do que o I2C pode fazer, ele também pode ler e gravar dados em vários dispositivos. Cobriremos mais sobre I2C em nossos próximos tutoriais, fazendo a interface de vários módulos que funcionam com o protocolo I2C.
Espero que você tenha entendido o projeto e aprendido algo útil com ele. Se você tiver alguma dúvida, poste-as na seção de comentários abaixo ou use os fóruns para obter ajuda técnica.
O código completo foi fornecido abaixo; você pode baixar arquivos de cabeçalho com todo o código daqui.