Linux

Alias, RS485, interrupções com PIC 16F877A

interrupções com PIC
interrupções com PIC

Como prometido no post sobre rs485 com Arduino, agora vamos ver como fazer a comunicação bidirecional, completando assim o post sobre o assunto; mas além disso vamos entrar em detalhes importantes sobre interrupções com PIC (introduzido nesse post). Veremos como controlar uma interrupção adequadamente, achar as flags correspondentes e buscar as respostas sobre um determinado PIC no datasheet. Para finalizar, esse post usará como base o PIC16F877A para os exemplos. Iniciaremos pelas ferramentas.


PICmicro Database
Essa ferramenta é essencial para quem trabalha com MCU PIC. Com ela você poderá ver todas as características de uma determinada micro-controladora, filtrar por recursos ou simplesmente descontrair vendo os diversos sabores de PIC que existem. Ela trabalha offline e está disponível para Android no Google Play, no link acima.

ElectroDroid
Essa ferramenta é excepcional; possui diversas calculadoras para calculos específicos de projetos eletrônicos, além de plugins que dão mais poder à ferramenta. Entre os plugins, há um simulador de circuito, mas não deixe de visitar o link do Google Play para confirmar.

interrupções com PIC
interrupções com PIC – PIC16F877A

Como escolher o PIC

Existem muitos fatores que influenciam na escolha da MCU e, dependendo do tamanho do projeto, centavos podem ser representativos em escala de produção. Tamanho de circuito, número de trilhas, recursos periféricos, saídas PWM, comunicação USB e outros recursos variam de modelo para modelo, então o primeiro passo é amadurecer a idéia do objetivo, posteriormente escolher a MCU. Um detalhe que deve ser levado em consideração é a intensidade de processamento e complexidade do código e da operação. A quantidade dos diversos tipos de memória de cada MCU varia drasticamente e é necessário ter esse recurso de sobra ou muito bem planejado para não ter grandes surpresas durante uma fase mais avançada do desenvolvimento.

Especificamente esse post é baseado no P16F877A porque é a MCU padrão dos exemplos da IDE MikroC e como estou me adaptando à board de desenvolvimento (EasyPIC), preferi utilizar uma MCU que minimizasse possíveis dúvidas.

Comunicação RS485

A comunicação com o CI RS485 é transparente, de forma que a comunicação se dá pela UART, bastando escrever dados seriais. O ‘pulo do gato’ está no chaveamento dos pinos DE e RE do MAX485 e a forma de ligá-los é bastante simples; faz-se um jumping entre eles. O que definirá se os dados sairão ou entrarão é mais do que o TX e RX da UART, fazendo-se fundamental o chaveamento de controle de fluxo, descrito e detalhado no código adiante.

A comunicação RS485 possui duas partes fundamentais – o Master e o Slave. Isto é porque não podem ambos iniciar uma comunicação no barramento, pois não haveria como controlar a leitura e escrita sincronizada. Então, essa rede possui 1 Master e N Slaves.

A tarefa do Master é ser o controlador do barramento, que pode conter até 32 dispositivos em uma distância máxima de 1200 metros! Ou seja, toda a conversa é iniciada pelo Master e todos os Slaves ficam ‘escutando’ o barramento esperando que haja alguma tarefa para si.

A mensagem enviada pelo master é disparada como um broadcast no barramento; todos os dispositivos escutarão as mensagens, mas a resposta deverá partir exclusivamente do dispositivo a qual a mensagem pertença. Isso é possível graças a um identificador, normalmente colocado ao inicio da mensagem. Quando o Slave responde, novamente a mensagem trafega como um broadcast, porém é imediatamente descartado após a leitura do primeiro byte, que identifica a mensagem como uma resposta. Esses detalhes serão descritos no decorrer do código, mais adiante.

Indo mais a fundo, fica claro que o chaveamento do CI RS485 nos slaves está em um modo e no Master está de outro modo. Assim o é. Então, há duas maneiras para o Slave aguardar por uma mensagem.

Polling

Esse é o modo mais simples; em um loop infinito com um delay, o programa tentará validar dados no buffer na UART. Encontrando dados, passa a executar a tarefa de tratamento da mensagem de entrada e saída. Apesar de ser de fácil implementação, possui alguns contras, entre os quais, o consumo de energia certamente será maior, pois a MCU executará uma quantidade X de instruções a cada ciclo. Também nesse modo, é possível que haja pequenos delays na recepção e resposta pois a MCU pode estar executando outras tarefas que precedam a verificação de dados seriais.

