Índice:

AVR Assembler Tutorial 7: 12 etapas
AVR Assembler Tutorial 7: 12 etapas

Vídeo: AVR Assembler Tutorial 7: 12 etapas

Vídeo: AVR Assembler Tutorial 7: 12 etapas
Vídeo: Getting started with AVR and Atmel Studio 7 2024, Julho
Anonim
AVR Assembler Tutorial 7
AVR Assembler Tutorial 7

Bem-vindo ao Tutorial 7!

Hoje vamos primeiro mostrar como limpar um teclado e, em seguida, mostrar como usar as portas de entrada analógica para se comunicar com o teclado. Faremos isso usando interrupções e um único fio como entrada. Faremos a fiação do teclado de modo que cada tecla pressionada envie uma voltagem única para a entrada analógica, o que nos permitirá distinguir pela voltagem qual tecla foi pressionada. Em seguida, enviaremos o número pressionado para o nosso analisador de registro para mostrar que tudo está acontecendo como deveria. Existem várias armadilhas nas quais você pode se deparar ao usar o conversor analógico para digital (ADC) no ATmega328p e assim o faremos faça as coisas em alguns estágios no caminho para tentar descobrir como evitá-las. Também veremos por que usar o conversor analógico para digital não é a melhor maneira de controlar um teclado, embora use menos portas em seu microcontrolador. Neste tutorial, você precisará de:

  1. um teclado. Você pode comprar um ou fazer o que eu fiz e limpar um.
  2. 2 cabeçalhos femininos para o teclado (se você estiver removendo um)
  3. conectando fios
  4. uma placa de ensaio
  5. 4 resistores de 1 Kohm
  6. 1 resistor de 15 kohm
  7. 1 resistor de 3,3 Kohm
  8. 1 resistor de 180 ohms
  9. 1 resistor de 680 ohms
  10. um multímetro digital
  11. seu analisador do Tutorial 5

Você pode querer pular as primeiras etapas se já tiver um teclado e não precisar limpá-lo.

Aqui está um link para a coleção completa de meus tutoriais de assembler AVR:

Etapa 1: limpar um teclado 1

Limpar um teclado 1
Limpar um teclado 1
Limpar um teclado 1
Limpar um teclado 1
Limpar um teclado 1
Limpar um teclado 1
Limpar um teclado 1
Limpar um teclado 1

Há muito tempo, quando até mesmo seus avós eram apenas crianças, as pessoas costumavam usar esses dispositivos de aparência estranha, que tinham longos cabos plugados na parede, para se comunicarem uns com os outros. Eles eram chamados de "telefones" e geralmente eram coisas de plástico baratas que faziam um som irritante quando alguém ligava para você (não que os toques de "Justin Bieber" de hoje não sejam igualmente irritantes). Em qualquer caso, esses dispositivos tinham teclados neles que eram muito simples e fáceis de limpar e têm 2 teclas extras ("rediscar" e "flash") dos teclados que você pode comprar e reutilizar como "teclas de seta", "teclas de menu" ou qualquer outra coisa. Portanto, vamos começar limpando um teclado de um telefone antigo. Primeiro pegue o telefone (eu uso um GE, conforme mostrado nas fotos) e separe-o para revelar a fiação. Em seguida, pegue um cinzel e solte os pequenos botões de plástico que prendem o teclado e remova o teclado.

Etapa 2: limpar um teclado 2

Limpar um teclado 2
Limpar um teclado 2
Limpar um teclado 2
Limpar um teclado 2
Limpar um teclado 2
Limpar um teclado 2

Agora pegue uma serra de PVC e corte o plástico ao redor dos orifícios da fechadura e, em seguida, corte ao redor da borda para obter a profundidade certa, deixando um teclado fino.

Em seguida, coloque o teclado de volta usando os pequenos pinos que sobraram depois de você ter cortado a parte superior deles na última etapa e use um ferro de solda para simplesmente enfiar o ferro quente em cada orifício do pino que derreterá o plástico e espalhará sobre o parte inferior do teclado formando novos "botões" que manterão o teclado no lugar como antes.

Eu gosto de limpar os três alto-falantes e talvez outras coisas como interruptores e outras coisas que estão na placa. No entanto, desta vez não vou limpar os interruptores e outras coisas porque temos outros objetivos no momento. Além disso, há um IC linear TA31002 nele, que é uma campainha de telefone. A folha de dados é facilmente encontrada e baixada online, fornecendo a pinagem e os recursos. Portanto, vou deixá-lo soldado à placa por enquanto e depois brincar com ele mais tarde. Eu gostaria de conectá-lo a um osciloscópio e ver que sinais legais posso obter dele. Talvez até faça uma campainha com isso. Quem sabe.

De qualquer forma, quando você terminar de destruir o telefone e limpar as peças, terminaremos de fazer nosso teclado.

Etapa 3: limpar um teclado 3

Limpar um teclado 3
Limpar um teclado 3
Limpar um teclado 3
Limpar um teclado 3
Limpar um teclado 3
Limpar um teclado 3

Use um pavio dessoldador e remova os cabos de fita da parte inferior do teclado, certificando-se de que os orifícios na placa de circuito estejam desobstruídos e, em seguida, conecte dois conectores fêmeas na placa onde os orifícios estão. Você provavelmente terá que cortar seus cabeçalhos para que sejam cabeçalhos de 4 pinos.

Agora que os conectores estão conectados, você pode conectá-lo a uma placa de ensaio, pegar um multímetro e testar as teclas inserindo o multímetro em pinos aleatórios e medindo a resistência. Isso permitirá que você mapeie as chaves. É difícil ver como as teclas estão conectadas às saídas olhando para o circuito, mas se você usar um multímetro, pode conectá-lo a quaisquer dois pinos e pressionar os botões até ver um número na tela em vez de um circuito aberto. Esta será a pinagem dessa chave.

Mapeie todas as chaves para os pinos de saída desta forma.

Etapa 4: Conecte o teclado

Ligue o teclado
Ligue o teclado
Ligue o teclado
Ligue o teclado

Agora siga o diagrama de fiação e conecte o teclado à placa de ensaio.

Como isso vai funcionar, colocaremos 5V no lado esquerdo e o lado direito vai para GND. O primeiro pino à direita no diagrama vai para o primeiro de nossos pinos analógicos no microcontrolador Atmega328p. Quando nenhum botão for pressionado, o sinal será 0 V, e quando cada um dos diferentes botões for pressionado, a entrada para a porta analógica variará entre 0 V e 5 V com uma quantidade diferente dependendo de qual tecla foi pressionada. Escolhemos os valores do resistor de forma que cada caminho contivesse uma resistência diferente das demais. A porta analógica do microcontrolador recebe um sinal analógico e o divide em 1024 canais diferentes entre 0 V e 5 V. Isso significa que cada canal tem uma largura de 5 V / 1024 = 0,005 V / canal = 5 mV / canal. Portanto, a porta analógica pode distinguir as tensões de entrada, desde que sejam diferentes em mais de 5 mV. Em nosso caso, escolhemos os valores do resistor de forma que quaisquer dois pressionamentos de tecla enviem um sinal de tensão que difira em mais do que isso, de modo que o microcontrolador deve ser capaz de decidir facilmente qual tecla foi pressionada. O grande problema é que todo o sistema é muito barulhento, então precisaremos escolher uma faixa de voltagens para mapear a cada pressionamento de botão - mas falaremos disso um pouco mais tarde.

Observe que podemos controlar um teclado de 14 botões usando apenas uma única linha de entrada para o controlador. Esse é um dos aspectos úteis das entradas analógicas.

Agora, nossa primeira tentativa de controlar o teclado será fazer com que um pressionamento de tecla cause uma interrupção, a sub-rotina de interrupção lerá a porta de entrada analógica e decidirá qual tecla foi pressionada e, em seguida, emitirá esse número para nossa sub-rotina de analisador de registro que exibirá o valor-chave em binário em nossos 8 LEDs que configuramos no Tutorial 5.

Etapa 5: Conecte o teclado ao seu analisador

Conecte o teclado ao seu analisador
Conecte o teclado ao seu analisador
Conecte o teclado ao seu analisador
Conecte o teclado ao seu analisador

As imagens mostram como queremos conectar o teclado ao microcontrolador para que possamos ver a saída no visor do analisador. Basicamente, simplesmente conectamos a saída do teclado ao pino 0 do PortC, que também é chamado de ADC0 no ATmega328P.

