Lendo e Escrevendo nos pinos do Arduino com linguagem C/C++

Arduino ou Microcontroladores AVR
Este post faz parte da série Programação em C/C++ para Microcontroladores AVR. Leia também os outros posts da série:

Este artigo faz parte de uma série que tem como objetivo abordar de maneira prática a programação em C/C++ para microcontroladores AVR. Aqui utilizarei um Arduino UNO dotado de um ATMEGA328P-PU e um Shield EDU-IFSP para realizar certas atividades, onde apresentarei diversos periféricos do microcontrolador. Dessa vez veremos características da programação C/C++ voltada para microcontroladores e começaremos a trabalhar com os pinos e configurá-los.

 

 

O ATmega328/P

 

Os microcontroladores AVR foram desenvolvidos em 1995 na Noruega pela Atmel, que atualmente pertence a Microchip (fabricante dos microcontroladores PIC). Com uma estrutura RISC avançada e com hardware voltado para programação C, os microcontroladores AVR permitem uma melhor performance ao executar um código desse tipo.

 

Quando programamos um microcontrolador é importante conhecê-lo internamente. A seguir, nas Tabelas 1 e 2, temos algumas informações do ATMEGA328/P, porém é importante estudar seu datasheet pois as informações deste artigo encontram-se de forma resumidas.

 

Tabela 1 - Características básicas do MCU Atmega328P.

Características básicas

Tensão de operação:

1,8 V a 5,5 V (CLOCK)

Arquitetura:

RISC avançada (8 bits)

CLOCK externo:

Até 20 MHz

CLOCK interno:

Até 8 MHz

Memória de programa (FLASH):

32 KBytes (16384 x 16)

Memória EEPROM:

1 KBytes (1024 x 8)

Memória de de dados ou dinâmica (SRAM):

2 KBytes (2048 x 8)

Registradores de trabalho de uso geral:

32 Bytes (32 x 8)

Pinos programáveis:

23

ADC:

6 dos 23

(TIMER) PWM:

 

Tabela 2 - Características básicas de memória Flash e SRAM.

 

 

 

 

Características básicas dos pinos do ATMEGA328P

 

