Bits em Linguagem C - Conceito e Aplicação

bits

O domínio de operações com bits é essencial quando se está trabalhando em programação de microcontroladores. Sempre será necessário usar bits para a configuração de registradores, configuração de funções específicas e também para leitura de status para tomada de decisão. Quando se trabalha com a linguagem Assembly essas operações são mais naturais, já que existem operações diretas para isso. Por outro lado a linguagem C também trás a facilidade de acesso aos registradores e manipulação de bits através dos operadores lógicos bit a bit. Neste artigo iremos abordar o uso de bits em Linguagem C e as principais operações lógicas em linguagem C.

 

 

Operações lógicas para usar bits em Linguagem C

 

Antes de conhecer os operadores binários da Linguagem C, vamos relembrar as operações lógicas em sistemas digitais. Thiago Lima apresentou um excelente resumo sobre portas lógicas e vamos usar o seu artigo como referência.

 

Lógica Não (NOT)

 

Inverte o estado do bit.

 

Tabela verdade:

 bits-not

 

Lógica E (AND)

 

A saída será igual a 1 somente se todos os bits de entrada forem iguais a 1. Se pelo menos um dos bits for 0, a saída será 0.

 

Tabela verdade:

 bits-and

 

Lógica OU (OR)

 

A saída assumirá nível lógico 1 se pelo menos 1 bit de entrada for igual a 1. Somente assumirá nível lógico 0 se todas as entradas apresentarem nível lógico 0.

 

Tabela verdade:

 bits-or

 

Lógica Ou-Exclusivo (XOR)

 

A saída será igual a 0 se as entradas forem iguais. Caso as entradas forem diferentes a saída assumirá o valor 1.

 

Tabela verdade:

 bits-XOR

 

 

Operadores binários em linguagem C

 

A linguagem C apresenta uma grande variedade de operadores. A seguir são apresentados os operadores para operações binarias, bit a bit:

 

Operador

Função

&

E (AND)

|

OU (OR)

^

OU-EXCLUSIVO (XOR)

~

NOT ou Complemento de 1

<<

Deslocamento à esquerda

>>

Deslocamento à direita

 

Os operadores &, |, ^ e ~ funcionam como apresentado anteriormente e têm as saidas conforme exibidos em suas tabelas verdades. Os operadores de deslocamento fazem o shift de bits para esquerda ou direita.

 

Exemplo:

 

Vamos assumir que x incialmente tenha o valor 0b00000001, valor 1 em decimal.

 

 

Após a operação acima,  será atribuido a x o valor 0b000000100, valor 4 em decimal.

 

Se em seguida realizarmos uma operação de deslocamento à direita:

 

 

Após essa operação será atribuído à variável x o valor 0b00000010, valor 2 em decimal.

 

Note que a operação de deslocamento à esquerda multiplica por dois a cada shift. Já o deslocamento à direita, divide por dois a cada shift. Dessa forma pode-se também utilizar esses operadores para multiplicação ou divisão por 2, sendo mais eficiente que utilizando o operador de multiplicação.

 

 

Usando máscara de bits

 

Para manipulação dos bits utilizam-se máscaras de bits que possibilitam a alteração ou leitura de bits específicos sem a alteração de outros. A seguir são exibidas algumas operações.

 

Ativando um bit

 

Para ativar um bit especifico de uma variável ou registrador, ou seja, colocar nível lógico 1, utiliza-se o operador |(OU). Por exemplo, desejamos colocar em nivel 1 o bit 5 do PORTB, no ATmega328. Para isso fazemos a seguinte operação:

 

 

 

X

X

X

X

X

X

X

X

                      -> valor presente no registrador PORTB

|

0

0

1

0

0

0

0

0

                       -> máscara para alteração do bit 5
 

X

X

1

X

X

X

X

X

                        -> resultado, apenas o bit 5 é alterado

 

Para facilidade na criação da máscara, utiliza-se o operador de deslocamento à esquerda, ficando da seguinte forma:

 

 

Será feita a lógica OU com o byte criado na operação (1<<5), que deslocou o valor '1' 5 vezes para a esquerda.

 

A operação pode ser simplificada, ficando da seguinte forma:

 

 

Limpando um bit

 

Para limpar um bit específico de uma variável ou registrador, ou seja, colocar nível lógico 0, utiliza-se o operador & (AND). Vamos utilizar o mesmo registrador e bit utilizado no exemplo anterior como exemplo:

 

 

 

X

X

X

X

X

X

X

X

                                 -> valor presente no registrador PORTB

&

1

1

0

1

1

1

1

1

                                 -> máscara para alteração do bit 5
 

X

X

0

X

X

X

X

X

                                 -> resultado, apenas o bit 5 é alterado

 

Usando o operador de deslocamento ficará da seguinte forma:

 

 

Note que é necessário inverter os valores para a máscara ficar da forma desejada.

 

A operação pode ser simplificada, ficando da seguinte forma:

 

 

Invertendo o estado de um bit

 

Para inverter o estado lógico de um bit utiliza-se o operador ^ (OU-Exclusivo). Continuamos com o mesmo bit e registrador dos exemplos anteriores:

 

 

 

X

X

1

X

X

X

X

X

                            -> valor presente no registrador PORTB

^

0

0

1

0

0

0

0

0

                            -> máscara para alteração do bit 5
 

X

X

0

X

X

X

X

X

                            -> resultado, o bit 5 é invertido

 

Usando o operador de deslocamento ficará da seguinte forma:

 

 

A operação pode ser simplificada, ficando da seguinte forma:

 

 

Testando valor de um bit

 

Para teste de um bit também utilizaremos a lógica & (AND) para operação com a máscara de bits. Por exemplo, temos uma tecla ligada ao pino 2 do PORTD do Atmega328. Para leitura desse pino utilizamos o registrador PIND. A operação ficará da seguinte forma:

 

 

 

X

X

X

X

X

T

X

X

                                -> valor presente no registrador PIND

&

0

0

0

0

0

1

0

0

                                -> máscara para alteração do bit 2
 

0

0

0

0

0

T

0

0

                                 -> resultado, o valor do bit estará presente no resultado

 

Caso o bit de teste tenha o valor 1, o resultado conterá o valor 1 somente na posição do bit, caso contrário o resultado será 0.

 

Esta operação pode ser usada em uma estrutura de descição if, por exemplo:

 

 

 

Criando Macros

 

Fernando Deluno Garcia apresentou uma excelente série sobre o Pré-Processador C. Utilizando seus atigos como referência, vamos criar algumas macros para manipulação de bits utilizando as operações apresentadas.

 

  • set bit

 

  • clear bit

 

  • toogle bit

 

  • teste bit

 

 

Exemplo de aplicação

 

O exemplo a seguir exibe o uso das macros apresentadas para manipulação de bits no Atmega328P. Foi utilizada a IDE Arduino, para que você possa facilmente testar, utilizando a placa Arduino UNO.

 

 

Podemos também usar a compilação condicional, conforme apresentada no artigo Pré-processador C: Compilação condicional, escrito por Fernando Deluno Garcia, e testar o tamanho de código gerado, usando macros e as funções do Arduino:

 

 

Compile nas duas condições e verifique o tamanho do código gerado em cada uma delas. Note que o código gerado utilizando macros é bem menor do que quando utilizando as funções Arduino.

 

As macros utilizadas acimas podem ser aplicadas em diversas plataformas e facilitam em operações com bits.

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.

Fábio Souza
Engenheiro com experiência no desenvolvimento de projetos eletrônicos embarcados. Hoje é diretor de operações do portal Embarcados, onde trabalha para levar conteúdos de eletrônica, sistemas embarcados e IoT para o Brasil. Também atua no ensino eletrônica e programação pelo Brasil. É entusiastas do movimento maker, da cultura DIY e do compartilhamento de conhecimento, publica diversos artigos sobre eletrônica e projetos open hardware, como o projeto Franzininho Participou da residência hacker 2018 no Redbull Basement. Quando não está ministrando palestras, cursos ou workshops, dedica seu tempo “escovando bits” ou projetando placas eletrônicas.

10
Deixe um comentário

avatar
 
5 Comment threads
5 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
6 Comment authors
Ivanizio RamalhoRafael DiasHumberto Trindade da SilvaphfbertoletiFabio_Souza_Embarcados Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Rui Conti
Visitante
Rui Conti

Ótimo artigo, Fábio. Apenas apontando uma correção: na parte onde você explica a leitura dos bits, fala-se no texto da leitura do 2º bit mas no código lê-se o 4º. No mais, parabéns!

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Olá Rui, muito obrigado pela correção. Abraços

Ivanizio Ramalho
Visitante
Ivanizio Ramalho

Olá Fábio, uma didática excelente, parabéns!

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Muito obrigado Ivanizio. Muito bom ler isso!

Se tiver alguma sugestão para artigos, deixe comentário.

Abraços

Rafael Dias
Visitante
Rafael Dias

outro ponto interessante também é a utilização de bit-fields para a realização destas operações de manipulação de bits. É uma operação que, dependendo do compilador e da arquitetura, pode deixar a desejar se comparado a manipulação dos bits através de máscaras e operações de deslocamento.

Muito legal o seu artigo, Fabio. Parabéns!

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

ótima observação Rafael, realmente são muito utilizados.

Valeu.

Humberto Trindade da Silva
Visitante
Humberto Trindade

Excelente artigo!! Parabéns!

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Olá Humberto, muito obrigado!
Abraços

phfbertoleti
Visitante
phfbertoleti

Muito bom!

Fabio_Souza_Embarcados
Visitante
Fabio_Souza_Embarcados

Valeu Pedrão. Abraços