No entanto, há algumas coisas adicionais. Também conectaremos um botão ao PD2. Ou seja, Pegue um fio de seu trilho de 5V para um botão e do outro lado do botão para PD2 e, por último, queremos desconectar o pino AREF de nosso trilho de 5V e, em vez disso, deixá-lo desconectado. Poderíamos inserir um capacitor de desacoplamento de 0,1 microfarad se quiséssemos. Este é um capacitor de cerâmica com um 104 escrito nele. Os primeiros dois dígitos são o número e o último dígito é a potência de 10 pelo qual multiplicamos para obter uma resposta em picofarads (pico significa 10 ^ -12), então 104 significa 10 x 10 ^ 4 picofarads, que é o mesmo que 100 nanofarads (nano significa 10 ^ -9), que é o mesmo que 0,1 microfarads (micro significa 10 ^ -6). De qualquer forma, tudo o que isso faz é estabilizar o pino AREF quando podemos usá-lo como nosso pino de referência.

Também queremos um resistor de 1 Mohm entre PD2 e o terra. Vamos definir PD2 como um pino de saída em 0 V e estaremos disparando em uma borda positiva nesse pino. Queremos que a borda desapareça imediatamente quando soltarmos o botão, então inseriremos esse resistor "pull down".

O motivo pelo qual queremos o botão é porque queremos acionar nosso conversor analógico-digital a partir do pino INT0 no chip, que também é PD2. Eventualmente, gostaríamos de pressionar a tecla para acionar o ADC e também fornecer a entrada a ser convertida sem ter um botão separado, mas devido à forma como o tempo funciona, começaremos com um botão separado para acionar o ADC e, assim que passarmos todos os detectar os bugs e ter certeza de que tudo está funcionando corretamente, então resolveremos os problemas de ruído e tempo que surgem com o acionamento ao pressionar o mesmo botão que desejamos ler.

Portanto, por enquanto, a maneira como funciona é manter uma tecla pressionada, pressionar o botão para acionar o ADC e, em seguida, soltar e, com sorte, o valor binário do botão que pressionamos aparecerá no analisador.

Então, vamos escrever um código que fará isso.

Etapa 6: Quais chaves de alternância devemos definir?

Quais chaves de alternância devemos definir?
Quais chaves de alternância devemos definir?

