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

Dicas de firmware incorporado:como inicializar matrizes em C com formas de onda de sinal e outros dados de arquivo

Este artigo mostra como inicializar matrizes em um programa C com valores de arquivos de texto.


Este artigo mostra como inicializar matrizes em um programa C com valores de arquivos de texto. Os dados não são armazenados nos arquivos de origem. Os arquivos são lidos quando o programa é compilado. Matrizes unidimensionais e multidimensionais são consideradas. Os exemplos também mostram como controlar a colocação de matrizes na RAM ou memória não volátil e selecionar quais arquivos de dados usar para inicialização.

O compilador usado para os exemplos é o GCC para ARM com um microcontrolador de 32 bits como destino. Todos os exemplos usam C padrão e funcionaram com este compilador.


Noções básicas de inicialização de uma matriz


Um array pode ser inicializado com valores quando é “declarado”. Uma declaração típica é mostrada aqui. Os valores entre chaves são chamados de “inicializadores”.




Se o tamanho do array não for especificado entre colchetes, o tamanho será o número de inicializadores. Se houver menos inicializadores do que o tamanho da matriz, os elementos extras serão definidos como 0. É um erro ter mais inicializadores do que o tamanho da matriz.


Espaço em branco


Os inicializadores devem ser separados por vírgulas. Adicionar “espaço em branco” está OK. Neste caso, o espaço em branco é “em branco” ou espaços. O conjunto de caracteres de espaço em branco inclui em branco (ou espaço), tabulação, nova linha, retorno de carro, tabulação vertical e avanço de formulário. Nova linha e retorno de carro são usados ​​para indicar o final de uma linha no código-fonte C. Eu conheço o formulário feed, mas a guia vertical?

Em geral, C não se importa se uma instrução contém espaço em branco ou continua em outra linha. A declaração aqui é equivalente à acima. É comum ver muitas, muitas linhas de inicializadores para grandes arrays. Talvez até páginas. Em algum ponto, podemos dizer:“Existe uma maneira melhor?”





Inicializando uma matriz a partir de um arquivo


O código-fonte C é executado por meio de um pré-processador antes da compilação. Um recurso comumente usado dos pré-processadores C é a “inclusão de arquivo”. Aqui está uma citação do famoso livro “The C Programming Language” de Kernighan e Ritchie.

“A inclusão de arquivos facilita o manuseio de coleções de #defines e declarações ( entre outras coisas ). ”

Eu adicionei o itálico para “entre outras coisas”. Embora geralmente incluamos arquivos “.c” e “.h”, o pré-processador não se preocupa com a extensão do nome de um arquivo. Qualquer arquivo de texto está OK. Portanto, a seguinte sintaxe funciona para inicializar um array.






O arquivo não deve conter nenhum caractere especial que às vezes fica oculto para a formatação de um documento. Mantenha simples. Sem formato de rich text. Sem cabeçalhos de coluna. Apenas números, vírgulas e espaços em branco. Aqui está um arquivo criado com o bloco de notas do Windows.






Aqui está a matriz na memória mostrada com um depurador. Nesse caso, a matriz está na RAM conforme indicado pelos endereços altos na coluna Localização.





Armazenamento de uma matriz em memória não volátil e seleção de um arquivo de dados


No exemplo acima, a matriz é uma variável global e nada especifica onde colocar a matriz. O compilador e o vinculador assumem que a matriz pode ser modificada pelo programa e colocada na RAM. Os valores iniciais estão na memória não volátil (“NVM”, normalmente memória Flash), e a matriz na RAM é inicializada a partir desses dados por um código que é executado antes do programa principal. Esses dados em NVM não são acessados ​​pelo programa. Se o array não for modificado (é uma “constante”), ele é colocado apenas no NVM e acessado diretamente pelo programa. Isso economiza RAM, que geralmente é insuficiente. Dizer ao compilador e ao linker que uma matriz não será alterada e localizá-la no NVM é normalmente feito com o “ const " qualificador. Aqui está um exemplo e uma olhada no resultado. A coluna Location mostra-o baixo no mapa de memória, que para este microcontrolador é a memória Flash.




O #define e #if instruções de pré-processamento podem ser usadas para fornecer opções para localizar a matriz e selecionar quais arquivos de dados são usados ​​para inicialização. Aqui está um exemplo que oferece a opção de localizar uma matriz na RAM ou NVM.




O #if construção é um exemplo de “inclusão condicional”. Neste caso, ele controla se o “ const ”Qualificador é usado ao declarar a matriz. Funciona porque a declaração pode estar em mais de uma linha ou, dito de outra forma, espaço em branco está OK.



Aqui está um exemplo de como usar a inclusão condicional para selecionar o arquivo para inicialização.





Testando com uma grande matriz


Eu tinha um grande arquivo de dados aleatórios representando uma forma de onda de ruído e usei-o para testar a inicialização de um grande array em NVM. Aqui está um gráfico dos dados e da declaração.







Aqui está o início do arquivo.




O arquivo csv original não tinha vírgula após os valores. Eles foram facilmente adicionados usando um editor que pode usar expressões em operações de Localizar / Substituir. Neste caso, usei a expressão para um delimitador de linha, “\ R”. O Find foi “\ R” e o Replace foi “, \ R”. Uma operação Localizar / Substituir adicionou todas as vírgulas para 10.000 valores.



Tudo funcionou muito bem e compilado muito rápido! Aqui está o início da matriz na memória. O depurador dividiu bem a exibição em grupos de 100 elementos cada.





Matrizes multidimensionais


E se os dados forem organizados em duas ou mais dimensões? Vejamos uma matriz bidimensional declarada como uint16_t test [2] [3] . Em C, o subscrito à direita (3) é um array unidimensional com elementos contíguos na memória. O subscrito à esquerda (2) significa que há duas dessas matrizes de três elementos. Este é o arranjo de memória dos seis elementos:



[0,0] [0,1] [0,2] [1,0] [1,1] [1,2]



A ordenação na memória é importante porque acessar elementos consecutivos na memória incrementando o subscrito direito é mais rápido do que acessar elementos incrementando o subscrito esquerdo, o que requer “saltos” através da memória. Se a matriz continha dois vetores de 1.000 elementos, a organização deve ser test [2] [1000] para o acesso mais rápido.



Aqui está um exemplo de inicialização de uma matriz bidimensional. Observe que os inicializadores são agrupados com chaves adicionais agrupando os inicializadores para os arrays unidimensionais do subscrito direito.




Este formato cria um problema para um arquivo de dados que pode conter apenas números, vírgulas e espaços em branco. O que acontece se as chaves adicionais forem omitidas?




O compilador preenche a matriz indo da esquerda para a direita pelos inicializadores com o subscrito à direita preenchendo primeiro. O compilador que estou usando dá um aviso:“ faltando colchetes no inicializador ”. Não há problema se o número de inicializadores for exatamente o mesmo que o número de elementos no array. No entanto, se não for igual, não está claro como preencher a matriz se não houver chaves para atuar como guias.



A matriz pode ser preenchida a partir de vários arquivos com vários #include afirmações. Aqui está um exemplo onde a inicialização está completamente entre colchetes com pares de chaves. Eu deixo de fora os detalhes mostrados nos exemplos anteriores.





Inicializando matrizes em uniões


Uma união é uma variável que pode conter objetos de diferentes tipos que compartilham a mesma memória e o compilador mantém o controle dos objetos como se fossem coisas diferentes. Esse arranjo pode ser útil para um aplicativo embutido com pouca memória. Aqui está um exemplo com vetor [6] com uma dimensão e matriz [2] [3] com duas dimensões. Eles são duas matrizes que ocupam os mesmos locais na memória.




A regra para inicializar uma união é a primeira coisa na união ( vetor [6] ) é preenchido com os inicializadores. Se a ordem das matrizes foi invertida, o compilador dá um aviso porque os inicializadores não estão completamente entre colchetes. Observe as chaves ao redor de #include são duplicados. Acho que o conjunto externo inclui todos os inicializadores para a união e o conjunto interno é para um tipo de matriz.



Aqui está o arquivo. Eu tenho duas linhas, mas não importa. Apenas mais espaço em branco.




Aqui está a matriz na memória. Observe a localização inicial do vetor [] e matriz [] [] são os mesmos.




Existem outras maneiras de inicializar matrizes multidimensionais de um único arquivo com apenas números, vírgulas e espaço em branco? Por favor, diga-nos adicionando um comentário.


Dica bônus:cordas


E quanto a cordas? Aqui está um exemplo de inicialização de uma string.




Um #include entre aspas não funciona. Meu editor, que conhece a sintaxe C, me dá muitos pontos de interrogação e sublinhados irregulares. Caracteres para as novas linhas e o #include em si são inicializadores! O pobre editor está confuso. Esta bagunça compila, mas a string é preenchida com os caracteres que vemos aqui e não do arquivo.




A solução é colocar aspas no arquivo.




Em seguida, use uma declaração como esta.




Observe que as aspas ao redor do nome do arquivo fazem parte do #include sintaxe e não controlam inicializadores. Aqui está o resultado em RAM.








É importante observar que todos os exemplos devem funcionar em teoria com qualquer compilador. No entanto, alguns exemplos podem ser incomuns e podem causar problemas com alguns compiladores. Por favor, deixe-nos saber nos comentários se você encontrar um problema.

Integrado

  1. Nuvem e como ela está mudando o mundo da TI
  2. ST conduz AI para dispositivos embarcados de borda e nó com caixa de ferramentas de desenvolvedor de rede neural STM32
  3. MÓDULO DE DADOS:monitores de grande porte com alto brilho e função easyTouch
  4. Microchip:ADCs de 24 e 16 bits com taxas de dados de até 153,6 kSPS
  5. Contrinex:sensores inteligentes prontos para a nuvem e cortinas de luz de segurança com interface Bluetooth
  6. Matrizes em C++ | Declare | Inicializar | Ponteiro para exemplos de matriz
  7. Alocação dinâmica de matrizes em C++ com exemplo
  8. Java BufferedReader:Como Ler Arquivo em Java com Exemplo
  9. Como tornar IOT real com Tech Data e IBM Parte 2
  10. Como tornar a IoT real com Tech Data e IBM Parte 1