Table of Contents

Registros

Um dos conceitos importantes que estão na base da compreensão dos microcontroladores são os registros. Para que possamos trabalhar com um microcontrolador é fundamental conhecer este dispositivo.

Essencial

Botões do equipamento de cassetes

O registro é como um painel de botões num controlo doméstico. Tem botões, que podem estar ligados ou desligados. Um dos melhores exemplos é um radio de cassetes. Estes equipamentos, como deve recordar, tem seis botões de controlo:

Cada botão faz algo, mas apenas quando corretamente acionado. Por exemplo, o botão Parar não faz nada caso a cassete não esteja a Tocar – só no caso de estar a tocar é que a sua ativação resulta em algo observável. Avançar ou Retroceder, por sua vez, podem ser pressionados a qualquer momento, dado que a cassete pode ser movimentada em ambas as direções, independentemente se está a Tocar ou não. Gravar começa quando o botão Tocar é Gravar são pressionados simultaneamente. Poderá tentar pressionar vários botões ao mesmo tempo – caso em que, o equipamento de cassetes poderá fazer algo inesperado ou mesmo deixar de funcionar.

Os registros do microcontrolador comportam-se da mesma forma – cada botão faz algo, quando usado corretamente. Quando pressionamos o botão errado, o microcontrolador pode não deixar de funcionar, mas também não irá funcionar. Na realidade, não existem botões de registro, em vez disso existe um conjunto de transístores, os quais ligam ou desligam a eletricidade. Os microcontroladores mais simples tem 8 comutadores com base em transístores de um só registo. Um registo pode ser considerado como um número de 8 bits, onde cada bit é registado no estado de cada um dos transístores. Por exemplo, um bit com o valor de 1 pode significar que o comutador está ligado e com o valor 0 que o comutador está desligado.

Botões do Registo e valores dos bits

Uma vez que o estado dos registos pode facilmente ser mostrado como um número, um registo pode ser comparado com a memória, a qual pode guardar dados do tamanho de um número. Com esta comparação, podemos depreender que os registros são espaços de memória. A diferença entre registos e espaços de memória é que a ultima apenas guarda informação, enquanto o registo na realidade controla algo mais. Por exemplo, se o valor binário 01100001 se encontrar escrito no registo, significa que três dos 8 botões encontram-se pressionados o que implicará algum acontecimento.

No equipamento de cassetes é possível pressionar cada botão separadamente, enquanto que num registo é mais difícil mudar o valor de um comutador ou bit. Normalmente é necessário alterar todo o conteúdo do registo. Antes de avançar para a mudança de bit, devemos ter conhecimento que existem um grande número de registos no microcontrolador. Algumas partes do microcontrolador são controladas por dezenas de registros. A variedade de registos implica haver uma forma de distinguir entre diferentes os diferentes registos o que é feito nomeando-os. Um registo, por exemplo, e denominado PORTB. Na realidade, estes nomes existem apenas para tornar mais simples o desenvolvimento na medida que cada nome corresponde a um endereço numérico.

Utilização

Para escrever num registo ou ler um valor dele, deve ser endereçada a variável em C. O exemplo seguinte demonstra a escrita de um valor binário num registo imaginário REG seguindo-se para a leitura de um valor da variável reg. Os valores binários distinguem-se por 0b (zero à esquerda), de forma que o compilador interprete o sistema numérico.

  REG = 0b01100001;
  unsigned char reg = REG;

Não existe nada de difícil em escrever e ler valores de registo, mas pode ser um quanto complicado se se pretende alterar o valor de apenas um dos bits. Para alterar bits, precisamos de saber matemática binária e recorrer a sistemas numéricos diferentes. Não é impossível lidar apenas com sistema binário, mas poderá tornar-se um quanto complicado, uma vez que os números binários podem tornar-se longos, razão pela qual a maioria das pessoas recorre a números hexadecimais.

Números hexadecimais

No sistema hexadecimal, os números não são apenas 0 e 1 como no sistema binário, ou 0 a 9 no sistema decimal, mas antes de 0 a F. Um número hexadecimal consiste em quatro bits. A tabela ao lado mostra os números binários e os correspondentes hexadecimais. Os números binários são convertidos em hexadecimais lendo os bits ao mesmo tempo, começando pelo de mais baixo nível. Os níveis são lidos da direita para a esquerda e os seus números começam em 0. Por exemplo, o bit de nível mais baixo (nível 0) é 0, e o de nível mais alto é 1. No exemplo anterior, o valor binário do registo é 01100001, o que corresponde a 61 em hexadecimal sendo escrito como 0x61 (zero à esquerda) em C.

