15/08/14 Frederico Möller 2
Sumário
● Memória Volátil● Memória Permanente● EEPROM● EEPROM.read()● Exemplo IX● Exercício IX
● EEPROM.write()● Exemplo X● Armazenamento de
valores int e float● Função itoa()● Função atoi()
15/08/14 Frederico Möller 3
Sumário
● Conversão de valores float
● Exercício Final● Problemas dessa
forma de conversão● Operações de bitshift
15/08/14 Frederico Möller 4
Memória volátil
● Uma variável nada mais é que um endereço de memória que armazena um dado.
● Em todos os programas que fizemos até agora, neste curso, o Arduíno foi capaz de armazenar e acessar dados armazenados em sua memória.
● Tais dados no entanto, eram perdidos assim que o Arduíno era desligado, ou seja, estavam armazenados na memória volátil.
15/08/14 Frederico Möller 5
Memória volátil
● Muitos dos projetos feitos em arduíno não precisam de que o mesmo guarde os dados toda vez que é desligado. Podemos dizer que pelo propósito do Arduino, a maioria de seus projetos está bem servida com a memória volátil, ou seja aquela que morre junto com o fornecimento de energia da plataforma de prototipagem.
15/08/14 Frederico Möller 6
Memória permanente
● A memória permanente começa a se mostrar necessária no Arduino, principalmente quando temos que guardar configurações , mapeamentos de robôs , rotas e protocolos de comunicações.
● E é obvio que a plataforma possui uma memória permanente. Os programas carregados no Arduino são gravados em uma memória flash.
15/08/14 Frederico Möller 7
EEPROM
● Existe no entanto a memória EEPROM, no Arduino. E nela o usuário pode comandar a leitura e armazenamento de dados de forma permanente.
● Os dados gravados na memória EEPROM não são perdidos nem quando se grava um novo programa no Arduino. Uma vez gravado dado só é perdido (normalmente), quando um programa grava um novo dado em cima do antigo
15/08/14 Frederico Möller 8
EEPROM
● A memória EEPROM do Arduino é própria do seu microcontrolador e portanto sua capacidade vai depender do ATmega utilizado.
● No nosso caso, temos um ATmega328 sua memória EEPROM tem 1kB (kilobyte dividos em 1024 endereços de 1 byte.
● Mais informações sobre a memória EEPROM em geral se encontram na seção de leitura complementar.
15/08/14 Frederico Möller 9
EEPROM
● Para gravar e ler dados na memória EEPROM, o programa precisa ter a biblioteca EEPROM.h inclusa.
● Essa biblioteca é canônica da IDE do Arduino e portanto não precisa ser instalada separadamente. A IDE vem inclusivecom 3 exemplos prontos.
15/08/14 Frederico Möller 10
EEPROM.read()
● Normalmente os endereços da EEPROM de um Arduino vem com o valor 255 em cada. O endereço 0 pode vir com um valor diferente.
● A leitura de um endereço da memória EEPROM é feito atravéz do comando EEPROM.read(add)
● Add é o endereço de memória, no nosso caso um valor de 0 a 1023.
15/08/14 Frederico Möller 11
EEPROM.read()
● Normalmente os endereços da EEPROM de um Arduino vem com o valor 255 em cada. O endereço 0 pode vir com um valor diferente.
● A leitura de um endereço da memória EEPROM é feito atravéz do comando EEPROM.read(add)
● Add é o endereço de memória, no nosso caso um valor de 0 a 1023.
15/08/14 Frederico Möller 12
Exemplo IX
● Vamos a um exemplo bem simples. Vamos ler o que tem gravado no endereço 12 dos nossos arduinos.
● Uma vez que desejamos obter apenas uma leitura, a função loop não será utilizada
15/08/14 Frederico Möller 13
Exemplo IX
● Notem a inclusão da biblioteca EEPROM, da construção do programa na função setup, na função EEPROM.read() e na função loop sem nada em seu escopo.
15/08/14 Frederico Möller 14
Exemplo IX
● A variável a poderia ser do tipo char, no entanto isso resultaria na impressão de um valor da tabela ASCII ao invés de um numérico quando a função Serial.print(a) fosse chamada.
15/08/14 Frederico Möller 15
Exercício IX
● Durante a construção deste curso pelo menos um arduíno foi utilizado para testar as funções da biblioteca EEPROM.
● Usando o que foi aprendido até agora, descubram se o seu arduino é o que foi usado como cobaia, ou pelo menos se alguém deixou algo gravado na memória dele.
● Para facilitar, apenas os endereços iniciais foram usados nos testes.
15/08/14 Frederico Möller 16
Exercício IX
● Durante a construção deste curso pelo menos um arduíno foi utilizado para testar as funções da biblioteca EEPROM.
● Usando o que foi aprendido até agora, descubram se o seu arduino é o que foi usado como cobaia, ou pelo menos se alguém deixou algo gravado na memória dele.
● Para facilitar, apenas os endereços iniciais (0 a 32) foram usados nos testes.
15/08/14 Frederico Möller 17
Exercício IX
● O problema proposto pode até ter parecido complicado, no entanto se eu tivesse pedido "varra a memória em busca de alterações" estaria na cara que o que foi proposto pouco difere do exemplo passado
15/08/14 Frederico Möller 18
Exercício IX
● A diferença é que dessa vez temos uma variável de endereço, esta varia de valor dentro de um ciclo for.
● Coloquei aqui de 0 a 32, mas ela poderia variar dentro de qualquer intervalo de 0 a 1023
15/08/14 Frederico Möller 19
Exercício IX
● Dentro do ciclo for, o endereço é lido, o valor é armazenado na variável "a" e então é impresso na saída serial.
● Temos um delay para que seja possível acompanhar visualmente o valor armazenado em cada endereço.
15/08/14 Frederico Möller 20
EEPROM.write(add,val)
● A função EEPROM.write serve para armazenarmos um valor na memória EEPROM do arduino.
● Em add, colocamos o endereço de memória, que no nosso caso é um valor inteiro de 0 a 1023.
● Em val, vai o valor a ser armazenado, que é um byte, ou seja, um valor de 0 a 255.
15/08/14 Frederico Möller 21
Exemplo X
● Vamos fazer agora, um programa que leia o 3º endereço de memória (2), se este for maior que 100, ou então igual a 0, ele vai alterar esse valor para 1, se não, ele vai multiplicar esse valor por 2.
● Essa operação deve ser executada apenas uma vez, quando o arduino for ligado.
● O valor armazenado na memória deve ser exibido após a atualização.
15/08/14 Frederico Möller 22
Exemplo X
● Uma vez que as ações devem ocorrer apenas quando o arduino for ligado, nenhuma linha de código deve ser escrita dentro da função loop.
15/08/14 Frederico Möller 23
Exemplo X
● Inicialmente chamamos a biblioteca EEPROM.
● No setup, começamos por ligar a comunicação serial.
● Em seguida lemos o 3º endereço de memória.
15/08/14 Frederico Möller 24
Exemplo X
● O principal desse programa não é nem a leitura e gravação da memória EEPROM, mas sim o teste condicional.
15/08/14 Frederico Möller 25
Exemplo X
● Na excessão, ou seja, se val for diferente de zero e menor que 100 o valor de val vai ser multiplicado por 2.
● Atualizado, val é gravado no endereço 2 e depois é exibido via serial.
15/08/14 Frederico Möller 26
Armazenando valoes int e float
● O que aconteceria se tentassemos armazenar um valor inteiro em um endereço ROM?
● De acordo com o exemplo anterior, vimos que o fato da variável ser inteira não impede com que ela seja armazenada. Se o tamanho dela for o mesmo de um char, ou seja, um byte (0 a 255) ela vai ser armazenada sem problemas. Mas o que aconteceria se tentássemos armazenar um int maior que 255? Ou um valor float?
15/08/14 Frederico Möller 27
Armazenando valoes int e float
● O que aconteceria se tentassemos armazenar um valor inteiro em um endereço ROM?
● De acordo com o exemplo anterior, vimos que o fato da variável ser inteira não impede com que ela seja armazenada. Se o tamanho dela for o mesmo de um char, ou seja, um byte (0 a 255) ela vai ser armazenada sem problemas. Mas o que aconteceria se tentássemos armazenar um int maior que 255? Ou um valor float?
15/08/14 Frederico Möller 29
Armazenando valoes int e float
● Se observarem, ao invés de 1996, o arduino lê o valor de 204... Ao invés de 15.56, ele lê o valor 15.
● Por que isso acontece?● Variaveis int e float em geral, reservam 4 bytes
na memória para armazenar valores, no caso do arduino uno e similares, 2 bytes. Como os endereços de memória tem apenas um byte, apenas o byte menos significativo é armazenado.
15/08/14 Frederico Möller 30
Armazenando valores int e float
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1
1 1 0 0 1 1 0 0
1996Embinário
Apenas o byte menosSignificativo é armazenado
196 em binário
15/08/14 Frederico Möller 31
Armazenando valores int e float
● Infelizmente, na maioria das vezes, nos interessa armazenar valores int ou float, estes com mais de um byte de tamanho.
● Felizmente exitem diversas formas de contornar esse problema.
15/08/14 Frederico Möller 32
Armazenando valores int e float
● Infelizmente, na maioria das vezes, nos interessa armazenar valores int ou float, estes com mais de um byte de tamanho.
● Felizmente exitem diversas formas de contornar esse problema.
15/08/14 Frederico Möller 33
A função itoa(valor int,vetor char*,base)
● Essa é uma função da biblioteca stdio.h.
● Ela converte um valor inteiro em uma string.
● Ela faz essa conversão transformando cada dígito em um caracter, portanto 1996 tem 4 dígitos e precisará de uma string de 4 posições.
● Com essa string, basta chamar a função itoa, colocar o valor inteiro e a string dentro dos parenteses e a função fará a conversão.
● É preciso colocar também a base desejada, 10 para decimal, 16 para hexadecimal...
15/08/14 Frederico Möller 34
A função atoi(vetor char*)
● Essa é outra função da biblioteca stdio.h.● Ela converte uma string em um valor inteiro.● Diferente da itoa, nessa função, devemos
associar uma variável ao seu resultado.● Portanto a sitaxe correta será:
– Variável inteira=atoi(string)
15/08/14 Frederico Möller 35
Conversão de valores float
● A conversão de valores float já não é tão simples. Apesar de existir a função atof, a função ftoa não é canônica do C.
● Alguns programadores recomendam o uso da função sprintf, que imprime a saída de uma função printf em uma string, no entanto ela não costuma funcionar corretamente, pelo menos no arduino, para valores float.
15/08/14 Frederico Möller 36
Conversão de valores float
● Existe uma função chamada to_string, mas seu uso exige a importação de mais bibliotecas e por isso nós não veremos ela aqui.
● É interessante notar que qualquer valor numérico armazenado no arduino é racional.
● Sabendo disso é perfeitamente possível armazenar valores de ponto flutuante usando as funções atoi e itoa...
15/08/14 Frederico Möller 37
Exercício Final
● Este vai ser nosso último exercício nesse curso. Implementar uma função que armazene e uma que leia números de ponto flutuante na memória EEPROM do arduino.
● Não é uma tarefa fácil, mas ela pode ser executada de diversas formas.
● Lembrem-se que a função deve permitir que outros floats sejam armazenados sem apagar os que já foram armazenados.
15/08/14 Frederico Möller 38
Exercício Final
● Para facilitar, vamos nos limitar duas casas decimais e números de no máximo ordem 2 (ou seja, nada maior que 99.99, ou menor que -99.99)
● Como foi dito, é necessário poder armazenar vários números, pelo menos 10 floats devem ser armazenados sem que algum deles tenha que ser deletado.
15/08/14 Frederico Möller 39
Exercício Final
● Vamos ter que incluir, além da biblioteca EEPROM a biblioteca stdlib, para podermos usar as funções itoa e atoi.
● A primeira função implementada vai ser a responsável por armazenar o valor float na memória EEPROM.
15/08/14 Frederico Möller 40
Exercício Final
● Essa função deverá ser do tipo void, uma vez que ela não retorna valor algum, apenas armazena o valor na memória.
● Ela recebe um inteiro como endereço de memória e um float como valor a ser armazenado
15/08/14 Frederico Möller 41
Exercício Final
● É interessante observar que o endereço aqui não corresponde ao endereço real de memória. Como o valor vai ser convertido em uma string, vários endereços serão usados para armazenar um float.
15/08/14 Frederico Möller 42
Exercício Final
● Para evitar que se tenha que calcular o primeiro endereço, ou que a função tenha 6 entradas, reservamos a faixa de endereços do 512 ao 571 para armazenamento de floats.
15/08/14 Frederico Möller 43
Exercício Final
● Cada seqüência de 6 endereços equivale a um endereço "float". Por exemplo, os endereços do 512 ao 517 equivalem ao endereço 0 dessa função. Do 518 ao 513 temos o endereço 1 e assim por diante.
15/08/14 Frederico Möller 44
Exercício Final
● Inicialmente temos duas variáveis int declaradas, a i, que servirá como contadora de um ciclo for, e a valor_conv que é o valor float multiplicado por 100.
● Temos um vetor char de 6 posições chamado buffer declarado logo em seguida.
15/08/14 Frederico Möller 45
Exercício Final
● Quando multiplicamos o valor float por 100 obtemos um inteiro com no máximo 4 dígitos e um sinal.
● Esse inteiro é convertido para um vetor de char pela função itoa.
15/08/14 Frederico Möller 46
Exercício Final
● Em seguida cada posição do vetor é armazenada em um endereço de memória.
● Aqui é que entra a conversão do endereço da função para o endereço real.
15/08/14 Frederico Möller 47
Exercício Final
● Em cada passagem no ciclo for o endereço real de memória é atualizado dentro da função EEPROM.write pela expressão 512 + 6*add +i
15/08/14 Frederico Möller 48
Exercício Final
● 512 é onde começamos nossa "faixa reservada"
● 6*add é o endereço da função. É multiplicado por 6 por causa do tamanho da variável buffer [6]
● O i é cada posição do buffer.
15/08/14 Frederico Möller 49
Exercício Final
● A função seguinte é a ler_float, como o nome diz, ela lê um valor float armazenado na memória.
● É uma função tipo float, pois vai retornar um valor desse tipo.
15/08/14 Frederico Möller 50
Exercício Final
● A função recebe um valor inteiro, é o endereço de memória onde ela vai buscar o float.
● O endereço dado à função não corresponde aos endereços reais onde o valor float está armazenado.
15/08/14 Frederico Möller 51
Exercício Final
● Dentro da função são declarados um vetor de char, que vai futuramente receber cada byte do float armazenado na memória EEPROM.
15/08/14 Frederico Möller 52
Exercício Final
● Um inteiro i, que será usado como contador em um ciclo for.
● Um inteiro val_int, que vai receber a conversão string para inteiro realizado pela função atoi.
15/08/14 Frederico Möller 53
Exercício Final
● Uma variável float val_float que vai receber a conversão do valor inteiro para o valor flutuante.
● Essa variável poderia ser suprimida. Ela só está aqui para facilitar a visualização da lógica do exercício.
15/08/14 Frederico Möller 54
Exercício Final
● Após a declaração de variáveis, temos um ciclo for onde cada posição do buffer recebe o valor armazenado em um endereço de memória EEPROM.
15/08/14 Frederico Möller 55
Exercício Final
● A regra de conversão também foi usada aqui. Se o endereço na função for 3, o ciclo for fará com que os endereços 530,531,532,533,534 e 535 sejam lidos.
15/08/14 Frederico Möller 56
Exercício Final
● Ao término do ciclo, o buffer, já contendo todos os caracteres armazenados em uma determinada faixa da memória EEPROM é convertido em um inteiro pela função atoi.
15/08/14 Frederico Möller 57
Exercício Final
● A variável val_int é convertida em float e dividida por 100 (uma vez que na função de armazenamento, multiplicamos por 100)
● O valor convertido é a saída desta função.
15/08/14 Frederico Möller 58
Exercício Final
● Por fim um pequeno programa para demonstrar o funcionamento das funções
● Temos as variáveis float a e b, valendo 15.56 e 99.99 respectivamente.
15/08/14 Frederico Möller 59
Exercício Final
● As variáveis float c e d são declaradas, mas não tem valor definido.
● Usando a função armazena_float, armazenamos a no endereço 0 e b no endereço 1.
15/08/14 Frederico Möller 60
Exercício Final
● Ou seja, "a" está disposta nos endereços 512,513,514,515,516,517... e b do 518 ao 525.
15/08/14 Frederico Möller 61
Exercício Final
● Com a função ler_float recuperamos o valor desses endereços e os atribuimos às variáveis c e d.
● Por fim os valores são impressos. Os resultados podem ser facilmente conferidos no serial monitor.
15/08/14 Frederico Möller 62
Problemas dessa forma de conversão
● Já de cara podemos ver alguns problemas com esse tipo de método.
● Ao multiplicarmos o float por uma constante e salvar o resultado em um int, restringimos muito os valores float a serem lidos, se tivessemos que salvar o número 999.87, não conseguiríamos, pois 99987 está fora dos limites int do arduino uno.
15/08/14 Frederico Möller 63
Problemas dessa forma de conversão
● Já de cara podemos ver alguns problemas com esse tipo de método.
● Ao multiplicarmos o float por uma constante e salvar o resultado em um int, restringimos muito os valores float a serem lidos, se tivessemos que salvar o número 999.87, não conseguiríamos, pois 99987 está fora dos limites int do arduino uno.
15/08/14 Frederico Möller 64
Problemas dessa forma de conversão
● Podemos, claro, aprimorar esse método.● Um método válido seria, por meio de if-elses,
descobrir qual o tamanho da parte inteira do float, converter cada dígito dela em char e armazenar e depois multiplicar por 10 a parte fracionária, converter a parte inteira do novo número para caracter, subtrair o novo valor de sua parte inteira, multiplicar por 10 de novo...
15/08/14 Frederico Möller 65
Problemas dessa forma de conversão
● No entanto, isso iria requerer, além do espaço de memória para cada caracter do valor float, um para endereçar (dizer onde começa e onde termina o valor armazenado) e outro para dizer quantas casas decimais tinha a parte fracionária.
● As operações bit a bit no entanto resolvem muito bem esse problema.
15/08/14 Frederico Möller 66
Operações de bitshift
● Os operadores << e >> são os operadores de bitshift e são capazes de empurrar os bits de variáveis byte, int, ou long int (desde que o tamanho seja menor ou igual a 32 bits) para a esquerda ou para a direita.
● Por exemplo, o int 19800... ele pode ser escrito em binário como:
0 0 1 10 1 0 1 0 1 1 00 1 0 0
15/08/14 Frederico Möller 67
Operações de bitshift
● Realizando o bitshift de 4 casas para a esquerda, obtemos:
● Que equivale ao int 54656● Enquanto o bitshift de 4 casas para a direita
nos dá:
● Que equivale ao int 1237
0 0 1 11 0 1 0 10 0 1
1 1 0 1 0 1 10 1 0 0 0 0 0 0
0 0 0
15/08/14 Frederico Möller 68
Operadores bitshift
● O código ao lado exemplifica a utilidade do uso de bitshift para a conversão de dados.
● Podemor ir "shiftando" uma variável int de 8 em 8 bits de forma a pegarmos cada byte dela.
15/08/14 Frederico Möller 69
Operadores bitshift
● Esses bytes podem ser armazenados em posições de uma string, ou em endereços da memórita EEPROM.
● Depois, fazendo o bitshifting no sentido reverso, podemos reaver o valor decomposto.
15/08/14 Frederico Möller 70
Bitshift para floats
● Operadores de bitshift não funcionam com valores float e double, para armazenar esses valores é necessário fazer primeiro uma conversão para int (usando multiplicadores para eliminar a parte fracionária).
● A vantagem é que conseguimos usar, em geral, menos bytes para converter floats em um vetor de char, usando bitshift do que converter cada dígito em um caracter.
15/08/14 Frederico Möller 71
A melhor alternativa para floats
● Mesmo usando operadores bitshift, passar floats para um vetor de chars, principalmente se estivermos focando no armazenamento em endereços da EEPROM é um processo chato.
● A melhor alternativa para lidar com valores float, nesse caso é: EVITA-LOS.
● As entradas analógicas do arduino recebem valores inteiros, as digitais, booleanos.
15/08/14 Frederico Möller 72
A melhor alternativa para floats
● É perfeitamente possível manter os valores nesses estados, ou converter desses para char e armazenar na memória.
● Um bom programa deve deixar para fazer as conversões matemáticas que resultarão em valores float somente quando estes forem imprenscindíveis, como por exemplo, na hora de exibi-los para o usuário.
15/08/14 Frederico Möller 73
O Fim deste curso
● Esse curso é uma mera introdução da ferramenta Arduino. Muita coisa, como o uso de servo-motores, displays lcd, a biblioteca wire, o interfaceamento do Arduino com outros dispositivos, não foi explorada aqui.
● Alguns desses itens poderão ser vistos em cursos futuros, mas dificilmente vocês encontrarão um curso que aborde tudo o que o Arduino pode oferecer.
15/08/14 Frederico Möller 74
O Fim deste curso
● O domínio sobre essa plataforma só pode ser conseguido com seu constante uso.
● Uma das grandes vantagens do Arduino é o seu número de tutoriais na internet, façam bom uso deles, assim como os de fóruns de discussões, apostilas e livros sobre a plataforma.
15/08/14 Frederico Möller 75
Revisão
● Nessa lição, aprendemos sobre:– Memória volátil e memória permanente– A biblioteca EEPROM do Arduino.– Gravar e ler dados na memória EEPROM do
Arduino– Converter variaveis maiores para vetores de
variáveis menores
15/08/14 Frederico Möller 76
Leitura complementar
● Todos os operadores em c++– http://www.cplusplus.com/doc/tutorial/operators/
● História das memórias ROM– http://etcbinaria.wordpress.com/2011/01/21/evolucao-memoria-rom/
● Duas formas de converter int para vetor char:– http://sapiensmechatronicus.blogspot.com.br/2013/
05/comunicacao-serial-do-msp430-via-xbee.html
15/08/14 Frederico Möller 77
Referências bibliográficas
● MCROBERTS Micheal, Beginning Arduino, 1ªED
● SCHILDT Hebert, C completo e total, 3ªED● http://www.arduino.cc/
15/08/14 Frederico Möller 78
Informações adicionais
● Esses slides são a 1ª versão deste curso e sofrerão alterações
● Uma apostila está sendo feita e será disponibilizada em breve.
● Novas versões desses slides, a apostila, os códigos dos exercícios e dos exemplos feitos aqui poderão ser baixados nos seguintes links:
15/08/14 Frederico Möller 79
Informações adicionais
● Site do PET Mecatrônica/BSI:– http://sites2.jf.ifsudestemg.edu.br/?q=downloads
● Blog Homo Sapiens-Mechatronicus:– http://sapiensmechatronicus.blogspot.com.br/
● Blog projetos de jogos:– http://fredericomollerped.blogspot.com.br/
Top Related