Interrupções com PIC

A maneira mais clean de lidar com esse tipo de tarefa é com a utilização de interrupções. Ao meu ver, há uma semelhança muito grande com threads em programação desktop. Explico mais detalhadamente.

Quando habilitamos um determinado recurso na MCU, quando esse recurso é utilizado ele gera uma interrupção; um bit é marcado em reação ao evento. As interrupções podem ser desabilitadas ou pode-se habilitar de uma a todas, mas para isso é necessário basicamente ter o datasheet da MCU à mão. A grosso modo, a interrupção é como se fosse uma thread, que reage ao evento assincronamente. Os detalhes serão vistos no código, não se preocupe.

interrupções com PIC
interrupções com PIC – interrupções

Ainda mais sobre as interrupções, elas são controladas por estágio; um conjunto de chaves que se ligam. O desenho do início deste post descreve com clareza uma interrupção; é como o chaveamento de um interruptor de luz. Para conhecer as chaves, deve-se procurar no datasheet por Interrupts. No datasheet do PIC16F877A, a tabela de interrupções é a seguinte:

Os circulos são as chaves necessárias para ligar as interrupções até o RCIF, marcado com um quadrado. Então, para saber quais chaves ligar, siga o esquema do datasheet e anote as chaves necessárias.

A vantagem de utilizar interrupção é que o processador não precisará fazer nada, ficará dormindo até que seja ‘despertado’ por um evento – quando o master disparar uma mensagem no barramento e essa mensagem chegar ao Slave, um bit é levantado e a implementação da função de interrupções começa a executar seu código, normalmente analisando qual interrupção aconteceu.

Falando diretamente da família F16, o conjunto de chaves necessários para habilitar a interrupção na recepção serial é inicialmente o GIE, ou Global Interrupt Enable. O GIE é a chave geral à qual todos os demais conjuntos de chaves se ligam, como se pode ver na tabela anterior. Se esta chave estiver desligada, nenhuma interrupção específica será utilizada.

Ligando o GIE, o próximo a habilitar é o PEIE ou, Peripheral Interrupt Enable. Essa chave controla as interrupções periféricas. Enfim, para habilitar a interrupção no RX do UART, deve-se habilitar o RCIE. E como saber essas relações sem ter que decorar nada? – resposta simples! RTFM (Read The Fine Manual).

No exemplo de interrupção utilizado nesse post, deve ser habilitada a interrupção de recepção serial, descrito no datasheet como RCIF (Receive Interrupt Flag). Um Ctrl+F no datasheet e encontrei o registrador responsável por essa flag, o PIR1:

interrupções com PIC
interrupções com PIC

Então para habilitá-lo há diversas maneiras, mas preferi utilizar a IDE MikroC, segurando a tecla Ctrl e clicando sobre uma variável qualquer do PIC padrão (escreva por exemplo, PORTC), abre-se a página de constantes, que foi o que utilizei para definir as minhas variáveis da maneira mais clara no código adiante.

Controle da interrupção

Quando uma interrupção acontece, a primeira tarefa é desligar a chave geral; não é prudente manipular interrupções com interrupções acontencendo a todo o tempo. Depois, analisa-se qual interrupção aconteceu e executa-se o bloco de códigos designado para tratar aquele tipo de evento. Ao termino, o bit da interrupção deve ser limpo e posteriormente a chave geral deve ser religada.

No decorrer do código pode ser bastante cansativo lembrar o nome de todos o bits de cabeça. Criar uma variável para cada também não é uma boa providência, pois isso consome preciosos recursos. Então para solucionar esse problema, utiliza-se o alias. Assim posso chamar o bit PIR1.RCIE de INTERRUPT_RX, o que parece bem auto-explicativo.

Agora vamos ver detalhes de todos os recursos citados até esse momento.

Código de exemplo RS485

Esse é o código do Slave:

interrupções com PIC
interrupções com PIC

As conexões físicas devem ser feitas assim no MAX485:

