Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial Internet of Things >> Integrado

Uniões em C Embarcado Explicadas: Compartilhamento Eficiente de Memória e Mensagens

Entendendo Uniões em C Embarcado

Em sistemas embarcados, uma união é uma poderosa estrutura de dados que permite armazenar diferentes tipos de dados na mesma localização de memória. Este artigo percorre os fundamentos das uniões, mostra exemplos práticos e explica por que são uma ferramenta essencial para aplicações com restrição de memória e sensíveis a largura de banda.

A Diferença entre Estrutura e União em C Embarcado

Anteriormente, cobrimos estruturas: uma forma de agrupar variáveis heterogêneas em uma única entidade. Em C, uniões são um construto complementar que também agrupa diferentes tipos, mas com uma distinção chave – cada membro compartilha o mesmo endereço de memória.

Exemplo Introdutório

Declarar uma união é quase idêntico a declarar uma estrutura; você simplesmente substitui struct por union:

union test { uint8_t c; uint32_t i; };

O modelo define dois membros: c ocupa um byte, e i ocupa quatro bytes. Para criar uma variável deste tipo:

union test u1;

Acessar membros usa o operador ponto:

u1.i = 10; m = u1.c; // m deve ser uint8_t

Como o tamanho de armazenamento de uma união iguala o tamanho de seu maior membro, u1 ocupa quatro bytes. Escrever em i sobrescreve a mesma memória que c usaria, então os dois membros são mutuamente exclusivos.

Precisamos de Espaço de Memória Compartilhado?

Imagine dois dispositivos embarcados, Dispositivo A e Dispositivo B, que trocam dados de status, velocidade e posição (veja Figura 1). Os itens de dados e seus tamanhos são:

Uniões em C Embarcado Explicadas: Compartilhamento Eficiente de Memória e Mensagens

Figura 1
Variável Tamanho (bytes) Significado
power 1 Carga da bateria
op_mode 1 Modo de operação
temp 1 Temperatura ambiente
x_pos 2 Coordenada X
y_pos 2 Coordenada Y
vel 2 Velocidade

Se o Dispositivo B exigir cada pedaço de informação, uma estrutura simples precisaria de nove bytes, e cada rodada de comunicação transferiria um frame de 9 bytes (veja Figura 2). No entanto, em muitos cenários reais, os três tipos de mensagem são mutuamente exclusivos: às vezes apenas status, às vezes apenas posição, às vezes apenas velocidade. Nesse caso, a maior carga útil é de quatro bytes (a mensagem de posição). Uma união que compartilha um buffer de quatro bytes pode conter qualquer uma das três mensagens, reduzindo o tamanho do frame de nove para quatro bytes (veja Figura 3).

Uniões em C Embarcado Explicadas: Compartilhamento Eficiente de Memória e Mensagens

Figura 2

Uniões em C Embarcado Explicadas: Compartilhamento Eficiente de Memória e Mensagens

Figura 3

Usando Uniões para Pacotes de Mensagem

Abaixo criamos duas estruturas – uma para status e outra para posição – e as incorporamos em uma união junto com o campo de velocidade:

struct status_s { uint8_t power; uint8_t op_mode; uint8_t temp; }; struct position_s { uint16_t x_pos; uint16_t y_pos; }; union msg_union { struct status_s status; struct position_s position; uint16_t vel; };

O tamanho da união é de quatro bytes (o tamanho de position_s), que é compartilhado entre todos os três tipos de mensagem.

Como Rastrear o Membro Ativo da União

Quando um receptor lê uma união, ele deve saber qual membro é válido. O padrão comum é uma união marcada: um campo separado que registra o membro ativo. Podemos adicionar um byte msg_type antes da união:

struct message_s { uint8_t msg_type; // 's' = status, 'p' = position, 'v' = velocity union { struct status_s status; struct position_s position; uint16_t vel; } msg; };

Ao transmitir o byte msg_type junto com a união, o destinatário pode interpretar corretamente a carga útil sem conhecimento prévio de sua forma.

A Solução Alternativa: Alocação Dinâmica de Memória

Outra abordagem é alocar memória dinamicamente para cada tipo de mensagem. O transmissor definiria msg_type e alocaria apenas bytes suficientes para aquela carga útil. O receptor então interpretaria os dados recebidos com base em msg_type e liberaria a memória quando terminado. Embora isso possa ser ligeiramente mais eficiente em memória, alocação dinâmica introduz sobrecarga de tempo de execução e a necessidade de desalocação explícita, razão pela qual muitos desenvolvedores embarcados preferem a estratégia de união estática.

Próximo: Aplicações de Uniões

Uniões também são frequentemente usadas para extrair pedaços menores de dados de uma palavra maior – uma técnica especialmente valiosa ao analisar protocolos de comunicação ou registradores de hardware. Fique atento para o próximo artigo desta série, onde mergulhamos nesses casos de uso.

Para explorar mais artigos sobre C embarcado, visite o índice de artigos.

Integrado

  1. Escolhendo a Linguagem de Programação Ideal para Soluções de IIoT Industrial
  2. Fundamentos de Programação de Microprocessadores
  3. Aproveitando Dados na Internet da Confiabilidade: Estratégias para Gestão Eficaz
  4. Democratizando a Internet das Coisas: IoT Satélite de Próxima Geração Traz Conectividade Universal e Acessível
  5. Descubra as 9 Linguagens de Programação Imperdíveis de 2021
  6. Uniões em C Explicadas: Gerenciamento Eficiente de Memória para Múltiplos Tipos de Dados
  7. O Futuro dos Data Centers: Tendências, Tecnologia e Sustentabilidade
  8. Aproveitando o Poder da Nuvem para IoT: Desbloqueando Conectividade Perfeita e Insights de Dados
  9. Entendendo a Programação de Robôs: Métodos Explicados
  10. Unidades de Medida de Compressores: Guia Claro dos Termos Comuns