Você está na página 1de 12

PALAVRAS-CHAVE

Microcontrolador 8051, Microcontrolador PIC 16F877A,


Memória EEPROM E2PROM
PROGRAMAÇÃO C PARA
MICROCONTROLADORES
REQUISITOS PARA ESTUDO
8051 E PIC Este é um tópico avançado e presume que você já tenha
compreendido as seguintes outras unidades de estudo:
 LEITURA DE SENSORES;

UNIDADE DE ESTUDOS  DISPLAY LCD;

MEMÓRIA
METODOLOGIA
EEPROM; I2C 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
CONTEÚDO entre o 8051 e a EEPROM será aplicado o protocolo de
PROGRAMÁTICO comunicação I2C abordado em seus aspectos gerais e a
biblioteca i2c.h proverá operações de leitura e escrita na
 A memória EEPROM 24C02; memória cujos dados poderão ser conferidos no mapa
de memória em nível de simulação. Para salvar dados
 Armazenamento de dados; índices; maiores do que 1 Byte a variável será quebrada em
 Comunicação I2C; endereço I2C; A biblioteca i2c.h partes menores para tornar o seu armazenamento
 Tags de identificação da string; possível.
 Salvando e lendo dados;
A abordagem desta unidade de estudos utiliza a
 Visualizando os dados da EEPROM no simulador; programação C para o microcontrolador AT89S52, da
apagando os dados da EEPROM; família MCS-51 ou popularmente chamada de “8051” de
 Salvando tipo de dado int; modo que as informações salvas na EEPROM 24C02
sejam exibidas em display LCD 16x2. Depois a atividade
 Tipos de dados em C;
é realizada com a programação C para o
 flag carryout; microcontrolador PIC16F877A da família PIC 16F que
 Avaliação: Entrega das Atividades propostas com dispõe de memória EEPROM interna.
memória EEPROM;

RECURSOS
Para desenvolver e experimentar este material é
necessário um computador com sistema operacional
APRESENTAÇÃO Windows XP ou posterior e baixar o pacote de
programas disponível em www.u8051.com.br o qual
Nesta unidade de estudos vamos conhecer o
contém as seguintes ferramentas de desenvolvimento:
funcionamento e a aplicação da memória EEPROM
Compilador 8051 (JFE Editor), Compilador PIC (PCW),
necessária para salvar informações antes do circuito ser
Software de simulação Proteus-ISIS.
desligado. Este componente tem como finalidade salvar
e recuperar valor de variáveis, senhas, configurações do
sistema, etc.
AVALIAÇÃO DE DESEMPENHO
As variáveis são alocadas na memória RAM do A secção ATIVIDADES PROPOSTAS apresenta um
microcontrolador e quando o sistema é desligado esses conjunto de exercícios de dificuldade incremental a fim
dados de execução são perdidos. Muitas aplicações não de avaliar o seu entendimento a cerca desta unidade de
podem perder os dados de execução, isto é, o sistema estudos.
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
RESULTADOS ESPERADOS
dados do sistema e recupera-la, mesmo que o sistema Ao concluir o desenvolvimento das atividades propostas,
permaneça desligado por anos. você deverá ser capaz de utilizar a memória EEPROM
para salvar e recuperar dados nestes modelos de
microcontroladores.

u8051.com.br MEMÓRIA EEPROM - Página 1/12


1.
1. A COMUNICAÇÃO I2C
A MEMÓRIA EEPROM Trata-se do protocolo de comunicação I2C, orginalmente
desenvolvido pela Phillips que utiliza apenas duas vias para
comunicação entre componentes que têm suporte I2C. As vias
As memórias EEPROM (Electrically-Erasable Programable Read- são:
Only Memory) são geralmente utilizadas em projetos que é SDA (serial data) e SCL (serial clock).
necessário salvar informações em tempo de execução (running
time) do sistema, como por exemplo: contagens, parâmetros do Cada componente I2C tem ID especificado pelo fabricante. A
sistema, senhas, entre outros dados. Assim, quando o sistema EEPROM 24C02 têm ID 160, enquanto que o RTC DS1307 tem
for ligado novamente, as informações podem ser recuperadas ID 208, por exemplo.
da memória com o valor anterior.
É possível “pendurar” vários dispositivos I2C nas linhas SDA e SCL
Dizemos então que a EEPROM é uma memória não-voilátil (barramento I2C) como demonstrado na figura 3.
pois seus dados não se perdem quando da falta de energia. Por
outro lado, a memória RAM do microcontrolador é do tipo
Barramento I2C
volátil, pois a cada energização as variáveis são redefinidas com
os valores especificados no código-fonte.

ID 208
ID 160

Fig. 3: Dois
1.1 dispositivos

A EEPROM 24C02 conectados na


rede I2C

Observe que os dispositivos estão conectados em paralelo ao


barramento I2C. Então, é o ID que determina o dispositivo de
destino. Mas adiante estudaremos outros detalhes importantes
relacionados ao ID do dispositivo.

O código a seguir demonstra a leitura do índice 0 na EEPROM


24C02 cujo ID é 160:
Figura 1: Memoria EEPROM Figura 2: Memoria Pinagem EEPROM ID
Índice lido
char cont;
cont=read_i2c(160, 0);
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
Após execução destes comandos char cont receberá o valor 26
de ciclos de escrita e leitura. Cada ciclo de escrita ocorre ao
se considerarmos a tabela 1. A função read_i2c conecta ao
salvar um dado, já o de leitura acontece quando buscamos o
dispositivo escolhido (EEPROM) e executa a operação de leitura
dado salvo na memória. Qualquer acesso que fazemos à
do índice determinado.
memória EEPROM diminui o ciclo de vida dela.
A seguir temos o código que salva a variável char cont no índice
0 da EEPROM a qual tem ID 160:

Índice destino
char cont=26;
1.2 save_i2c(160, 0, cont);

ARMAZENANDO DADOS A função save_i2c conecta ao dispositivo escolhido (EEPROM) e


executa a operação de escrita no índice de destino. Por isso, o
A memória EEPROM armazena dados de 8 bits (1 Byte), que na
linguagem C é o tipo char. A exemplo do modelo 24C02, são valor 26 será salvo no índice 0 da memória, substituindo o valor
256 (0 a 255) espaços de armazenamento. anterior.

Cada espaço tem um endereço de Dado


memória ou índice. Podemos então Índice
Armazenado
dizer que a memória 24C02 têm 256 0 26
índices de memória. 1
A tabela 1 ilustra os índices da 2 1.3
memória EEPROM. 3
4 A BIBLIOTECA I2C.H
...
Tabela 1: Espaços de memória identificados por
Indice ou endereço 255 Encontra-se na pasta C:\8051\SDCC\INCLUDE e implementa as
seguintes definições e funções do protocolo I2C:

Para salvar uma variável (escrever) na EEPROM, devemos


especificar o índice de destino. Por exemplo, na tabela 1 o valor Comando Efeito
“26” foi salvo no índice 0 da EEPROM. Essa informação fica retida #define scl Px_y Define o I/O do 8051
no chip mesmo quando ele for desligado, e segundo a conectado à linha SCL
fabricante ATMEL, o tempo de armazenamento é 100 anos. #define sda Px_y Define o I/O do 8051
conectado à linha SDA
Já para recuperar uma informação (ler), devemos especificar de Salva variável no índice
save_i2c(ID, índice, variável);
qual índice virá a informação. Por exemplo, ao ler o índice 0 da do ID escolhido
Busca dado salvo no
tabela 1 a EEPROM fornecerá o valor “26”. Tanto as operações variável=read_i2c(ID, índice);
índice do ID escolhido
de escrita quanto de leitura diminuem 1 ciclo de vida do
chip no total de 1 milhão de acessos. Tabela 2: Funções da biblioteca i2ch

u8051.com.br MEMÓRIA EEPROM - Página 2/12


Na figura 6 temos um exemplo de execução o programa.
1.4 Logo após você terá a explicação de funcionamento.

ESQUEMÁTICO 8051 E /* P RO G R AM A 1 */

EEPROM 24C02
#include<at89x52.h>
#include<lcd.h>
#define BT_AVANCAR P3_2
#define BT_SOMAR P3_3
O circuito da figura 4 apresenta a conexão entre o #define EEPROM 160
microcontrolador e a memória. O Display LCD será utilizado #define sda P2_6
para exibir as operações de leitura e escrita na EEPROM. #define scl P2_7
#include<i2c.h>

bit b1, b2;


char horaL, minL, horaD, minD, indice;

void atualizaLCD();
void atualizaCursor();
void leMemoria();
//******************************
void main(){
leMemoria();
lcd_init();
atualizaLCD();
atualizaCursor();

while(1)
{
if(BT_SOMAR==0 && b1==0)
{
b1=1;
if(indice==0)
{
horaL++;
if(horaL>23) horaL=0;
save_i2c(EEPROM, 0, horaL);
}
if(indice==1)
{
minL++;
save_i2c(EEPROM, 1, minL);
}
atualizaLCD();
}
if(BT_SOMAR==1) b1=0;

if(BT_AVANCAR==0 && b2==0)


{
b2=1;
Fig. 4: Conexão da EEPROM ao 8051 indice++;
if(indice>3) indice=0;
atualizaCursor();
Você encontrará esta simulação na pasta }
C:\8051\ISIS77\EXEMPLOS\8051_EEPROM_COM_LCD.DSN if(BT_AVANCAR==1) b2=0;
}
Este esquema foi desenhado no software Proteus-ISIS versão 7 }
ou posterior utilizando os seguintes componentes: //******************************
void atualizaLCD()
{
Referência Componente lcd_cursor(0);
AT89C52 Microcontrolador AT89C52 lcd_gotoxy(1,1);
24C02C Memória EEPROM 24C02 lcd_puts("LIG ");
LM016L Display LCD 16x2 lcd_putval(horaL, '2d');
lcd_putchar(':');
BUTTON Botões AVANCAR e SOMAR
lcd_putval(minL, '2d');
lcd_gotoxy(2,1);
lcd_puts("DES ");
Uma versão portátil deste lcd_putval(horaD, '2d');
simulador pode ser lcd_putchar(':');
executada a partir da pasta lcd_putval(horaD, '2d');
8051\ISIS77\BIN\ISIS.EXE atualizaCursor();
}
Figura 5: Executando o //******************************
Simulador ISIS void atualizaCursor()
{
A biblioteca i2.h implementa o protocolo I2C no 8051 através if(indice==0) lcd_gotoxy(1,6);
dos I/O’s definidos nas diretivas #define sda e #define scl antes if(indice==1) lcd_gotoxy(1,9);
do #include<i2c.h>. Já a comunicação com o LCD é lcd_cursor(1);
implementada na biblioteca lcd.h. Você verá a declaração destas }
bibliotecas no programa 1: //******************************
void leMemoria()
{
horaL=read_i2c(EEPROM, 0);
minL=read_i2c(EEPROM, 1);
1.5 //incluir mais comandos...
}
SALVANDO INFORMAÇÕES
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. //Fig. 6: Tela do programa 1

u8051.com.br MEMÓRIA EEPROM - Página 3/12


Você pode revisar a unidade de estudos DISPLAY LCD para No teste “if” acima, é necessário que o botão seja pressionado
entender as instruções lcd_init. lcd_gotoxy, lcd_putchar, lcd_puts e que b1 seja igual a 0. A variável b1 já recebeu 0 no momento
e lcd_cursor. Por isso, essas instruções não serão aqui da sua declaração. Por isso, basta apenas que o botão seja
pressionado para executar cont++.
detalhadas. Nosso foco será a EEPROM.
O problema aqui é: se o botão for mantido pressionado, a
As variáveis horaL, minL, horaD e horaL armazenam o horário de variável cont somará repetidamente, invés de somar uma única
início e fim da temporização, sendo horas até o limite de 23 e vez. Para resolver, devemos atribuir b1=1 após executar cont++
minutos até 59. Por isso, o tipo char (que vai até o limite de 255) como segue o exemplo:
poderá armazenar o horário. Além disso, o tipo de dado char é
compatível com a memória EEPROM de 8bits. Botão pressionado b1 não tem mais o valor 0
A figura 6 apresenta as variáveis e o dado que elas armazenam:
if(BT_SOMAR==0 && b1==0){
horaL minL
cont++;
b1=1;
}

horaD minD Observe que acrescentamos b1=1 após a instrução cont++.


Com efeito, o teste “if” necessita que o botão esteja pressionado
e que x seja 0. Por mais que o botão seja pressionado, o teste
Observe que na função main ocorre um “salto” para a função “b1==0” não é verdadeiro. Portanto, o comando cont++ será
leMemoria com o objetivo de buscar na EEPROM os valores executado outra vez.
anteriores das variáveis.
Mas podemos acrescentar uma condição para que seja somado
A função leMemoria está novamente: Que o usuário solte o botão. Assim temos:
Dado
incompleta, pois falta ainda, ler os Índice
Armazenado if(BT_SOMAR==0 && b1==0){
índices 1, 2 e 3 da EEPROM. A 0 horaL
tabela 3 mostra em qual índice 1 minL cont++;
cada informação deve ser lida e 2 horaD b1=1;
guardada. 3 minD }
Botão solto b1 recebe o valor inicial
Tabela 3: Mapa da Memória

Executado o último comando da função leMemoria ocorre então if(BT_SOMAR==1) b1=0;


o “retorno” para a função main em que as demais funções são
executadas.
Para saber se o botão foi solto, o teste “if” verifica respectivo I/O
A variável char indice vai de 0 a 3 correspondendo ao campo está em nível 1. Se isto for verdadeiro, então redefinimos b1 ao
que o usuário está ajustando seguindo a tabela 3. Por isso, seu valor inicial da sua declaração que é 0.
podemos, através da variável indice posicionar corretamente o
cursor piscante, bem como determinar qual variável deve ser Agora, com b1=0 basta que o botão seja pressionado
novamente para que o comando cont++ seja executado mais
somada que leva a dedução da tabela 4. uma vez.

A variável b1 é uma flag que serve para sinalizar se um evento


já aconteceu (neste caso, o evento clique). A variável do tipo bit
Valor de Variável alterada no Posição do pode assumir os valores 0 e 1, apenas. Isto é, são variáveis
pos botão SOMAR cursor booleanas que ocupam apenas 1 bit da RAM do
indice==0 horaL (hora ligar) (1,6) microcontrolador.
indice==1 minL (minutos ligar) (1,9)
Observe que o valor de horaL é salvo no índice 0 e que a função
indice==2 horaD (hora desligar) (2,6) leMemória, busca o valor salvo neste mesmo índice. Cada
indice==3 mind (minutos desligar) (2,9) 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.
Tabela 4: Variável pos é referência de ajustes e de posição do cursor

1.7
VISUALIZANDO OS DADOS
1.6 DA EEPROM NO ISIS
EVENTO CLIQUE
Durante a simulação é possível visualizar os dados Armazenados
Observe que no programa 1 a definição BT_SOMAR equivale ao na memória EEPROM.
I/O P3.3. Para saber se o botão foi pressionado, o teste “if”
verifica respectivo I/O está em nível 0.

Para isso, basta pausar a simulação


#define BT_SOMAR P3_3 e acessar o menu Debug>I2C
Memory Internal Memory.
int cont=0;
bit b1=0;

I/O P3.3 b1 foi declarada com o valor


0
Fig. 8: Visualizando os dados da EEPROM
if(BT_SOMAR==0 && b1==0){
cont++;
}

u8051.com.br MEMÓRIA EEPROM - Página 4/12


/* P RO G R AM A 2 */
1.8 #include<at89x52.h>
APAGANDO OS DADOS DA #include<lcd.h>
#define BT_AVANCAR P3_2

EEPROM NO ISIS #define BT_SOMAR


#define EEPROM
P3_3
160
#define sda P2_6
#define scl P2_7
#include<i2c.h>
Para limpar o conteúdo da
EEPROM encerre simulação e #define NUM_MIN 0
insira um novo componente #define NUM_MAX 9
24C02C exatamente sobre o
bit b1, b2;
componente “antigo”. Em seguida char indice, num[8]={5,1,9,9,6,0,2,6};
o ISIS perguntará se você deseja char nome[4]={'C','A','S','A'};
substituir o componente (Replace
Componente?) e clique no botão void atualizaLCD();
OK. Fig. 9: Substituindo o componente void atualizaCursor();
void leMemoria();
//******************************
void main()
{
leMemoria();
lcd_init();
atualizaLCD();
atualizaCursor();

1.9 while(1)
{
VETORES EM C if(BT_SOMAR==0 && b1==0)
{
b1=1;
Um vetor é uma variável indexada, ou seja, comporta várias if(indice<8) //ajustando numero
informações do tipo de dado em que o vetor é declarado. {
num[indice]++;
Considere a seguinte declaração:
if(num[indice]>NUM_MAX)
{
char num[8]={5,1,9,9,6,0,2,6}; num[indice]=NUM_MIN;
}
O vetor num têm 8 índices e cada um armazena um dado do save_i2c(EEPROM, indice, num[indice]);
}
tipo char. Assim temos no vetor num os índices 0 ao 7 conforme else //ajustando nome
o exemplo abaixo. {
nome[indice-8]++;
num[0]
num[1]
num[2]
num[3]
num[4]
num[5]
num[6]
num[7]

if(nome[indice-8]>'E')
{
nome[indice-8]='A';
}
char num[8]={5 , 1 , 9 , 9 , 6 , 0 , 2 , 6 }; save_i2c(EEPROM, indice, nome[indice-8]);
}
atualizaLCD();
}
if(BT_SOMAR==1) b1=0;

if(BT_AVANCAR==0 && b2==0)


{
b2=1;
indice++;
if(indice>11) indice=0;
atualizaCursor();
}
if(BT_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();
1.10 }
//******************************
SALVANDO NUMERO DE void atualizaCursor()
{
TELEFONE E NOME if(indice<8)lcd_gotoxy(1, indice+1);
else lcd_gotoxy(2, indice-7);
lcd_cursor(1);
O programa 2 faz uso do vetor num para armazena um número }
//******************************
telefônico de 9 dígitos e do vetor nome para armazenar o nome void leMemoria()
de quem atende no respectivo número. {
unsigned char i;
Você terá a descrição de funcionamento logo após ao código
do programa. for(i=0; i<8; i++){
num[indice]=read_i2c(EEPROM, i);
}
A figura 10 ilustra a tela de execução do programa.
nome[0]=read_i2c(EEPROM, 8);
nome[1]=read_i2c(EEPROM, 9);
nome[2]=read_i2c(EEPROM,10);
nome[3]=read_i2c(EEPROM,11);
}
Fig.10: Tela do programa 2
u8051.com.br MEMÓRIA EEPROM - Página 5/12
Para salvar cont/256 no índice 0 e cont%256 no índice 1
MAPA DE MEMÓRIA USADA PELO PROGRAMA aplicamos os seguintes comandos:
O programa 2 ocupou 12 endereços de memória EEPROM,
sendo 0 a 11 decimal ou 0x00 a 0x0B
save_i2c(EEPROM, 0, cont/256); //salva 1
save_i2c(EEPROM, 1, cont%256); //salva 44
0 5 1 1 2 9 3 9
4 6 5 0 6 2 7 6 Teremos os seguintes dados na memória:
8 C 9 A 10 S 11 A 0 1 2 3
1 (01) 44 (2C)
Tabela 5: Mapa de dados da EEPROM 24C02 Tabela 5: valor 300 salvo dos índices 0 e 1 da EEPROM

Você pode sempre poderá conferir os dados que estão salvos Para recuperar o dado é preciso ler e “unir” os valores destes
na EEPROM. Para isso veja o tópico 1.7. mesmos índices aplicando multiplicação “*” e soma “+”.

0 1 2 3
1 (01) 44 (2C)
x 256 +
256 + 44 = 300

Sendo 255 o valor máximo do Byte, temos que o valor máximo


Fig. 11: Mapa de dados da EEPROM 24C02 simulado armazenável com 2 índices seja:

0 1 2 3
Quando a janela do mapa de memória for exibida, você poderá 255 (FF) 255 (FF)
ajustar o tamanho da fonte clicando nela com o botão direito e
x 256 +
escolhendo a opção Set Font.
65280 + 255 = 65535

FUNCIONAMENTO DO PROGRAMA 2
Vamos analisar o funcionamento do Programa 2 considerando O programa 3 utiliza os índices 0 e 1 da EEPROM para salvar a
que você já entendeu o Programa 1. Ao todo são 8 dígitos do variável int cont.
telefone e 4 dígitos para o nome, totalizando a navegação entre
11 campos de dados no LCD. Temos como referência a variável /* P RO G R AM A 3 */
indice.

Quando indice está entre 0 e 7, o botão SOMAR aumenta o valor #include<at89x52.h>


do vetor num[indice]. Isto é, se indice for 0 então num[0], que #include<lcd.h>
#define BT_SOMAR P3_3
contém o valor 5 será somado e terá agora 6. #define EEPROM 160
#define sda P2_6
Se indice estiver acima de 7, então o vetor nome é que deve ser #define scl P2_7
alterado. Mas observe que nome tem apenas 4 índices, logo, #include<i2c.h>
nome[8] seria inválido. Por isso, temos nome[pos-8]++. O
comando for(i=0;i<8;i++) lcd_putchar(num[i]+48); mostra todos bit b1;
int cont=12345;
os 8 índices do vetor num no LCD. Lembre-se de que somamos
+48 para converter os números para ASCII; void atualizaLCD();
void atualizaCursor();
Já for(i=0;i<4;i++) lcd_putchar(nome[i]); exibe o conteúdo do void leMemoria();
vetor nome. Aqui não é necessário converter para ASCII por que //******************************
já estamos manipulando caracteres. void main(){
leMemoria();
lcd_init();
Lembre-se de que escolhemos armazenar apenas letras no vetor atualizaLCD();
nome. Aqui os caracteres válidos são: A, B, C, D, E por que atualizaCursor();
aplicamos o filtro if(nome[pos-8]>'E') nome[pos-8]='A';
while(1){
if(BT_SOMAR==0 && b1==0){
b1=1;
cont++;
save_i2c(EEPROM, 0, cont/256);
1.11 save_i2c(EEPROM, 1, cont%256);

SALVANDO DADO DE 16 }
atualizaLCD();

BITS (TIPO DE DADO INT)


if(BT_SOMAR==1) b1=0;
}
}
//******************************
Vimos que a memória EEPROM armazena dados de 8 bits (1 void atualizaLCD(){
Byte), o tipo char em C. Mas existem aplicações em que se faz lcd_cursor(0);
necessário salvar variáveis do tipo int que tem o tamanho de 2 lcd_gotoxy(1,1);
lcd_putval(cont, '5d');
Bytes, ou seja, o dobro do tipo char. Por isso, devemos quebrar
atualizaCursor();
a variável int de 16bits em duas partes de 8bits (char). }
//******************************
Para ilustrar considere a variável int cont. void atualizaCursor(){
lcd_gotoxy(1,5);
int cont=300; lcd_cursor(1);
}
O valor máximo de 1 Byte é 255. Então o valor 300 não pode ser //******************************
armazenado em um único índice da EEPROM. É preciso void leMemoria(){
cont=(read_i2c(EEPROM, 0)*256);
“quebrar” a variável int em duas variáveis char com a operação cont=cont+read_i2c(EEPROM, 1);
de divisão “/” e módulo “%” que obtém o resto da divisão. }

Considere: int cont=300;


cont/256;  300/256 = 1,17
cont%256;  300%256 = 44
u8051.com.br MEMÓRIA EEPROM - Página 6/12
cont++;
if(CY==0)
{
1.12 lcd_gotoxy(2,1);
lcd_puts("Carry Out Flag");
O TIPOS DE DADOS }

ANSI-C Considere int cont=32767, se ocorrer uma operação de adição


cont++ o evento carryout será ativado e a flag CY recebe 0, pois
o tipo de dado int não tem espaço suficiente para alocar o valor
Valores que pode 32768. Um modo simples de evitar o evento carryout é verificar
Tipo de dado Bits Bytes a flag CY.
armazenar (alcance)
0a1
bit 1
(128 disponíveis)
signed char 8 1 -128 a +127
ATIVIDADES PROPOSTAS
unsigned char 8 1 0 a 255
1
signed int 16 2 -32768 a + 32767  Desenhar o esquemático da figura 4 no software
simulador ISIS;
unsigned int 16 2 0 a 65535  Digitar e compilar o programa 1 no software JFE;
 Simular o programa 1 no software ISIS;
-2147483648 a  Ampliar os ajustes das horas e minutos de todos os 4
signed long 32 4
+2147483648 campos da figura 6, limitando as horas e minutos em
unsigned long 32 4 0 a 4294967295 valores válidos.
±1,175494E-38 a  Salvar e recuperar os 4 campos de ajuste de tempo;
float 32 4
±3,402823E+38

Tabela 8: Tipos de dados em C (Padrão ANSI-C) 2


 Digitar e compilar o programa 2 no software JFE;
 Simular o programa 2 em conjunto com o esquemático
A função exibeInt(tipo de dado) recebe como parâmetro o valor
da figura 4;
a ser exibido no LCD. O tipo de dado declarado na função deve
 Simular o programa 6 em conjunto com o esquemático
ser do mesmo tipo de dado da variável que desejamos exibir.
da figura 2;
 Os dígitos válidos do telefone devem ser somente 0 a 9;
Considere:
 Ampliar o número de telefone para 11 dígitos;
char cont=100;  Ampliar o tamanho do nome de 4 para 8 letras que
O parâmetro da função deverá ser: exibeInt(char variável) contemplem somente o alfabeto maiúsculo;
 Salvar e recuperar todas as informações personalizáveis
unsigned char cont=200; do usuário (telefone e nome);
Parâmetro da função: exibeInt(unsigned char variável)

int cont=20000; 3
O parâmetro da função deverá ser: exibeInt(int variável)  Digitar e compilar o programa 3 no software JFE;
 Simular o programa 3 em conjunto com o esquemático
unsigned int cont=60000; da figura 4;
Parâmetro da função: exibeInt(unsigned int variável)  Acrescentar a tecla ZERA conectada em P3.4;
 Alterar o contador para suportar contagens até 50000,
long int cont=90000; bem como salvar essa faixa de valores;
Parâmetro da função: exibeInt(long int variável)  Desafio supremo: exibir e salvar contagem até 99999
utilizando a variável long int cont. Dica: você usará os
Ao ler uma posição de memória você dever armazenar o dado valores /65536, /256%256 para salvar o dado em 3
numa variável que tenha essa capacidade de armazenamento. posições da memória EEPROM.

Por exemplo, o valor lido da EEPROM sempre caberá numa


variável do tipo unsigned char, exceto no exemplo do programa
2 em que o dado é lido da memória e multiplicado por 256.

1.13
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 nos sistemas
críticos e sem tolerância a falhas, é importante tratar essa flag
após cada operação aritmética para identificar se a variável de
destino 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, significando erro na operação.

u8051.com.br MEMÓRIA EEPROM - Página 7/12


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 7
5 6
(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.

FUNÇÕES DE ACESSO DA
3.2
EEPROM INTERNA DO PIC
O código seguir demonstra a leitura do índice 7 na EEPROM do
PIC:
índice
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; índice


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:

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

u8051.com.br MEMÓRIA EEPROM - Página 8/12


3.3 ESQUEMÁTICO PIC E DISPLAY LCD #include<16F877A.h>
#fuses nowdt, nobrownout, xt, noput
O circuito da figura 10 apresenta o microcontrolador conectado #use fast_io(C)
ao display LCD para que na tela sejam exibidas as operações de #use delay(clock=4000000) // Programa 4
leitura e escrita na EEPROM.
#include<lcd.h>
#define AVANCAR PIN_C1
#define SOMAR PIN_C0

int1 b1,b2;
signed char horaL, minL, horaD, minD, indice;

void atualizaLCD();
void atualizaCursor();
void leMemoria();
//******************************
void main()
{
set_tris_C(0b00000111);
leMemoria();
lcd_init();
atualizaLCD();
atualizaCursor();
while(1)
{
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 feeva le.br pucrs ufrgs uninter faccat ita unisanta unoe ste anhanguera usp 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

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


{
b1=1;
if(indice==0)
{
horaL++;
write_eeprom(0, horaL);
}
Figura 10: Conectando o display LCD 16x2 ao microcontrolador if(indice==1) minL++;
PIC16F877A
atualizaLCD();
}
Você encontrará esta simulação na pasta if(input(SOMAR)==1) b1=0;
C:\8051\ISIS77\EXEMPLOS\PIC_DISPLAY_LCD.DSN

Observe que quando os I/O’s do PIC são utilizados para leitura if(input(AVANCAR)==0 && b2==0)
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, b2=1;
esses I/O’s ficam em coletor aberto ou tristate, necessitando de indice++;
resistores pull up R1 e R2 para definir o estado lógico 1 destas if(indice>3) indice=0;
“entradas” de teclas. Veja a tabela 12. atualizaCursor();
}
Este esquema foi desenhado no software Proteus-ISIS versão 7
if(input(AVANCAR)==1) b2=0;
ou posterior utilizando os seguintes componentes:
}
Referência Componente }
PIC16F877A Microcontrolador PIC16F877A //******************************
LM016L Display LCD 16x2 void atualizaLCD()
BUTTON Botões AVANCAR e SOMAR {
lcd_cursor(0);
RES Resistor 4K7
lcd_gotoxy(1,1);
printf(lcd_putc, "LIG %02i:%02i", horaL, minL);
lcd_gotoxy(2,1);
Uma versão portátil deste
simulador pode ser printf(lcd_putc, "DES %02i:%02i", horaD, minD);
executada a partir da pasta atualizaCursor();
8051\ISIS77\BIN\ISIS.EXE }
//******************************
Figura 11: Executando o void atualizaCursor()
Simulador ISIS {
if(indice==0) lcd_gotoxy(1,6);
if(indice==1) lcd_gotoxy(1,9);
A biblioteca lcd.h comunica com o PIC através do PORT B, mas
esta definição pode ser editada dentro da biblioteca se //if(indice==2) lcd_gotoxy(?,?);
necessário. Para incluir o protocolo de comunicação com o LCD //if(indice==3) lcd_gotoxy(?,?);
você verá a declaração da biblioteca lcd.h na seguinte ordem: lcd_cursor(1);
}
#include<16F877A.h> //******************************
#fuses nowdt, nobrownout, xt, noput, noprotect void leMemoria()
#use delay(clock=4000000) {
#include<lcd.h> //busca na EEPROM as variaveis
horaL=read_eeprom(0);
minL=read_eeprom(?);
3.4 PROGRAMAÇÃO //horaD=read_eeprom(?);
A seguir temos a programação para o //minD=read_eeprom(?);
circuito da figura 10: ela permite ajustar os //Fig. 12: Tela do }
parâmetros de um temporizador: horário de programa 4
ligar e o horário de desligar um dispositivo
elétrico. Na figura 12 temos um exemplo de
execução o programa.
u8051.com.br MEMÓRIA EEPROM - Página 9/12
O funcionamento do programa 4 está detalhado no item 1.5, //******************************
mas o compilador aqui utilizado para o PIC é o PIC-C Compiler void atualizaLCD(){
que implementa algumas funções para manipular os I/O’s do char i;
microcontrolador. São elas: lcd_cursor(0);
lcd_gotoxy(1,1);
set_tris_IO(0bXXXXXXX); //IO é o PORT (A,B,C,D ou E) 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]);
No PIC você deve especificar os I/O’s que serão utilizados como atualizaCursor();
entrada de dados (leitura de botões). A instrução set_tris define }
a direção dos dados sendo 0=Output e 1=Input. //******************************
void atualizaCursor(){
Comando em binário literal: set_tris_C(0b00000111); if(indice<8)lcd_gotoxy(1, indice+1);
Efeito: C7, C6, C5 e C4 são saídas. C3, C2, C1 e C0 são entradas else lcd_gotoxy(2, indice-7);
lcd_cursor(1);
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 void leMemoria(){
//comandos para ler os dados da EEPROM nos
Tabela 12: Definido a direção dos dados do PORT C //endereços 0 a 11
num[0]=read_eeprom(0);
A função input(IO) lê o nível lógico encontrado no I/O num[1]=read_eeprom(1);
especificado. A diretiva #use fast_io(IO) especifica que o //ler demais endereços...
programador irá decidir quais I/O’s serão entrada com o }
comando set_tris(IO).
TIPO DE DADO INT16 E SIGNED INT (PIC)
O tipo de dado signed int16 ou signed long suporta faixa de
SALVANDO NUMERO DE
3.5 valores negativos e positivos. O tipo int16 ou long opera
somente com a faixa de valores positiva. Na tabela a seguir
TELEFONE E NOME (PIC) temos um comparativo de alcance destes dois tipos de dados:
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 Tipo de dado Alcance de armazenamento
de quem atende no respectivo número. signed int16 ou
signed long
-32768 a +32767
A figura 13 ilustra a tela de
execução do programa. int16 ou
long
0 a 65535
Fig. 13: Tela do programa 5 Tabela 13: Diferença entre o tipos de dado int16 e signed int16
#include<16F877A.h>
#fuses nowdt, nobrownout, xt, noput, noprotect
#use fast_io(C) 2 SALVANDO TIPO DE DADO INT16
#use delay(clock=4000000)
#include<lcd.h>
A EEPROM armazena dados de 8 bits (1 Byte), o tipo char em C.
#define AVANCAR PIN_C1 Mas existem aplicações em que se faz necessário salvar variáveis
#define SOMAR PIN_C0 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
int1 b1,b2; duas partes que resultem em duas variáveis do tipo char. Para
char indice, num[8]={5,1,9,9,6,0,2,6}; ilustrar considere a variável int16 cont.
char nome[4]={'C','A','S','A'};
int16 cont=300;
void atualizaLCD();
void atualizaCursor(); O valor máximo de 1 Byte é 255. Então o valor 300 não pode ser
void leMemoria(); armazenado em um único índice da EEPROM. É necessário
//****************************** “quebrar” a variável int16 em duas variáveis char com a
void main(){ operação de divisão “/” e módulo “%” que obtém o resto da
leMemoria(); divisão.
lcd_init();
atualizaLCD(); cont=300;
atualizaCursor();
// Programa 5 cont/256;  300/256 = 1,17
while(1){ cont%256;  300%256 = 44
if(input(SOMAR)==0 && b1==0) {
b1=1;
if(indice<8){ Para salvar cont/256 no índice 0 e cont%256 no índice 1
num[indice]++; aplicamos os seguintes comandos:
write_eeprom(indice, num[indice]);
} write_eeprom(0, cont/256);
else{ write_eeprom(1, cont%256);
nome[indice-8]++;
if(nome[indice-8]>'E'){ Teremos os seguintes dados na memória interna do PIC:
nome[indice-8]='A';
0 1 2 3
} 1 (01) 44 (2C)
write_eeprom(indice, num[indice-8]);
} Tabela 5: valor 300 salvo dos índices 0 e 1 da EEPROM
atualizaLCD();
}
Para recuperar o dado é preciso ler e “unir” os valores destes
if(input(SOMAR)==1) b1=0;
mesmos índices aplicando multiplicação “*” e soma “+”.
if(input(AVANCAR)==0 && b2==0){ 0 1 2 3
b2=1; 1 (01) 44 (2C)
indice++;
x 256 +
if(indice>11) indice=0;
atualizaCursor(); 256 + 44 = 300
}
if(input(AVANCAR)==1) b2=0;
}
}
u8051.com.br MEMÓRIA EEPROM - Página 10/12
O programa 6 utiliza os índices 0 e 1 da EEPROM para salvar a ATIVIDADES PROPOSTAS
variável int16 cont.
1
// Programa 6  Desenhar o esquemático da figura 10 no software
#include<16F877A.h> simulador ISIS;
#fuses nowdt, nobrownout, xt, noput  Digitar e compilar o programa 1 no software PIC-C
#use fast_io(C) Compiler;
#use delay(clock=4000000)  Simular o programa 4 no software ISIS;
#include<lcd.h>  Ampliar os ajustes das horas e minutos de todos os 4
campos da figura 12, limitando as horas e minutos em
#define SOMAR PIN_C0 valores válidos.
 Salvar e recuperar os 4 campos de ajuste de tempo;
int1 b1;
int16 cont=12345;

void atualizaLCD();
2
void exibeInt(int16 valor);  Digitar e compilar o programa 4 no software PIC-C
void atualizaCursor(); Compiler;
void leMemoria();  Simular o programa 4 em conjunto com o esquemático
//****************************** da figura 10;
void main(){  Simular o programa 5 em conjunto com o esquemático
leMemoria(); da figura 10;
lcd_init();  Os dígitos válidos do telefone devem ser somente 0 a 9;
atualizaLCD();  Ampliar o número de telefone para 11 dígitos;
atualizaCursor();  Ampliar o tamanho do nome de 4 para 8 letras que
while(1){ contemplem somente o alfabeto maiúsculo;
if(input(SOMAR)==0 && b1==0) {  Salvar e recuperar todas as informações personalizáveis
b1=1; do usuário (telefone e nome);
cont++;
write_eeprom(0, cont/256);
write_eeprom(1, cont%256); 3
atualizaLCD();  Digitar e compilar o programa 6 no software JFE;
}  Simular o programa 6 em conjunto com o esquemático
if(input(SOMAR)==1) b1=0; 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;
void atualizaLCD(){  Desafio supremo: exibir e salvar contagem até 99999
lcd_cursor(0); utilizando a variável long int16 cont;
lcd_gotoxy(1,1);
exibeInt(cont);
atualizaCursor();
}
//******************************
void exibeInt(int16 valor){
printf(lcd_putc, "%05li", valor);
}
//******************************
void atualizaCursor(){
lcd_gotoxy(1,11);
lcd_cursor(1);
}
//******************************

CONCLUSÃO
void leMemoria(){
unsigned char parte2;
cont=(read_eeprom(0)*256);
parte2=read_eeprom(1);
Analisamos as características técnicas da EEPROM 24C02 e a
cont=cont+parte2;
} 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
A função exibeInt(tipo de dado) recebe como parâmetro o valor visualizados no mapa de memória em nível de simulação. Para
a ser exibido no LCD. O tipo de dado declarado na função deve salvar dados maiores do que 1 Byte, utilizou-se um algoritmo
ser do mesmo tipo de dado da variável que desejamos exibir. para quebrar a variável em partes menores para tornar o seu
Considere: armazenamento possível. Com a EEPROM externa no 8051 ou a
interna do PIC foi possível salvar e recuperar as informações,
char cont=200; mesmo após o circuito ser desligado. Para finalizar, é importante
Então o parâmetro da função deverá ser: considerar que toda memória EEPROM, seja externa ou
exibeInt(char variável) embutida no microcontrolador tem um ciclo de vida que reduz
a cada operação de escrita ou leitura de dados.
signed char cont=100;
Então o parâmetro da função deverá ser:
exibeInt(signed char variável)

signed int16 cont=20000; LICENÇA DE USO DESTE MATERIAL


O parâmetro deverá ser: exibeInt(signed int16 variável) Todas as informações apresentadas funcionam em nível de
simulação de software. Você pode baixa-las no site
int16 cont=60000; www.u8051.com.br e utiliza-las de forma parcial ou integral e
livremente como material didático.
O parâmetro da função deverá ser: exibeInt(int16 variável)
Documento atualizado em 22/11/2022 21:43
int32 cont=90000; Prof. Cristian M.G (cristiancimol@gmail.com)
Então o parâmetro da função deverá ser: www.u8051.com.br
exibeInt(long int32 variável)

u8051.com.br MEMÓRIA EEPROM - Página 11/12


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<60;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;
}

u8051.com.br MEMÓRIA EEPROM - Página 12/12

Você também pode gostar