Laranja e Marrom são TX e RX ligados à MCU. O branco é controle de fluxo. A ligação com pilha AA foi apenas para saber onde é ground e onde é VCC, alimentados diretamente pelo PIC. No exemplo da IDE utiliza-se os pinos RC6 e RC7 que são TX e RX e o pino de controle RC2, porém na board de desenvolvimento o pino utilizado é RC0.

Os resistores das extremidades são 56R, os outros dois são 4K7.

No video, estou rodando direto da placa de desenvolvimento de uma empresa em que trabalhei, conversando diretamente com um terminal (GtkTerm) utilizando um conversor RS232 para RS485, também da lightcomm:

Nem todos os passos de um um produto que estamos desenvolvendo podem ser exibidos, mas quando o produto estiver disponível para o mercado, farei uma avaliação e indicarei onde comprar, pois com certeza será útil a muitas pessoas.

Se gostou, não deixe de compartilhar; dê seu like no video e inscreva-se no nosso canal Do bit Ao Byte Brasil no YouTube.

Prefere seguir-nos pelo facebook? Basta curtir aqui.

Prefere twitter? @DobitAoByte.

Próximo post a caminho!


9 comments
  1. Jonathan Gonzaga

    Excelente explicação, meus parabéns. Gostaria de te fazer algumas perguntas:
    1- No exemplo você desabilita todas as interrupções apenas para poder tratar a atual, isso é mesmo necessário? Meu projeto por exemplo utiliza interrupção do TImer 0 para varredura de botões e interrupção da Uart para recepção serial, e não vi haver conflito com isso, pelo menos na simulação.
    2- Acha que é possível implementar uma interrupção para a comunicação Uart RS 232 e outra para RS 485? Digo isso pois aparentemente a flag usada para sinalização da interrupção serial é sempre a mesma, RCIF, correto? Estou utilizando um PIC 18F4550 e o Mikro C.

  2. Suhanko

    Olá, Jonathan. Obrigado!
    Tem vários outros tutoriais com interrupção no site, vale dar uma pesquisada.

    Essa prática de desabilitar a chave geral das interrupções é necessária porque se você tiver habilitado as interrupções periféricas, elas podem ocorrer a qualquer momento (nos modelos compatíveis com esse tutorial)

    Se você estiver tratando uma interrrupção e outra ocorrer, seu tratamento será interrompido para atender o novo evento.

    Esse modelo específico de PIC tem interrupções de alta prioridade e de baixa prioridade. As interrupções de alta prioridade interferirão em qualquer interrupção de baixa (interrupções na página 97 do datasheet: http://ww1.microchip.com/downloads/en/devicedoc/39632c.pdf).

    Nunca programei nesse modelo, mas batendo o olho no datasheet vi que só de interrupções, ele tem 10 registradores!

    O datasheet também recomenda o uso do MPLAB devido à complexidade, mas eu não sei se é tendenciosa a recomendação, por isso acho mesmo que precisaria testar. Eu tenho alguns desse aqui, só que entre tantos que tenho, é um dos que ainda não sairam da caixa (tenho muitos modelos porque gosto de experimentar quando estou com tempo livre).

    Eu até estava citando aqui alguma coisa das interrupções desse modelo, mas você vai mesmo ter que ler o datasheet porque tem diferenças enormes no modo de tratamento das interrupções nesse PIC parrudão.

    Abraços!

  3. Jonathan Gonzaga

    Opa beleza? Valeu pela resposta rápida, não esperava hehe.
    Bom, eu usei o datasheet pra configurar e ambas funcionam. A do Timer 0 por exemplo varre os botões a cada 13ms mais ou menos, enquanto isso no loop eu leio os dados de um RTC Ds 1307 e escrevo num Lcd I2C. Na prática há uma certa demora pra atualizar o Lcd, mas creio que seja pelo fato de haver dois dispositivos no barramento trabalhando “simultaneamente”. Quando uso Bluetooth por exemplo pra acionar as cargas funciona normalmente. Eu dei uma lida no help do MikroC e ele mostra que para setar multiplas interrupções pode se testar as flags dentro da mesma função, porém um if pra cada uma. Fiz isso e deu certo. Já com relação as prioridades coloquei alta para o Timer e baixa para a Uart. Bom não sei se fiz algo errado, mas simulação e prática estão ok Sou novo em programação, estou aprendendo para o meu TCC.
    Obrigado pela atenção.
    Abraço.

Comments are closed.

%d blogueiros gostam disto: