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, especialista em sistemas 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. É entusiastas do movimento maker, da cultura DIY e do compartilhamento de conhecimento, publica diversos artigos sobre eletrônica e projetos open hardware. Com iniciativas como o projeto Franzininho e projetos na área de educação, leva a cultura maker para o Brasil capacitando e incentivando professores e alunos a usarem tecnologia em suas vidas. Participou da residência hacker 2018 no Red Bull Basement.

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