• Nenhum resultado encontrado

MEMORIA EEPROM PROGRAMAÇÃO C PARA MICROCONTROLADORES 8051 E PIC

N/A
N/A
Protected

Academic year: 2022

Share "MEMORIA EEPROM PROGRAMAÇÃO C PARA MICROCONTROLADORES 8051 E PIC"

Copied!
8
0
0

Texto

(1)

MEMÓRIA EEPROM

PROGRAMAÇÃO C PARA MICROCONTROLADORES

8051 E PIC

PALAVRAS-CHAVE

Microcontrolador 8051, Microcontrolador PIC 16F877A, Memória EEPROM E2PROM

MEMORIA EEPROM

Nesta unidade de estudos vamos conhecer o funcionamento e a aplicação da memória EEPROM necessária para salvar informações antes do circuito ser desligado. Este componente tem como finalidade salvar e recuperar valor de variáveis, senhas, configurações do sistema, etc.

As variáveis são alocadas na memória RAM do microcontrolador e quando o sistema é desligado esses dados de execução são perdidos. Muitas aplicações não podem perder os dados de execução, isto é, o sistema precisa retomar o funcionamento a partir do ponto em que estava antes da queda de energia, com a mesma senha, os mesmos ajustes, por exemplo. Por isso, a memória EEPROM se torna alternativa para reter os dados do sistema e recupera-la, mesmo que o sistema permaneça desligado por anos.

METODOLOGIA

Serão analisadas as características técnicas da EEPROM 24C02, uma memória externa ao 8051, bem como o ciclo de vida útil e a estrutura de armazenamento organizada em índices ou posições de memória. Para comunicação entre o 8051 e a EEPROM será aplicado o protocolo de comunicação I2C abordado em seus aspectos gerais e a biblioteca i2c.h proverá operações de leitura e escrita na memória cujos dados poderão ser conferidos no mapa de memória em nível de simulação. Para salvar dados maiores do que 1 Byte a variável será quebrada em partes menores para tornar o seu armazenamento possível.

A abordagem desta unidade de estudos utiliza a programação C para o microcontrolador AT89S52, da família MCS-51 ou popularmente chamada de “8051” de modo que as informações salvas na EEPROM 24C02 sejam exibidas em display LCD 16x2.

Depois a atividade é realizada com a programação C para o microcontrolador PIC16F877A da família PIC 16F que dispõe de memória EEPROM interna.

RECURSOS

Para desenvolver e experimentar este material é necessário um computador ou notebook com sistema operacional Windows ou posterior e baixar o pacote de programas disponível em www.u8051.com.br o qual contém as seguintes ferramentas de desenvolvimento: Compilador 8051, Compilador PIC, Software de simulação Proteus-ISIS.

AVALIAÇÃO DE DESEMPENHO

A secção ATIVIDADES PROPOSTAS apresenta um conjunto de exercícios de dificuldade incremental a fim de avaliar o seu entendimento a cerca desta unidade de estudos.

RESULTADOS ESPERADOS

Ao concluir o desenvolvimento das atividades propostas, você deverá ser capaz de utilizar a memória EEPROM para salvar dados nestes modelos de microcontroladores.

(2)

MEMÓRIA EEPROM

1. A MEMÓRIA EEPROM 24C02

As memórias EEPROM (Electrically-Erasable Programable Read- Only Memory) são geralmente utilizadas em projetos que é necessário salvar informações em tempo de execução (running time) do sistema após o seu desligamento, como por exemplo:

contagens, parâmetros do sistema, senhas, entre outros dados.

Figura 1: Memoria EEPROM Figura 2: Memoria Pinagem EEPROM

Nesta unidade de estudos utilizaremos a memória EEPROM 24C02 com espaço de armazenamento de 256 Bytes. As memórias da família 24Cxx têm vida útil de mais de um milhão de ciclos de escrita e leitura. Cada ciclo de escrita ocorre ao salvar um dado, já o de leitura acontece quando buscamos o dado salvo na memória.

1.2

ARMAZENAMENTO DE DADOS

A memória EEPROM armazena dados de 8 bits, que na linguagem C é o tipo char. A exemplo do modelo 24C02, são 256 (0 a 255) espaços de armazenamento de 1 byte (8 bits). Cada espaço é um índice ou endereço de memória. Podemos então dizer que a memória 24C02 têm 256 índices de memória.

A tabela 1 ilustra os índices da memória EEPROM.

0 1 2 3

4 5 6 7

(dado: 25)

8 9 ... 255

Tabela 1: Espaços de memória identificados por Indice ou endereço

Quando desejamos escrever um dado, ou seja, salvar uma variável na EEPROM, devemos especificar o índice em que o dado será salvo. Por exemplo, na tabela 1 o valor 25 foi salvo no índice 7 da EEPROM. Essa informação fica retida no chip mesmo quando ele for desligado, e segundo a fabricante ATMEL, o tempo de armazenamento é 100 anos.

Já para ler um dado, isto é, recuperar uma informação salva, devemos especificar o mesmo índice em que a informação foi armazenada. Por exemplo, ao ler o índice 7 da tabela 1 a EEPROM fornecerá o valor “25”. Tanto as operações de escrita quando de leitura diminuem 1 ciclo de vida do chip no total de 1 milhão de acessos.

1.3

COMUNICAÇÃO I

2

C

O protocolo de comunicação I2C foi orginalmente desenvolvido pela Phillips que utiliza apenas duas vias para comunicação entre componentes que têm suportam ao protocolo. As vias são:

SDA (serial data) e SCL (serial clock).

Cada componente I2C tem seu ID especificado pelo fabricante.