Vamos primeiro pensar em como vamos codificar isso para que o controlador possa ler a entrada do teclado e transformá-la em um valor numérico correspondente ao botão que foi pressionado. Vamos usar o Conversor Analógico para Digital (ADC) que é integrado ao Atmega328p. Usaremos AREF como nossa voltagem de referência e a saída do teclado será conectada à PortaC0 ou PC0. Observe que este pino também é chamado de ADC0 para Conversor Analógico-Digital 0. Pode ser uma boa idéia para você ler a Seção 12.4 sobre interrupções para o ATmega328P e também o capítulo 24 sobre o Conversor Analógico-Digital antes de começarmos iniciado ou pelo menos ter essas seções prontas para referência. Para configurar o microcontrolador para que ele saiba o que fazer com um sinal de entrada analógico e como interagir com nosso programa, primeiro temos que definir alguns dos vários ADC bits de registro relacionados. Eles são essencialmente equivalentes aos antigos interruptores nos primeiros computadores. Você liga ou desliga um interruptor ou, ainda mais atrás, conecta os cabos entre uma tomada e outra, de modo que os elétrons que alcançam aquela bifurcação na estrada encontrem um portão fechado e outro aberto, forçando-o a seguir um caminho diferente no labirinto de circuitos e, portanto, realizando uma tarefa lógica diferente. Ao codificar em linguagem assembly, temos acesso próximo a essas funções do microcontrolador, o que é uma das coisas atraentes em fazer isso em primeiro lugar. É mais "prático" e muito menos está acontecendo "nos bastidores", por assim dizer. Portanto, não pense em definir esses registros como uma tarefa tediosa. Isso é o que torna a linguagem assembly interessante! Estamos adquirindo um relacionamento muito pessoal com o funcionamento interno e a lógica do chip e fazendo com que ele faça exatamente o que queremos - nem mais nem menos. Nenhum ciclo de clock desperdiçado. Portanto, aqui está uma lista das opções que precisamos definir:

  1. Desligue o bit ADC de redução de energia, PRADC, que é o bit 0 do registro PRR, pois se esse bit estiver ativado, ele desligará o ADC. O registro de redução de energia é essencialmente uma maneira de desligar várias coisas que usam energia quando você não precisa delas. Como estamos usando o ADC, queremos ter certeza de que ele não está desabilitado dessa forma. (Consulte PRADC na página 46)
  2. Selecione o canal de entrada analógica para ser ADC0 desligando MUX3… 0 no registro ADC Multiplexer Selection (ADMUX) (consulte a tabela 24-4 página 249); eles já estão desligados por padrão, então realmente não precisamos fazer isso. No entanto, estou incluindo, pois se você usar uma porta diferente da ADC0, precisará alternar essas opções de acordo. Várias combinações de MUX3, MUX2, MUX1, MUX0 permitem que você use qualquer uma das portas analógicas como sua entrada e você também pode alterá-las rapidamente se quiser ver vários sinais analógicos diferentes ao mesmo tempo.
  3. Desligue os bits REFS0 e REFS1 no registro ADMUX para que possamos usar AREF como nossa tensão de referência em vez de uma referência interna (consulte a página 248).
  4. Ligue o bit ADLAR em ADMUX para que o resultado seja "ajustado à esquerda"; discutiremos essa escolha na próxima etapa.
  5. Defina o bit ADC0D no Registro de desativação de entrada digital (DIDR0) para desligar a entrada digital para PC0. Estamos usando essa porta para entrada analógica, portanto, podemos também desativar a entrada digital para ela.
  6. Defina ISC0 e ISC1 no Registro de controle de interrupção externa A (EICRA) para indicar que queremos disparar na borda ascendente de um sinal de tensão para o pino INT0 (PD2), consulte a página 71.
  7. Limpe os bits INT0 e INT1 no Registro de máscara de interrupção externa (EIMSK) para indicar que não estamos usando interrupções neste pino. Se tivéssemos de habilitar interrupções neste pino, precisaríamos de um manipulador de interrupção no endereço 0x0002, mas em vez disso, estamos configurando para que um sinal neste pino acione a conversão ADC, a conclusão da qual é tratada pela interrupção completa de conversão ADC em endereço 0x002A. Consulte a página 72.
  8. Defina o bit ADC Enable (ADEN) (bit 7) no controle ADC e registro de status A (ADCSRA) para habilitar o ADC. Consulte a página 249.
  9. Poderíamos iniciar uma única conversão definindo o bit de conversão inicial ADC (ADSC) cada vez que quiséssemos ler o sinal analógico, no entanto, por agora preferimos que ele fosse lido automaticamente sempre que alguém apertar o botão, então, em vez disso, habilitaremos o ADC Bit Autotrigger Enable (ADATE) no registro ADCSRA para que o acionamento seja feito automaticamente.
  10. Também definimos os bits ADPS2..0 (os bits AD Prescalar) para 111 de modo que o relógio do ADC seja o relógio da CPU dividido por um fator de 128.
  11. Selecionaremos a origem do acionamento ADC como PD2, também chamado de INT0 (Solicitação de interrupção externa 0). Fazemos isso alternando os vários bits no registro ADCSRB (consulte a Tabela 24-6 na página 251). Vemos pela tabela que queremos ADTS0 desativado, ADTS1 ativado e ADTS2 desativado para que o ADC seja acionado por esse pino. Observe que, se quisermos amostrar continuamente a porta analógica, como se estivéssemos lendo algum sinal analógico contínuo (como amostragem de som ou algo assim), definiríamos isso para o modo de execução livre. O método que estamos usando para definir o acionamento no PD2 aciona uma leitura ADC da porta analógica PC0 sem causar uma interrupção. A interrupção virá quando a conversão for concluída.
  12. Habilite o bit ADC Interrupt Enable (ADIE) no registro ADCSRA para que, quando a conversão analógica para digital for concluída, ela gere uma interrupção para a qual podemos escrever um manipulador de interrupção e colocar em.org 0x002A.
  13. Defina o bit I em SREG para habilitar interrupções.

Exercício 1: Certifique-se de ler as seções relevantes na folha de dados para cada uma das configurações acima para que você entenda o que está acontecendo e o que aconteceria se as alterássemos para configurações alternativas.

Etapa 7: escreva o manipulador de interrupção

Na última etapa, vimos que configuramos isso de forma que uma borda ascendente detectada no PD2 acione uma conversão analógica para digital no PC0 e, quando essa conversão for concluída, ele lançará uma interrupção de conversão completa do ADC. Agora queremos fazer algo com essa interrupção. Se você examinar a Tabela 12-6 na página 65, verá uma lista das possíveis interrupções. Já vimos a interrupção RESET no endereço 0x0000 e a interrupção Timer / Counter0 Overflow no endereço 0x0020 em tutoriais anteriores. Agora queremos dar uma olhada na interrupção ADC que vemos na tabela no endereço 0x002A. Portanto, no início do nosso código em linguagem assembly, precisaremos de uma linha que diz:

.org 0x002Arjmp ADC_int

que irá pular para nosso manipulador de interrupção rotulado ADC_int sempre que o ADC tiver concluído uma conversão. Então, como devemos escrever nosso manipulador de interrupção? A maneira que o ADC funciona é realizando o seguinte cálculo:

ADC = Vin x 1024 / Vref

Então, vamos ver o que acontece se eu pressionar o botão "rediscar" no teclado. Nesse caso, a tensão no PC0 mudará para algum valor, digamos 1,52 V, e como Vref está em 5 V teremos:

ADC = (1,52 V) x 1024/5 V = 311,296

e assim seria um 311. Se quiséssemos converter isso de volta para uma tensão, apenas inverteríamos o cálculo. Não precisaremos fazer isso, entretanto, uma vez que não estamos interessados nas tensões reais apenas em distingui-las. Quando a conversão é concluída, o resultado é armazenado em um número de 10 bits colocado nos registradores ADCH e ADCL e nós o fizemos "ajustado à esquerda", o que significa que os 10 bits começam no bit 7 do ADCH e vão até bit 6 do ADCL (há um total de 16 bits nesses dois registradores e usamos apenas 10 deles, ou seja, 1024 canais). Poderíamos ter o resultado "ajustado à direita" se quiséssemos apagando o bit ADLAR no registro ADMUX. O motivo de escolhermos o ajuste à esquerda é porque nossos sinais estão distantes o suficiente para que os dois últimos dígitos do número do canal não sejam relevantes e são provavelmente apenas ruídos, então vamos distinguir os pressionamentos de tecla usando apenas os 8 dígitos superiores, em outras palavras, só precisaremos olhar para ADCH para descobrir qual botão foi pressionado. Portanto, nosso manipulador de interrupções deve simplesmente ler o número do ADCH registrar, converter esse número em um valor de teclado e, em seguida, enviar esse valor para nossos LEDs de analisador de registro para que possamos verificar que pressionar um "9", digamos, fará com que os LEDs correspondentes a "00001001" acendam. agora, porém, precisamos primeiro ver o que aparece no ADCH quando pressionamos os vários botões. Então, vamos escrever um manipulador de interrupção simples que apenas envia o conteúdo do ADCH para a tela do analisador. Então, aqui está o que precisamos:

ADC_int: analisador lds, ADCH; carregue o valor de ADCH em nossos analisadoresbi EIFR, 0; limpe o sinalizador de interrupção externa para que esteja pronto para funcionar novamente.

Agora, você deve ser capaz de apenas copiar o código de nosso analisador no tutorial 5 e adicionar esta interrupção e as configurações de alternância e executá-lo. Exercício 2: Escreva o código e execute-o. Veja se você obtém o ADCH exibido no visor do analisador. Tente pressionar a mesma tecla várias vezes. Você sempre obtém o mesmo valor no ADCH?

Etapa 8: Mapeie os Valores de Keypress

Mapeie os Valores de Keypress
Mapeie os Valores de Keypress

O que precisamos fazer agora é converter os valores em ADCH em números correspondentes à tecla que foi pressionada. Fazemos isso escrevendo o conteúdo de ADCH para cada pressionamento de tecla e, em seguida, convertendo-o em um número decimal, como fiz na imagem. Em nossa rotina de tratamento de interrupções, consideraremos todo um intervalo de valores como correspondente a cada pressionamento de tecla, de modo que o ADC mapeie qualquer coisa nesse intervalo para um determinado pressionamento de tecla.

Exercício 3: Faça este mapeamento e então reescreva sua rotina de interrupção ADC.

Aqui está o que eu comprei para o meu (o seu provavelmente será diferente). Observe que eu o configurei com uma faixa de valores para cada pressionamento de tecla.

