|
resinba
|
 |
« em: Agosto 15, 2008, 22:11:25 » |
|
Vamos lá então tentar explicar o código, que tem a ver com este tópico: http://www.electronicapt.com/forum/index.php?topic=1430.0Para começar vamos então mesmo para o fim do código... vamos então para o PIC_CONFIG... ;************************************************ PIC_CONFIG ;*** Rotina de configuração do PIC *** ;************************************************ Em cima temos o endereço para o inicio desta rotina, que tem como função configurar o PIC clrf PORTA clrf PORTB clrf flag clrf tempo clrf STATUS A instrução "clrf" tem como função limpar registos, neste caso vamos garantir que quando o programa começar todas as variáveis que nos interessam fiquem limpas bsf STATUS, RP0 "bsf" esta instrução põe a nÃvel "1" um bit determinado por nós, de uma variável pré definida também por nós. Neste caso vamos activar o bit "RP0" (bit 5) do registo STATUS, que tem como função activar o banco 1, da RAM. movlw b'11111111' "movlw", esta instrução cria um determinado valor e coloca-o no registo W, neste caso vamos gerar o valor 255 em decimal, ou se preferirem FF em hexadecimal, ou 11111111 em binário, porque preferi em binário? Bem iram saber mais há frente... movwf TRISB esta instrução "movwf", move determinado valor que se encontra no acumulador (registo W), para um registo há nossa escolha. Voltando a "11111111", preferi em binário "b", pois o que vamos definir é o Que vai se passar com o PORTO B, ou seja vamos definir quais os do PORTO B que são saÃda e os que são entrada... como vamos precisar de seis entradas para este circuito e como o PORTO B do chip até tem oito pinos, então é mais que natural usar este porto para as entradas, levando em conta que para a saÃda iremos precisar de quatro pinos e o PORTO A até tem cinco pinos, então a escolha é mais que acertada. Mas, voltando ao PORTO B... temos que levar em conta que para determinado pino de determinado PORTO ser entrada o seu bit correspondente, que se encontra no registo "TRIS" (registo do sistema que tem como função definir quais pinos são entrada e quais são saÃda) tem que estar a nÃvel "1", se quisesse-mos que esse pino fosse saÃda ele teria que estar a nivel "0", assim defeniu-se que tobos os pinos do PORTO B são entradas, é preferÃvel por-se pinos que não são usados como entradas, pois assim não iram provocar danos nenhuns ao circuito. movlw b'11110000' movwf TRISA Neste caso definimos que os pinos de menor peso do PORTO A (RA0, RA1, RA2, RA3, RA4 e RA5) são saÃdas, agora podem perguntar o porque do registo que eu defini em "movlw b'11111111'", ser a oito bits, quando na realidade o PORTO A ter só cinco bits... bem o chip elimina neste caso o que está a mais, sem provocar danos. movlw b'11000111' movwf OPTION_REG Aqui fomos configurar o registo OPTION REGISTER, e este ficou com as seguintes caracterÃsticas começando do bit de maior peso para o de menor peso: - bit7: pull-up off - bit6: intrupt activo no flanco ascendente - bit5: fonte de clock interna para o TMR0 - bit4: TMR0 activa no flanco ascendente do clock - bit3: prescaler activado para o TMR0 - bit2 a bit0: "111" factor de divisão e 255 para o TMR0 Sobre os últimos três bits há que explicar o que se passa... o TMR0 (TIMER) é um registo do sistema de oito bits que tem como única função, contar. Sempre que o registo atinge o valor maximo (255) ele activa uma flag (T0IF) do INTCON (registo dos interrupts), indicando que o registo encheu e começou a contagem de novo, ora, como este registo soma sempre um bit ao seu registo quando recebe um impulso de clock, terÃamos então 255us para este encher. Para se poder alterar esses valores usa-se o prescaler, que não passa de um divisor de clock, seja ele interno ou externo, no nosso caso usamos o interno como sabemos que o clock do chip é de 1us, e como coloca-mos o prescaler a 255, teremos então assim que esperar 255us para que o TMR0 some um bit ao seu registo. bcf STATUS, RP0 "bcf", esta instrução é o inverso da "bsf", ora se a primeira activava um bit de um registo esta por sua vez coloca-o a nÃvel "0" call TEMPO "call" tal como o "goto" são instruções de salto, a diferença é que a primeira é sempre acompanhada por um "return", ou seja neste caso preciso... saltamos para a sub-rotina TEMPO o código vai lendo e executando até achar a instrução "return" que faz o programa saltar para a instrução logo a seguir ao "call", neste caso até é um return. return Com este "return" saltamos para fora da rotina PIC_CONFIG ;*************************** END ;*** Fim do programa *** ;***************************
|
|
|
|
« Última modificação: Agosto 15, 2008, 23:44:39 por resinba »
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #1 em: Agosto 16, 2008, 12:56:30 » |
|
Vamos aqui fazer um pequeno parêntesis, e falar sobre as instruções Assembler usadas nos PIC antes da famÃlia 18. Na realidade o código Assembler é muito parecido com o usado no 8085, a diferença básica é que (no caso dos PICs) o código Assembler é composto por apenas 35 instruções... Que são as seguintes: Antes de mais há que levar em conta que existem dois tipos de registos (posições de memoria, variáveis) distintos, que são os registos gerais (tanto do sistema "SFR" e os "GPR"), e existe um registo especial que se encontra por baixo da "ALU" que é o registo w, é nesne registo que todos os resultados de todas as operações caem, tendo depois quem programa definir para onde quer por este valor. - OPERAÇÕES ORIENTADAS A REGISTOS (BYTES)- ADDWF: soma o valor que se encontra no registo w, a um registo há nossa escolha e coloca-o ou no registo w ou no outro. exemplo: addwf teste,f ao usar o "f" ou "1", estou a dizer que quero o resultado no registo teste se tivesse usado o "w" ou o "0" o resultado seria guardado no registo w reg w=20 reg teste=10 resultado reg w=20 reg teste =30 - ANDWF: faz a operação lógica "and" entre o registo w e um registo há nossa escolha, colocando o valor num local há nossa escolha. exemplo: andwf teste, f reg w=10111 reg teste=11000010 resultado reg teste=10 - CLRF: limpa determinado registo. exemplo: clrf meu reg meu=120 resultado reg meu=0 -CLRW: limpa exclusivamente o registo w. exemplo: clrw reg w=55 resultado reg w=0 - COMF: complemento de "f", ou seja com esta instrução vamos inverter os dados de determinado registo. exemplo: comf ai,f reg ai=1101 resultado reg ai=11110010 - DECF: decrementa o registo "f", há nossa escolha, e coloca o resultado onde nós queremos. exemplo: decf teste,f reg teste=20 resultado reg teste=19 -DECFSZ: decrementa o registo "f" e salta se for zero... problemas?  ok, não é facil há primeira... esta instrução é de decisão tal como umas quantas outras... vamos lá ver como ela trabalha... 1º decrementa o registo (por exemplo registo menos). 2º analisa o resultado: a) ser diferente de zero executa a instrução a seguir. b) se o resultado for zero salta a instrução logo a seguir a "decfsz" e executa a instrução seguinte exemplo: decfsz tempo, 1 goto LOOP_DELAY_1 bsf flag,6 Neste caso vamos decrementar o registo tempo (tempo=tempo-1), se o valor de tempo for maior que zero a instrução a ser executada será "goto LOOP_DELAY_1", mas se o resultado for zero a instrução a ser executada será então "bsf flag,6". - INCF: incrementa o registo "f", neste caso vamos incrementar um bit ao registo (reg teste=reg teste+1). exemplo: incf teste,f reg teste=10 resultado reg teste=11 -INCFSZ: incrementa o registo "f" salta se o valor for zero, esta instrução é exactamente o oposto há "defsz", pois se "decfsz" faz (registo=registo-1), a instrução "infsz" faz (registo=registo+1) exemplo: incfsz tempo, 1 goto LOOP_DELAY_1 bsf flag,6 Neste caso o registo vai enchendo graças a (reg=reg+1), não esquecer que isto só acontece uma vez por turno e sempre que a instrução de decisão é executada, pelo menos uma das outras duas tem que ser, isto porque neste caso se saltarmos para "goto LOO_DELAY_1" nunca iremos executar a "bsf flag,6", agora se esta parte do código estive-se de outra maneira... incfsz tempo, 1 bsf flag,6 goto LOOP_DELAY_1 Neste caso se o valor de "tempo" for diferente de zero, a próxima instrução a ser executada é "bsf flag,6" indo logo a seguir a instrução "goto LOOP_DELAY_1". - IORWF: OR inclusivo entre o registo W e o registo f. exemplo: iorwf teste,w reg w=11111001 reg teste=10101010 resultado teste=10101010 w=11111011 hehehe... desta vez para os fintar mandei o resultado para o registo w - MOVF: move o registo "f", para dentro dele mesmo ("f" ou"1"),ou para o registo w ("w" ou "0"), quando se a primeira possibilidade é para ver se o registo está a zero ou tem algum valor no seu interior... pois se este estiver a zero ele irá afectar a flag "zero" do registo STATUS. No segundo caso vamos apenas movimentar o seu valor para o registo w. exemplo: movf teste,f reg STATUS *****0** reg teste=0 resultado reg teste=0 reg STATUS *****1** ou ainda movf teste,w reg w=0 reg teste=21 resultado reg w=21 reg teste=21 - MOVWF: move o valor que se encontra no registo w para um registo há nossa escolha. exemplo: movwf teste reg w=12 reg teste=45 (atenção que poderia ser outro valor qualquer) resultado reg w=12 reg teste=12 - NOP: sem operação, esta instrução faz exactamente isso "nada", tem como função base "queimar" um ciclo maquina. exemplo: nop resultado um ciclo maquina foi gasto sem fazer nada. -RLF: roda pela esquerda através do bit carry. A ideia é simples imaginem um registo de oito bits, e pretendem movimentar o registo, assim com esta instrução podem no faze-lo sem perder informação, pois o sistema vai ao registo STATUS pedir "emprestado" a flag carry para não se perder informação. exemplo: rlf teste,w reg w=0 reg teste=1110 0110 carry=0 resultado reg teste=1110 0110 carry=1 reg w=1100 1100 - RRF: roda pela direita através do bit carry. A ideia é simples imaginem um registo de oito bits, e pretendem movimentar o registo, assim com esta instrução podem no faze-lo sem perder informação, pois o sistema vai ao registo STATUS pedir "emprestado" a flag carry para não se perder informação. exemplo: rrf teste,w reg w=0 reg teste=1110 0110 carry=0 resultado reg teste=1110 0110 carry=0 reg w=01110011 - SUBWF: subtrai o registo w ao registo f, e coloca o resultado ou no registo w ou no registo f, (reg f-reg w=resultado). exemplo: subwf teste,f reg w=10 ref teste=30 resultado reg teste=20 reg w=10 - SWAMPF: troca os nibles (conjuntos de 4bits), nos registos. exemplo: swampf teste,1 reg teste=11110000 resultado reg teste=00001111 - XORWF: OR esclusivo, entre o registo w e outro há nossa escolha. exemplo: xorwf teste,1 reg teste=10101111 reg w=10110101 resultado reg w=10110101 reg teste=11010
|
|
|
|
« Última modificação: Agosto 17, 2008, 19:05:22 por resinba »
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
|
|
resinba
|
 |
« Responder #3 em: Agosto 16, 2008, 23:08:40 » |
|
Bem ainda não comecei a explicar o código, mas olha conta lá os problemas com código para se poder alterar. Outra coisa, vou continuar a actualizar o campo que se encontra em cima sobre as instruções, e quando tiver concluÃdo avanço então para a explicação do código.
|
|
|
|
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #4 em: Agosto 18, 2008, 13:34:49 » |
|
OPERAÇÃO ORIENTADA A REGISTOS (BITS)
Nesta secção vamos saber como analisar e alterar bits especÃficos dos registos.
- BCF: Limpa determinado bit de determinado registo. exemplo: bcf teste,5 reg teste=11111111 resultado reg teste=11011111
- BSF: Neste caso activa determinado bit de determinado registo exemplo: bsf teste,6 reg teste=10010111 resultado reg teste=11010111
Agora vêem duas instruções parecidas com "decfsz" e "incfsz", pois são instruções de decisão.
- BTFSC: testa determinado bit de determinado registo e salta se for zero. exemplo: btfsc teste,5 goto SALTO_A goto SALTO_B neste caso se o bit(5) do registo teste for "1", o programa executa a instrução "goto SALTO_A". Agora se o mesmo bit estiver a "0", então o programa salta a instrução "goto SALTO_A" e executa então a instrução "goto SALTO_B".
- BTFSs: testa determinado bit de determinado registo e salta se for um. exemplo: btfss teste,5 goto SALTO_A goto SALTO_B neste caso se o bit(5) do registo teste for "0", o programa executa a instrução "goto SALTO_A". Agora se o mesmo bit estiver a "1", então o programa salta a instrução "goto SALTO_A" e executa então a instrução "goto SALTO_B".
|
|
|
|
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #5 em: Agosto 18, 2008, 14:12:55 » |
|
OPERAÇÕES DE CONTROLO E DE LITERAIS
- ADDLW: soma o literal ao registo w. exemplo: addlw d'10' adiciona o literal com valor "10" em decimal ao registo w reg w=20 resultado reg w=30
- ANDLW: faz a operação logica "AND" entre o literal e o registo w . exemplo: andlw b'11001101' reg w=111111111' resultado reg w=11001101
-CALL: com esta instrução podemos chamar uma sub-rotina, executamos esse sub-rotina, e ao encontrar a instrução "return" o programa salta para a linha logo a segir há instrução "call". exemplo: ... call LOOP bcf teste,4 ... Quando o programa chega à instrução "call LOOP", o program counter memoriza a posição do programa, e salta para a sub-rotina LOOP, que poderia ser a seguinte:
LOOP btfss teste,4 return bsf PORTB,1 return assim, se o bit(4) do registo teste fosse "0", a sub-rotina saltava logo para... (já vou explicar). Agora, se o bit(4) fosse "1" o programa iria por o bit(1) do porto b a nivel "1" e iria saltar então... Bem, aqui entra então o return, assim sempre que na sub-rotina LOOP apanhar a instrução return, o program counter vai buscar a posição memorizada anteriormente e soma-lhe "1", que irá então saltar para a posição "bcf teste,4".
NOTA: a instrução "call" não pode ser executada mais de oito vezes dentro de sub-rotinas, ou seja não podem "chamar" mais de oito sub-rotinas com a instrução "call", pois o stack pointer só tem oito posições de memoria para guardar a informação, indo assim a nona cair sobre a primeira posição e por ai fora.
- CLRWDT: limpa o watchdog timer, e limpa também o prescaler. clrwdt reg WDT=? resultado reg WDT=0 WDT prescaler=0 (encontra-se no OPTION_REG) TO=1 (encontra-se no STATUS) PD=1 (encontra-se no STATUS)
-GOTO: esta instrução tem parecenças com o "call", sem a agravante de não se poder usar mais de oito vezes interligadas. Mas, com a agravante que teremos de usar outra vez a quando de uma sub rotina estar terminada, pois ela não faz o salto de retorno. exemplo: ... goto LOOP LOOP_2 ... quando o programa chegar a "goto LOOP" ele salta para ai e executa o que vem a seguir, que poderia ser algo assim...
LOOP btfss teste,0 goto LOOP_2 ... o porgrama ao chegar a LOOP vai testar o bit(0) do registo teste, se este for zero salta então para LOOP_2, continuando o programa a partir desse ponto, caso contrario o programa salta a instrução "goto LLOP_2" e continua a executar as instruções que se seguem em LOOP.
- IORLW: faz a operação logica "OR" entre o literal e o registo w . exemplo: andlw b'11001101' reg w=11110111 resultado reg w=11110111
- MOVLW: move determinado valor para o registo w. exemplo: movlw d'21' reg w=? resultado reg w=21
- RETFIE: "return" de um interrupt. Quando o nosso programa está preparado para interrupts, esta instrução deve ser usada, pois quando existe um interrupt, o sistema salta automaticamente para a posição 0x0004, e convem, depois de ele executar a sub-rotina de interrupt, apanhar um "retfie" para voltar há rotina principal. exemplo: org 0x0004 movf SATUS,0 movwf var_status,1 ... retfie Eis uma possÃvel sub-rotina de interrup, quando a instrução chegar a "retfie", o programa salta para a rotina principal, e activa novamente o "GIE" que se encontra no registo INTCON.
- RETLW: return com literal, quando a sub-rotina chegar a "retlw", ele volta para a rotina principal, e carrega no registo w o literal. exemplo: ... retlw d'123' reg w=? resultado reg w=123
- RETURN: esta já sabemos, é usada para as sub-rotinas normais em conjunto com a instrução "call".
- SLEEP: faz com que o chip entre em modo de standby, para poupança de energia.
- SUBLW: faz a subtracção de um literal com o registo w. exemplo: sublw d'23' reg w=12 resultado reg w=11
- XORLW: faz a operação lógica "XOR" entre o literal e o registo w . exemplo: andlw b'11001101' reg w=11110111 resultado reg w=111010
Assim, termino a explicação sobre as instruções de assembler para este tipo de chip. no próximo topico começo então a explicar o código.
|
|
|
|
« Última modificação: Agosto 18, 2008, 22:57:01 por resinba »
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #6 em: Agosto 19, 2008, 10:13:27 » |
|
A EXPLICAÇÃO DO CÓDIGO
bem, quando peguei no projecto, levei certos dados em consideração, dados esses que me iriam ajudar a desenvolver o código, em que consistiam no seguinte:
- 6 entradas formadas por interruptores. - 4 saidas.
Com estes dados iniciais, e levando em conta o tipo de chip, associei logo as entradas ao PORTO B (pois é formado por oito entradas/saÃdas), e as saÃdas ao PORTO A (tem cinco entradas/saÃdas), não o fiz por ser obrigatório ser assim, pois um PORTO pode ter pinos como entradas e pinos como saÃdas, mas, para facilitar o código, optei por fazer dessa maneira.
Quanto há velocidade, como esta não é crucial optei pelos 4MHz, e isso, porque depois nos cálculos de temporização, o trabalho ser facilitado, pois o ciclo maquina é nos dado da seguinte maneira (1/(fclk/4)), assim como a frequência de clock é de 4MHz e como esta internamente é dividida por quatro, iremos ter então 1MHz, que o seu inverso dá então 1us, que belo numero para fazer contas, pois como cada instrução leva 1us a ser feita, há excepção dos "call" e dos "goto" que usam dois ciclo maquina, os cálculos tornam-se mais fáceis.
Pronto, com estes dados pode então partir para o passo seguinte... esse passo é muito importante para quem usa entradas do tipo ligado/desligado, mas por partes mecânicas (interruptores, botões de pressão e relés). O Problema em sà chama-se "DEBAUCING", e consiste basicamente num sem números de impulsos, que dois contactos metálicos fazem por "selfs" (faiscas), durante o perÃodo que estes se estão ou a aproximar ou a afastar um do outro, isso para um micro controlador é atrofiante, pois onde ele devia de estar há espera de um impulso, leva é com "carradas" deles. Para se resolver esse problema há varias técnicas, desde as formadas por hardware (uso de condensadores, ou mesmo circuitos lógicos), ou pelas formadas por software (uso de rotinas de delay), que é o caso desta. Levei em linha de conta que os botões eram acionados por uma pessoa, e assim sendo sabia que o perÃodo mÃnimo de debaucing é de 8ms, perÃodo mÃnimo de tempo que levamos desde que começamos a premir no botão e até ele estar completamente premido. Para facilitar usei como valor de delay 50ms, que para um Humano continua a ser extremamente rápido, e como tinha que usar outro tipo de delay (5s), que mais tarde foi reduzido para 1,5s, os 50ms caiam que nem "gingas".
No caso desta montagem o programa analisa as entradas, uma a uma "btfss PORTB,x", em que o valor "x" varia entre o valor "0" e o valor "5" (correspondentes aos PORTOS B (0 a 5), sempre que uma entrada é activada e depois de confirmada o programa irá saber qual foi a entrada activada e envia para a saÃda o valor correspondente em código BCD.
|
|
|
|
« Última modificação: Agosto 19, 2008, 10:31:38 por resinba »
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #7 em: Agosto 19, 2008, 11:17:30 » |
|
O COMEÇO E A CONFIGURAÇÂO
list p=16F84A ; Aqui listamos a directiva que define o micro-controlador #include <p16F84A.inc> ; Aqui importamos as definições das variáveis internas do chip
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC ; protecção do codigo (CP) OFF, watchdog timer (WDT) OFF, Power-up Timer PWRT) ON, oscilador do tipo HS
;***** VARIABLE DEFINITIONS tempo EQU 0x0C ;definição da posição de memoria (RAM) para a variável tempo flag EQU 0x0D ; definição da posição de memoria (RAM)para a variável flag
;********************************************************************** ORG 0x000 ;Posição da memoria flash para o inicio do programa call PIC_CONFIG ; chamamos a sub-rotina PIC_CONFIG, onde vamos definir certos parâmetros para o chip goto MAIN ; salta para a rotina principal
Bem a parte que se segue foi um copy/paste do que já tinha dito.
;************************************************ PIC_CONFIG ;*** Rotina de configuração do PIC *** ;************************************************
Em cima temos o endereço para o inicio desta rotina, que tem como função configurar o PIC
clrf PORTA clrf PORTB clrf flag clrf tempo clrf STATUS
A instrução "clrf" tem como função limpar registos, neste caso vamos garantir que quando o programa começar todas as variáveis que nos interessam fiquem limpas
bsf STATUS, RP0
"bsf" esta instrução põe a nÃvel "1" um bit determinado por nós, de uma variável pré definida também por nós. Neste caso vamos activar o bit "RP0" (bit 5) do registo STATUS, que tem como função activar o banco 1, da RAM.
movlw b'11111111'
"movlw", esta instrução cria um determinado valor e coloca-o no registo W, neste caso vamos gerar o valor 255 em decimal, ou se preferirem FF em hexadecimal, ou 11111111 em binário, porque preferi em binário? Bem iram saber mais há frente...
movwf TRISB
esta instrução "movwf", move determinado valor que se encontra no acumulador (registo W), para um registo há nossa escolha. Voltando a "11111111", preferi em binário "b", pois o que vamos definir é o Que vai se passar com o PORTO B, ou seja vamos definir quais os do PORTO B que são saÃda e os que são entrada... como vamos precisar de seis entradas para este circuito e como o PORTO B do chip até tem oito pinos, então é mais que natural usar este porto para as entradas, levando em conta que para a saÃda iremos precisar de quatro pinos e o PORTO A até tem cinco pinos, então a escolha é mais que acertada. Mas, voltando ao PORTO B... temos que levar em conta que para determinado pino de determinado PORTO ser entrada o seu bit correspondente, que se encontra no registo "TRIS" (registo do sistema que tem como função definir quais pinos são entrada e quais são saÃda) tem que estar a nÃvel "1", se quisesse-mos que esse pino fosse saÃda ele teria que estar a nivel "0", assim defeniu-se que tobos os pinos do PORTO B são entradas, é preferÃvel por-se pinos que não são usados como entradas, pois assim não iram provocar danos nenhuns ao circuito.
movlw b'11110000' movwf TRISA
Neste caso definimos que os pinos de menor peso do PORTO A (RA0, RA1, RA2, RA3, RA4 e RA5) são saÃdas, agora podem perguntar o porque do registo que eu defini em "movlw b'11111111'", ser a oito bits, quando na realidade o PORTO A ter só cinco bits... bem o chip elimina neste caso o que está a mais, sem provocar danos.
movlw b'11000111' movwf OPTION_REG
Aqui fomos configurar o registo OPTION REGISTER, e este ficou com as seguintes caracterÃsticas começando do bit de maior peso para o de menor peso: - bit7: pull-up off - bit6: intrupt activo no flanco ascendente - bit5: fonte de clock interna para o TMR0 - bit4: TMR0 activa no flanco ascendente do clock - bit3: prescaler activado para o TMR0 - bit2 a bit0: "111" factor de divisão e 255 para o TMR0 Sobre os últimos três bits há que explicar o que se passa... o TMR0 (TIMER) é um registo do sistema de oito bits que tem como única função, contar. Sempre que o registo atinge o valor maximo (255) ele activa uma flag (T0IF) do INTCON (registo dos interrupts), indicando que o registo encheu e começou a contagem de novo, ora, como este registo soma sempre um bit ao seu registo quando recebe um impulso de clock, terÃamos então 255us para este encher. Para se poder alterar esses valores usa-se o prescaler, que não passa de um divisor de clock, seja ele interno ou externo, no nosso caso usamos o interno como sabemos que o clock do chip é de 1us, e como coloca-mos o prescaler a 255, teremos então assim que esperar 255us para que o TMR0 some um bit ao seu registo.
bcf STATUS, RP0
"bcf", esta instrução é o inverso da "bsf", ora se a primeira activava um bit de um registo esta por sua vez coloca-o a nÃvel "0"
call TEMPO
"call" tal como o "goto" são instruções de salto, a diferença é que a primeira é sempre acompanhada por um "return", ou seja neste caso preciso... saltamos para a sub-rotina TEMPO o código vai lendo e executando até achar a instrução "return" que faz o programa saltar para a instrução logo a seguir ao "call", neste caso até é um return.
return
Com este "return" saltamos para fora da rotina PIC_CONFIG ;*************************** END ;*** Fim do programa *** ;***************************
A sub-rotina TEMPO tem como função básica carregar um determinado valor no registo tempo, tal como podem ver:
;******************************** TEMPO ;*** Rotina que gera 5s *** ;******************************** movlw d'100' ; carrega no registo w o valor 100 (em decimal) movwf tempo ; carrega no registo tempo o valor que se encontra no registo w (100 em decimal) return ; sai da sub-rotina TEMPO, e volta para a linha a seguir há linha "call TEMPO".
|
|
|
|
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #8 em: Agosto 20, 2008, 23:27:59 » |
|
O CENTRO DAS DECISÕES
Bem o nome diz tudo, é neste ponto que tudo é decidido, é aqui que se vai descobrir qual botão foi premido, se ele foi validado ou não, se passaram mais de 1,5s sem nada acontecer. Tem que se levar em conta que depois do PIC_CONFIG, a rotina a seguir é o MAIN. Bem, vou deixar-me de tretas e vou apresentar então esse parte.
;********************************************** TESTA_TECLA ;*** Rotina que testa as teclas *** ;********************************************** se o registo flag(0) estava a "0" então saltamos para este ponto que vai testar qual do botões foi premido
btfss PORTB,0 ;testa se o botão um foi premido goto UM ;se foi salta para a rotina UM btfss PORTB,1 ;testa se o botão dois foi premido goto DOIS ;se foi salta para a rotina DOIS btfss PORTB,2 ;testa se o botão tres foi premido goto TRES ;se foi salta para a rotina TRES btfss PORTB,3 ;testa se o botão quatro foi premido goto QUATRO ;se foi salta para a rotina QUATRO btfss PORTB,4 ;testa se o botão cinco foi premido goto CINCO ;se foi salta para a rotina CINCO btfss PORTB,5 ;testa se o botão seis foi premido goto SEIS ;se foi salta para a rotina SEIS bsf flag, 0 ;se nada acontecer activa a flag(0) goto MAIN ;salta para a rotina MAIN
;************************ MAIN ;*** Rotina MAIN *** ;************************ btfss flag, 0 ;a flag(0) vai indicar se alguma tecla foi premida e validada ou não goto TESTA_TECLA ;se não foi salta para a rotina TESTA_TECLA bcf flag, 0 ; aconteça o que acontecer a flag(0) é limpa btfss flag,6 ;a flag(6) indica se já passaram os 5s ou não call DELAY ;se não executa a sub-rotina DELAY btfss flag,6 ;volta a testar a flag(6), não vá o diabo tece-las goto MAIN ;se o tempo (5s) ainda não passou salta de novo para o inicio da rotina MAIN call TEMPO ;se o tempo (5s) já passou, então chama-mos a sub-rotina TEMPO clrf flag ;limpa todos os bits do registo flag clrf PORTA ;limpa a informação BCD que havia antes, fazendo com que no display fique a "0" goto MAIN ;salta novamente para o inicio da rotina MAIN
|
|
|
|
« Última modificação: Agosto 21, 2008, 11:55:04 por resinba »
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
bettencourt
|
 |
« Responder #9 em: Agosto 21, 2008, 20:30:04 » |
|
Tas a ter um gande tabalho a fazer isso... mas ta a ficar 5* Para mim ta a ser mais facil perceber o assembly do pic, visto tar a "mexer" na pratica com ele Parabéns e Obrigado
|
|
|
|
|
Registado
|
|
|
|
|
resinba
|
 |
« Responder #10 em: Agosto 22, 2008, 10:27:57 » |
|
Sabes isto é daquelas coisas que me dá gozo fazer... E sempre que posso tento ajudar, quem precisa, pois também ade haver o dia que eu preciso, como se costuma dizer uma mão lava a outra. 
|
|
|
|
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #11 em: Agosto 22, 2008, 11:02:09 » |
|
CONFIRMAÇÃO DA TECLA PREMIDA E GERAÇÃO DE CÓDIGO BCD
Anteriormente, no "O CENTRO DAS DECISÕES", tinha se visto como se detectava se uma tecla tinha sido premida, agora vamos ver como se confirma como esse tecla foi premida, para alem disso também se irá ver como se gera o código BCD.
Mais um pequeno parêntesis... o código BCD (para quem não sabe), é um código do tipo binário, formado por quatro linhas, mas, com uma grande diferença... é que o código binário normal com quatro linhas conseguimos fazer contagens de 0 a 15 (B'0000' a B'1111'), mas o código BCD só conta de 0 a 9 (B'0000' a B'1001').
Vou só fazer a descrição da primeira rotina, pois todas as seis são exactamente iguais umas, às outras, alterando só os nomes das rotinas, dos LOOP's e do código BCD. Bem, aqui vai o código:
;********************************** imaginemos, que a rotina anterior detectou que a tecla um foi premida, então salta UM ;*** Rotina que gera o BCD 1 *** para este ponto via "goto UM", e começa a executar o código... ;********************************** call DELAY ; primeiro "chama" a sub-rotina DELAY para fazer uma pausa de 50ms btfsc PORTB, 0 ;de pois dos 50ms terem acabado vamos ver se o botão um continua premido goto LOOP_UM_1 ;se não saltamos para LOOP_UM_1 movlw d'1' ; se sim carregamos o valor "1" no registo w movwf PORTA ;agarramos no valor "1" e enviamos para o PORTO A, e já temos o "1" BCD na saida do PIC LOOP_UM btfss PORTB,0 ;aqui testamos se o botão continua premido goto LOOP_UM ;se sim continuamos neste LOOP interminavelmente call TEMPO ;se não chamamos a sub-rotina TEMPO para azararmos o contador de segundos goto MAIN ;saltamos para a rotina MAIN LOOP_UM_1 bsf flag, 0 ;activamos a flag(0), porque a tecla não foi validada, e assim fazemos uma contagem do ;perÃodo a OFF. goto MAIN ;salta para MAIN
;************************************ DOIS ;*** Rotina que gera o BCD 2 *** ;************************************ call DELAY btfsc PORTB, 1 goto LOOP_DOIS_1 movlw d'2' movwf PORTA LOOP_DOIS btfss PORTB,1 goto LOOP_DOIS call TEMPO goto MAIN LOOP_DOIS_1 bsf flag, 0 goto MAIN
;************************************ TRES ;*** Rotina que gera o BCD 3 *** ;************************************ call DELAY btfsc PORTB, 2 goto LOOP_TRES_1 movlw d'3' movwf PORTA LOOP_TRES btfss PORTB,2 goto LOOP_TRES call TEMPO goto MAIN LOOP_TRES_1 bsf flag, 0 goto MAIN
;************************************** QUATRO ;*** Rotina que gera o BCD 4 *** ;************************************** call DELAY btfsc PORTB, 3 goto LOOP_QUATRO_1 movlw d'4' movwf PORTA LOOP_QUATRO btfss PORTB,3 goto LOOP_QUATRO call TEMPO goto MAIN LOOP_QUATRO_1 bsf flag, 0 goto MAIN
;************************************* CINCO ;*** Rotina que gera o BCD 5 *** ;************************************* call DELAY btfsc PORTB, 4 goto LOOP_CINCO_1 movlw d'5' movwf PORTA LOOP_CINCO btfss PORTB,4 goto LOOP_UM call TEMPO goto MAIN LOOP_CINCO_1 bsf flag, 0 goto MAIN
;************************************ SEIS ;*** Rotina que gera o BCD 6 *** ;************************************ call DELAY btfsc PORTB, 5 goto LOOP_SEIS_1 movlw d'6' movwf PORTA LOOP_SEIS btfss PORTB,5 goto LOOP_SEIS call TEMPO goto MAIN LOOP_SEIS_1 bsf flag, 0 goto MAIN
|
|
|
|
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
resinba
|
 |
« Responder #12 em: Agosto 22, 2008, 11:42:54 » |
|
SUB-ROTINAS TEMPO E DELAY
Estas duas sub-rotinas estão interligadas, e complementam-se uma há outra, uma porque quera os 50ms, e os 1,5s que são dados pela variável tempo.
Aqui está o codigo:
;******************************** TEMPO ;*** Rotina que gera 5s *** ;******************************** movlw d'100' ;move o valor d'100' para o registo w, com o valor 100, temos 5s, e com o valor 30, temos 1,5s movwf tempo ;move o valor que se encontra no registo w para o registo tempo return ;sai da sub-rotina
;************************************************** DELAY ;*** Rotina que provoca um atraso de 50ms *** ;************************************************** clrf TMR0 ;limpa o registo do temporizador (TMR0) clrf INTCON ;limpa o registo INTECON, por causa da flagT0IF movlw d'60' ;move o valor d'60' para o registo w movwf TMR0 ;move esse valor para o registo TMR0 LOOP_DELAY btfss INTCON, T0IF ;testa o a flag T0IF do registo INTCON, que fica activa quando o TMR0 der OVERFLOW goto LOOP_DELAY ;se não estiver activa salta para LOOP_DELAY decfsz tempo, 1 ;se estiver activa, decrementa a variavel tempo e "vê" se esta já chegou a zero goto LOOP_DELAY_1 ;se não chegou salta para LOOP_DELAY_1 bsf flag,6 ;se tempo=0, então activa a flag(6). O tempo passou dos 1,5s ou dos 5s! LOOP_DELAY_1 clrf INTCON ;limpa o INTCON return ;sai da sub rotina
Pronto o código está feito explicado, o tempo de concepção foi de alguns dias, mas, na realidade traduziu-se em cerca de 2 a 3 horas por dia durante um perÃodo de mais ou menos cinco dias.
|
|
|
|
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|
bettencourt
|
 |
« Responder #13 em: Agosto 23, 2008, 21:13:51 » |
|
começando por esta parte pequena parte goto LOOP_DELAY_1 ;se não chegou salta para LOOP_DELAY_1 bsf flag,6 ;se tempo=0, então activa a flag(6). O tempo passou dos 1,5s ou dos 5s! LOOP_DELAY_1 clrf INTCON ;limpa o INTCON return ;sai da sub rotina
quando faz o return ele vai para onde? LOOP_DELAY ou goto LOOP_DELAY_1
|
|
|
|
|
Registado
|
|
|
|
|
resinba
|
 |
« Responder #14 em: Agosto 23, 2008, 21:38:28 » |
|
Nop, sabes ele pode saltar para muitos sÃtios...
Tens que levar em linha de conta qual parte do programa invocou a instrução "call DELAY", imagina o "C", ele é composto por funções, e as funções para alem de outras coisas tem o nome, agoara imagina que estas dentro de uma função e invocas outra, então o programa salta para essa função, executa-a, e depois de terminada volta para a instrução seguinte que se encontra na 1ªfunção.
void multiplica() { ... } //quando terminada salta para a linha a seguir de onde foi invocada
Void main { ... multiplica (23); //neste ponto saltamos para a função multiplica ... }
No nosso caso pode ser...
;********************************** imaginemos, que a rotina anterior detectou que a tecla um foi premida, então salta UM ;*** Rotina que gera o BCD 1 *** para este ponto via "goto UM", e começa a executar o código... ;********************************** call DELAY ; primeiro "chama" a sub-rotina DELAY para fazer uma pausa de 50ms btfsc PORTB, 0 ;Salta para este ponto
;************************************ DOIS ;*** Rotina que gera o BCD 2 *** ;************************************ call DELAY btfsc PORTB, 1 ;ou para este
;************************************ TRES ;*** Rotina que gera o BCD 3 *** ;************************************ call DELAY btfsc PORTB, 2 ;ou para este
;************************************** QUATRO ;*** Rotina que gera o BCD 4 *** ;************************************** call DELAY btfsc PORTB, 3 ;ou para este
;************************************* CINCO ;*** Rotina que gera o BCD 5 *** ;************************************* call DELAY btfsc PORTB, 4 ;ou para este
;************************************ SEIS ;*** Rotina que gera o BCD 6 *** ;************************************ call DELAY btfsc PORTB, 5 ;ou para este
;************************ MAIN ;*** Rotina MAIN *** ;************************ btfss flag, 0 ;a flag(0) vai indicar se alguma tecla foi premida e validada ou não goto TESTA_TECLA ;se não foi salta para a rotina TESTA_TECLA bcf flag, 0 ; aconteça o que acontecer a flag(0) é limpa btfss flag,6 ;a flag(6) indica se já passaram os 5s ou não call DELAY ;se não executa a sub-rotina DELAY btfss flag,6 ;ou ainda salta para esta
Como podes ver, sempre que existe um "call DELAY", o programa salta para a sub-rotina DELAY e quando esta estiver terminada, salta para a instrução logo a seguir há instrução "call" que chamou a sub-rotina.
Não sei se me consegui fazer entender...
|
|
|
|
« Última modificação: Agosto 23, 2008, 21:59:29 por resinba »
|
Registado
|
Por favor, alterem o meu email no msn pois tenho outro email dedicado aos foruns, e vou bloquear todos os que se encontram no antigo email.
|
|
|
|