A EEPROM 24C02 têm ID 160, enquanto que o RTC DS1307 tem ID 208. É possível “pendurar” vários dispositivos I2C nas linhas SDA e SCL (ou barramento I2C) como demonstrado na figura 3.

Observe que os dispositivos conectados ao barramento I2C estão conectados em paralelo, então o ID é que distingue qual componente está realizando a comunicação. O código a seguir demonstra a leitura do índice 7 na EEPROM 24C02:

#define EEPROM 160 char cont;

cont=read_i2c(EEPROM, 7);

Após execução destes comandos char cont receberá o valor 25 se considerarmos a tabela 1. A função read_i2c conecta ao dispositivo escolhido (EEPROM) e executa a operação de leitura do índice determinado.

A seguir temos o código que salva a variável char cont no índice 7 da EEPROM:

#define EEPROM 160 char cont=26;

save_i2c(EEPROM, 7, cont);

A função save_i2c conecta ao dispositivo escolhido (EEPROM) e executa a operação de escrita no índice determinado. Por isso, o valor 26 será salvo no índice 7 da memória, substituindo o valor anterior.

1.3

A BIBLIOTECA i2C.H

É encontrada na pasta 8051\SDCC\INCLUDE que implementa as seguintes definições e funções do protocolo de comunicação I2C:

Comando Efeito

#define scl Px_y Define o I/O do 8051 conectado à linha SCL

#define sda Px_y Define o I/O do 8051 conectado à linha SDA save_i2c(ID, índice,

variável); Salva variável no índice do ID escolhido variável=read_i2c(ID,

índice); Busca dado salvo no índice do ID escolhido Tabela 2: Funções da biblioteca i2ch

1.4

ESQUEMÁTICO 8051 E EEPROM 24C02 COM DISPLAY LCD

O circuito da figura 4 apresenta a conexão entre o microcontrolador e a memória. O Display LCD será utilizado para exibir as operações de leitura e escrita na EEPROM.

Este esquema foi desenhado no software Proteus-ISIS versão 7 ou posterior utilizando os seguintes componentes:

Referência Componente

AT89C52 Microcontrolador AT89C52 24C02C Memória EEPROM 24C02 LM016L Display LCD 16x2 BUTTON Botões AVANCAR e SOMAR Fig. 3: Dois

dispositivos conectados na rede I2C

ID 160 ID 208

Barramento I2C

Fig. 4: Conexão do microcontrolador e a EEPROM

índice

(3)

MEMÓRIA EEPROM // Programa 1

Uma versão portátil deste simulador pode ser executada a partir da pasta 8051\ISIS77\BIN\ISIS.EXE

Figura 5: Executando o Simulador ISIS

A biblioteca i2.h implementa o protocolo I2C no 8051 através dos I/O’s escolhidos no comando #define que deve constar antes da biblioteca i2c.h. Já a comunicação com o LCD é fornecida na biblioteca lcd.h. Você verá a declaração destas bibliotecas na seguinte ordem:

#include<at89x52.h>

#include<lcd.h>

#define sda P2_6

#define scl P2_7

#include<i2c.h>

1.5

PROGRAMAÇÃO

A seguir temos a programação para o circuito da figura 4: ela permite ajustar os parâmetros de um temporizador: horário de ligar e o horário de desligar um dispositivo elétrico. Na figura 6 temos um exemplo de execução o programa.

#include<at89x52.h>

#include<lcd.h>

#define AVANCAR P3_2

#define SOMAR P3_3

#define EEPROM 160

#define sda P2_6

#define scl P2_7

#include<i2c.h>

bit b1, b2;

char horaL, minL, horaD, minD, pos;

void atualizaLCD();

void atualizaCursor();

void leMemoria();

//******************************

void main() { leMemoria();

lcd_init();

atualizaLCD();

atualizaCursor();

while(1) {

if(SOMAR==0 && b1==0) {

b1=1;

if(pos==0) {

horaL++;

save_i2c(EEPROM, 0, horaL);

}

if(pos==1) minL++;

atualizaLCD();

}

if(SOMAR==1) b1=0;

if(AVANCAR==0 && b2==0) {

b2=1;

pos++;

if(pos>1) pos=0;

atualizaCursor();

}

if(AVANCAR==1) b2=0;

}

} //******************************

void atualizaLCD() { lcd_cursor(0);

lcd_gotoxy(1,1);

lcd_puts("LIG ");

lcd_putchar(horaL/10+48);

lcd_putchar(horaL%10+48);

lcd_putchar(':');

lcd_putchar(minL/10+48);

lcd_putchar(minL%10+48);

lcd_gotoxy(2,1);

lcd_puts("DES ");

lcd_putchar(horaD/10+48);

lcd_putchar(horaD%10+48);

lcd_putchar(':');

lcd_putchar(minD/10+48);

lcd_putchar(minD%10+48);

atualizaCursor();

} //******************************

void atualizaCursor()

{ if(pos==0) lcd_gotoxy(1,6);

if(pos==1) lcd_gotoxy(1,9);

lcd_cursor(1);

} //******************************

void leMemoria()

{ horaL=read_i2c(EEPROM, 0);

}

Você pode revisar a unidade de estudos DISPLAY LCD para entender as instruções lcd_init. lcd_gotoxy, lcd_putchar, lcd_puts e lcd_cursor, por isso, essas instruções não serão aqui detalhadas. Nosso foco será a EEPROM.

As variáveis horaL, minL, horaD e horaL armazenam o horário de início e fim da temporização, sendo horas até o limite de 23 e minutos até 59. Por isso, o tipo char tendo alcance de 0 até 255 atende bem à essa aplicação, além de ser também o tipo de dado que pode ser salvo e lido no índice da memória EEPROM.

Observe que na função main ocorre um “salto” para a função leMemoria. A função read_i2c (ou read_eeprom no PIC) busca na EEPROM o dado salvo no índice 0 e atribui à variável char horaL.

Executado o último comando da função leMemoria ocorre então o

“retorno” para a função main em que as demais funções são executadas. A variável char pos é referência ao item que o usuário está ajustando na tela, conforme a figura 7.

Por isso, o programa toma como referência a variável pos para posicionar o cursor piscante, bem como determinar qual variável deve ser somada que leva a dedução da tabela 4.

Valor de

pos Variável alterada no

botão SOMAR Posição do cursor pos==0 horaL (hora ligar) (1,6) pos==1 minL (minutos ligar) (1,9) pos==2 horaD (hora desligar) (?,?) pos==3 mind (minutos desligar) (?,?) Tabela 4: Variável pos é referência de ajustes e de posição do cursor

1.6 EVENTO CLIQUE PARA SOMAR

O programa 1 usa-se a lógica do evento pressionar-e-soltar o botão para evitar a repetição. A variável b1 registra o instante em que o botão SOMAR é pressionado. Por exemplo, quando SOMAR é pressionado, a variável horaL é aumenta uma unidade (+1) e o seu valor é salvo no índice 0 da EEPROM, pelo comando save_i2c (ou write_eeprom no PIC) e então b1 recebe 1. Não importa agora que SOMAR ainda esteja pressionado, pois o teste b1==0 é falso e não ocorre mais a repetição dos comandos deste if. Porém, ao soltar este botão, a variável b1 retorna a 0, podendo então, registrar um novo clique.

Observe que o valor de horaL é salvo no índice 0 e que a função leMemória, busca o valor salvo neste mesmo índice. Cada variável deve ser salva e lida em seu índice exclusivo. Para salvar a variável minL, poderíamos especificar o índice 1 por exemplo.

1.7 VISUALIZANDO OS DADOS DA EEPROM Durante a simulação é possível

visualizar os dados armazenados na memória EEPROM. Para isso, basta pausar a simulação e acessar o menu Debug>I2C Memory Internal Memory.

1.8 APAGANDO OS DADOS DA EEPROM Para limpar o conteúdo da EEPROM encerre simulação e exclua o componente 24C02C do esquemático. Em seguida adicione o componente novamente e refaça as conexões da figura 4.

1.9

VETORES EM C

Um vetor é uma variável indexada, ou seja, comporta várias informações do tipo de dado em que o vetor é declarado.

Considere a seguinte declaração:

char num[11]={5,1,9,9,6,0,2,6,8,9,7};

O vetor mensagem têm 11 índices e cada um armazena um dado do tipo char. Assim temos que o vetor tenha os índices 0 ao 11 conforme o exemplo ao lado.

As variáveis indexadas armazenam valores do mesmo tipo. Esses dados armazenados são denominados itens do vetor.

//Fig. 6: Tela do programa 1

pos=0 pos=1

pos=2 pos=3 Fig. 7

Fig. 8: Visualizando os dados da EEPROM

num[0]=5;

num[1]=1;

num[2]=9;

num[3]=9;

num[4]=6;

num[5]=0;

num[6]=2;

num[7]=6;

num[8]=8;

num[9]=9;

num[10]=7

(4)

MEMÓRIA EEPROM

// Programa 3 1.10

SALVANDO NUMERO DE

TELEFONE E NOME (8051)

O programa 2 faz uso do vetor num que armazena o número telefônico de 9 dígitos e do vetor nome para armazenar o nome de quem atende no respectivo número.

A figura 9 ilustra a tela de execução do programa.

#include<at89x52.h>

#include<lcd.h>

#define AVANCAR P3_2

#define SOMAR P3_3

#define EEPROM 160

#define sda P2_6

#define scl P2_7

#include<i2c.h>

bit b1, b2;

char pos, num[8]={5,1,9,9,6,0,2,6};

char nome[4]={'C','A','S','A'};

void atualizaLCD();

void atualizaCursor();

void leMemoria();

//******************************

void main(){

leMemoria();

lcd_init();

atualizaLCD();

atualizaCursor();

while(1){

if(SOMAR==0 && b1==0){

b1=1;

if(pos<8){

num[pos]++;

save_i2c(EEPROM, pos, num[pos]);

} else{

nome[pos-8]++;

if(nome[pos-8]>'E') nome[pos-8]='A';

save_i2c(EEPROM, pos, num[pos-8]);

}

atualizaLCD();

}

if(SOMAR==1) b1=0;

if(AVANCAR==0 && b2==0){

b2=1;

pos++;

if(pos>11) pos=0;

atualizaCursor();

}

if(AVANCAR==1) b2=0;

}

} //******************************

void atualizaLCD(){

char i;

lcd_cursor(0);

lcd_gotoxy(1,1);

for(i=0;i<8;i++) lcd_putchar(num[i]+48);

lcd_gotoxy(2,1);

for(i=0;i<4;i++) lcd_putchar(nome[i]);

atualizaCursor();

} //******************************

void atualizaCursor(){

if(pos<8)lcd_gotoxy(1,pos+1);

else lcd_gotoxy(2,pos-7);

lcd_cursor(1);

} //******************************