ADC_int:; Analisador de controle de interrupção externa; preparar para novos numberlds buttonH, ADCH; O ADC é atualizado quando o ADCH é lido clccpi buttonH, 240brlo PC + 3; se ADCH for maior, então é um analisador 1ldi, 1; então carregue o analisador com um retorno de 1rjmp; e retornar o botão clccpi H, 230; se ADCH for maior que um analisador 2brlo PC + 3ldi, 2rjmp return clccpi buttonH, 217brlo PC + 3ldi analisador, 3rjmp return clccpi buttonH, 203brlo PC + 3ldi analisador, 4rjmp return clccpi buttonH, 187brlo PC + 3ldi analisador, 3rjmp return clccpi buttonH, 203brlo PC + 3ldi analisador, 4rjmp return clccpi buttonH, 187brlo PC + 3ldi analisador, 5rjmp return clccpi buttonH, 203brlo PC + analisador 3ldi, 4rjmp return clccpi buttonH, 187brlo PC + 3ldi analisador, 5rjmp return clccpi buttonH, Analisador 155brlo PC + 3ldi, botão clccpi de retorno 6rjmp H, analisador 127brlo PC + 3ldi, 255; definiremos o flash como all onrjmp return clccpi buttonH, 115brlo PC + 3ldi analisador, 7rjmp return clccpi buttonH, 94brlo PC + 3ldi analisador, 8rjmp return clccpi buttonH, 62brlo PC + 3ldi analisador, 9rjmp return clccpi buttonH, 37brlo PC + 3ldi Analyzer, 8rjmp return clccpi buttonH, 62brlo PC + 3ldi analisador, 9rjmp return clccpi buttonH, 37brlo PC + 3ldi analisador, 0b11110000; asterisco é a metade superior onrjmp return clccpi buttonH, 28brlo PC + 3ldi Analyzer, 0rjmp return clccpi buttonH, 17brlo PC + 3ldi Analyzer, 0b00001111; o sinal de hash é a metade inferior onrjmp return clccpi buttonH, 5brlo PC + 3ldi Analyzer, 0b11000011; a rediscagem é o 2 superior inferior 2rjmp return ldi analisador, 0b11011011; caso contrário, ocorreu um erro return: reti

Etapa 9: Código e vídeo para a versão 1

Anexei meu código para esta primeira versão do driver do teclado. Neste, você precisa apertar a tecla e depois apertar o botão para fazer com que o ADC leia a entrada do teclado. O que preferimos não é nenhum botão, mas o sinal para fazer a conversão vem do próprio pressionamento de tecla. Exercício 3: Monte e carregue este código e experimente. Você pode ter que alterar os vários limites de conversão para corresponder às suas tensões de pressionamento de tecla, uma vez que eles provavelmente diferem dos meus. O que acontece se você tentar usar uma entrada do teclado para o ADC0 e para o pino de interrupção externa em vez de por meio de um botão? Também irei anexar um vídeo da operação desta primeira versão do nosso driver de pressionamento de tecla. Você notará que no meu código, há uma seção inicializando o Stack Pointer. Existem vários registradores que podemos querer empurrar e retirar da pilha quando estamos manipulando variáveis e outros enfeites e também existem registradores que podemos querer salvar e restaurar mais tarde. Por exemplo, SREG é um registro que não é preservado nas interrupções, portanto, os vários sinalizadores que são definidos e limpos como resultado das operações podem ser alterados se uma interrupção ocorrer no meio de algo. Portanto, é melhor empurrar SREG para a pilha no início de um manipulador de interrupção e, em seguida, retirá-lo novamente no final do manipulador de interrupção. Eu o coloquei no código para mostrar como ele é inicializado e para antecipar como precisaremos dele mais tarde, mas como não nos importamos com o que acontece com SREG durante as interrupções em nosso código, não usei a pilha para isso. Observe também que usei a operação de deslocamento para definir vários bits nos registros durante a inicialização. Por exemplo na linha:

temp IDI, (1 <> sts EICRA, temp

O comando "<<" na primeira linha do código acima é uma operação de deslocamento. Ele basicamente pega o número binário 1, que é 0b00000001, e o desloca para a esquerda pelo valor do número ISC01. Esta é a posição do bit denominado ISC01 no registro EICRA. Como ISC01 é o bit 1, o número 1 é deslocado para a posição 1 esquerda para se tornar 0b00000010. Da mesma forma, o segundo, ISC00, é o bit 0 do EICRA e, portanto, o deslocamento do número 1 é zero posições para a esquerda. Se der outra olhada no arquivo m328Pdef.inc que você baixou no primeiro tutorial e está usando evrr desde então, você verá que é apenas uma longa lista de instruções ".equ". Você descobrirá que ISC01 é igual a 1. O montador substitui todas as instâncias dele por 1 antes mesmo de começar a montar qualquer coisa. Eles são apenas nomes para bits de registro para ajudar a nós, humanos, a ler e escrever códigos. Agora, a linha vertical entre as duas operações de deslocamento acima é uma operação "ou" lógica. Aqui está a equação:

0b00000010 | 0b00000001 = 0b00000011

e é isso que estamos carregando (usando "ldi") em temp. A razão pela qual as pessoas usam esse método para carregar valores em um registrador é que ele permite usar o nome do bit em vez de apenas um número e isso torna o código muito mais fácil de ler. Também existem duas outras técnicas que usamos. Usamos as instruções "ori" e "andi". Isso nos permite definir e limpar os bits, respectivamente, sem alterar nenhum dos outros bits em um registro. Por exemplo, quando eu usei

ori temp, (1

essa temperatura "ou" é com 0b00000001 que coloca 1 no bit zero e deixa todo o resto inalterado. Também quando escrevemos

andi temp, 0b11111110

isso muda o bit zero de temp para 0 e deixa todo o resto inalterado.

Exercício 4: Você deve examinar o código e certificar-se de que entendeu cada linha. Você pode achar interessante encontrar métodos melhores para fazer as coisas e escrever um programa melhor. Existem centenas de maneiras de codificar as coisas e tenho certeza de que você pode encontrar uma maneira muito melhor do que a minha. Você também pode encontrar (Deus me livre!) Erros e omissões. Nesse caso, gostaria de ouvir sobre eles para que possam ser corrigidos.

Ok, agora vamos ver se podemos nos livrar desse botão supérfluo …

Etapa 10: Código para a versão 2

A maneira mais simples de se livrar do botão é removê-lo completamente, esquecer a entrada para PB2 e apenas mudar o ADC para "Modo de execução livre".

Em outras palavras, simplesmente altere o registro ADCSRB para que ADTS2, ADTS1 e ADTS0 sejam todos zeros.

Em seguida, defina o bit ADSC em ADCSRA como 1, que iniciará a primeira conversão.

Agora faça o upload para o seu microcontrolador e você verá que o número correto aparece no visor enquanto você pressiona o botão e apenas enquanto pressiona o botão. Isso ocorre porque o ADC está continuamente amostrando a porta ADC0 e exibindo o valor. Quando você tira o dedo do botão, o "salto do botão" fará com que alguns valores aleatórios ocorram muito rapidamente e então voltará para a entrada de 0V. Em nosso código, temos este 0V aparecendo como 0b11011011 (porque o pressionamento de tecla `0 'já está usando o valor de exibição 0b00000000)

No entanto, esta não é a solução que desejamos por dois motivos. Primeiro, não queremos ter que segurar o botão. Queremos pressioná-lo uma vez e ter o número exibido (ou usado em algum novo código em um tutorial posterior). Em segundo lugar, não queremos amostrar continuamente o ADC0. Queremos que ele faça uma única leitura, converta-o e entre em repouso até que um novo pressionamento de tecla acione uma nova conversão. O modo de execução livre é melhor se a única coisa que você deseja que o microcontrolador faça é ler continuamente alguma entrada analógica - como se você quisesse exibir as temperaturas em tempo real ou algo assim.

Então, vamos encontrar outra solução …

Etapa 11: Como nos livramos do botão? Versão 3

Como nos livramos do botão? Versão 3
Como nos livramos do botão? Versão 3

Existem várias maneiras de proceder. Primeiro, poderíamos adicionar hardware para nos livrar do botão. Por exemplo, podemos tentar colocar um transistor no circuito na linha de saída do pressionamento de tecla de modo que ele receba um pequeno fluxo de corrente da saída e envie um pulso de 5 V para o pino de interrupção PD2.

No entanto, provavelmente seria muito barulhento no mínimo e, na pior das hipóteses, não permitiria tempo suficiente para uma leitura precisa do teclado, já que a saída de tensão do teclado não teria tempo de se estabilizar antes que a leitura do ADC fosse capturada.

Portanto, preferimos apresentar uma solução de software. O que gostaríamos de fazer é adicionar uma interrupção no pino PD2 e escrever um manipulador de interrupção para ele que chama uma única leitura do pino do teclado. Em outras palavras, nos livramos da interrupção do autotrigger do ADC e adicionamos uma interrupção externa que chama o ADC dentro dela. Dessa forma, o sinal para ler o ADC vem depois que o sinal PD2 já ocorreu e isso pode dar às coisas tempo suficiente para se estabilizarem em uma tensão precisa antes que o pino PC0 seja lido e convertido. Ainda teríamos uma interrupção de conclusão ADC que envia o resultado para a tela do analisador no final.

Faz sentido? Bem, vamos fazer isso …

Dê uma olhada no novo código anexado.

Você vê as seguintes mudanças:

  1. Adicionamos um rjmp no endereço.org 0x0002 para lidar com a interrupção externa INT0
  2. Alteramos o registro EIMSK para indicar que queremos interromper no pino INT0
  3. Alteramos o pino ADATE no registro ADCSRA para desativar o autotriggering
  4. Nós nos livramos das configurações ADCSRB, pois elas são irrelevantes quando o ADATE está desligado
  5. Não precisamos mais redefinir o sinalizador de acionamento externo, pois a rotina de interrupção INT0 faz isso automaticamente quando é concluída - anteriormente não tínhamos uma rotina de interrupção, apenas acionamos o ADC de um sinal naquele pino, então tivemos que desmarque essa bandeira com a mão.

Agora, no manipulador de interrupções, simplesmente chamamos uma única conversão do ADC.

Exercício 5: execute esta versão e veja o que acontece.

Etapa 12: Código e vídeo para a versão de trabalho

Como vimos na última versão, a interrupção do botão não funciona muito bem porque a interrupção é disparada em uma borda ascendente para o pino PD2 e, em seguida, o manipulador de interrupção chama a conversão ADC. No entanto, o ADC obtém a leitura da tensão antes de se estabilizar e, portanto, faz uma leitura sem sentido.

O que precisamos é introduzir um atraso entre a interrupção no PD2 e a leitura do ADC no PC0. Faremos isso adicionando um temporizador / contador, uma interrupção de estouro do contador e uma rotina de atraso. Felizmente, já sabemos como fazer isso no Tutorial 3! Então, vamos apenas copiar e colar o código relevante de lá.

Eu dei o código resultante e um vídeo mostrando-o em operação.

Você notará que as leituras não são tão precisas quanto seria de se esperar. Provavelmente, isso se deve a uma série de fontes:

  1. estamos tocando na saída de tensão do teclado para disparar em PD2, o que afeta a leitura em PC0.
  2. não sabemos realmente quanto tempo devemos atrasar após o acionamento para obter a melhor leitura.
  3. leva alguns ciclos para a conversão do ADC ser concluída, o que significa que não podemos disparar rapidamente no teclado.
  4. provavelmente há ruído no próprio teclado.
  5. etc …

Portanto, embora tenhamos conseguido fazer o teclado funcionar, e agora pudéssemos usá-lo em aplicativos usando os valores das teclas pressionadas de alguma outra forma, em vez de apenas enviá-los para o visor do analisador, não é muito preciso e é muito irritante. É por isso que eu acho que a melhor maneira de conectar teclados é simplesmente colocar cada saída do teclado em uma porta diferente e decidir qual tecla é pressionada por quais portas vêem uma tensão. Isso é fácil, muito rápido e muito preciso.

Na verdade, existem apenas duas razões pelas quais alguém desejaria usar um teclado da maneira que fizemos aqui:

  1. Ele usa apenas 2 dos pinos em nosso microcontrolador em vez de 8.
  2. É um grande projeto para mostrar diferentes aspectos do ADC no microcontrolador, que é diferente das coisas padrão que você pode encontrar por aí, como leituras de temperatura, potenciômetros de giro, etc. Eu queria um exemplo de leituras simples acionadas e acionamento automático de pino externo em vez de apenas o modo de devorador de CPU de execução livre.

De qualquer forma, aqui estão alguns exercícios finais para você:

Exercício 6: Reescreva o manipulador de interrupção completa de conversão ADC para usar uma Tabela de Consulta. Ou seja, Para que teste o valor analógico com o primeiro item da tabela e se for maior retorna da interrupção, se não for então incrementa Z para o próximo item da tabela e retorna ao teste novamente. Isso irá encurtar o código e limpar a rotina de interrupção e torná-la mais agradável. (Vou dar uma solução possível no próximo passo) Exercício 7: Conecte seu teclado a 8 pinos no microcontrolador e escreva o driver simples para ele e experimente o quão melhor ele é. Você pode pensar em algumas maneiras de fazer nosso método funcionar melhor?

Isso é tudo para este tutorial. Anexei a versão final com dicas. Conforme nos aproximamos de nosso objetivo final, usaremos o teclado mais uma vez no Tutorial 9 para mostrar como controlar sete telas de segmento com ele (e construir algo interessante que usa as teclas extras no teclado do telefone) e então iremos em vez disso, mude para controlar as coisas com o pressionamento de botões (já que esse método se encaixa melhor com o produto final que estamos construindo com esses tutoriais) e vamos apenas arquivar o teclado.

Vejo você na próxima vez!

Recomendado: