HOME PROJETOS PROGRAMAÇÃO |
O microcontrolador funciona extraindo instruções da memória de programa apontadas pelo Program Counter.
O Program Counter possui 13 bits e é formado pelos registradores PCH e PCL.
O registrador PCL pode ser lido e gravado por instruções e pode receber valores de 0 a 255 (0x00 a 0xFF).
O registrador PCH não pode ser acessado diretamente por uma instrução e apenas seus bits de 8 a 12 são usados.
O envio de valores ao registrador PCH é feito indiretamente utilizando-se para isso o registrador PCLATH que pode ser lido e gravado.
O mecanismo de desvio funciona da seguinte maneira:
Quando o PCL recebe um valor, isto é, quando o PCL é alterado por qualquer motivo, isso faz com que o PCH
seja carregado com o conteúdo do registrador PCLATH e a próxima instrução do programa seja extraida do endereço
formado pelo par PCH:PCL. Esse fato torna possível desenvolvermos programas onde desvios baseados em cáculos sejam
possíveis, além dos desvios normalmente feitos com as instruções CALL e GOTO.
A figura abaixo, extraida do data sheet de um microcontrolador, mostra os dois casos de como o Program Counter pode ser alterado.
No desenho superior é mostrado o caso de uma alteração direta no PCL, quando este é alterado por uma instrução de
soma ou movimentação. Neste caso os 5 bits menos significativos de PCLATH são carregados nos bits 8 a 12 de PCH e a
próxima instrução será extraida da localização de memória apontada pelo endereço então formado.
O desenho inferior mostra como as instruções GOTO e CALL alteram o Program Counter.
Os 11 bits menos significativos ( 0 a 10 ) são provenientes do código de uma dessas instruções e somente os bits 4
e 3 do PCLATH são carregados nos bits 12 e 11 do PCH formando um endereço completo. Os bits 11 e 12 do Program Counter
contêm o número da página de memória a ser acessada, sendo que cada página tem tamanho de 2K (2048 bytes).
O Program Counter, formado por PCH:PCL, vai conter sempre um endereço de 13 bits da memória de programa de onde será extraida
a proxima instrução a ser executada. Como o Program Counter tem 13 bits, é possível endereçar 8192 bytes (8K) na memória de
programa cujos endereços vão de 0x0000 a 0x1FFF. É fato que nem todos os microcontroladores possuem 8K de memória. Chips
como o 16F877A possuem 8K enquanto um 16F628A possue 2K e um 16F627A possue apenas 1K. Assim sendo, para microcontroladores
com mais de 2K de memória, é sempre necessário carregar o PCLATH com a parte alta do endereço que se quer acessar, usando
a instrução MOVLW HIGH(label). As páginas são numeradas de 0 a 3.
|
O exemplo abaixo não tem utilidade prática mas serve para verificar o funcionamento do que foi explicado acima. Um registrador chamado "resultado" será incrementado por uma chamada ao label "somax". O registrador W conterá um número para ser somado em "resultado".
resultado RES 1 ; registrador clrf resultado ; limpa o resultado movlw HIGH(somax) ; parte alta do endereco da "somax" movwf PCLATH ; guarda parte alta do endereco movlw .9 ; numero a somar em resuldato call somax ; vai somar clrf PCLATH ; restaura o PCLATH goto $ ; não sai daqui ; somax sublw .10 ; ajusta o numero a somar addwf PCL,f ; altera o PCL com o deslocamento incf resultado,f ; soma 10 incf resultado,f ; soma 9 incf resultado,f ; soma 8 incf resultado,f ; soma 7 incf resultado,f ; soma 6 incf resultado,f ; soma 5 incf resultado,f ; soma 4 incf resultado,f ; soma 3 incf resultado,f ; soma 2 incf resultado,f ; soma 1 return ; retorna para quem chamou
A memória de dados pode ser endereçada de modo indireto através do registradores FSR e INDF.
Para conseguir endereçar uma localização na memória de dados, deve-se carregar o registrador FSR com o endereço da posição que se deseja endereçar. Pode-se fazer isso com as instruções:
ponto RES .10 ; getadd movlw ponto ; obtem o endereço da posição movwf FSR ; carrega o registrador indexador
Para mover um valor para essa posição ou ler o valor da posição, deve-se referenciar o endereço com INDF com mostrado abaixo:
ler movf INDF,w ; obtem o valor da posição em FSR movwf rx ; salva valor lido ; mover movlw 0xA9 ; carrega valor a mover movwf INDF ; move o valor para a posição de FSR
O exemplo abaixo mostra como limpar uma área da memória de dados:
area res 10 ; ct res 1 ; contador movlw .10 ; vamos limpar 10 bytes movwf ct ; salva no contador movlw area ; endereco inicial movwf FSR ; carrega o contador limpar movlw 0x00 ; carrega zeros binarios em W movwf INDF ; move W para o endereco atual incf FSR,f ; avanca o endereco decfsz ct,f ; tira 1 do contador goto limpar ; se ct > 0 continua limpando nop ; continua aqui se ct == 0 . .
Na família 18F, existe os registradores FSR0, FSR1 e FSR2 que permitem o acesso à memória usando os
registradores correspondentes INDF0, INDF1 e INDF2. Existem, também, os registradores POSTINC0, POSTINC1 e POSTINC2
que são usados para incrementar os registradores FSR0, FSR1 e FSR2 respectivamente, sem necessidade de usar a
instrução INCF FSR0,f. Assim, se desejarmos acessar um dado apontado por FSR2, fazendo com que, após o acesso,
este aponte para o byte seguinte, usamos a instrução MOVF POSTINC2,w que carregará o dado apontado por FSR2
no registrador W e incrementará automaticamente FSR2. Do mesmo modo como POSTINCn incrementam os
registradores FSRn, temos os registradores POSTDEC0, POSTDEC1 e POSTDEC2 que decrementam os registradores
FSR0, FSR1 e FSR2 respectivamente.
Table Read é uma forma de acesso aos dados que residem na memória de programa.
Para definir esses dados na memória de programa usa-se DT como no exemplo abaixo:
mensagem DT "SISTEMA NO AR"
A definição acima gera instruções RETLW como visto abaixo:
mensagem RETLW "S" RETLW "I" RETLW "S" RETLW "T" RETLW "E" RETLW "M" RETLW "A" RETLW " " RETLW "N" RETLW "O" RETLW " " RETLW "A" RETLW "R"
A diretiva DT gera uma instrução RETLW cuja função é carregar o registrador W com o valor definido no seu operando e, em seguida, carregar o PC (program counter) com o valor corrente do stack causando um desvio. Isso pode ser aproveitado para extrair dados da memória de programas como se esses dados residissem numa tabela, daí o termo "Table Read".
O exemplo abaixo mostra como o acesso aos dados é feito. Primeiramente define-se a tabela "mensagem", cuja primeira instrução é a soma do valor contido no registrador W ao registrador PCL (linha 3). A seguir, na linha 6, carrega-se o W com zero e faz-se a chamada "CALL mensagem" na linha 7. Ao executar a instrução ADDWF PCL,f, na linha 3, o valor contido no registrador W é somado ao PCL, que nesse momento possui o endereço da instrução seguinte (linha 4), isto é, o endereço do primeiro "S" da palavra "SISTEMA" que, na verdade, é a instrução RETLW "S" gerada pelo DT. Assim, ao retornar para alinha 8, W vai conter "S". O processo se repete carregando-se em W o valor 1, na linha 9 e fazendo-se nova chamada "CALL mensagem". Agora, ao retornar, W conterá " I ".
1 GOTO leitura 2 ; 3 mensagem ADDWF PCL,f 4 DT "SISTEMA NO AR" 5 ; 6 leitura MOVLW 0 7 CALL mensagem 8 MOVWF ..... ; W retorna com "S" 9 MOVLW 1 10 CALL mensagem 11 MOVWF ..... ; W retorna com "I" 12 : 13 : 14 :
Na família 18F, diferentemente da 16F, pode-se ler e gravar dados na memória de programa durante a execução sua execução. O que segue é a simples tradução do que está escrito no datasheet do microcontrolador PIC18F4520 que define como podem ser feitas as operações na memória de programa:
"A memória flash pode ser lida, gravada e apagada durante sua operação normal.
Uma leitura da memória de programa é executada um byte por vez. Uma escrita na memória de programa é feita em blocos de
64 bytes de cada vez. A memória de programa é apagada em blocos de 64 bytes por vez. Uma operação de apagamento 'bulk erase'
não pode ser feita pelo código do usuário. Gravar ou apagar a memória de programa fará cessar a carga de instruções até
que a operação seja completada. A memória de programa não pode ser acessada durante uma operação de gravação ou apagamento, assim,
o código não pode ser executado. Um temporizador interno se encarrega de terminar as operações de escrita e apagamento.
Um valor escrito na memória de programa não precisa ser uma instrução válida. Executar um localização da memória de programa
que não seja uma instrução válida resultará num NOP."
Para ler e escrever na memória de programa existem as instruções TBLRD e TBLWT. Como a memória de programas é formada por palavras de 16 bits e a memória de dados é formada por 8 bits, essas instruções permitem fazer a transferência de dados entre uma e outra de forma automatica. As figuras abaixo, extraidas do próprio datasheet do PIC18F4520, mostram como se efetuam essas operações.
TBLRD - Leitura da memória de programaDe acordo com a figura acima, temos tres registradores, TBLPTRU, TBLPTRH e TBLPTRL que servem de apontadores para a localização da memória de programa de onde devemos ler os dados. A instrução TBLRD será usada para fazer a leitura e, após essa operação, o dado lido será colocado no registrador TABLAT. O exemplo abaixo mostra a sequência de instruções para executar uma leitura na memória de programa:
. . ; . . ; . . ; movlw UPPER(dado) ; carrega a parte superior do endereco movwf TBLPTRU ; prepara o apontador U movlw HIGH(dado) ; carrega a parte alta do endereco movwf TBLPTRH ; prepara o apontador H movlw LOW(dado) ; carrega a parte baixa do endereco movwf TBLPTRL ; carrega o apontador L ler TBLRD *+ ; le o dado e incrementa os apontadores movf TABLAT,w ; move o dado lido para o registrador W xorlw 0x00 ; verifica o que foi lido btfsc STATUS,Z ; se leu zeros goto fim ; entao acabou . . ; senao, faz alguma coisa com o dado lido . . ; . . ; goto ler ; vai ler o proximo dado . . ; . . ; fim . . ; . . ; . . ; ORG 0x800 ; posiciona no endereco 0x800 da memoria dado DB "Isto e um exemplo" ; define os dados na memoria de programa DB 0x00 ; indicador de fim dos dados . . ; . . ; . . ;
Apesar da simplicidade mostrada na figura acima, a operação de escrita na memória de programa é mais complicada do que se possa imaginar pois, antes de escrever, os dados preexistentes devem ser apagados antes da escrita. Além disso, não se pode escrever byte por byte na memória de programa. A escrita deve ser feita em blocos de 64 bytes que devem ser previamente enviados para 64 registradores internos pela instrução TBLWT. Como a instrução TBLWT usa o registrador TABLAT, que pode conter somente dados de 8 bits, essa instrução deve ser executada 64 vezes para preencher os registradores internos com os dados antes que a escrita propriamente dita possa ser feita. Quando os 64 registradores internos tiverem sido preenchidos, através da instrução TBLWT, pode-se, então, iniciar a operação de escrita seguindo-se a sequência descrita no datasheet do PIC18F4520, transcrita abaixo:
|
Conforme o data sheet do microcontrolador, esse procedimento pode levar 6ms para ser realizado. Além disso, a releitura da memória, para verificação dos dados, deve ser feita porque, após um número muito grande de alterações, a memória fica estressada e pode haver erro na escrita dos dados.
Um exemplo de escrita na memória de dados pode ser visto na página 80 do data sheet do microcontrolador PIC18F4520.
H P S P I N Desde 04 de Março de 2010 Atualização: 08 de Oct de 2024 |