void leMemoria(){

//comandos para ler os dados da EEPROM }

Vamos analisar o funcionamento do Programa 2 considerando que você já observou a abordagem do Programa 1. Ao todo são 11 dígitos do telefone e 4 dígitos do nome, totalizando a navegação entre 15 campos de dados no LCD, tendo como referência a variável pos. Quando pos está entre 0 e 10, o botão SOMAR aumenta o valor do vetor num[pos]. Isto, é, se pos for 0 então num[0], que contém o valor 5 será somado e terá agora 6. Se pos estiver acima de 10, então o vetor nome é que deve ser alterado. Mas observe que nome tem apenas 4 índices, logo, nome[11] é inválido. Por isso, temos nome[pos-11]++. O comando for(i=0;i<8;i++) lcd_putchar(num[i]); mostra todos os 8 índices do vetor num no LCD, enquanto que for(i=0;i<4;i++) lcd_putchar(nome[i]); exibe o nome.

Lembre-se de que escolhemos armazenar apenas letras no vetor nome. Aqui os caracteres válidos são: A, B, C, D, E por que aplicamos o filtro if(nome[pos-8]>'E') nome[pos-8]='A';

2

SALVANDO TIPO DE DADO INT

Vimos que a memória EEPROM armazena dados de 8 bits (1 Byte), o tipo char em C. Mas existem aplicações em que se faz necessário salvar variáveis do tipo int que tem o tamanho de 2 Bytes, ou seja, o dobro do tipo char. Por isso, é necessário quebrar a variável int em partes que resultem em duas variáveis do tipo char. Para ilustrar considere a variável int cont.

int cont=300;

O valor máximo de 1 Byte é 255. Então o valor 300 não pode ser armazenado em um único índice da EEPROM. É necessário

“quebrar” a variável int em duas variáveis char com a operação de divisão “/” e módulo “%” que obtém o resto da divisão.

cont=300;

cont/256; → 300/256 = 1,17 cont%256; → 300%256 = 44

Para salvar cont/256 no índice 0 e cont%256 no índice 1 aplicamos os seguintes comandos:

save_i2c(EEPROM, 0, cont/256);

save_i2c(EEPROM, 1, cont%256);

Teremos os seguintes dados na memória:

0 1 (01) 1 44 (2C) 2 3

Tabela 5: valor 300 salvo dos índices 0 e 1 da EEPROM

Para recuperar o dado é preciso ler e “unir” os valores destes mesmos índices aplicando multiplicação “*” e soma “+”.

0 1 (01) 1 44 (2C) 2 3

Sendo 255 o valor máximo de cada índice, temos que o valor máximo armazenável com 2 índices seja:

O programa 3 utiliza os índices 0 e 1 da EEPROM para salvar a variável int cont.

#include<at89x52.h>

#include<lcd.h>

#define SOMAR P3_3

#define EEPROM 160

#define sda P2_6

#define scl P2_7

#include<i2c.h>

bit b1;

int cont=12345;

void atualizaLCD();

void exibeInt(int valor);

void atualizaCursor();

void leMemoria();

//******************************

void main(){

leMemoria();

lcd_init();

atualizaLCD();

atualizaCursor();

while(1){

if(SOMAR==0 && b1==0) {

b1=1;

cont++;

save_i2c(EEPROM, 0, cont/256);

save_i2c(EEPROM, 1, cont%256);

atualizaLCD();

}

if(SOMAR==1) b1=0;

}

} //******************************

void atualizaLCD() { lcd_cursor(0);

lcd_gotoxy(1,1);

exibeInt(cont);

atualizaCursor();

} //******************************

void exibeInt(int valor) { lcd_putchar(valor/10000+48);

lcd_putchar(valor%10000/1000+48);

lcd_putchar(valor/100%10+48);

lcd_putchar(valor/10%10+48);

lcd_putchar(valor%10+48);

} //******************************

void atualizaCursor() { lcd_gotoxy(1,5);

lcd_cursor(1);

} //******************************

void leMemoria(){

unsigned char parte2;

cont=(read_i2c(EEPROM, 0)*256);

parte2=read_i2c(EEPROM, 1);

cont=cont+parte2;

}

0 255 (FF) 1 255 (FF) 2 3

Fig. 9: Tela do programa 2

// Programa 2

x 256 +

256 + 44 = 300

x 256 +

25280 + 255 = 65535

(5)

MEMÓRIA EEPROM

TIPO DE DADO INT E UNSIGNED INT (8051) O tipo de dado int suporta faixa de valores negativos e positivos.

O tipo unsigned int opera somente com a faixa de valores positiva. Na tabela a seguir temos um comparativo de alcance destes dois tipos de dados:

Tipo de dado Alcance de armazenamento

int -32768 a +32767

unsigned int 0 a 65535

Tabela 8: Diferença entre o tipo de dado int e unsigned int

A função exibeInt(tipo de dado) recebe como parâmetro o valor a ser exibido no LCD. O tipo de dado declarado na função deve ser do mesmo tipo de dado da variável que desejamos exibir.

Considere:

char cont=100;

O parâmetro da função deverá ser: exibeInt(char variável) unsigned char cont=200;

Parâmetro da função: exibeInt(unsigned char variável) int cont=20000;

O parâmetro da função deverá ser: exibeInt(int variável) unsigned int cont=60000;

Parâmetro da função: exibeInt(unsigned int variável) long int cont=90000;

Parâmetro da função: exibeInt(long int variável) Ao ler uma posição de memória você dever armazenar o dado numa variável que tenha essa capacidade de armazenamento.

Por exemplo, a variável parte2 do exemplo abaixo deverá ser do tipo int parte2:

int parte2=0;

parte2=(read_i2c(EEPROM, 0)*256);

FLAG CARRYOUT

Quando tentamos executar uma operação de soma cujo resultado seja maior do que a capacidade de armazenamento da variável de destino, ocorre o “vai um” ou carryout flag (CY).

Esta unidade de estudos não mergulha neste nível de segurança para validação de operações com variáveis, mas caso nos sistemas críticos e sem tolerância a falhas, é importante tratar essa flag após cada operação com variáveis para identificar se ela comportou o valor atribuído. O trecho a seguir soma a variável cont e o comando seguinte verifica se a flag CY está em 0, detectando erro na operação.

cont++;

if(CY==0) {

lcd_gotoxy(2,1);

lcd_puts("Carry Out Flag");

}

Considere int cont=32767, se ocorrer uma operação de adição cont++ o evento carryout será ativado e a flag CY recebe 0, por que o tipo de dado int não tem espaço suficiente para alocar o valor 32768. Um modo simples de evitar o evento carryout é verificar a flag CY.

ATIVIDADES PROPOSTAS 1

Desenhar o esquemático da figura 4 no software simulador ISIS;

Digitar e compilar o programa 1 no software JFE;

Simular o programa 1 no software ISIS;

Ampliar os ajustes das horas e minutos de todos os 4 campos da figura 7, limitando as horas e minutos em valores válidos.

Salvar e recuperar os 4 campos de ajuste de tempo;

2

Digitar e compilar o programa 2 no software JFE;

Simular o programa 2 em conjunto com o esquemático da figura 4;

Simular o programa 6 em conjunto com o esquemático da figura 2;

Os dígitos válidos do telefone devem ser somente 0 a 9;

Ampliar o número de telefone para 11 dígitos;

Ampliar o tamanho do nome de 4 para 8 letras que contemplem somente o alfabeto maiúsculo;

▪ Salvar e recuperar todas as informações personalizáveis do usuário (telefone e nome);

3

Digitar e compilar o programa 3 no software JFE;

Simular o programa 3 em conjunto com o esquemático da figura 4;

Acrescentar a tecla zera conectada em P3.4;

Alterar o contador para suportar contagens até 50000, bem como salvar essa faixa de valores;

▪ Desafio supremo: exibir e salvar contagem até 99999 utilizando a variável long int cont. Dica: você usará os valores /65536, /256%256 para salvar o dado em 3 posições da memória EEPROM.

3. A MEMÓRIA EEPROM DO PIC

O microcontrolador PIC16F877A dispõe de EEPROM interna com capacidade de 256 Bytes. Isto significa que não precisamos conectar uma EEPROM externa para salvar os dados a exemplo do que ocorre no 8051. É claro que existem variações do 8051 que dispõe de EEPROM bem como há modelos do PIC que não tem essa memória interna.

3.1

ARMAZENAMENTO DE DADOS

A memória EEPROM armazena dados de 8 bits, que na linguagem C é o tipo char. No PIC16F877A são 256 (0 a 255) espaços de armazenamento com 1 byte (8 bits) cada. Um espaço é um índice ou endereço de memória. Podemos então dizer que este PIC tem 256 índices de memória.

A tabela 9 ilustra os índices da memória EEPROM do PIC.

0 1 2 3

4 5 6 7

(dado: 25)

8 9 ... 255

Tabela 9: Espaços de memória identificados por Indice ou endereço

Quando desejamos escrever um dado, ou seja, salvar uma variável na EEPROM, devemos especificar o índice em que o dado será salvo. Por exemplo, na tabela 9 o valor 25 foi salvo no índice 7 da EEPROM. Essa informação fica retida no chip mesmo quando ele for desligado, e segundo a fabricante MICROCHIP, o tempo de armazenamento é mais de 40 anos.

Já para recuperar a informação salva, devemos especificar o mesmo índice em que a informação foi armazenada. Por exemplo, ao ler o índice 7 da tabela 1 a EEPROM fornecerá o valor “25”. Tanto as operações de escrita quando de leitura diminuem 1 ciclo de vida do chip no total de 1 milhão de acessos.

3.2

FUNÇÕES DE ACESSO DA EEPROM INTERNA DO PIC

O código seguir demonstra a leitura do índice 7 na EEPROM do PIC:

char cont;

cont=read_eeprom(7);

A função read_eeprom executa a operação de leitura do índice determinado. No exemplo acima ocorreu a leitura do índice 7 e a variável char cont receberá o valor 25 se considerarmos a tabela 9.

A seguir temos o código que salva a variável char cont no índice 7 da EEPROM:

char cont=26;

write_eeprom(7, cont);

A função write_eeprom executa a operação de escrita no índice determinado. Por isso, após a execução destes comandos, o valor 26 será salvo no índice 7 da memória, substituindo o valor anterior.

Temos no PIC-C Compiler as seguintes funções de acesso à EEPROM do PIC:

índice índice

(6)

MEMÓRIA EEPROM

Engenharia Curso de microcontrolador online pic 8051 programação jfe pic c compiler projeto s microgenios gravador cu scopic aeci sp progisp u sbasp atmega Arduino faculdade unisinos feevale.br pucrs ufrgs uninter faccat ita unisanta unoeste anhanguera u sp unesp feec feelt ufrj pucminas unitaumaua ime unopar fam ufsc pucpr fei fatec uninove ead uniceug Anchieta uceff ufpel rogercom ufal edu br fpb up unifacs fatecpr feitep univap fen/ufg famen dombosco utfpr cefet uni pifam senai impacta unilasalle uva uc s.br unifor upe.br unig.br ifrs.edu.br

// Programa 4

Comando Efeito

write_eeprom(índice, variável); Salva variável no índice variável=read_eeprom(índice); Busca dado

salvo no índice Tabela 10: Funções de acesso a EEPROM

3.3

ESQUEMÁTICO

PIC E DISPLAY LCD O circuito da figura 10 apresenta o microcontrolador conectado ao display LCD para que na tela sejam exibidas as operações de leitura e escrita na EEPROM.

Figura 10: Conectando o display LCD 16x2 ao microcontrolador PIC16F877A

Observe que quando os I/O’s do PIC são utilizados para leitura de sensores de contato (as teclas), os I/O’s utilizados devem ser configurados como input através da função set_tris. Por isso, esses I/O’s ficam em coletor aberto ou tristate, necessitando de resistores pull up R1 e R2 para definir o estado lógico 1 destas

“entradas” de teclas. Veja a tabela 12.

Este esquema foi desenhado no software Proteus-ISIS versão 7 ou posterior utilizando os seguintes componentes:

Referência Componente

PIC16F877A Microcontrolador PIC16F877A LM016L Display LCD 16x2

BUTTON Botões AVANCAR e SOMAR

RES Resistor 4K7

Uma versão portátil deste simulador pode ser executada a partir da pasta 8051\ISIS77\BIN\ISIS.EXE

Figura 11: Executando o Simulador ISIS

A biblioteca lcd.h comunica com o PIC através do PORT B, mas esta definição pode ser editada dentro da biblioteca se necessário. Para incluir o protocolo de comunicação com o LCD você verá a declaração da biblioteca lcd.h na seguinte ordem:

#include<16F877A.h>

#fuses nowdt, nobrownout, xt, noput, noprotect

#use delay(clock=4000000)

#include<lcd.h>

3.4

PROGRAMAÇÃO

A seguir temos a programação para o circuito da figura 10: ela permite ajustar os parâmetros de um temporizador: horário de ligar e o horário de desligar um dispositivo elétrico. Na figura 12 temos um exemplo de execução o programa.

#include<16F877A.h>

#fuses nowdt, nobrownout, xt, noput, noprotect

#use fast_io(C)

#use delay(clock=4000000)

#include<lcd.h>

#define AVANCAR PIN_C1

#define SOMAR PIN_C0 int1 b1,b2;

signed char horaL, minL, horaD, minD, pos;

void atualizaLCD();

void atualizaCursor();

void leMemoria();

//******************************

void main() {

set_tris_C(0b00000111);

leMemoria();

lcd_init();

atualizaLCD();

atualizaCursor();

while(1) {

if(input(SOMAR)==0 && b1==0) {

b1=1;

if(pos==0) {

horaL++;

write_eeprom(0, horaL);

}

if(pos==1) minL++;

atualizaLCD();

}

if(input(SOMAR)==1) b1=0;

if(input(AVANCAR)==0 && b2==0) {

b2=1;

pos++;

if(pos>1) pos=0;

atualizaCursor();

}

if(input(AVANCAR)==1) b2=0;

} }

//******************************

void atualizaLCD() {

lcd_cursor(0);

lcd_gotoxy(1,1);

lcd_putc("LIG ");

lcd_putc(horaL/10+48);

lcd_putc(horaL%10+48);

lcd_putc(':');

lcd_putc(minL/10+48);

lcd_putc(minL%10+48);

lcd_gotoxy(2,1);

lcd_putc("DES ");

lcd_putc(horaD/10+48);

lcd_putc(horaD%10+48);

lcd_putc(':');

lcd_putc(minD/10+48);

lcd_putc(minD%10+48);

atualizaCursor();

}

//******************************

void atualizaCursor() {

if(pos==0) lcd_gotoxy(1,6);

if(pos==1) lcd_gotoxy(1,9);

lcd_cursor(1);

}

//******************************

void leMemoria() {

horaL=read_eeprom(0);

}

O funcionamento do programa 4 está detalhado no item 1.5, mas o compilador aqui utilizado para o PIC é o PIC-C Compiler que implementa algumas funções para manipular os I/O’s do microcontrolador. São elas:

set_tris_IO(0bXXXXXXX); //IO é o PORT (A,B,C,D ou E) No PIC você deve especificar os I/O’s que serão utilizados como entrada de dados (leitura de botões). A instrução set_tris define a direção dos dados sendo 0=Output e 1=Input.

Comando em binário literal: set_tris_C(0b00000111);

Efeito: C7, C6, C5 e C4 são saídas. C3, C2, C1 e C0 são entradas

I/O C7 C6 C5 C4 C3 C2 C1 C0

Val 0 0 0 0 0 1 1 1

Direção Saída Saída Saída Saída Saída Entr Entr Entr Tabela 12: Definido a direção dos dados do PORT C

//Fig. 12: Tela do programa 4

(7)

MEMÓRIA EEPROM

// Programa 6 A função input(IO) lê o nível lógico encontrado no I/O

especificado. A diretiva #use fast_io(IO) especifica que o programador irá decidir quais I/O’s serão entrada com o comando set_tris(IO).

3.5

SALVANDO NUMERO DE TELEFONE E NOME (PIC)

O programa 5 faz uso do vetor num que armazena o número telefônico de 9 dígitos e do vetor nome para armazenar o nome de quem atende no respectivo número.

A figura 13 ilustra a tela de execução do programa.

#include<16F877A.h>

#fuses nowdt, nobrownout, xt, noput, noprotect

#use fast_io(C)

#use delay(clock=4000000)

#include<lcd.h>

#define AVANCAR PIN_C1

#define SOMAR PIN_C0 int1 b1,b2;

char pos, num[8]={5,1,9,9,6,0,2,6};

char nome[4]={'C','A','S','A'};

void atualizaLCD();

void atualizaCursor();

void leMemoria();

//******************************

void main(){

leMemoria();

lcd_init();

atualizaLCD();

atualizaCursor();

while(1){

if(input(SOMAR)==0 && b1==0) { b1=1;

if(pos<8){

num[pos]++;

write_eeprom(pos, num[pos]);

} else{

nome[pos-8]++;

if(nome[pos-8]>'E') nome[pos-8]='A';

write_eeprom(pos, num[pos-8]);

}

atualizaLCD();

}

if(input(SOMAR)==1) b1=0;

if(input(AVANCAR)==0 && b2==0){

b2=1;

pos++;

if(pos>11) pos=0;

atualizaCursor();

}

if(input(AVANCAR)==1) b2=0;

} }

//******************************

void atualizaLCD(){

char i;

lcd_cursor(0);

lcd_gotoxy(1,1);

for(i=0;i<8;i++) lcd_putc(num[i]+48);

lcd_gotoxy(2,1);

for(i=0;i<4;i++) lcd_putc(nome[i]);

atualizaCursor();

}

//******************************

void atualizaCursor(){

if(pos<8)lcd_gotoxy(1,pos+1);

else lcd_gotoxy(2,pos-7);

lcd_cursor(1);

}

//******************************

void leMemoria(){

//comandos para ler os dados da EEPROM }

TIPO DE DADO INT16 E SIGNED INT (PIC) O tipo de dado signed int16 ou signed long suporta faixa de valores negativos e positivos. O tipo int16 ou long opera somente com a faixa de valores positiva. Na tabela a seguir temos um comparativo de alcance destes dois tipos de dados:

Tipo de dado Alcance de armazenamento signed int16 ou

signed long -32768 a +32767 int16 ou

long 0 a 65535

Tabela 13: Diferença entre o tipos de dado int16 e signed int16

2

SALVANDO TIPO DE DADO INT16

A EEPROM armazena dados de 8 bits (1 Byte), o tipo char em C.

Mas existem aplicações em que se faz necessário salvar variáveis do tipo int16 que tem o tamanho de 2 Bytes, ou seja, o dobro do tipo char. Por isso, é necessário quebrar a variável int16 em duas partes que resultem em duas variáveis do tipo char. Para ilustrar considere a variável int16 cont.

int16 cont=300;

O valor máximo de 1 Byte é 255. Então o valor 300 não pode ser armazenado em um único índice da EEPROM. É necessário

“quebrar” a variável int16 em duas variáveis char com a operação de divisão “/” e módulo “%” que obtém o resto da divisão.

cont=300;

cont/256; → 300/256 = 1,17 cont%256; → 300%256 = 44

Para salvar cont/256 no índice 0 e cont%256 no índice 1 aplicamos os seguintes comandos:

write_eeprom(0, cont/256);

write_eeprom(1, cont%256);

Teremos os seguintes dados na memória:

0 1 (01) 1 44 (2C) 2 3

Tabela 5: valor 300 salvo dos índices 0 e 1 da EEPROM

Para recuperar o dado é preciso ler e “unir” os valores destes mesmos índices aplicando multiplicação “*” e soma “+”.

0 1 (01) 1 44 (2C) 2 3

O programa 6 utiliza os índices 0 e 1 da EEPROM para salvar a variável int16 cont.

#include<16F877A.h>

#fuses nowdt, nobrownout, xt, noput, noprotect

#use fast_io(C)

#use delay(clock=4000000)

#include<lcd.h>

#define SOMAR PIN_C0 int1 b1;

int16 cont=12345;

void atualizaLCD();

void exibeInt(int16 valor);

void atualizaCursor();

void leMemoria();

//******************************

void main(){

leMemoria();

lcd_init();

atualizaLCD();

atualizaCursor();

while(1){

if(input(SOMAR)==0 && b1==0) { b1=1;

cont++;

write_eeprom(0, cont/256);

write_eeprom(1, cont%256);

atualizaLCD();

}

if(input(SOMAR)==1) b1=0;

} }

//******************************

void atualizaLCD(){

lcd_cursor(0);

lcd_gotoxy(1,1);

exibeInt(cont);

atualizaCursor();

}

//******************************

void exibeInt(int16 valor){

lcd_putc(valor/10000+48);

lcd_putc(valor%10000/1000+48);

lcd_putc(valor/100%10+48);

lcd_putc(valor/10%10+48);

lcd_putc(valor%10+48);

} //******************************

void atualizaCursor(){

lcd_gotoxy(1,5);

lcd_cursor(1);

}

//******************************

void leMemoria(){

unsigned char parte2;

cont=(read_eeprom(0)*256);

parte2=read_eeprom(1);

cont=cont+parte2;

} Fig. 13: Tela do programa 5

x 256 +

256 + 44 = 300

(8)

MEMÓRIA EEPROM A função exibeInt(tipo de dado) recebe como parâmetro o valor

a ser exibido no LCD. O tipo de dado declarado na função deve ser do mesmo tipo de dado da variável que desejamos exibir.

Considere:

char cont=200;

Então o parâmetro da função deverá ser:

exibeInt(char variável) signed char cont=100;

Então o parâmetro da função deverá ser:

exibeInt(signed char variável) signed int16 cont=20000;

O parâmetro deverá ser: exibeInt(signed int16 variável) int16 cont=60000;

O parâmetro da função deverá ser: exibeInt(int16 variável) int32 cont=90000;

Então o parâmetro da função deverá ser:

exibeInt(long int32 variável)

ATIVIDADES PROPOSTAS 1

Desenhar o esquemático da figura 10 no software simulador ISIS;

Digitar e compilar o programa 1 no software PIC-C Compiler;

Simular o programa 4 no software ISIS;

Ampliar os ajustes das horas e minutos de todos os 4 campos da figura 12, limitando as horas e minutos em valores válidos.

Salvar e recuperar os 4 campos de ajuste de tempo;

2

Digitar e compilar o programa 4 no software PIC-C Compiler;

Simular o programa 4 em conjunto com o esquemático da figura 10;

Simular o programa 5 em conjunto com o esquemático da figura 10;

Os dígitos válidos do telefone devem ser somente 0 a 9;

Ampliar o número de telefone para 11 dígitos;

Ampliar o tamanho do nome de 4 para 8 letras que contemplem somente o alfabeto maiúsculo;

▪ Salvar e recuperar todas as informações personalizáveis do usuário (telefone e nome);

3

Digitar e compilar o programa 6 no software JFE;

Simular o programa 6 em conjunto com o esquemático da figura 10;

Acrescentar a tecla zera conectada no PORT C2;

Alterar o contador para suportar contagens até 50000, bem como salvar essa faixa de valores na EEPROM;

▪ Desafio supremo: exibir e salvar contagem até 99999 utilizando a variável long int16 cont;

CONCLUSÃO

Analisamos as características técnicas da EEPROM 24C02 e a estrutura de armazenamento organizada em índices ou posições de memória. Para comunicação entre o 8051 e a EEPROM utilizou-se o protocolo de comunicação I2C com a biblioteca i2c.h para ler e escrever dados, os quais puderam visualizados no mapa de memória em nível de simulação. Para salvar dados maiores do que 1 Byte, utilizou-se um algoritmo para quebrar a variável em partes menores para tornar o seu armazenamento possível. Com a EEPROM externa no 8051 ou a interna do PIC foi possível salvar e recuperar as informações, mesmo após o circuito ser desligado.

LICENÇA DE USO DESTE MATERIAL

Todas as informações apresentadas funcionam em nível de simulação de software. Você pode baixa-las no site www.u8051.com.br e utiliza-las de forma parcial ou integral e livremente como material didático.

Documento atualizado em 21/02/2022 16:59 Prof. Cristian M.G ([email protected])

www.u8051.com.br

ANEXOS:

BIBLIOTECA i2C.H

Nesta página você encontra a biblioteca i2c.h para o microcontrolador 8051 para implementar a comunicação entre o microcontrolador a EEPROM 24C02.

Biblioteca i2c.h para 8051

Você deve copiar o código i2c.h (logo abaixo) e colar no JFE.

Em seguida, deverá clicar no menu File >

Save As... e salvar na pasta

8051\SDCC\INCLUDE e preencher o nome i2c.h e finalmente clicar no botão Salvar.

#define TEMPO 1

//***************************************************

void delay_i2c(char i){

int j;

while(i--) for(j=0;j<30;j++);

}

//***************************************************

void start(void){

sda=1;

delay_i2c(TEMPO);

scl=1;

delay_i2c(TEMPO);

sda=0;

}

//***************************************************

void stop(){

sda=0;

delay_i2c(TEMPO);

scl=1;

sda=1;

}

//***************************************************

void write(unsigned char dat){

unsigned char i;

for(i=0;i<8;i++){

scl=0;

sda=(dat&0x80>>i)?1:0;

delay_i2c(TEMPO);

scl=1;

} }

//***************************************************

void ack(void){

scl=0;

delay_i2c(TEMPO);

sda=1;

delay_i2c(TEMPO);

scl=1;

delay_i2c(TEMPO);

scl=0;

}

//***************************************************

void noack(void){

scl=0;

delay_i2c(TEMPO);

sda=1;

delay_i2c(TEMPO);

scl=1;

}

//***************************************************

unsigned char read(){

unsigned char i,buff=0;

sda=1;

for(i=0;i<8;i++){

scl=1;

if(sda) buff|=(0x80>>i);

scl=0;

}

return buff;

}

//***************************************************

void save_i2c(char id,char addr,char ch){

start(); write(id); ack(); write(addr);

ack(); write(ch); ack(); stop();

delay_i2c(100);

}

//***************************************************

char read_i2c(char id,char addr){

unsigned char buff;

start(); write(id); ack();

write(addr); ack(); start();

write(id|1); ack(); buff=read();

noack(); stop();

return buff;

}

Referências

Documentos relacionados

A diferença central é que neste chip é que ao definir as linhas do teclado como entrada de dados, os respectivos I/O’s apresentam estado lógico coletor aberto, que

Memory ou Mem ó ria Programavel Somente para Leitura) na qual ira memorizar de maneira permanente as instru çõ es do programa; Uma mem ó ria RAM (Random Access Memory ou Mem ó ria

O objetivo, tal como visto anteriormente, era traçar um modelo de quadro descritivo para a emissão da ‘Opinião Desfavorável’ em português do Brasil que pudesse servir de suporte

Equipamentos de emergência imediatamente acessíveis, com instruções de utilização. Assegurar-se que os lava- olhos e os chuveiros de segurança estejam próximos ao local de

Tal será possível através do fornecimento de evidências de que a relação entre educação inclusiva e inclusão social é pertinente para a qualidade dos recursos de

d) Tanto na Roma Antiga como nos dias atuais a questão agrária tem sido uma incomoda situação que a humanidade não conseguiu resolver e assim como na antiguidade, hoje esse tema

1. No caso de admissão do cliente, a este e/ou ao seu representante legal são prestadas as informações sobre as regras de funcionamento da ESTRUTURA RESIDENCIAL

As faixas críticas encontradas e os níveis críticos sugeridos de teores foliares dos nutrientes para lavouras de café irrigadas no primeiro ano de adubação ficaram entre 27,3 e 34,8