Olá, como estão? A princípio iremos falar sobre otimização e organização de memória, assim diminuindo o consumo de FLASH(memória estática) e SRAM (memória dinâmica) do seu projeto. Assim obtendo um melhor desempenho em seu microcontrolador. Entretanto para este projeto usaremos o KIT básico com Arduíno da WJ Componentes.
Componentes Utilizados
OU
Funcionamento do Projeto de Otimização
Como foi comentado anteriormente hoje iremos explicar como otimizar e diminuir o consumo de espaço em FLASH e SRAM. Em seguida iremos apresentar um código-fonte onde iremos otimiza-lo.
Métodos para Otimização
1º Função
Utilizar funções é muito útil para a organização e economia de espaço, portanto, é importante o aprendizado de funções para projetos complexos. A economia de espaço varia conforme o código-fonte. Entretanto, ela sempre irá trazer grande diminuição de espaço utilizado e otimização, se for usado da forma correta. Por exemplo:
Antes da implementação de funções:
//Setup -------------------------------------
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}
//Loop --------------------------------------
void loop() {
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
Serial.println("PISCA LED");
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
Serial.println("PISCA LED NOVAMENTE");
}
Portanto ocupam 2020 bytes (6%) da memória FLASH e 218 (10%) de variáveis globais.
Após a implementação de funções:
//Protótipo de Função ----------------------
void pisca();
//Setup ------------------------------------
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}
//Loop -------------------------------------
void loop() {
pisca();
Serial.println("PISCA LED");
pisca();
Serial.println("PISCA LED NOVAMENTE");
}
//Pisca LED --------------------------------
void pisca(){
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
}
Portanto ocupam 2008 bytes (6%) da memória FLASH e 218 (10%) de variáveis globais.
2º NÃO UTILIZAR VARIÁVEL GLOBAL
Embora a maioria dos programadores e código-fonte usarem variáveis globais. Não é uma boa prática o uso dela, pois, elas ficam armazenadas “eternamente” na memória SRAM. Porém, quando declaramos uma variável local (dentro de uma função), assim que saímos daquela função ela será liberada (variáveis simples). Por exemplo:
Utilizando variável global:
//Variáveis Globais -------------------------
int tempo = 1000;
//Setup -------------------------------------
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}
//Loop --------------------------------------
void loop() {
digitalWrite(13, HIGH);
delay(tempo);
digitalWrite(13, LOW);
Serial.println("PISCA LED");
digitalWrite(13, HIGH);
delay(tempo);
digitalWrite(13, LOW);
Serial.println("PISCA LED NOVAMENTE");
}
Portanto ocupam 2048 bytes (6%) da memória FLASH e 218 bytes (10%) de variáveis globais.
Utilizando variável local:
//Setup -------------------------------------
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}
//Loop --------------------------------------
void loop() {
int tempo = 100;
digitalWrite(13, HIGH);
delay(tempo);
digitalWrite(13, LOW);
Serial.println("PISCA LED");
digitalWrite(13, HIGH);
delay(tempo);
digitalWrite(13, LOW);
Serial.println("PISCA LED NOVAMENTE");
}
Portanto ocupam 2020 bytes (6%) da memória FLASH e 218 bytes (10%) de variáveis globais.
3º Macro F() e PROGMEM
Conforme utilizamos esses modificadores em nosso projeto, estamos armazenando as informações na memória FLASH ao invés da memória SRAM. Entretanto, ela só podem ser inseridas em dados estáticos. Ou seja, não podemos alterar os dados contidos nas variáveis que utilizam os modificadores macro F() ou PROGMEM durante a execução do código-fonte, é possível somente estar realizando a leitura dos dados contidos nelas.
Sem macro F() e PROGMEM:
//Variáveis Globais ------------------------
const char text[] = "Vou ocupar memoria em SRAM";
//Setup ------------------------------------
void setup() {
Serial.begin(9600);
}
//Loop -------------------------------------
void loop() {
Serial.println("Vou ocupar memoria em SRAM");
Serial.println(text);
}
Portanto ocupam 1560 bytes (4%) da memória FLASH e 248 bytes (12%) de variáveis globais.
Com macro F() e PROGMEM:
//Variáveis Globais ------------------------
const PROGMEM char text[] = "Vou ocupar memoria a FLASH";
//Setup ------------------------------------
void setup() {
Serial.begin(9600);
}
//Loop -------------------------------------
void loop() {
Serial.println(F("Vou ocupar memoria a FLASH"));
Serial.println(text);
}
Portanto ocupam 1580 bytes (4%) da memória FLASH e 188 bytes (9%) de variáveis globais.
4º Tipo de Dados
Existem diversos tipos de dados, cada uma delas ocupam um número de espaço em memória pré-determinado, assim podemos diminuir o espaço ocupado por elas utilizando o tipo de dado correto. Por isso segue tabela com todos os tipos de dados.
Tipo de Dados: | Tamanho em Bytes: | Pode Conter: |
---|---|---|
void | 0 | Nada (NULL) |
bool | 1 | True (1) ou False (0) |
char | 1 | Caracteres da tabela ASCII ou valor entre -128 e 127 |
usingned char, byte e uint8_t | 1 | Caracteres da tabela ASCII ou valor entre 0 e 255 |
short e int16_t | 2 | Valor entre -32.768 e 32.767 |
word e uint16_t | 2 | Valor entre 0 e 65.535 |
int | 2 ou 4 (Due, Zero e MKR1000) | Valor entre -32.768 e 32.767 ou -2.147.483.648 e 2.147.483.647 |
usingned int | 2 ou 4 (Due, Zero e MKR1000) | Valor entre 0 e 65.535 ou 0 e 4.294.967.295 |
long e int32_t | 4 | Valor entre -2.147.483.648 e 2.147.483.647 |
usingned long e uint32_t | 4 | Valor entre 0 e 4.294.967.295 |
float | 4 | 6 a 7 dígitos de precisão |
double | 4 ou 8 (Due, Zero e MKR1000) | 6 a 7 dígitos de precisão ou 12 a 14 dígitos de precisão |
Outra boa prática pouco adotada que ajuda a otimizar e desenvolver um código-fonte multiplataforma, é utilizar o tipo de dado int16_t ao invés de int, para que assim possamos ter certeza de que estamos ocupando 2 bytes de memória. Assim também para int8_t e int32_t.
Seleção de tipos errada:
//Variáveis Globais -----------------------
int led = 13;
//Setup ------------------------------------
void setup() {
pinMode(led, OUTPUT);
}
//Loop -------------------------------------
void loop() {
long int tempo = 60000;
digitalWrite(led, HIGH);
delayMicroseconds(tempo);
digitalWrite(led, LOW);
}
Portanto ocupam 758 bytes (2%) da memória FLASH e 9 bytes (0%) de variáveis globais.
Seleção de tipos corretos:
//Definições ------------------------------
#define led 13
//Setup -----------------------------------
void setup() {
pinMode(led, OUTPUT);
}
//Loop ------------------------------------
void loop() {
uint16_t tempo = 60000;
digitalWrite(led, HIGH);
delayMicroseconds(tempo);
digitalWrite(led, LOW);
}
Portanto ocupam 746 bytes (2%) da memória FLASH e 9 bytes (0%) de variáveis globais.
5º Estrutura de Repetições
Utilize as estruturas de repetições para evitar a repetição de algoritmos, assim melhorando o desempenho e diminuindo o tamanho utilizado no código-fonte.
Sem Estrutura de Repetições:
//Setup -----------------------------------
void setup() {
Serial.begin(9600);
}
//Loop -------------------------------------
void loop() {
Serial.println(F("Olá, tudo bem?"));
Serial.println(F("EXEMPLO"));
Serial.println(F("EXEMPLO"));
Serial.println(F("EXEMPLO"));
Serial.println(F("EXEMPLO"));
Serial.println(F("EXEMPLO"));
Serial.println(F("WJ COMPONENTES"));
}
Portanto ocupam 1640 bytes (5%) da memória FLASH e 188 bytes (9%) de variáveis globais.
Com Estrutura de Repetições:
//Setup ------------------------------------
void setup() {
Serial.begin(9600);
}
//Loop -------------------------------------
void loop() {
Serial.println(F("Olá, tudo bem?"));
for(byte i = 0; i<5;i++){
Serial.println(F("EXEMPLO"));
}
Serial.println(F("WJ COMPONENTES"));
}
Portanto ocupam 1608 bytes (4%) da memória FLASH e 188 bytes (9%) de variáveis globais.
Montagem do Projeto de Otimização
Logo após compra dos componentes na WJ Componentes, vamos à montagem! Em seguida conectamos os LEDs na protoboard com os resistores que conectamos nos catodos dos LEDs. Por fim ligamos no anodo dos LEDs os pinos 9, 10, 11, 12 e 13 do Arduíno UNO.
Contudo segue abaixo uma imagem que demonstra a montagem do circuito.
Diagrama Esquemático do Projeto de Otimização
Código-fonte do Projeto de Otimização
Em seguida terá o código completo do projeto.
//Variáveis Globais -------------------------------------------------------------------------------
int led1 = 13, led2 = 12, led3 = 11, led4 = 10, led5 = 9;
byte tempo = 1000;
String text = "Um dia, um cão ia atravessando uma ponte, carregando um osso na boca. Olhando para baixo, viu sua própria imagem refletida na água. Pensando ver outro cão, coçou-lhe logo o osso e pôs-se a latir. Mal, porém, abriu a boca, seu próprio osso caiu na água e se perdeu para sempre.";
//Setup -------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(led5, OUTPUT);
}
//Loop --------------------------------------------------------------------------------------------
void loop() {
digitalWrite(led1, HIGH);
delay(tempo);
digitalWrite(led1, LOW);
delay(tempo);
digitalWrite(led1, HIGH);
delay(tempo);
digitalWrite(led1, LOW);
delay(tempo);
Serial.println(text);
Serial.println("Moral da História: Vale mais um passarinho na mão do que dois voando");
digitalWrite(led2, HIGH);
delay(tempo);
digitalWrite(led2, LOW);
delay(tempo);
digitalWrite(led2, HIGH);
delay(tempo);
digitalWrite(led2, LOW);
delay(tempo);
}
Então no total este código-fonte está ocupando 3868 bytes (11%) de memória FLASH e 560 bytes (27%) de variáveis globais na memória SRAM (dinâmica).
Vamos dar uma olhada mais de perto no código:
1º Etapa
Primeiramente teremos que verificar se conseguiremos adicionar alguma função no nosso código, para assim simplificá-lo. Na função loop possuímos uma estrutura que se repete onde ela é responsável por piscar o LED, podendo assim colocá-la dentro de uma função, porém, na primeira vez executada ele pisca o LED 1, já na segunda vez ele pisca o LED 2. Portanto teremos que passar também para a função qual LED queremos que ele pisque. Ficando da seguinte forma:
//Variáveis Globais ------------------------------------------------------------------------------
int led1 = 13, led2 = 12, led3 = 11, led4 = 10, led5 = 9;
byte tempo = 1000;
String text = "Um dia, um cão ia atravessando uma ponte, carregando um osso na boca. Olhando para baixo, viu sua própria imagem refletida na água. Pensando ver outro cão, coçou-lhe logo o osso e pôs-se a latir. Mal, porém, abriu a boca, seu próprio osso caiu na água e se perdeu para sempre.";
//Protótipo da Função -----------------------------------------------------------------------------
void piscaLed(byte led);
//Setup -------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(led5, OUTPUT);
}
//Loop --------------------------------------------------------------------------------------------
void loop() {
piscaLed(led1);
Serial.println(text);
Serial.println("Moral da História: Vale mais um passarinho na mão do que dois voando");
piscaLed(led2);
}
//Pisca LED ---------------------------------------------------------------------------------------
void piscaLed(byte led){
digitalWrite(led, HIGH);
delay(tempo);
digitalWrite(led, LOW);
delay(tempo);
digitalWrite(led, HIGH);
delay(tempo);
digitalWrite(led, LOW);
delay(tempo);
}
2º Etapa
Com essa alteração código-fonte terminou ocupando mais linhas, porém, isso não quer dizer que estamos consumindo mais espaço, por exemplo, só com essa modificação o código utilizou 3810 bytes (11%) de memória FLASH assim totalizando uma redução de 58 bytes de memória utilizada, já na memória SRAM (dinâmica) de variáveis globais permaneceu igual. Em seguida identificamos onde podemos adicionar estruturas de repetições, para evitar repetição de algoritmo, conseguimos estar colocando duas estruturas de repetição, uma void Setup e outra na função piscaLed.
//Variáveis Globais -------------------------------------------------------------------------------
int led1 = 13, led2 = 12, led3 = 11, led4 = 10, led5 = 9;
byte tempo = 1000;
String text = "Um dia, um cão ia atravessando uma ponte, carregando um osso na boca. Olhando para baixo, viu sua própria imagem refletida na água. Pensando ver outro cão, coçou-lhe logo o osso e pôs-se a latir. Mal, porém, abriu a boca, seu próprio osso caiu na água e se perdeu para sempre.";
//Protótipo da Função ----------------------------------------------------------------------------
void piscaLed(byte led);
//Setup ------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
for(byte i=9;i<=13;i++){
pinMode(i, OUTPUT);
}
}
//Loop --------------------------------------------------------------------------------------------
void loop() {
piscaLed(led1);
Serial.println(text);
Serial.println("Moral da História: Vale mais um passarinho na mão do que dois voando");
piscaLed(led2);
}
//Pisca LED ---------------------------------------------------------------------------------------
void piscaLed(byte led){
for(byte i=0;i<2;i++){
digitalWrite(led, HIGH);
delay(tempo);
digitalWrite(led, LOW);
delay(tempo);
}
}
3º Etapa
Além disso com esta simples modificação a memória FLASH foi para 3790 bytes (11%) totalizando uma redução de 20 bytes de memória utilizada, já na memória SRAM (dinâmica) de variáveis globais permaneceu igual. Então verificamos os tipos de dados das variáveis, nas variáveis dos LEDs estão com o tipo int, porém, para declaração de pinos a melhor seria a define, por não consumir memoria FLASH e nem SRAM. Na variável tempo também está errada, pois, o tipo byte consegue armazenar no máximo 255 e ela está armazenando 1000, então teremos que mudar para tipo const int por ela ser uma constante que não muda durante o programa. Para finalizar na variável text mudamos para char e podemos colocar o modificador PROGMEM para assim armazenar na memória FLASH.
//Definições --------------------------------------------------------------------------------------
#define led1 13
#define led2 12
#define led3 11
#define led4 10
#define led5 09
//Variáveis Globais -------------------------------------------------------------------------------
const int tempo = 1000;
const PROGMEM char text[] = "Um dia, um cão próprio ia atravessando uma ponte, carregando um osso na boca. Olhando para baixo, viu sua imagem refletida na água. Pensando ver outro cão, coçou-lhe logo o osso e pôs-se a latir. Mal, porém, abriu a boca, seu próprio osso caiu na água e se perdeu para sempre.";
//Protótipo da Função -----------------------------------------------------------------------------
void piscaLed(byte led);
//Setup -------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
for(byte i=9;i<=13;i++){
pinMode(i, OUTPUT);
}
}
//Loop --------------------------------------------------------------------------------------------
void loop() {
piscaLed(led1);
Serial.println(text);
Serial.println("Moral da História: Vale mais um passarinho na mão do que dois voando");
piscaLed(led2);
}
//Pisca LED ---------------------------------------------------------------------------------------
void piscaLed(byte led){
for(byte i=0;i<2;i++){
digitalWrite(led, HIGH);
delay(tempo);
digitalWrite(led, LOW);
delay(tempo);
}
}
4º Etapa
Com essa modificação a memória FLASH foi para 2406 bytes (7%) e a memória SRAM (dinâmica) de variáveis globais foi para 258 bytes (12%), assim totalizando uma redução de 1384 bytes de FLASH e 302 bytes de memória SRAM. Em seguida tiraremos a variável tempo de global e colocar ela na função piscaLed como variável local. Ficando da seguinte forma:
//Definições --------------------------------------------------------------------------------------
#define led1 13
#define led2 12
#define led3 11
#define led4 10
#define led5 09
//Variáveis Globais -------------------------------------------------------------------------------
const PROGMEM char text[] = "Um dia, um cão próprio ia atravessando uma ponte, carregando um osso na boca. Olhando para baixo, viu sua imagem refletida na água. Pensando ver outro cão, coçou-lhe logo o osso e pôs-se a latir. Mal, porém, abriu a boca, seu próprio osso caiu na água e se perdeu para sempre.";
//Protótipo da Função -----------------------------------------------------------------------------
void piscaLed(byte led);
//Setup -------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
for(byte i=9;i<=13;i++){
pinMode(i, OUTPUT);
}
}
//Loop --------------------------------------------------------------------------------------------
void loop() {
piscaLed(led1);
Serial.println(text);
Serial.println("Moral da História: Vale mais um passarinho na mão do que dois voando");
piscaLed(led2);
}
//Pisca LED ---------------------------------------------------------------------------------------
void piscaLed(byte led){
const int tempo = 1000;
for(byte i=0;i<2;i++){
digitalWrite(led, HIGH);
delay(tempo);
digitalWrite(led, LOW);
delay(tempo);
}
}
5º Etapa
Contudo nessa alteração não tivemos mudança de memória FLASH nem de memória SRAM. Agora colocaremos o modificador macro F() na função Serial.println, em seguida para finalizar estaremos realizando uma inversão de sinal no digitalWrite da função piscaLed, em vez de enviar sinais de ligado ou desligado para os pinos, porém, teremos que dobrar a quantidade do loop no for. Ficando da seguinte forma:
//Definições --------------------------------------------------------------------------------------
#define led1 13
#define led2 12
#define led3 11
#define led4 10
#define led5 09
//Variáveis Globais -------------------------------------------------------------------------------
const PROGMEM char text[] = "Um dia, um cão próprio ia atravessando uma ponte, carregando um osso na boca. Olhando para baixo, viu sua imagem refletida na água. Pensando ver outro cão, coçou-lhe logo o osso e pôs-se a latir. Mal, porém, abriu a boca, seu próprio osso caiu na água e se perdeu para sempre.";
//Protótipo da Função -----------------------------------------------------------------------------
void piscaLed(byte led);
//Setup -------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
for(byte i=9;i<=13;i++){
pinMode(i, OUTPUT);
}
}
//Loop --------------------------------------------------------------------------------------------
void loop() {
piscaLed(led1);
Serial.println(text);
Serial.println(F("Moral da História: Vale mais um passarinho na mão do que dois voando"));
piscaLed(led2);
}
//Pisca LED ---------------------------------------------------------------------------------------
void piscaLed(byte led){
const int tempo = 1000;
for(byte i=0;i<4;i++){
digitalWrite(led, !digitalRead(led));
delay(tempo);
}
}
Assim finalizamos todo o código com a explicação sobre o projeto com Arduíno UNO.
Resultado do Projeto de Otimização
Por fim esse foi o resultado obtido com o projeto.
Agradecemos sua Presença
Por fim, espero que tenham gostado e aprendido. Então compartilhe com seus colegas e deixe um comentário de qual projeto deveria ser o próximo aqui no Blog da WJ Componentes!!
Enfim estarei deixando o arquivo Arduíno e Fritzing, link dos posts anteriores referentes ao projeto e software e sites utilizados.
Fique à vontade para tirar suas dúvidas nos comentários.
Software e Sites Utilizados
Post Relacionados
- Código Morse com Arduíno UNOOlá, como estão? Hoje iremos desenvolver um decodificador de código… Leia mais: Código Morse com Arduíno UNO
- Como Programar pelo Celular o Arduíno!Olá, como estão? A princípio iremos explicar como programar pelo… Leia mais: Como Programar pelo Celular o Arduíno!
- Como Programar por BlocosOlá, como estão? A princípio iremos falar sobre alguns sites… Leia mais: Como Programar por Blocos
- Contador com Botões no Arduíno UNOOlá, como estão? A princípio iremos realizar um contador. Entretanto… Leia mais: Contador com Botões no Arduíno UNO
- Jogo da Forca com Arduíno UNOOlá, como estão? A princípio iremos falar sobre a Serial… Leia mais: Jogo da Forca com Arduíno UNO
Posts mais Recentes
- Programando Relé RF 4331 -Instruções de emparelhamento do modo de alternância Modo de… Leia mais: Programando Relé RF 433
- Acionando motor DC por meio do pino “Touch” do ESP-32Neste projeto, vamos explorar uma aplicação ainda mais dinâmica e… Leia mais: Acionando motor DC por meio do pino “Touch” do ESP-32
- Acendendo led RGB por meio do pino “Touch” do ESP-32No último post, exploramos o fascinante mundo dos pinos touch… Leia mais: Acendendo led RGB por meio do pino “Touch” do ESP-32
- Utilizando os Pinos touch do ESP32Nesse projeto Vamos aprender a usar os pinos touch´s do… Leia mais: Utilizando os Pinos touch do ESP32
- Como Programar e Localizar o Endereço de uma Tela OLED I2C com Arduinoeste guia, vou levá-lo através dos passos para programar uma… Leia mais: Como Programar e Localizar o Endereço de uma Tela OLED I2C com Arduino
Julio Cesar Bonow Manoel
Cursando Engenharia da Computação pelo Centro Universitário Facens e atua no desenvolvimento de projetos na WJ Componentes. Participante da equipe de robótica Omegabotz.
Deixe um comentário