IOC – Interrupt On Change com PIC16F1827

ioc

Esse post está diretamente relacionado com um projeto pronto a ser apresentado no blog após a publicação dos demais recursos empregados nessa MCU. Especificamente neste, vamos falar de interrupções externas na mudança de estado de um pino qualquer que contenha o recurso IOC.

Nesse modelo de PIC o IOC está disponível em todos os pinos da PORTB.

Falei sobre interrupções em outros 3 posts, aqui, aqui e aqui.

Existem interrupções internas e externas e nesses posts anteriores falo apenas de interrupções internas. Com IOC podemos “sentir” uma interrupção externa em um pino da mesma forma que controlamos eventos em programação de janelas (por exemplo onmouseover e onmouseout em javascript, para detectar quando o ponteiro está sobre algo e quando não está mais), tendo os estados de LOW e HIGH para cada um dos pinos da porta B. Então podemos ter um counter que contabiliza o tempo de um botão pressionado e finaliza-se o counter quando o botão for liberado. Mas isso é só um exemplo, porque no projeto que deu origem a esse post será necessário mais de um pino e o motivo será detalhado mais adiante, com exemplo de polling em substituição à interrupção.

Existem várias vantagens em se utilizar interrupções, das quais citarei o wake up da MCU em outro post, onde colocaremos esse modelo de PIC pra dormir até que um evento ocorra, e assim economizaremos energia.

Outra vantagem é o fato de que as interrupções funcionam de forma similar a threads; enquanto a MCU monitora os eventos (sejam elas interrupções internas ou externas), o código principal pode estar rodando em um loop e ser interrompido quando um evento ocorrer – o evento pode então ser tratado por outra porção de código dentro da função de interrupções, uma função externa ao tratamento de interrupções ou simplesmente apontar uma outra flag controlada no código principal.

A MCU (MicroControler Unit) escolhida para esse projeto é o PIC16F1827 que trabalha a partir de 1.8v até 5.5v, e conta com uma série de interessantes recursos periféricos. Esse modelo conta também com um ótimo oscilador interno que vai de 31kHz a 32MHz.




Na primeira imagem do post está o diagrama de IOC, estando ele por trás do pino, como pode ser visto. Isso significa que o pino pode ser utilizado para interrupções independente de qualquer outra utilização para ele, ou seja, não se preocupe em configurar TRIS e PORT.

Se você está familiarizado com Arduino (onde também se pode tratar algumas interrupções de um modo simples), talvez falar de PIC te cause estranheza, mas é bastante divertido e te aproximará mais do hardware do que Arduino em seu modo de uso habitual. Acima citei a configuração da porta; enquanto em Arduino uma porta se configura assim:

Em PIC deve-se indicar a direção em uma variável e a utilização do pino em outra (LOW,HIGH):

Nesse modelo de PIC, RA1 é o primeiro pino à direita (pino 18). Então pode-se fazer uma associação dessa forma:

Assim utilizamos uma variável clara relacionada ao LOW e HIGH do pino. Alguns pinos possuem mais do que uma funcionalidade, mas não vou me extender para que isso não vire uma aula de PIC.

Configurando IOC

Sendo franco, passei várias horas sofrendo para entender como configurar IOC. Eu já havia utilizado a porta RB0 para receber interrupção externa e associado a um polling já resolveria meu problema, mas fiz questão de utilizar o recurso mais apropriado para este projeto. O problema foi que lí sobre as interrupções no datasheet a partir da página 81, porém a informação que eu precisava estava na página 131, o que só descobri no dia seguinte.

Ativando o Módulo

A melhor maneira de associar é lembrando que a partir do núcleo, chaves vão se conectando para ativar os recursos de hardware. A primeira chave a ser ligada saíndo do núcleo é o IOCIE. Esse bit deve ser configurado no registrador INTCON, portando dentro de main() (para quem usa MikroC) essa referencia é fundamental:
INTCON.IOCIE = 1

Configuração individual dos pinos

Para permitir interrupções individuais nos pinos da porta B, primeiramente deve-se setar os bits das portas que receberão interação. Para pull up utiliza-se os bits IOCBPx do registrador IOCBP e os bits de IOCBNx do registrador IOCBN para identificar a queda, podendo-se utilizar os dois simultaneamente:
IOCBP.IOCBP4 = 1 ativará IOC na porta RB4, lembrando que não há necessidade de configurar o pino para nada mais.

Interrupt Flag

Quando um evento ocorre, pelo menos 2 bits são levantados no registrador INTCON:

INTCON.INTF – Interruption Flag. A partir de então deve-se varrer os bits relacionados aos pinos, caso queira identificar o pino de origem da interrupção:
INTCON.IOCBF4 é o bit da RB4. Se esse bit estiver em 1, então foi quem originou a interrupção.

Limpando as interrupções

A remoção das interrupções fica a encargo do programador, ou seja, existe uma rotina importante para manipulação de interrupções.

Lembre-se sempre de que o bit que é utilizado para identificar o pino que recebeu interrupção deve ser limpo para que possa ser reutilizado. Para tal, simplesmente volte-o para 0:
INTCON.IOCBF4 = 0

Para não fazer polling desnecessariamente atrás de algum bit com interrupção, o melhor é aguardar que INTCON.INTF tenha sido levantado. Logo, esse é mais um bit que deve ser limpo:
INTCON.INTF = 0

Tratando interrupções



Para não tirá-lo da leitura, vou revisar um pouco do que expliquei em outro post sobre interrupções.

Partindo do core, a primeira coisa que queremos é que as interrupções sejam percebidas, então levantamos a flag INTE (INTerrupt Enabled).

Deve-se então levantar a chave geral para começar a receber interrupções:
GIE (General Interrupt Enabled)

Interrupções periféricas:
PEIE (Peripheral Interrupts Enabled)

E como estamos tratando interrupções do IOC, devemos levantar esse bit:
IOCIE (Interrupt On Change Interrupt Enabled)

Quando uma interrupção acontece, a primeira coisa a fazer é desligar a chave geral, porque outras interrupções podem acontecer e só dá pra tratar uma interrupção por vez; se a chave geral permanecer ativa, então qualquer execução será interrompida quando outra interrupção chegar. A rotina para isso é simples:
1- desligar a chave geral para não receber novas interrupções
2- tratar o evento
3- limpar os bits INTF e do pino
4- levantar a chave geral.

Circuito para teste
ioc_bb

O teste foi feito com esse circuito acima. Tive uma rotina dura até perceber que anomalias que estavam acontecendo era pela falta de um filtro. Até então não estava utilizando capacitor em VDD (VDD para entrada e VCC para ground) e só descobri os ruídos um dia após iniciar a busca pelo funcionamento da interrupção.

 

 

Código para o teste

O código sequer está limpo, mas nem me dei ao trabalho porque até o último post apresentarei o código final empregado no projeto, então “entre mas não repare a bagunça”.

Pra finalizar essa etapa, um video de alguns segundos mostrando algumas interrupções sendo geradas.

Eu havia informado possíveis mudanças no post. Existem mudanças importantes a considerar, mas invés de mudar esse post, leia esse novo post, contendo o código limpinho e um video onde falo 13 vezes a palavra ‘interrupção/interrupções’, mas mostro como funciona os 2 estados da IOC.

O projeto é um contabilizador de moedas, ou ‘porquinho eletrônico’, espero que acompanhem até o final!

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!

Comments

comments

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.

Deixe uma resposta