Para alterar os bits num número (registo, variável ou noutro local) é necessário realizar operações binárias. As operações binárias é uma operação entre dois números binários, onde cada um dos bits é sujeito à sua operação lógica. Normalmente um microcontrolador suporta quatro operações lógicas, cada qual tendo vários nomes. A secção seguinte descreve as operações lógicas por detrás de cada uma destas operações binárias com um só bit ou com múltiplos bits.

Negação, Multiplicação lógica, Adição lógica and disjunção exclusiva

 

Isto é tudo que precisamos saber para alterar apenas um bit. A teoria per si poderá não ser suficiente, no entanto, pelo que daremos alguns exemplos a seguir.

Definindo um único bit positivo

Definir um único bit como positivo

Para definir apenas um bit num registo para positivo (1) deve ser operada uma adição lógica. Um dos operandos da operação deve ser o registo em conjunto com outro número binário, onde o único bit positivo é aquele que se pretende ver ligado no registo. O número binário é denominado de mascara de bits. Abaixo segue o código em C para a operação em causa:

  // Vamos supor que REG = 0x0F
  REG = REG | 0x11; // primeiro método
  REG |= 0x11;      // segundo método
  // Novo REG = 0x1F

Definindo um único bit negativo

Definir um único bit como baixo

Para definir apenas um bit num registo para negativo (0) deve ser operada uma multiplicação lógica. Um dos operandos da operação deve o registo e outro a mascara de bits, na qual o único bit negativo é o que precisa de ser definido como negativo. A seguir segue o código em C da operação em causa:

  // Vamos supor que REG = 0x0F
  REG = REG & 0xFE; // primeiro método
  REG &= 0xFE;      // segundo método
  // Novo REG = 0x0E

 

Inverter um só bit

Inverter um só bit

Para inverter um ou mais bits num registo é necessário recorrer a uma disjunção exclusiva. Um dos operandos na operação deve ser o registo e outro a mascara de bits, onde o único bit positivo é aquele que precisa de ser invertido no registo. Segue-se o exemplo de código em C:

  // Vamos supor que  REG = 0x0F
  REG = REG ^ 0x11; // primeiro método
  REG ^= 0x11;      // segundo método (usa apenas um por inversão)
  // Novo REG = 0x1E

Invertendo todo o registo

Invertendo todo os bits

Para inverter todos os bits num registo, deve ser usada a negação. Esta operação é unitária, oque significa que recorre apenas um operando. Segue um exemplo de código C para tal operação:

  // Vamos supor que REG = 0x0F
  REG = ~REG;
  // Novo REG = 0xF0

Ler um valor de um único bit

Ler um valor de um único bit

Para ler um ou mais valores de um registo na mesma operação é necessário recorrer a mesma operação para a definição de um bit positivo – multiplicação logica. Um dos operandos deverá ser o registo e o outro a mascara de bits, onde o único bit positivo é aquele que precisa de ser lido do registo. A seguir apresenta-se um exemplo de código em C para realizar esta operação:

  // Vamos supor REG = 0x0F
  unsigned char x = REG & 0x01;
  // Novo x = 0x01

 

Deslocar um bit

Algumas linguagens de programação tem na verdade umas quantas operações de bits, que tornam mais fácil a programação. Entre estas encontram-se as operações de deslocamento de bits as quais deslocam os bits da esquerda para a direita no seio de um número binário. A maior vantagem das operações de deslocamento no seio de registos é a sua habilidade para converter níveis de bits em mascaras de bits e vice-versa. A imagem na direita mostra uma operação de deslocamento à esquerda. No entanto o deslocamento de bits não é uma operação lógica e não tem símbolo correspondente, sendo identificada em C por «”. O deslocamento à esquerda é usado para transformar um nível de bits numa mascara de bits. Por exemplo, para obter a mascara do 6º bit (NB! Nível 5), o numero 1 tem que ser deslocado à esquerda 5 vezes. Segue-se um exemplo da operação em C:

Deslocar à esquerda

A imagem na direita mostra uma operação de deslocamento à esquerda. No entanto o deslocamento de bits não é uma operação lógica e não tem símbolo correspondente, sendo identificada em C por «”. O deslocamento à esquerda é usado para transformar um nível de bits numa mascara de bits. Por exemplo, para obter a mascara do 6º bit (NB! Nível 5), o numero 1 tem que ser deslocado à esquerda 5 vezes. Segue-se um exemplo da operação em C:

REG = 0x01 << 5;
// Novo REG = 0x20
Deslocar à direita

A operação de deslocamento à direita funciona de forma semelhante ao deslocamento à esquerda. É representada em C como “»”. O deslocamento à direita é usado para obter um valor lógico de um único bit. Vamos supor que o bit a ser lido não é o de mais baixo nível, mas por exemplo de nível 5. Neste caso, o resultado poderá ser tanto 0x20 como 0x00, mas por vezes o resultado 1 ou 0 é necessário o que implica deslocamento à direita. Segue-se um exemplo de código em C para o efeito:

// Vamos supor que REG = 0x20
unsigned char x = REG >> 5;
// Novo x = 0x01 (or simply 1)

Se um bit for deslocado à direita de uma posição mais baixa ou à esquerda a partir de uma posição mais alta através a operação de deslocamento de bits, este desaparece. Algumas linguagens de programação incluem operações de rotação de bits, nas quais os bits não desaparecem, mas movem-se da posição mais baixa para a mais alta e vice-versa. Em C não existem tais operações, mas o programador poderá desenvolve-las. Todas as operações com bits funcionam com bits bem como com variáveis e constantes.

Registos AVR

Para na realidade fazer algo nos registos do microcontrolador AVR, precisamos de saber como usar esse microcontrolador em particular. Cada microcontrolador vem dotado de vários folhas de dados (datasheets), as quais descrevem toda a estrutura e funcionalidades do microcontrolador. A folha de dados também escreve os registos. A seguir analisamos um exemplo da descrição dos registos de um microcontrolador AVR.

Um dos registos AVRs a partir da folha de dados

A imagem mostra o registo UCSRnA do microcontrolador ATmega128, nomenclatura que significa “USART Control and Status Register A”. O registo é usado para configurar o modulo do AVR denominado USART e ler os seus estados. Todos os nomes dos registos do AVR são identificados por caracteres em maiúsculas, mas como poderá verificar, os nomes de registo incluem também algumas letras minúsculas. Uma letra minúscula é usada para denotar o índex do modulo. Uma vez que o ATmega128 tem 2 módulos muito semelhantes, e para evitar descreve-los duas vezes, sendo descritos apenas uma vez devendo neste caso o n ser lido como 0 ou 1. Neste sentido, o ATmega128 tem dois registos UCSR0A e UCSR1A.

O conceito de registo e marcada por uma caixa de 8 retângulos com uma linha espessa a sua volta. Cada retângulo representa um bit. Os níveis dos bits são identificados por debaixo do retângulo – aumentando o numero da direita para a esquerda. Uma vez que o AVR é um microcontrolador de 8 bits, a maioria dos registos também o são. Existem no entanto algumas exceções, alguns registos de 16 bits, mas estes na verdade consistem em dois registos de 8 bits. Tal como cada registo é identificado por um nome, cada bit num registo é identificado por um nome – tal como os botões no equipamento de cassetes. Cada bit descrito na folha de dados. Os nomes de bits também são abreviações devendo o n mais baixo ser substituído pelo índice do modulo, tal como no nome dos registos. Alguns registos não usam todos os 8 bits, caso em que o retângulo de tal bit é identificado por um hífen.

Debaixo dos bits do registo existem duas linhas, que identificam se o bit é possível de ler (R), possível de escrever (W), ou ambos (R/W). Por exemplo, os estados dos bits não podem ser reescritos e mesmo que tal seja tentado num programa, o bit continuara inalterado. Se o bit estiver identificado como possível de escrever (W), a sua leitura resultará sempre num valor especificado na folha de dados. A segunda linha especifica o valor por defeito do bit, o qual é assumido sempre que o microcontrolador é reiniciado.

Enquanto que os registos AVR apontam para espaços de memória reais, os nomes de bits identificam o número de nível do bit correspondente. Pelo que é necessário transformar os nomes em mascaras de bits recorrendo a uma operação de deslocamento, de forma a manipular os bits do registo. O código seguinte demonstra um exemplo que atua sobre o registo do modulo USART 0.

  // Define bit TXC0 como alto
  UCSR0A |= (1 << TXC0);
 
  // Define o bit U2X0 como baixo 
  UCSR0A &= ~(1 << U2X0);
 
  // Lê o valor da mascara de bits UDRE0 
  unsigned char u = (UCSR0A & (1 << UDRE0));
 
  // Neste ponto o valor de u é tanto 0 como 32
  // o que permite usa-lo na operação lógica
  if (u)
  {
     // Inverte o bit MPCM0
     UCSR0A ^= (1 << MPCM0);
  }
 
  // Por vezes é necessário adequirir um valor especifico de 0 ou 1
  // pelo que a leitura do bit deve ser deslocada para a direita
  u >>= UDRE0;
 
  // Agora o valor de u é 0 ou 1