Tema 4
Tema 4
Tema 4
Descrição geral e acesso aos periféricos externos mais importantes dos microcontroladores,
Programação para realização de sistemas completos de monitoração e controle com a
plataforma Arduino e com microcontroladores da família PIC.
PROPÓSITO
Acionar e coletar dados de dispositivos externos aos microcontroladores, complementares aos
sistemas embarcados nas aplicações de monitoração e controle, é importante para a formação
do projetista desses sistemas que programa as interfaces de entrada e saída para integrar as
funções não atendidas pelos periféricos internos, mas que são essenciais no desenvolvimento
do projeto.
PREPARAÇÃO
Antes de iniciar o conteúdo deste tema, tenha instalado o compilador CCS, o ambiente MPLAB
e o simulador PICSimLab, além de fazer um cadastro no simulador Tinkercad.
OBJETIVOS
MÓDULO 1
MÓDULO 2
MÓDULO 3
MÓDULO 4
INTRODUÇÃO
Sempre que uma determinada aplicação precisar de algum periférico diferente dos fornecidos
dentro do microcontrolador, eles podem ser adicionados posteriormente. Esses periféricos são
chamados de periféricos externos, pois, evidentemente, são externos ao chip do
microcontrolador, diferentemente dos que já estão no chip, que são chamados de periféricos
internos.
Dessa forma, quando não é possível encontrar um microcontrolador que tenha todos os
periféricos necessários internamente, pode-se comprar o periférico separadamente, soldá-lo na
mesma placa de circuito impresso e fazê-lo se comunicar com o microcontrolador.
Neste conteúdo, interagiremos com os periféricos externos mais comuns, que são utilizados
para estabelecer interfaces com os usuários e para criar um sistema completo de controle.
MÓDULO 1
TRANSMISSÃO DE DADOS
A transmissão de dados é um modo de transmitir dados digitais ou analógicos em um meio de
comunicação para um ou mais dispositivos.
PONTO A PONTO
PONTO A MULTIPONTO
MULTIPONTO A MULTIPONTO
Assim, ela atua quando um dispositivo visa transmitir um conjunto de informações para um ou
vários dispositivos destinatários.
Os dados digitais vêm do dispositivo de origem na forma de fluxos de bits digitais. Esses fluxos
de dados são então colocados em um meio de comunicação, que pode ser paralelo ou serial,
permitindo, portanto, que eles sejam entregues para o dispositivo de destino.
TRANSMISSÃO PARALELA
Os dados, nesse caso, são trocados por meio de um modo de transferência paralela. Esse
modo de operação resulta em atrasos mínimos na transferência de cada palavra, pois todos os
bits de dados são transmitidos simultaneamente, sendo que, para transmitir n bits, são
utilizados n fios ou linhas. Dessa forma, cada bit tem sua própria linha e todos os n bits de um
grupo são transmitidos em um pulso de clock de um dispositivo para outro.
Uma desvantagem desse tipo de transmissão, no entanto, decorre do fato de mais linhas
paralelas implicarem em chips maiores, com mais portas, ocupando mais espaço. Em função
disso, o uso de periféricos externos com portas paralelas para comunicação tem se tornado
menos usual. Em geral, somente alguns conversores analógicos-digitais de alta velocidade têm
mantido o uso de portas paralelas. Os microcontroladores usam as suas portas de entrada e
saída digitais, normalmente duas ou três de 8 bits cada, para se comunicarem com periféricos
externos de interface paralela.
TRANSMISSÃO SERIAL
A transmissão serial possui a vantagem principal de utilizar poucos fios ou linhas para a
transmissão. Os dados, neste caso, são transmitidos por meio de um único bit por vez, usando
um intervalo de tempo fixo para cada bit. Assim, todos os bits de dados são transmitidos em
uma única linha de maneira serial, com apenas um único bit enviado com cada pulso de clock.
Então, para um byte (8 bits), como 10011010, ser enviado da origem para o destino, ele pode
ser transmitido a partir do bit menos significativo (0), seguido pelos bits seguintes até o mais
significativo (1), tudo através de uma única linha de comunicação.
Transmissão assíncrona
A transmissão assíncrona envia apenas um caractere (byte) por vez. A sincronização de bits
entre os dois dispositivos é possível usando o bit de início e o bit de parada. O primeiro indica o
início dos dados, isto é, alerta o receptor para a chegada de um novo grupo de bits. Portanto,
um bit de início, geralmente 0, deve ser adicionado no começo de cada byte. Já o bit de parada
indica o fim dos dados, ou seja, permite que o receptor saiba que o byte está concluído. O bit
de parada é, geralmente, de valor 1. A adição de bits ao início e ao final aumenta o número de
bits de dados. Logo, mais largura de banda é consumida na transmissão assíncrona.
Transmissão síncrona
A transmissão síncrona não usa bits de início e parada. Nesse método, o fluxo de bits pode ser
combinado em quadros maiores que podem conter vários bytes, ou seja, não há intervalo entre
os vários bytes no fluxo de dados. Na ausência de bits de início e parada, a sincronização de
bits é estabelecida entre o emissor e o receptor por um bit de temporização, um pino adicional
de clock que sincroniza a transmissão de cada bit. Logo, para receber os dados sem erros, o
receptor e o emissor operam na mesma frequência de clock. Como vários bytes podem ser
colocados na transmissão sem qualquer espaço entre eles, é responsabilidade do receptor
separar o fluxo de bits em bytes para reconstruir as informações originais.
Antes do I2C as comunicações chip a chip utilizavam diversos fios em uma interface paralela,
muitas vezes exigindo chips periféricos com mais de 20 pinos usados para endereçamento,
seleção, controle e transferência de dados entre os chips.
O I2C realiza comunicações chip a chip usando apenas dois fios em uma interface serial,
permitindo que eles se comuniquem com menos pinos.
Os dois fios usados no I2C são chamados de clock (SCL) e dados (SDA). Esses dois fios
carregam endereçamento, seleção, controle e dados, um bit de cada vez.
O fio SDA carrega os dados, enquanto o fio SCL sincroniza o emissor e o receptor durante a
transferência; portanto, o I2C é de transmissão síncrona.
COMENTÁRIO
Chips que usam o barramento I2C podem realizar a mesma função que suas contrapartes de
interface paralela maiores, mas com muito menos pinos. Isso reduz muito o tamanho e o custo
desses chips.
Os dispositivos I2C são classificados como mestre (master) ou escravo (slave), sendo o
conjunto de dispositivos classificados como barramento I2C. Um dispositivo que inicia uma
mensagem é chamado de mestre, enquanto outro que responde a uma mensagem é chamado
de escravo.
Um dispositivo pode ser somente mestre, somente escravo ou alternar entre mestre e escravo,
conforme a necessidade do aplicativo.
O barramento I2C, como mostrado na Figura 1, pode conectar muitos chips, como conversores
(ADC e DAC), microcontroladores (µC) e outros em apenas dois fios. Cada dispositivo escravo
I2C tem seu próprio endereço exclusivo.
O I2C também oferece suporte a vários dispositivos mestre (master) no barramento ao mesmo
tempo, um recurso poderoso que otimiza o uso deste último, reduzindo ao mínimo o tráfego de
mensagens.
Para oferecer suporte a vários mestres, o I2C deve resolver conflitos de sinal quando dois ou
mais dispositivos mestres tentarem falar no barramento ao mesmo tempo.
Aplicações iniciais para I2C incluíam controle de volume e contraste em rádios e televisores.
O I2C se expandiu para incluir uma ampla gama de aplicativos.
Atualmente, o I2C pode ser encontrado em uma variedade de sistemas computacionais,
industriais, de entretenimento, médicos e militares, com potencial de crescimento quase
ilimitado.
Fonte: EnsineMe.
Figura 2 – Montagem para comunicação I2C entre duas placas Arduino Uno.
Fonte: EnsineMe.
Na placa Arduino da esquerda, na Figura 2, um botão (push button) é ligado entre os pinos 12
e GND. Na placa da direita, um LED é montado entre os pinos 13 e GND. No programa, ao se
pressionar o botão na placa mestre (Arduino Uno da esquerda), o LED acende na placa
escravo (Arduino Uno da direita). Os códigos para a placa mestre e para a placa escravo são
mostrados mais adiante.
Observe bem o código para verificar como a transmissão é configurada com o escravo
definindo seu endereço como 5 no setup(). Quando o botão é pressionado, a placa da
esquerda emite um caractere H. Caso contrário, ela emite um caractere L. Assim, quando
recebe o caractere, a placa escravo apaga ou acende o LED em função do caractere recebido.
CÓDIGO PARA O I2C MESTRE
void setup() {
Wire.begin();
pinMode(12, INPUT_PULLUP);
void loop() {
// Endereço do Escravo é 5
if (digitalRead(12) == LOW) {
Wire.beginTransmission(5);
Wire.write('H');
Wire.endTransmission();
delay(100);
} else {
Wire.beginTransmission(5);
Wire.write('L');
Wire.endTransmission();
delay(100);
void setup() {
// Endereço é 5
Wire.begin(5);
Wire.onReceive(react);
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
void loop() {
void react(int n) {
while (Wire.available()) {
char c = Wire.read();
if (c=='H') {
digitalWrite(13,HIGH);
} else {
digitalWrite(13,LOW);
}
O compilador CCS oferece suporte para o I2C baseado em hardware e um dispositivo I2C
mestre baseado em software.
Atenção! Para visualização completa da tabela utilize a rolagem horizontal
PROTOCOLO UART
UART (Universal Asynchronous Transmitter Receiver – Transmissor Receptor Universal
Assíncrono), é o protocolo mais comum usado para comunicação serial full duplex, ou seja,
onde o dispositivo pode transmitir e receber dados ao mesmo tempo.
Como seu próprio nome sugere, ele foi projetado para realizar comunicação assíncrona,
enviando e recebendo dados de um sistema para outro. Assim, o transmissor e o receptor
usam os parâmetros bit de início, bit de parada e uma temporização para sincronizar uns com
os outros.
Dessa forma, como o protocolo não tem sinal de sincronismo, um parâmetro muito importante é
o Baud Rate, que especifica a velocidade de recepção e envio, sendo que os dois dispositivos
devem utilizar a mesma taxa.
As taxas de comunicação assíncrona mais comumente usadas são 9600, 33600 e 115200 bps.
UART E RS232
PROTOCOLO
Os antigos computadores possuíam portas que seguiam o padrão RS232 para aceitar os
dados, que empregava um conector de nove pinos (DB9).
O protocolo UART gera dados de acordo com a lógica TTL, nos quais a lógica 1 é aceita entre
2,4 V a 5 V e lógica 0 entre 0 a 0,4 V.
Portanto, os dados do protocolo UART não podem ser transferidos diretamente na porta RS232
do computador.
Um driver de linha, ou conversor chamado MAX232, é usado para converter níveis TTL em
níveis RS232. Para se comunicar com computadores modernos por UART pode-se usar
conversores conhecidos como USB/Serial UART. Estes criam uma COM virtual que é usada
assim como os computadores antigos usavam a RS232.
Da mesma forma, temos outros padrões que são perfeitamente compatíveis com o protocolo
UART, como os padrões RS485 e RS422, muito usados em ambientes industriais.
No compilador CCS, temos funções para enviar dados pela porta serial. O código a seguir pode
ser usado para acessar a porta serial na placa 4 (PICGenios) do simulador PICSimLab.
Verifique que o programa envia mensagens e depois fica aguardando caracteres pela porta
serial. Quando o programa recebe um caractere, ele o devolve.
char i, j, textsize;
void main(){
setup_oscillator(OSC_8MHZ);
delay_ms(5000);
putc(13);
putc(message[j]);
delay_ms(100);
putc(13);
putc(10);
while(TRUE){
i = getc(); // Lê da UART
A instrução #use rs232 (UART1, baud = 9600) é usada para configurar o protocolo UART.
printf putc
if(kbhit()) getc()
PRINTF
IF(KBHIT())
GETC()
Lê o caractere.
SERIAL.PRINT()
Esta função imprime dados na porta serial como texto ASCII.
Esse comando pode ter várias formas. Os números são impressos usando um caractere ASCII
para cada dígito. Números de ponto flutuante são impressos de maneira similar a dígitos ASCII,
com duas casas decimais. Bytes são enviados como um único caractere. Caracteres e
sequências de caracteres são enviados como estão.
EXEMPLO
Os valores permitidos são: BIN (binário ou base 2), OCT (octal ou base 8), DEC (decimal ou
base 10), HEX (hexadecimal ou base 16).
Para números de ponto flutuante, esse parâmetro especifica o número de casas decimais a
serem usadas.
EXEMPLO
SERIAL.AVAILABLE()
Esta função retorna o número de caracteres (ou seja, bytes de dados) que chegaram ao buffer
serial e estão prontos para serem lidos.
SERIAL.READ()
Esta função retorna o primeiro (mais antigo) caractere no buffer e remove esse byte de dados
desse local. Portanto, quando todos os bytes de dados são lidos e nenhum novo dado serial
chega, o buffer fica vazio e Serial.available() retornará 0.
READSTRINGUNTIL()
Esta função permite combinar todos os caracteres da mensagem enviada em uma única string
do Arduino.
Nesse caso, estamos aguardando o caractere \n, que é o caractere de nova linha que vem no
final de uma string enviada no monitor serial do Arduino.
O exemplo a seguir mostra o controle de acender, apagar ou piscar um LED no pino 9 da placa
Arduino Uno. Ele pode ser simulado no Tinkercad.
int LED = 9;
int i;
int n;
char c;
void setup(){
pinMode(LED , OUTPUT);
Serial.begin(9600);
void loop() {
while (!Serial.available()){
delay(50);
c = Serial.read();
switch(c){
case '0':
digitalWrite(LED , LOW);
break;
case '1':
digitalWrite(LED , HIGH);
break;
case '2':
while (!Serial.available()){
delay(50);
c = Serial.read();
n = c-48;
n = constrain(n, 1, 9);
pisca(LED, n);
break;
default:
Serial.print("Entrada errada\n");
break;
int r = 0;
while(r< t){
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(500);
r+=1;
PROTOCOLO SPI
A SPI (Serial Peripheral Interface ou Interface Serial Periférica) é um protocolo comumente
usado para enviar dados entre microcontroladores e periféricos externos pequenos, tais como
registradores de deslocamento, sensores e cartões SD.
O barramento SPI usa linhas de clock e dados separadas com uma linha de seleção para
escolher o dispositivo com o qual se deseja conversar, conforme apresentado na Figura 3.
Para iniciar a comunicação SPI, o mestre (master) deve enviar o sinal do clock e selecionar o
escravo (slave) ativando o sinal CS.
COMENTÁRIO
Normalmente, CS é um sinal ativo em nível baixo. Logo, o mestre deve enviar um valor lógico 0
nesse pino para selecionar o escravo. O SPI é uma interface full-duplex; tanto o mestre como o
escravo podem enviar dados ao mesmo tempo através das linhas MOSI e MISO,
respectivamente.
A borda do clock serial sincroniza o deslocamento e a amostragem dos dados. A interface SPI
fornece ao usuário flexibilidade para selecionar a borda de subida ou descida do clock para
amostrar e/ou deslocar os dados.
Muitos microcontroladores têm periféricos SPI integrados que lidam com todos os detalhes de
envio e recebimento de dados e podem fazê-lo em velocidades muito altas. O protocolo SPI é
simples, existindo bibliotecas em compiladores para Arduino e PIC que facilitam a utilização
dos dispositivos.
SIMULANDO A TRANSMISSÃO DE DADOS
VERIFICANDO O APRENDIZADO
D) I e II estão corretas.
WIRE.BEGINTRANSMISSION(3);
WIRE.WRITE('A');
WIRE.ENDTRANSMISSION();
GABARITO
1. O que podemos dizer sobre a transmissão serial de dados?
II – Só pode ser síncrona, pois cada bit é enviado em cada pulso do clock (relógio).
A transmissão serial de dados tende a ser mais lenta do que a transmissão paralela, pois os
bits são enviados um por vez, ao contrário da transmissão paralela. No entanto, ela pode ser
assíncrona, e para transmitir n bits somente uma linha de dados é necessária, linha esta que
transmite os dados de forma serial.
Wire.beginTransmission(3);
Wire.write('A');
Wire.endTransmission();
MÓDULO 2
Em outras palavras, um sistema embarcado para controle deve ser capaz de ler dados de
sensores e enviar dados para atuadores.
Transdutor é o termo coletivo utilizado para os sensores, que podem ser acionados para
detectar uma ampla gama de diferentes formas de energia; e os atuadores, que podem ser
usados para alternar tensões ou correntes, “atuando” em um sistema.
A entrada específica pode ser luz, calor, movimento, umidade, pressão ou vários outros de um
grande número de fenômenos ambientais.
A saída é um sinal elétrico que, quando recebido por um microcontrolador, pode ser
processado e convertido para exibição legível no local do sensor ou transmitido
eletronicamente por uma rede para leitura ou processamento posterior.
O sinal elétrico fornecido pelo sensor também pode ser usado pelo microcontrolador para
estabelecer um controle. Em função do processamento do sinal, o código embarcado pode
enviar um sinal a um atuador de um sistema e este realizar um movimento, ou seja, ele recebe
um sinal elétrico e o combina com uma fonte de energia para criar movimento físico.
pneumático
hidráulico
elétrico
térmico
magnético
EXEMPLO
Os atuadores estão presentes em quase todas as máquinas ao nosso redor, desde sistemas
de controle de acesso eletrônico simples, como o vibrador dos telefones celulares, até
eletrodomésticos, veículos, dispositivos industriais e robôs. Exemplos comuns de atuadores
incluem motores elétricos, motores de passo, macacos hidráulicos, dentre outros.
Fonte: Shutterstock.com
Fonte: Shutterstock.com
TIPOS DE SENSORES QUANTO AO SINAL
GERADO
Sensores analógicos estão presentes nos mais diversos equipamentos e sistemas. Eles
produzem um sinal de saída contínuo ou uma tensão que é geralmente proporcional à
quantidade sendo medida.
EXEMPLO
Os sensores digitais produzem uma saída discreta representando um número ou dígito binário,
como um nível lógico “0” ou um nível lógico “1”. Nesse sentido, um simples botão (push button)
de uma placa pode ser considerado um sensor digital, indicando quando o usuário o
pressionou.
Eles são pequenos, baratos, de baixa potência, fáceis de usar e não se desgastam. Por essa
razão, são comumente encontrados em aparelhos instalados em residências ou empresas.
Os PIRs são basicamente feitos de um sensor piroelétrico que pode detectar níveis de radiação
infravermelha (RI). Todos os objetos emitem alguma radiação de baixo nível, e quanto mais
quente algo está, mais radiação é emitida.
O sensor em um detector de movimento é dividido em duas metades. A razão para isso é que
estamos procurando detectar o movimento (mudança) e não os níveis médios de RI.
As duas metades estão ligadas de modo que se anulam mutuamente. Se uma metade
perceber mais ou menos radiação IR do que a outra, situação esta que é típica de movimento
na área de detecção (detecting area), a saída será alta ou baixa.
A montagem da Figura 5, feita no simulador Tinkercad, mostra um exemplo de teste com o uso
de sensores digitais com microcontroladores. Nesta, um sensor PIR está ligado a uma placa
Arduino Uno.
Fonte: EnsineMe.
Figura 5 – Montagem de sensor PIR com Arduino.
Fonte: EnsineMe.
Os fios vermelho e preto ligados ao sensor PIR são a alimentação do sensor, retirada do
Arduino.
O fio amarelo é a saída do sensor PIR, que informa nível lógico alto quando percebe
movimento.
void setup() {
void loop() {
Quando usamos sensores analógicos precisamos medir, em geral, uma tensão que é
proporcional à quantidade sendo medida. Esse é o caso dos sensores de temperatura.
EXEMPLO
O LM35 ou o TMP36 são sensores de temperatura linear analógicos. Isso significa que a
tensão de saída é proporcional à temperatura.
Fonte: EnsineMe.
Figura 6 – Montagem de sensor de temperatura com Arduino.
Fonte: EnsineMe.
O código a seguir mostra a aquisição dos dados do sensor e a conversão para temperatura,
com envio do valor em graus Celsius para a porta serial. O código pode ser copiado e editado
no Tinkercad.
void setup()
pinMode(A0,INPUT);
Serial.begin(9600);
void loop()
Serial.print("Celsius: ");
Serial.print(tmpCel);
Serial.println(grau);
delay(1000);
O valor de temperatura, simulado no sensor, pode ser alterado ao se clicar nos ícones do
Tinkercad durante a simulação, alterando o valor como mostrado na Figura 7.
Fonte: EnsineMe.
Figura 7 – Alteração de temperatura no simulador.
Fonte: EnsineMe.
Ele usa sonar para determinar a distância de um objeto, assim como os morcegos.
Oferece excelente detecção de alcance sem contato, com alta precisão e leituras estáveis
em um pacote fácil de usar.
O transmissor (pino de trigger) envia um sinal, um som de alta frequência. Quando o sinal
encontra um objeto, ele é refletido e o receptor (pino de eco) o recebe. O tempo entre a
transmissão e a recepção do sinal nos permite calcular a distância até um objeto. Isso é
possível porque sabemos a velocidade do som no ar, que é de aproximadamente 343 m/s.
O sensor de distância do simulador Tinkercad usa o mesmo pino para transmitir e receber o
sinal. A Figura 9 mostra uma possível montagem.
Fonte: EnsineMe.
A entrada digital 7 da placa é utilizada para realizar a medida de tempo entre o pulso enviado e
recebido. Esse tempo é usado para calcular a distância. O código se encontra a seguir.
void setup() {
Serial.begin (9600);
void loop() {
// Dê um pulso baixo (LOW) curto antes para garantir um pulso alto limpo:
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW);
delayMicroseconds(5);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
pinMode(echoPin, INPUT);
Serial.print(cm);
Serial.print("cm");
Serial.println();
delay(250);
Veja que um pulso alto é preciso para disparar o envio do pulso ultrassônico. Para se ler o
intervalo de tempo entre o pulso de envio e retorno é usada a função pulseIn().
Se o valor HIGH é passado para a função (como nesse exemplo), esta última espera o pino ir
do estado LOW para o HIGH, começa a contar o tempo e, então, espera o pino ir para o estado
LOW para finalizar essa contagem, devolvida em microssegundos.
Como queremos saber a distância em centímetros, tivemos que usar a velocidade do som no
ar em centímetros por segundo, 34300 cm/s. Depois, calculamos quantos microssegundos o
som leva para percorrer um centímetro. Para isso, basta resolver a seguinte regra de três:
De acordo com o resultado, são necessários 29.15 µs para o som percorrer um centímetro.
Agora, com o valor da medida de tempo em microssegundos para o som ir e voltar ao sensor
(variável duração), basta dividir esse tempo por 29.15 para descobrir quantos centímetros ele
teve que percorrer.
Como o som precisa fazer o trajeto de ida e volta, finalizamos com a divisão do resultado por
dois para termos a distância entre o sensor e o objeto.
UTILIZAÇÃO DE ATUADORES
Diversos tipos de atuadores podem ser usados em sistemas embarcados com
microcontroladores. Além de motores DC, que podem ser acionados com sinal PWM, há
também outros tipos, como os motores de passo e os servo motores.
COMENTÁRIO
Os servos variam em tamanho, desde miniatura para pequenos projetos até tamanhos maiores
para fins industriais.
Dentro da biblioteca do Arduino existe um conjunto de funções que permite o envio de
comando para servo motores pequenos. O código a seguir faz uso dessas funções, que estão
na biblioteca servo.h.
Veja que a variável tipo servo que foi criada pode receber o comando write e, como parâmetro,
o ângulo para posicionar o servo motor.
void setup ()
s.attach(SERVO);
void loop()
s.write(pos);
delay(50);
s.write(pos);
delay(50);
Fonte: EnsineMe.
Figura 10 – Montagem de atuador servo motor no simulador Tinkercad.
Fonte: EnsineMe.
A) -45 °C a 500 °C
B) 50 °C a 1000 °C
C) -50 °C a 280 °C
D) 0 a 500 °C
E) -45 °C a -450 °C
VOID SETUP() {
VOID LOOP() {
PINMODE(TRIGPIN, OUTPUT);
DIGITALWRITE(TRIGPIN, LOW);
DELAYMICROSECONDS(5);
DIGITALWRITE(TRIGPIN, HIGH);
DELAYMICROSECONDS(10);
DIGITALWRITE(TRIGPIN, LOW);
PINMODE(ECHOPIN, INPUT);
MM = (DURACAO/2) / 291;
A)
analogWrite (13, HIGH);
delay (mm);
A)
B)
delay (mm);
B)
C)
delay (mm);
delay (mm);
C)
D)
delay (mm);
D)
E)
delay (mm);
delay (mm);
E)
GABARITO
Sabendo que um microcontrolador pode ler valores de 0 a 3,3 volts, qual o range de
temperatura que poderá ser medido?
2. Foi solicitado um projeto, utilizando Arduino, que controla a frequência com que um
LED pisca em função da proximidade de um objeto. Para isso, se utilizou um sensor de
distância por ultrassom. Dessa forma, quanto mais próximo o objeto do sensor, mais
rápido o LED deverá piscar. Escolha a opção que completa o código a seguir de forma
correta para conseguir esse efeito no LED do pino 13 do Arduino Uno.
void setup() {
void loop() {
pinMode(trigPin, OUTPUT);
digitalWrite(trigPin, LOW);
delayMicroseconds(5);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
pinMode(echoPin, INPUT);
mm = (duracao/2) / 291;
O código acende o LED no pino 13 com a função digitalWrite (13, HIGH). Em seguida, aguarda
um intervalo em milissegundos, com delay (mm). Esse valor em milissegundos (mm) é igual ao
valor da distância para o obstáculo em milímetros, calculada anteriormente. Depois apaga o
LED pelo mesmo intervalo de tempo. Com isso, quanto menor a distância, mais rápido o LED
piscará.
MÓDULO 3
Começaremos agora a ver mais detalhes para a programação do LCD (Liquid Crystal Display –
Display de Cristal Líquido), de displays de 7 segmentos e de displays gráficos.
LCD (LIQUID CRYSTAL DISPLAY – DISPLAY
DE CRISTAL LÍQUIDO)
O LCD possui um material que une as propriedades do líquido e dos cristais. Ele tem uma faixa
de temperatura dentro da qual as partículas são essencialmente tão móveis quanto poderiam
ser em um líquido, no entanto, são reunidas em uma forma semelhante a um cristal.
COMENTÁRIO
O LCD é um mostrador de saída muito mais informativo do que um único LED, pois é um
display que pode mostrar facilmente os caracteres em sua tela. Eles variam em tamanho, preço
e configuração, e podem ter desde algumas linhas até telas grandes. Alguns são até mesmo
projetados especificamente para um único aplicativo, tendo apenas a capacidade de exibir
gráficos definidos.
O LCD recebe informações e controle, e os requisitos são restritos para garantir que as
informações sejam enviadas a ele de forma que possa aceitá-las apropriadamente.
Primeiro, há uma discrepância de velocidade entre o LCD e o microcontrolador, pois este último
é muito mais rápido que o primeiro. Portanto, o programa do microcontrolador deve estar
totalmente ciente disso e compensar o tempo que o LCD fica ocupado trabalhando em dados
enviados anteriormente.
Além do pino GND e Vcc (alimentação de 5 V), o display possui 8 pinos para envio de dados
em paralelo (DB0 a DB7), ajuste de contrastes (VEE), pino de controle para selecionar envio de
dados para o registro de comando ou de dados (RS), leitura ou escrita no registro (RW), pino
de habilitação do dispositivo (EN) e entrada para alimentação da luz de fundo (backlight) nos
pinos Led+ e Led-.
Os caracteres escritos se baseiam na tabela ASCII. Neste LCD, cada caractere é exibido em
uma matriz de 5×7 pixels.
Fonte: EnsineMe.
Figura 11 – Pinagem de LCD 16x2.
Fonte: EnsineMe.
ATENÇÃO
Quando o display LCD não está habilitado, as linhas de dados ficam em um estado de alta
impedância. Isso significa que não interferem na operação do microcontrolador quando o
display não é usado.
A linha de controle EN (habilitar) é usada para permitir o envio de dados para o LCD. Uma
transição de alto para baixo nesse pino habilitará o módulo. Quando RS (Seleção de
Registrador) é baixo, os dados devem ser tratados como uma instrução de comando. Quando
RS está alto, os dados que estão sendo enviados são exibidos na tela. Assim, para exibir
qualquer caractere na tela, definimos RS alto.
Para programar a escrita em displays LCD de caracteres, é preciso seguir passos de envio de
comandos com temporização adequada, para que o display esteja preparado para receber os
dados, o valor ASCII de cada caractere que se deseja escrever.
Todo display possui um controlador que define que comandos devem ser utilizados. É esse
controlador que designa como devem ser os comandos para operar o LCD.
As funções auxiliam a utilização do LCD, realizam sua inicialização e também a dos passos e
temporizações necessárias para que o controlador tenha tempo de enviar os dados e acender
os caracteres no display.
O código a seguir pode ser utilizado no LCD da placa 4 (PICGenios) do simulador PICSimLab.
void main () {
lcd_init();
delay_ms(1000);
No IDE do Arduino existem muitas funções, dentro da biblioteca LiquidCrystal, para operar um
display LCD. Essa biblioteca permite que uma placa Arduino controle as telas (LCDs) baseadas
no chipset Hitachi HD44780 (ou compatível), encontrado na maioria dos LCDs baseados em
caracteres.
LIQUIDCRYSTAL()
Cria uma variável do tipo LiquidCrystal. O display pode ser controlado usando 4 ou 8 linhas de
dados. Para usar 4 bits, omita os números dos pinos de d0 a d3 e deixe essas linhas
desconectadas. O pino RW pode ser ligado ao terra (GND). Nesse caso, omita-o dos
parâmetros dessa função.
Sintaxe: os parâmetros a seguir devem ser substituídos pelo número do pino do Arduino ao
qual o pino correspondente do display está ligado.
LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7).
BEGIN()
Inicializa a interface para a tela LCD e especifica as dimensões (largura e altura) da tela. A
função begin() precisa ser chamada antes de qualquer outro comando da biblioteca LCD.
SETCURSOR()
Posiciona o cursor do LCD, isto é, define a localização na qual o texto subsequente gravado no
LCD será exibido.
CLEAR()
Limpa a tela LCD e posiciona o cursor no canto superior esquerdo.
Sintaxe: lcd.clear().
Fonte: EnsineMe.
/*
Circuito:
*/
void setup() {
lcd.begin(16, 2);
lcd.print("Usando o LCD");
void loop() {
lcd.setCursor(0, 1);
delay(1000);
lcd.print(millis() / 1000);
DISPLAY DE 7 SEGMENTOS
O display de 7 segmentos consiste em sete LEDs organizados de forma retangular, conforme
mostrado na Figura 13.
Cada um dos sete LEDs é chamado de segmento porque, quando iluminado, o segmento faz
parte de um dígito numérico (decimal e hexadecimal) a ser exibido.
Um oitavo LED adicional às vezes é usado dentro do mesmo pacote, permitindo a indicação de
um ponto decimal (DP) quando dois ou mais monitores de 7 segmentos são conectados juntos
para exibir números maiores que dez.
Cada um dos sete LEDs no display recebe um segmento posicional com um de seus pinos de
conexão. Esses pinos LED individuais são rotulados de A até G, representando cada LED
individual. Os outros pinos LED são conectados juntos para formar um pino comum.
Portanto, ao polarizar os pinos apropriados dos segmentos de LED em uma ordem específica,
alguns segmentos estarão acesos e outros não, permitindo que o padrão de caracteres
desejado do número seja gerado na tela. Isso nos permite exibir cada um dos dez dígitos
decimais de 0 a 9 na mesma exibição de 7 segmentos.
EXEMPLO
Para exibir o dígito numérico 0, precisaremos acender seis dos segmentos de LED
correspondentes a A, B, C, D, E e F. Assim, os vários dígitos de 0 a 9 podem ser exibidos
usando um display de 7 segmentos.
Cada posição será um número binário de 8 dígitos, um para cada segmento do display (A, B,
C, D, E, F, G e ponto).
Nesse número binário, consideraremos o dígito menos significativo como o segmento A, o
seguinte como B, e assim sucessivamente.
Dessa forma, para acender somente o segmento A, escreveríamos o número binário
0b00000001.
digitos[] = {
0b01111111, 0b01100111}
A placa 4 do simulador PICSimLab possui 4 displays de 7 segmentos. Eles estão ligados na
porta D (RD0 a RD7 correspondendo de A até ponto) e são multiplexados por quatro chaves
transistores, acionadas pelos pinos RA2, RA3, RA4 e RA5 (entradas DISP1, DISP2, DISP3 e
DISP4).
Como são multiplexados, cada display deve ser aceso por vez para apresentar um dígito. Esse
intervalo entre acender um display e outro deve ser rápido o suficiente para dar a ilusão visual
de que todos estão acesos ao mesmo tempo.
O código a seguir permite que se escreva os dígitos 1, 2, 3 e 4 em cada display. Ele pode ser
usado para criar um projeto no MPLAB para o PIC18F4550, compilar e usar o arquivo .hex
gerado para rodar o simulador PICSimLab.
#use delay(clock=4MHz)
int8 digitos[] = {
0b01111111, 0b01100111
};
output_d(digito[numero]);
delay_ms(25);
void main () {
while(true) {
}
DISPLAYS GRÁFICOS
Um display gráfico é exatamente o que seu nome sugere: um visor matricial capaz de exibir
imagens, letras e números gerados por meio do firmware do microcontrolador. Qualquer
aplicativo que precisa exibir mais do que apenas letras e números pode usar um display
gráfico.
EXEMPLO
É o caso de 128x64. Esse display contém 128 pontos ao longo do eixo X (ou horizontal) e 64
pontos ao longo do eixo Y (ou vertical).
Cada um desses pontos, às vezes chamados de pixel, pode ser ligado e desligado
independentemente um do outro.
O programador faz uso do software para informar a cada ponto quando ligar e desligar, e a
tecnologia utilizada pode ser a do próprio LCD.
Outra tecnologia para display gráfico que vem crescendo e se popularizando é a de OLED.
DISPLAY OLED
Os displays OLED (Organic Light-Emitting Diode – Diodo Orgânico Emissor de Luz) para uso
em monitores de TV têm uma excelente qualidade de imagem, apresentando cores brilhantes,
contraste infinito, taxa de resposta rápida e ângulos de visão amplos.
Fonte: Shutterstock.com
Fonte: Shutterstock.com
COMENTÁRIO
Os dispositivos OLED modernos usam muito mais camadas para torná-los mais eficientes e
duráveis, mas a funcionalidade básica permanece a mesma.
Mostradores gráficos de OLED para uso em sistemas embarcados podem ser encontrados por
baixíssimo custo no mercado. Os que trabalham com o controlador SSD1306 são um
exemplo.
Ele pode se comunicar com o microcontrolador de várias maneiras, incluindo I2C e SPI.
O SPI é geralmente mais rápido do que o I2C, mas requer mais pinos de E/S (Entrada e
Saída) . Por outro lado, o I2C requer apenas dois pinos e pode ser compartilhado com outros
periféricos I2C. Graças à versatilidade do controlador SSD1306, o módulo vem em diferentes
tamanhos e cores, por exemplo, 128x64 e 128×32, com OLEDs brancos ou azuis.
Todos esses diferentes requisitos de energia são satisfeitos usando os circuitos internos de
carga. Isso torna possível conectá-lo a um Arduino ou a qualquer microcontrolador de 5 V
facilmente, sem usar nenhum conversor de nível lógico.
Adafruit_SSD1306 display(-1);
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.clearDisplay();
display.display();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(27,30);
display.print("Ola!");
// Atualiza o display
display.display();
void loop() {
//
EMPREGANDO DISPLAYS
VERIFICANDO O APRENDIZADO
1. O TRECHO DE CÓDIGO A SEGUIR FOI USADO PARA ESCREVER EM
UM LCD DE 16 CARACTERES (COLUNAS) POR LINHA EM DUAS LINHAS,
LIGADO A UMA PLACA ARDUINO. ONDE SERÁ ESCRITO O DÍGITO 5?
LCD.SETCURSOR(0, 1);
LCD.PRINT(“125”);
VOID MAIN () {<BR/>
LCD_INIT();<BR/>
PRINTF(LCD_PUTC, “
LCD 123”);<BR/>
A) Será escrito “
LCD 123” na primeira linha.
C) Será escrito “
LCD 123” na segunda linha.
GABARITO
1. O trecho de código a seguir foi usado para escrever em um LCD de 16 caracteres
(colunas) por linha em duas linhas, ligado a uma placa Arduino. Onde será escrito o
dígito 5?
lcd.setCursor(0, 1);
lcd.print(“125”);
2. O trecho de código a seguir para o compilador CCS C foi usado para escrever em um
LCD de 16 caracteres por linha em duas linhas, ligado a um microcontrolador PIC. O que
será escrito e em que posição no LCD?
void main () {<br/>
lcd_init();<br/>
printf(LCD_PUTC, “
LCD 123”);<br/>
No CCS C a função printf foi adaptada para enviar caracteres ao LCD quando recebe o
parâmetro LCD_PUTC. Os caracteres são escritos como na função printf já conhecida.
Assim, o comando \n indica pular linha e a frase “LCD 123” é escrita na segunda linha.
MÓDULO 4
O programa pode estar em qualquer ponto de sua execução quando essa entrada for ativada.
É necessário fazer o equivalente a monitorar esse sinal não cem vezes por segundo, mas
centenas de milhares de vezes por segundo, enquanto são efetuadas todas as outras
operações que nosso programa precisa realizar.
Como podemos responder tão rapidamente e ainda ter tempo para fazer qualquer outro
trabalho em nosso programa?
MECANISMO DE INTERRUPÇÃO
Uma interrupção é um sinal assíncrono para a atenção do processador que pode ser originado
no hardware ou no software. O mecanismo de interrupção fornece uma maneira de evitar o
desperdício de tempo do processador, livrando-se de rotinas de pesquisa ineficazes em loops
fechados.
As interrupções permitem que o processador continue seu trabalho até que o evento que
dispara a interrupção ocorra. Também garante que a CPU receberá um sinal sempre que
ocorrer um evento que requeira sua atenção.
Uma interrupção é, portanto, um sinal para a CPU começar imediatamente a executar um
código diferente, código este que é escrito para responder à causa da interrupção.
ATENÇÃO
O advérbio “imediatamente”, utilizado aqui, pode significar, na melhor das hipóteses, “assim
que terminar a instrução atual”.
E, quanto menor for esse intervalo (latência mais baixa), será sempre melhor.
A CPU se lembrará da localização da próxima instrução que iria executar, armazenando seu
endereço em um registrador ou local de memória, e então pulará diretamente para o código
designado pelo programador para aquela interrupção particular.
Além de salvar o endereço da próxima instrução, muitas vezes também salvará o registrador
de status da CPU e desabilitará outras interrupções. Ela também irá, na maioria dos casos,
limpar automaticamente a solicitação de interrupção que acionou, de forma que uma única
solicitação de interrupção não resulte na entrada de uma rotina várias vezes.
VOCÊ SABIA
Caso fosse possível assistir à execução do código em câmera lenta, o contador do programa
estaria se movendo de uma instrução para a próxima e, então, quando a interrupção fosse
acionada, o contador de programa iria repentinamente parar em alguma área totalmente
diferente do programa, o ponto de entrada da ISR. Então, quando o ISR estivesse completo, o
contador de programa apontaria de repente para a próxima instrução como se nada tivesse
acontecido.
Finalmente, e como não poderia deixar de ser, a própria condição de interrupção deve ocorrer.
Um pino do microcontrolador sendo direcionado para nível baixo por um evento externo, por
exemplo, pode ser um acionamento programado de uma interrupção específica. Nesse caso,
seria uma interrupção externa.
O programa também terá uma ISR (muito semelhante a uma função) para cada interrupção
que será habilitada, e cada uma dessas ISRs será mapeada para sua fonte de interrupção
correspondente.
ATENÇÃO
É crucial que qualquer interrupção ativada sempre tenha uma ISR válida mapeada para ela.
Caso contrário, quando a interrupção disparar, a CPU começará a tentar executar o código em
algum local sem instruções, causando uma quebra no programa.
APLICAÇÕES DE INTERRUPÇÕES
Interrupções são úteis em muitas situações de programação. Por exemplo:
Para evitar que a CPU seja travada enquanto aguarda um processo iniciar. Um uso comum
para uma interrupção é notificar o processador de que uma transferência de dados pode
ocorrer.
Para responder a eventos críticos quanto ao tempo, como uma ação que deve ocorrer
imediatamente em uma condição de falha de energia.
Para fornecer uma saída de uma rotina na ocorrência de uma condição de erro.
Como podem ser habilitadas várias interrupções no programa, elas são comumente associadas
para a realização de uma tarefa.
Uma forma de interrupção à qual todos os microcontroladores podem responder é uma simples
mudança digital de estado em um pino especificado (geralmente chamado de pino de
interrupção externa).
É possível programar uma interrupção externa de modo que, cada vez que um pulso apareça,
uma rotina de interrupção seja ativada para acumular a contagem desses pulsos em uma
variável contador.
Outra rotina, disparada pelo temporizador e chamada a cada segundo, pode pegar esse
contador e guardar o valor resultante, este valor representa a contagem de pulsos por
segundo, gerando assim, uma taxa de contagem.
Essa mesma rotina pode fazer cálculos, apresentar os dados ao usuário ou enviá-los por rede
para outro sistema.
TIPOS E FORMAS DE INTERRUPÇÕES
EXTERNAS
Existem algumas maneiras diferentes de configurar uma interrupção externa, dependendo do
que o microcontrolador permite.
Em primeiro lugar, as interrupções externas podem ser disparadas por borda ou por nível.
Uma interrupção disparada por borda gera uma solicitação de interrupção apenas em uma
borda, isto é, quando a linha de interrupção vai de um estado para o estado oposto (1 -> 0 ou 0
-> 1).
Uma interrupção acionada por nível gera uma solicitação de interrupção sempre que a linha de
interrupção está no estado ativo. Sendo assim, uma interrupção acionada por baixo nível irá
gerar solicitações sempre que a linha estiver baixa. Além disso, um dado importante de ser
registrado é que ela continuará a gerar solicitações até que a linha seja elevada.
Para uma interrupção disparada por borda, a polaridade pode ser disparada pela borda
ascendente (0 -> 1) ou pela borda descendente (1 -> 0).
Para uma interrupção acionada por nível, a polaridade pode ser acionada por nível baixo
(sempre que a entrada for 0) ou por nível alto (sempre que a entrada for 1).
Novamente, essas são opções de configuração possíveis, mas nem toda entrada de
interrupção externa em cada microcontrolador oferecerá suporte a todas essas opções.
É ainda possível haver uma entrada de interrupção externa que dispara em qualquer mudança
lógica, ou seja, gerará uma solicitação de interrupção em uma transição alto-baixo (1 -> 0) ou
em uma transição baixo-alto (0 -> 1). Essa é apenas uma interrupção disparada por borda que
dispara automaticamente em ambas as bordas possíveis, em vez de apenas em uma borda
especificada.
ATENÇÃO
Observe também que a distinção entre interrupções acionadas por borda e por nível é
fundamental para todos os tipos de interrupções, não apenas as externas.
É importante, ao escrever a rotina de interrupção, que se tenha uma ideia do que precisa ser
feito imediatamente, no início da rotina, e o que pode ser feito depois.
Frequentemente, se desejará alterar uma ou mais saídas ou registradores ou ler uma ou mais
entradas/saídas bem no início da rotina.
Em seguida, é possível concluir todas as outras tarefas que devem ser feitas na rotina. Essa
regra depende intimamente de qual é a fonte de interrupção, de qual é a ação rotina desejada
e, na maioria dos casos, do que o hardware associado precisa.
SINALIZADORES E PRIORIDADE DE
INTERRUPÇÃO
Qualquer sinalizador de solicitação de interrupção definido, considerando que a permissão de
interrupção associada esteja definida, é considerado “pendente”.
Se apenas um sinalizador for encontrado definido, no final da instrução atual a CPU salta
para a rotina dessa interrupção. Ao fazer isso, o sinalizador de interrupção pode ser apagado
automaticamente (isso depende do projeto), o endereço de retorno (o endereço da próxima
instrução que seria executada) é salvo e talvez alguns sinalizadores de CPU também o sejam.
Com isso, possivelmente, alguns registradores de CPU serão comutados e a rotina de
interrupção começará a ser executada.
O que acontece, a seguir, com uma rotina de interrupção em execução e outras interrupções
pendentes também depende do projeto da CPU.
Quando a rotina termina, o estado de interrupção global será definido como parte da
restauração do estado que ocorre no final de uma rotina de interrupção.
Definir o estado de interrupção global aqui é legítimo, uma vez que ele teve que ser habilitado
para que a rotina fosse inserida em primeiro lugar. Portanto, a partir daí a próxima instrução do
código de fundo interrompido começará a ser executada e a CPU reconhecerá que há uma ou
mais interrupções pendentes. Novamente, a interrupção pendente de maior prioridade será
atendida no final dessa instrução, com quaisquer outras restantes pendentes, e assim por
diante.
Até agora, foram descritas apenas interrupções que interceptam o código de segundo plano.
Mas o que acontece quando uma interrupção tenta barrar outra interrupção?
EXEMPLO
INT1 foi acionada e sua rotina de interrupção está em execução, então vem uma solicitação de
interrupção em INT2. O que acontece agora?
Nesse caso, uma das duas situações a seguir pode ocorrer. A nova interrupção pode ser
bloqueada até que a rotina INT1 termine, quando, então, ela será atendida. Ou, se as
interrupções foram habilitadas dentro da rotina de INT1, ou se INT2 foi definido com uma
prioridade mais alta do que INT1, a rotina de INT1 será interrompida assim como aconteceu
com o código de segundo plano, então a rotina de interrupção de INT2 será executada.
Elas são essenciais para o cumprimento de requisitos de tempo em sistemas embarcados, mas
também podem destruir os dados de maneiras que pareceriam impossíveis.
A maioria dos problemas com interrupções está relacionada ao seu principal benefício, que é a
execução do código poder ser interrompida praticamente a qualquer momento. E o código
nunca sabe que foi interrompido.
É como se fosse possível congelar o tempo para o código de segundo plano, fazer o que quiser
com os dados ou E/S e, em seguida, reiniciar o tempo para o código de segundo plano.
Em uma analogia, seria como se alguém muito mais rápido que você retirasse a sua cadeira no
exato instante em que se preparava para se sentar. É assim que pode ser um software mal
projetado que usar interrupções.
Um exemplo de cuidado que se deve ter é na passagem de dados entre o código de segundo
plano e a rotina de interrupção. Ela deve ser evitada, mas não é uma circunstância rara para
uma interrupção. Em boa parte das rotinas de interrupção os programadores se utilizam de
passagem de dados para o código de segundo plano e/ou a recuperação de dados do código
de segundo plano, e é aí que algo pode dar errado. A ocorrência de problemas pode se dar
sempre que o código de segundo plano está no meio do acesso aos dados e uma interrupção
acontece, fazendo com que a rotina associada acesse os mesmos dados.
RECOMENDAÇÃO
Evitar ao máximo que duas rotinas atualizem os mesmos dados é mais seguro, mas nem
sempre contornável. Por isso, alguns testes e uma análise minuciosa no código são sempre
boas práticas na utilização de interrupções.
PROGRAMAÇÃO DE INTERRUPÇÃO
EXTERNA
Um exemplo de programação poderia ser um LED acionado por interrupção ao toque em um
botão. Dessa forma, se o pino é mantido alto por um resistor pullup e, em seguida, é reduzido
por algum sinal ou ação, a transição de alto para baixo no pino pode desencadear uma
interrupção.
Podemos realizar um programa de LED controlado por botão para detectar a transição desse
botão por meio de interrupção externa, alterando o LED de acordo. Outro LED pode ser
acionado por uso de função delay (atraso). Isso nos dará uma introdução simples às
interrupções externas.
O primeiro passo é consultar a ficha técnica do chip para ver qual(is) pino(s) suporta(m)
interrupções externas.
Elas estão nos pinos RB0, RB1 e RB2 da PORTB. Essas interrupções são acionadas pela
borda, ou seja, disparadas pela borda ascendente ou pela borda descendente do pulso.
#use delay(clock=4MHz)
#INT_EXT
void int_externa0() {
output_toggle(PIN_D1);
void main () {
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
while(true) {
output_toggle(PIN_D0);
delay_ms(1000);
Verifica-se que o clique no botão de interrupção 0, botão RBO/INT na placa 4, irá alternar
imediatamente entre acesso e apagado o LED D1, não importando se o programa esteja na
função de atraso (delay) que acende e apaga o LED D0.
Para habilitar e usar outras interrupções externas, por exemplo, a interrupção 1, basta usar as
diretivas:
#INT_EXT1
void externa1() {
………………;
E também
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT1);
Fonte: EnsineMe
Figura 14 – Montagem no simulador Tinkercad.
Fonte: EnsineMe
Essa transição de nível alto para baixo é capturada pelo programa a seguir utilizando a
interrupção externa com a função attachInterrupt() que chama a ISR ledchange.
bool on=false;
void setup()
pinMode(10, OUTPUT);
void loop()
delay(10000);
void ledchange(){
on=!on;
if(on)
digitalWrite(10, LOW );
else
digitalWrite(10, HIGH);
}
EMPREGANDO INTERRUPÇÕES
VERIFICANDO O APRENDIZADO
D) Nenhuma interrupção
#USE DELAY(CLOCK=4MHZ)
INT16 C = 0;
#INT_EXT
VOID INT_EXTERNA0() {
C++;
VOID MAIN () {
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(INT_EXT_L2H);
WHILE(TRUE) {
}
A) Incrementa a variável c toda vez que o pino da interrupção externa 0 muda de estado baixo
para alto.
B) Incrementa a variável c toda vez que o pino da interrupção externa 0 muda de estado alto
para baixo.
C) Incrementa a variável c toda vez que o pino da interrupção externa 0 muda de estado.
GABARITO
1. A contagem de pulsos por segundo deve ser usada para se saber a taxa de radiação
medida por um detector de radiação. Quantas interrupções são necessárias para contar
os pulsos por segundo que chegam a um pino de um microcontrolador?
Uma interrupção externa permite chamar uma rotina de interrupção que incremente um
contador a cada pulso percebido no pino externo. Uma interrupção interna por temporizador
permite que a cada intervalo de um segundo uma rotina informe quantos pulsos foram
contados e indique a taxa de radiação.
2. O que o programa para o compilador CCS C a seguir faz em uma placa com PIC?
#use delay(clock=4MHz)
Int16 c = 0;
#INT_EXT
void int_externa0() {
c++;
void main () {
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT_L2H);
while(true) {
CONCLUSÃO
CONSIDERAÇÕES FINAIS
Neste tema, discutimos os tipos mais comuns de periféricos externos aos microcontroladores e
como acioná-los usando protocolos de comunicação, bem como receber acionamento destes
por interrupção.
Agora você tem condições de projetar sistemas que empreguem periféricos externos
conectados aos microcontroladores.
AVALIAÇÃO DO TEMA:
REFERÊNCIAS
MONK, S. Programação com Arduino: começando com sketches. 1. ed. Porto Alegre:
Bookman, 2017.
PECKOL, J. K. Embedded Systems: a contemporary design tool. 1 ed. Nova Jersey, EUA:
Wiley, 2019.
EXPLORE+
Para saber mais sobre os assuntos tratados neste tema, leia os artigos:
Automação de tanques para aquicultura, de Kevin Manoel Guimarães e Daniel Lohmann.
CONTEUDISTA
Marcos Santana Farias
CURRÍCULO LATTES