Para trabalhar com os pinos do microcontrolador vamos utilizar grupos de registradores que são responsáveis pela configuração do modo que os pinos operam. Cada pino pode assumir três modos: a entrada, saída e entrada com pull-up como mostram as Tabelas 3 e 4. Cada grupo desses registradores refere-se a um port do controlador onde temos acesso a determinados pinos (Figura 1), sendo que cada pino corresponde diretamente a um bit desse PORT, para identificá-los utilizamos as letra, B, C e D (a nomenclatura pode mudar dependendo do modelo do microcontrolador: os registradores DDR determinam quem será entrada ou saída; os registradores PORT escrevem os valores lógicos HIGH ou LOW; para ler os valores de um port, utilizamos os registradores PIN.

 

Tabela 3 - Registrador de leitura e escrita.

Registradores de Controle e Configuração dos Terminais

PINOS ARDUINO UNO

BIT RELACIONADO

FUNÇÃO ESPECIAL

BIT:

Registrador: DDRB PORTB PINB

7

6

5

4

3

2

1

0

OSC1

OSC2

13

12

11

10

9

8

PB7

PB6

PB5

PB4

PB3

PB2

PB1

PB0

Registrador: DDRC PORTC PINC

 

PC6

PC5

PC4

PC3

PC2

PC1

PC0

 

RESET

A5

A4

A3

A2

A1

A0

Registrador: DDRD PORTD PIND

PD7

PD6

PD5

PD4

PD3

PD2

PD1

PD0

7

6

5

4

3

2

TXD

RXD

R/W

R/W

R/W

R/W

R/W

R/W

R/W

R/W

 

Tabela 4 - Estados possíveis dos pinos de entrada e saída.

Modos de entrada e saída (INPUT, OUTPUT)

DDRxn

PORTxn

PULL UP

Comentários

0

0

Não

INPUT sem PULL-UP (flutuante)

0

1

Sim

INPUT mornamente em estado HIGH (PULL-UP)

1

0

Não

OUTPUT em estado LOW

1

1

Não

OUTPUT em estado HIGH

 

 

Pinos do Arduino (ATMEGA328P-PU)
Figura 1 - Pinos do ATMEGA328P-PU.

 

Todos os pinos possuem diodos de proteção para VCC e Terra e resistor de pull-up (Rpu, min 20 kΩ max 50 kΩ) individualmente selecionáveis conforme indicado na figura 2. Em relação às características elétricas, cada pino pode suportar uma corrente máxima de 40 mA, sendo que cada PORT pode suportar 200 mA. Mas de acordo com o fabricante, embora cada porta possa fornecer mais que as condições de teste (20 mA para 5 V e 10 mA para 3 V), deve ser observado que a soma de alguns pinos não deve exceder 100 mA.

  • C0 - C5, D0- D4, ADC7, RESET;
  • B0 - B5, D5 - D7, ADC6, XTAL1, XTAL2;
  • C0 - C5, ADC7, ADC6;
  • B0 - B5, D5 - D7, XTAL1, XTAL2;
  • D0 - D4, RESET.

 

Tratando-se de um microcontrolador com uma a corrente máxima de operação baixa, e temos que garantir que ela não exceda a capacidade do micro. Para isso utilizamos alguma forma de acoplamento nos conformes do projeto. Eu particularmente uso MOSFET, driver de corrente (como o ULM2003) e, quando necessário, foto-acoplamento como PC817 (ou similares).

 

Esquema simplificado dos pinos do ATMEGA328P.
Figura 2 - Esquema simplificado dos pinos do ATMEGA328P.

 

 

Shield EDU-IFSP

 

O Shield EDU-IFSP é um projeto criado pelo grupo de Estudos em Robótica e Sistemas Embarcados (GERSE) com o objetivo de facilitar o processo de ensino de eletrônica e programação. No decorrer da série iremos utilizá-lo para realizar experiências e prototipar alguns projetos. A imagem a seguir mostra a relação de pinos do microcontrolador com o shield.

 

Relação de pinos Shield EDU-IFSP com o Microcontrolador.
Figura 3 - Relação de pinos Shield EDU-IFSP com o Microcontrolador.

 

 

Programando Microcontroladores

 

Quando programamos em linguagem C, assim como na linguagem utilizada no Arduino, temos que pré configurar algumas coisas, como o modo de operação de um terminal ou até mesmo a velocidade de comunicação serial. Isso geralmente ocorre na rotina void setup(), antes da rotina principal void loop(). Já na linguagem C isso ocorre na mesma rotina, mas antes de um loop infinito. A seguir, lendo e escrevendo os pinos, temos a estrutura básica do programa C/C++:

 

 

O primeiro programa que vamos fazer é blink_C, onde faremos o led do pino 13 piscar. Conforme as informações de hardware mostradas anteriormente, podemos ver que o pino 13 corresponde ao bit PB5 do PORTB e ao LED A do shield. Cole o código a seguir no arquivo criado no artigo anterior (main.cpp), compile e grave conforme mostrado mostra a Figura 4:

 

Compilação e gravação do Microcontrolador.
Figura 4 - Compilação e gravação do Microcontrolador.

 

 

Uma boa prática na programação é transformar funções pequenas em macros. Elas facilitam a leitura do programa e aumentam o reuso do código. Toda vez que vamos configurar ou escrever em um bit de um registrador, temos que usar operadores lógicos e deslocar bits. Esse é um bom exemplo em que uma macro pode ser aplicada. O próximo programa implementa macros para acessarmos os registradores do micro:

 

 

Agora vamos contar de 1 a 3 no display de 7 segmentos. Para alimentar o LCD mude o jumper JP1 de posição.

 

 

Note que existem casos que é mais prático para o programador usar a macro ou apenas os registradores. No entanto, dependendo da aplicação, ambos os casos irão dar trabalho. Outra coisa importante é todas as vezes que vamos escrever em um pino precisamos de duas informações: seu registrador e o bit correspondente. Sempre que duas variáveis são utilizadas juntas com muita frequência e, sendo elas relacionadas, é uma boa prática agrupá-las em um tipo struct. No próximo código irei agrupar os registradores e bits respectivos, tornando mais prático o uso em loops ou estruturas de decisões mais complexas:

 

 

Primeiro crio um tipo struct chamado gpio que armazena dois vetores: um capaz de armazenar o endereço físico dos registradores e outro que guarda os bits respectivos. Para a inicialização da variável lcd7, no primeiro vetor (PORT) utilizo o operador & para retornar o endereço físico e não o valor do registrador (o registrador PORT não pode ser lido e sim apenas escrito). A variável value_lcd é uma matriz que contém os estados respectivos aos números mostrados no display de 7 segmentos. Dessa forma, torna-se prático a operação com os pinos em loops ou estruturas mais complexas.

 

Agora vamos ler os botões do shield e mostrar um valor correspondente no LCD de 7 segmentos. Os pinos utilizados pela placa são PC1, PD7 e PB0. Além disso os botões táteis não têm resistores de pull-down, o que implica na utilização dos pull-up internos do microcontrolador. Além de lermos LOW para botão pressionado e HIGH para botão não pressionado, para ler os valores em um pino específico utilizamos o registrador PIN.

 

 

Nesse programa as configurações são feitas em cada bit individualmente. Ao colocar os pinos dos botões como entrada, o bit correspondente do registrador PORT passa a controlar o estado do pull-up, sendo lógica 1 para ativado. O resto do programa segue o mesmo conceito, pois pinos com funções diferentes fazem parte do mesmo PORT, então temos que operar bit a bit para não causar bugs no programa.

 

 

Considerações finais

 

Vimos algumas formas de se trabalhar com os pinos do microcontrolador e possíveis estratégias de manipulação dos registradores no programa. Uma coisa importante para se levar em consideração é que não estamos programando um computador comum, e sim um hardware inferior criado especialmente para certas aplicações. Temos que cuidar para que nosso programa esteja otimizado, sempre poupando ao máximo a memória  e garantindo a velocidade e robustez da aplicação.

 

No próximo artigo iremos continuar trabalhando com os pinos do microcontrolador, porém veremos de maneira mais prática. Vamos criar um robô seguidor de linha com o mínimo de código possível. Para isso iremos aprender a lidar com as interrupções externas do microcontrolador.

 

 

Saiba mais

 

ATmega328P Xplained Mini - Hardware

Integração entre Raspberry Pi e Atmega328P

Timers do ATmega328 no Arduino

 

Referências

 

ARDUINO. What is Arduino?. Disponível aqui. Acesso em: 22 jan. 2017.

 

ATMEL. ATmega328/P: ATmega328/P, DATASHEET COMPLETE. 2016. Disponível aqui. Acesso em: 22 jan. 2017.

 

AVELINO. Como programar para AVRs em C/C++? E utilizando o Arduino? 2015. Disponível aqui. Acesso em: 21 jan. 2017.

 

LIMA, Chaerles Borges. Vilaça, Marco V. M. AVR e Arduino Técnicas de Projeto. 2º edição. Florianópolis 2012, edição dos Autores.

 

LIMA, Chaerles Borges. Programação C para Arduino. 2013. Disponível aqui. Acesso em: 21 jan. 2017.

 

LIMA, Charles Borges. OS PODEROSOS µCONTROLADORES AVR. 2009. Instituto Federal de Educação, Ciência e Tecnologia de Santa Catarina, Florianópolis. Disponível aqui. Acesso em: 21 jan. 2017.

 

FLORENCIO, Heitor Medeiros. Sistemas Embarcados: Temporizadores e Contadores. Departamento de Engenharia de Computação e Automação, Universidade Federal do Rio Grande do Norte. Disponível aqui. Acesso em: 21 jan. 2017.

 

SOARES, Márcio José. CONFIGURANDO CORRETAMENTE OS REGISTRADORES DOS MICROCONTROLADORES AVR – parte 1: USO DOS REGISTROS PORTX, DDRX E PINX. Disponível aqui. Acesso em: 21 jan. 2017.

 

SOUZA, Fábio. Arduino UNO. Disponível aqui. Acesso em: 02 fev. 2017.

 

SOUZA, Fábio. Shield EDU-IFSP do GERSE - IFSP Guarulhos. 2017. Disponível aqui. Acesso em: 02 fev. 2017.

 

Arduino. Arduino Uno Rev3, Tech Specs. Disponível aqui. Acesso em: 02 fev. 2018.

 

GERSE, ShieldEdu-IFSP. Disponível aqui. Acesso em: 02 abril de 2018.

Outros artigos da série

<< Preparando o Eclipse para microcontroladores AVR
Este post faz da série Programação em C/C++ para Microcontroladores AVR. Leia também os outros posts da série:
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

6
Deixe um comentário

avatar
 
4 Comment threads
2 Thread replies
5 Followers
 
Most reacted comment
Hottest comment thread
5 Comment authors
Tales Iago BatistaFernandoPedro Igor BorçattiWanerFlavio Hernan Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Tales Iago Batista
Membro
Tales Iago Batista

Olá! Parabéns pelo texto. Nesse fim de semestre fiz um trabalho para a disciplina de Arquitetura de computadores, onde eu fiz uma "comunicação" entre dois Atmega 328p (arduino Uno) usando assembly. Fiz algo simples, mandar o sinal de um botão de um Arduíno A para o Arduíno B acender um led. Mas fiz tudo em 100% assembly usando o compilador Atmel. Ficou top de mais seu texto, eu só vi ele depois que fiz o trabalho, para mim só faltaria a questão de como referenciar a memoria (registrador), kkkkk de novo Parabéns! Uma coisa para finalizar, pq n usar um… Leia mais »

Fernando
Visitante
Fernando

Texto muito bom ! Me ajudou bastante ! Ótimo !

Waner
Visitante
Waner

Muito bom o texto.

Flavio Hernan
Visitante
Flavio Nunes

Olá Pedro
Bem legal esse tópico, descrevendo o acesso direto aos registradores do AVR, são todos esses acessos que a API do Arduino "esconde", no mais parabéns pelo artigo.

Só uma questão que você colocou varias vezes no seu texto, sobre o "display LCD", pela foto do seu shield, você está usando um display LED de 7 segmentos. Display de LED e LCD ( liquid crystal display) são duas tecnologias diferentes e cada uma possui a sua forma de controle.