13.05.2013 Views

Generación de retardos en la familia HC908 - Edudevices

Generación de retardos en la familia HC908 - Edudevices

Generación de retardos en la familia HC908 - Edudevices

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

COMENTARIO TECNICO<br />

<strong>G<strong>en</strong>eración</strong> <strong>de</strong> <strong>retardos</strong> <strong>en</strong> <strong>la</strong> <strong>familia</strong> <strong>HC908</strong><br />

Por el Ing. Gabriel Dubatti – www.ingdubatti.com.ar<br />

Introducción<br />

Una tarea muy frecu<strong>en</strong>te al programar microcontro<strong>la</strong>dores es <strong>la</strong> g<strong>en</strong>eración <strong>de</strong> <strong>retardos</strong>, <strong>en</strong> g<strong>en</strong>eral,<br />

para contro<strong>la</strong>r hardware periférico o para seña<strong>la</strong>r distintos tipos <strong>de</strong> ev<strong>en</strong>tos mediante luces o sonidos.<br />

En algunos casos pue<strong>de</strong> utilizarse para g<strong>en</strong>erar estos tiempos el módulo <strong>de</strong> timer incorporado<br />

<strong>en</strong> el microcontro<strong>la</strong>dor, pero para muchos otros hay que buscar otras soluciones <strong>de</strong>bido a los<br />

inconv<strong>en</strong>i<strong>en</strong>tes que se verán a continuación.<br />

Se muestra, a modo <strong>de</strong> ejemplo, como realizar una puerta serie por software <strong>en</strong> el procesador 68<strong>HC908</strong>JL3.<br />

<strong>G<strong>en</strong>eración</strong> <strong>de</strong> tiempos con el módulo <strong>de</strong> TIMER<br />

El módulo <strong>de</strong> TIMER suele ser utilizado mediante interrupciones <strong>de</strong> <strong>la</strong> sigui<strong>en</strong>te forma:<br />

• Se elige un valor <strong>de</strong> prescaler (que <strong>de</strong>termina el tiempo <strong>de</strong> avance <strong>de</strong>l registro <strong>de</strong> 16 bits <strong>en</strong><br />

función <strong>de</strong> <strong>la</strong> frecu<strong>en</strong>cia <strong>de</strong> bus). Cada cu<strong>en</strong>ta <strong>en</strong> el TIMER es un "tick".<br />

• Modo autorecargable: Se le da un valor <strong>de</strong> módulo al TIMER para que interrumpa por "Overflow"<br />

indicando <strong>la</strong> cantidad <strong>de</strong> "ticks" <strong>de</strong>seados (esto g<strong>en</strong>era un aviso periódico).<br />

• Modo libre: Se indica <strong>en</strong> uno <strong>de</strong> los canales <strong>de</strong>l TIMER <strong>de</strong>ntro <strong>de</strong> cuantos "ticks" queremos que<br />

Interrumpa sumando al valor actual <strong>de</strong>l TIMER <strong>la</strong> cantidad <strong>de</strong> "ticks" <strong>de</strong>seados y recalculándolo<br />

manualm<strong>en</strong>te <strong>en</strong> cada interrupción.<br />

El inconv<strong>en</strong>i<strong>en</strong>te <strong>de</strong> este método radica <strong>en</strong> lo que se <strong>de</strong>nomina <strong>la</strong>t<strong>en</strong>cia <strong>de</strong> <strong>la</strong>s interrupciones.<br />

O sea <strong>la</strong> <strong>de</strong>mora que se produce <strong>de</strong>s<strong>de</strong> el ev<strong>en</strong>to <strong>de</strong> tiempo <strong>de</strong>seado y el mom<strong>en</strong>to <strong>en</strong> que realm<strong>en</strong>te<br />

se ejecuta el código.<br />

Esta <strong>la</strong>t<strong>en</strong>cia ti<strong>en</strong>e <strong>la</strong> <strong>de</strong>sv<strong>en</strong>taja <strong>de</strong> no ser pre<strong>de</strong>cible ya que <strong>en</strong> <strong>la</strong> ejecución <strong>de</strong> una interrupción<br />

intervi<strong>en</strong><strong>en</strong> los sigui<strong>en</strong>tes factores: (si fuera pre<strong>de</strong>cible bastaría con restar al tiempo <strong>de</strong>seado al <strong>de</strong> <strong>la</strong> <strong>la</strong>t<strong>en</strong>cia)<br />

• Esperar a que se <strong>de</strong>stap<strong>en</strong> <strong>la</strong>s interrupciones (bit I <strong>de</strong>l registro CC):<br />

Si estamos ejecutando una sección <strong>de</strong> código que ti<strong>en</strong>e <strong>la</strong>s interrupciones <strong>de</strong>shabilitadas, esta<br />

esperará hasta que se habilit<strong>en</strong> para po<strong>de</strong>r ejecutar. Este tiempo pue<strong>de</strong> ser muy difícil <strong>de</strong><br />

estimar si estamos trabajando con varias interrupciones y no habilitamos <strong>la</strong> <strong>en</strong>trada <strong>de</strong> una<br />

interrupción "sobre" otra.<br />

• Esperar a que termine <strong>de</strong> ejecutar <strong>la</strong> instrucción <strong>en</strong> curso:<br />

Las instrucciones se procesan <strong>en</strong> forma "atómica" (o sea <strong>en</strong> forma indivisible) y por lo tanto<br />

para procesar una interrupción <strong>de</strong>be esperarse a que esta se complete. La cantidad <strong>de</strong> ciclos que<br />

<strong>de</strong>mora una instrucción <strong>en</strong> <strong>la</strong> <strong>familia</strong> <strong>HC908</strong> está compr<strong>en</strong>dida <strong>en</strong>tre 1 y 9 ciclos <strong>de</strong> <strong>la</strong> frecu<strong>en</strong>cia<br />

<strong>de</strong> bus.<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

• Tiempo <strong>de</strong> salvado <strong>de</strong> registros<br />

Cuando se logran <strong>la</strong>s condiciones anteriores, el microcontro<strong>la</strong>dor <strong>de</strong>be salvar el "contexto" actual<br />

<strong>de</strong> trabajo. Para ello, inserta <strong>en</strong> el stack los registros: PC,X,A,CC con una <strong>de</strong>mora adicional <strong>de</strong><br />

9 ciclos (suponi<strong>en</strong>do que <strong>de</strong>mora lo mismo que <strong>la</strong> instrucción SWI). Este tiempo al ser fijo,<br />

pue<strong>de</strong> ser restado <strong>de</strong>l tiempo <strong>de</strong>seado para corregirlo.<br />

La <strong>la</strong>t<strong>en</strong>cia hace que el método <strong>de</strong> trabajo por interrupciones se utilice para g<strong>en</strong>erar tiempos re<strong>la</strong>tivam<strong>en</strong>te<br />

gran<strong>de</strong>s <strong>en</strong> ciclos <strong>de</strong> bus, <strong>de</strong> modo que el error obt<strong>en</strong>ido sea <strong>de</strong>spreciable o promediado<br />

(por ejemplo: si programamos el TIMER para g<strong>en</strong>erar 10 interrupciones por segundo con el modo<br />

autorecargable, a pesar <strong>de</strong> <strong>la</strong> <strong>la</strong>t<strong>en</strong>cia, obt<strong>en</strong>dremos 10 interrupciones por segundo cada una con una pequeña<br />

<strong>de</strong>mora distinta, pero "no acumu<strong>la</strong>tiva" ).<br />

Para corregir estos efectos pue<strong>de</strong> usarse el TIMER sin interrupciones. Esto es, leyéndolo y esperando a que<br />

llegue al valor <strong>de</strong>seado. En este caso hay que t<strong>en</strong>er cuidado con <strong>la</strong> comparación, ya que si se hace<br />

"por igual" hay que estar seguro <strong>de</strong> que el tiempo que se <strong>de</strong>mora <strong>en</strong>tre lectura y lectura no haga que se pase<br />

el valor <strong>de</strong>seado "<strong>de</strong> <strong>la</strong>rgo" sin verlo y si se compara por "mayor o igual" hay que t<strong>en</strong>er cuidado con <strong>la</strong><br />

"circu<strong>la</strong>ridad" <strong>de</strong>l registro (o sea, luego <strong>de</strong> $FFFF se vuelve a $0000 y lo que era mayor ahora es m<strong>en</strong>or!).<br />

Cuando los tiempos a g<strong>en</strong>erar son muy chicos (pocos ciclos) hay que t<strong>en</strong>er <strong>en</strong> cu<strong>en</strong>ta <strong>la</strong> incertidumbre <strong>de</strong>l<br />

prescaler <strong>de</strong>l TIMER, ya que no sabemos <strong>en</strong> que valor se <strong>en</strong>cu<strong>en</strong>tra este divisor al iniciar el retardo.<br />

Si <strong>de</strong>seamos g<strong>en</strong>erar <strong>retardos</strong> <strong>de</strong> distintas duraciones, <strong>de</strong>beremos buscar una unidad <strong>de</strong> interrupción que sea<br />

común a todos los <strong>retardos</strong> y contar interrupciones para g<strong>en</strong>erar los ev<strong>en</strong>tos más <strong>la</strong>rgos.<br />

Por ejemplo: si necesitamos <strong>retardos</strong> <strong>de</strong> 15 mseg, 50 mseg y 100 mseg, po<strong>de</strong>mos usar 5 msegs <strong>de</strong> unidad y<br />

contar 3, 10 y 20 interrupciones respectivam<strong>en</strong>te o bi<strong>en</strong> trabajar el timer <strong>en</strong> modo libre y programar<br />

<strong>la</strong> <strong>de</strong>mora <strong>en</strong> cada caso.<br />

<strong>G<strong>en</strong>eración</strong> <strong>de</strong> <strong>retardos</strong> por <strong>de</strong>mora <strong>de</strong> <strong>la</strong>s instrucciones<br />

Dado que cada instrucción <strong>de</strong>l procesador requiere una <strong>de</strong>terminada cantidad <strong>de</strong> ciclos <strong>de</strong> bus para ser<br />

completada, surge <strong>la</strong> posibilidad <strong>de</strong> utilizar este "efecto secundario" para g<strong>en</strong>erar <strong>retardos</strong> <strong>de</strong> duración<br />

contro<strong>la</strong>da. Y dado que <strong>la</strong>s instrucciones <strong>de</strong>moran <strong>de</strong> 1 a 9 ciclos, pue<strong>de</strong>n obt<strong>en</strong>erse <strong>retardos</strong> muy cortos<br />

o <strong>la</strong>rgos y muy precisos.<br />

Es <strong>de</strong> notar que para que el retardo sea <strong>de</strong> <strong>la</strong> duración <strong>de</strong>seada: el código <strong>de</strong>be ejecutarse con <strong>la</strong>s<br />

interrupciones <strong>de</strong>shabilitadas ya que si se pres<strong>en</strong>ta una interrupción, al tiempo transcurrido se le <strong>de</strong>berá<br />

sumar todo el tiempo que tardo <strong>la</strong> interrupción <strong>en</strong> ejecutar. Si lo que se <strong>de</strong>sea es un retardo <strong>de</strong><br />

"por lo m<strong>en</strong>os" <strong>la</strong> <strong>de</strong>mora dada, por ejemplo para g<strong>en</strong>erar un pulso <strong>de</strong> "strobe", no hay problema<br />

<strong>en</strong> t<strong>en</strong>er <strong>la</strong>s interrupciones habilitadas.<br />

Este método ti<strong>en</strong>e el atractivo <strong>de</strong> po<strong>de</strong>r realizar alguna función útil mi<strong>en</strong>tras se está esperando<br />

(como borrar memoria, precargar registros, etc.).<br />

La instrucción <strong>de</strong> <strong>de</strong>mora por excel<strong>en</strong>cia es "NOP" (no operación) que no hace nada salvo<br />

<strong>de</strong>morar 1 ciclo <strong>la</strong> ejecución <strong>de</strong>l programa. Para g<strong>en</strong>erar <strong>de</strong><strong>la</strong>y más <strong>la</strong>rgos po<strong>de</strong>mos colocar varias<br />

instrucciones NOP seguidas, pero consultando <strong>la</strong>s hojas <strong>de</strong> datos <strong>de</strong>l procesador surg<strong>en</strong> variantes<br />

más interesantes:<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

Ciclos Bytes Código Com<strong>en</strong>tarios<br />

1 1 NOP -<br />

2 1 SEI Fuerza I=1<br />

2 1 CLI Fuerza I=0<br />

2 1 DAA Invalida registro A<br />

2 1 TSX Invalida registros H y X<br />

2 2<br />

NOP<br />

NOP<br />

-<br />

3 1 NSA Intercambia nibbles <strong>de</strong>l registro A<br />

3 2 BRN $ -<br />

4 2<br />

PSHA<br />

PULA<br />

Utiliza y libera un byte <strong>de</strong>l stack<br />

5 1 MUL<br />

PSHA<br />

Invalida registros A, X y CC (bits H y C)<br />

5 3<br />

PULA<br />

NOP<br />

Utiliza y libera un byte <strong>de</strong>l stack<br />

5 3 MOV $80,$80<br />

Invalida registro CC (bits V, N y Z)<br />

Usar cualquier dirección <strong>en</strong> página 0.<br />

6 2<br />

NSA<br />

NSA<br />

-<br />

7 1 DIV<br />

PSHA<br />

Invalida registros A, X y H<br />

7 3<br />

NSA<br />

PULA<br />

Utiliza y libera un byte <strong>de</strong>l stack<br />

8 3 (o 2)<br />

9 3<br />

9 4 (o 3)<br />

16 2 (o 1)<br />

BSR rutina<br />

..<br />

rutina: RTS<br />

NSA<br />

NSA<br />

NSA<br />

JSR rutina<br />

..<br />

rutina: RTS<br />

SWI<br />

...<br />

vector_swi: RTI<br />

Utiliza y libera dos bytes <strong>de</strong>l stack<br />

Se pue<strong>de</strong> utilizar un RTS exist<strong>en</strong>te y ahorrar un<br />

byte.<br />

Intercambia nibbles <strong>de</strong>l registro A<br />

Utiliza y libera dos bytes <strong>de</strong>l stack<br />

Se pue<strong>de</strong> utilizar un RTS exist<strong>en</strong>te y ahorrar un<br />

byte.<br />

Utiliza y libera 5 bytes <strong>de</strong>l stack<br />

Se pue<strong>de</strong> utilizar un RTS exist<strong>en</strong>te y ahorrar un<br />

byte.<br />

En <strong>la</strong> tab<strong>la</strong> se ac<strong>la</strong>ra que efecto co<strong>la</strong>teral ti<strong>en</strong>e realizar <strong>la</strong> <strong>de</strong>mora con <strong>la</strong>s instrucciones indicadas.<br />

Por ejemplo: <strong>la</strong> instrucción "NSA" <strong>de</strong>mora 3 ciclos pero intercambia los nibbles <strong>de</strong>l registro A,<br />

por lo que también se indica <strong>en</strong> <strong>la</strong> tab<strong>la</strong> que usando <strong>la</strong> instrucción "BRN xx" (branch never) se obti<strong>en</strong>e<br />

una <strong>de</strong>mora igual pero sin modificar ningún registro. También pue<strong>de</strong>n ponerse 3 "NOP"s pero a exp<strong>en</strong>sas<br />

<strong>de</strong> 1 byte extra y ningún b<strong>en</strong>eficio.<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

Si <strong>la</strong>s condiciones no nos permit<strong>en</strong> usar un ítem <strong>de</strong> <strong>la</strong> tab<strong>la</strong>, siempre po<strong>de</strong>mos g<strong>en</strong>erar una <strong>de</strong>mora<br />

concat<strong>en</strong>ando 2 o más ítems <strong>de</strong> <strong>la</strong> tab<strong>la</strong> que sí cump<strong>la</strong>n con <strong>la</strong>s condiciones <strong>de</strong>seadas.<br />

Cuando <strong>la</strong>s <strong>de</strong>moras a g<strong>en</strong>erar son <strong>de</strong> muchos ciclos es mucho más compacto obt<strong>en</strong>er dicha <strong>de</strong>mora<br />

por iteración. Así surg<strong>en</strong> los sigui<strong>en</strong>tes ejemplos:<br />

Ciclos Bytes Código Com<strong>en</strong>tarios<br />

769 3<br />

CLRA<br />

DBNZA $<br />

Fuerza registro A= 0<br />

Invalida registro CC (bits V=0, N=0 y Z=1)<br />

Fuerza registro A= 0. Invalida registro CC (V, N y<br />

5,8,11..770 4<br />

LDA #CTE<br />

DBNZA $<br />

Z)<br />

<strong>de</strong><strong>la</strong>y= CTE * 3 + 2 (CTE=1..256)<br />

256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 769 ciclos)<br />

773,776..1538 6<br />

LDA #CTE<br />

DBNZA $<br />

DBNZA $<br />

Fuerza registro A= 0. Invalida registro CC (V, N y<br />

Z)<br />

<strong>de</strong><strong>la</strong>y= CTE * 3 + 770 (CTE=1..256)<br />

256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 1537 ciclos)<br />

6,10,14..1026 5<br />

LDA #CTE<br />

loop: NOP<br />

DBNZA loop<br />

Fuerza registro A= 0. Invalida registro CC (V, N y<br />

Z)<br />

<strong>de</strong><strong>la</strong>y= CTE * 4 + 2 (CTE=1..256)<br />

256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 1025 ciclos)<br />

Fuerza registro X= 0. Invalida registro CC (V, N y<br />

8,14,20..1538 5<br />

LDX #CTE<br />

loop: NSA<br />

DBNZX loop<br />

Z)<br />

<strong>de</strong><strong>la</strong>y= CTE * 6 + 2 (CTE=1..256)<br />

256 => 0 (usar CLRX: un byte m<strong>en</strong>os, 1537 ciclos)<br />

Si CTE es impar : intercambia nibbles <strong>de</strong>l<br />

registro A; si es par : manti<strong>en</strong>e A.<br />

LDA #CTE<br />

Fuerza registro A= 0. Invalida registro CC (V, N y<br />

11,20,29..2306 6<br />

loop: NSA<br />

NSA<br />

Z)<br />

<strong>de</strong><strong>la</strong>y= CTE * 9 + 2 (CTE=1..256)<br />

DBNZA loop<br />

256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 2305 ciclos)<br />

La v<strong>en</strong>taja <strong>de</strong> los métodos <strong>de</strong> <strong>de</strong>mora por iteración es que cambiando <strong>la</strong>s instrucciones que están<br />

<strong>de</strong>ntro <strong>de</strong>l <strong>la</strong>zo, po<strong>de</strong>mos cambiar <strong>la</strong> <strong>de</strong>mora <strong>de</strong> cada iteración y por lo tanto el multiplicador<br />

<strong>en</strong> <strong>la</strong> fórmu<strong>la</strong> <strong>de</strong> "<strong>de</strong><strong>la</strong>y" (<strong>de</strong>mora total).<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

Para <strong>de</strong>moras aún mayores se pue<strong>de</strong>n utilizar los sigui<strong>en</strong>tes ejemplos <strong>de</strong> código:<br />

Ciclos Bytes Código Com<strong>en</strong>tarios<br />

7,10..197377 8<br />

12..589827 9<br />

7,16..590593 10<br />

14..150995714 13<br />

LDA #CTE1<br />

LDX #CTE2<br />

loop: DBNZX $<br />

DBNZA loop<br />

LDHX #CTE<br />

loop: AIX #-1<br />

STHX dirmem<br />

BNE loop<br />

LDA #CTE1<br />

LDX #CTE2<br />

loop: NSA<br />

NSA<br />

DBNZX loop<br />

DBNZA loop<br />

LDA #CTE1<br />

LDHX #CTE2<br />

loop: AIX #-1<br />

STHX dirmem<br />

BNE loop<br />

DBNZA loop<br />

Fuerza registros A= 0, X= 0. Invalida registro CC<br />

<strong>de</strong><strong>la</strong>y= 4 + CTE2 * 3 + (CTE1-1) * (3*256+3)<br />

(CTE1/2=1..256)<br />

256 => 0 (usar CLRA/X: uno o dos bytes m<strong>en</strong>os)<br />

Fuerza registros H= 0, X= 0. Invalida registro CC<br />

<strong>de</strong><strong>la</strong>y= 3 + CTE * 9 (CTE=1..65536)<br />

"dirmem" <strong>de</strong>be estar <strong>en</strong> página 0 (pue<strong>de</strong> ser el<br />

registro <strong>de</strong> canal <strong>de</strong> un timer que no se use)<br />

Fuerza registros A= 0, X= 0. Invalida registro CC<br />

<strong>de</strong><strong>la</strong>y= 4 + CTE2 * 9 + (CTE1-1) * (9*256+3)<br />

(CTE1/2=1..256)<br />

256 => 0 (usar CLRA/X: uno o dos bytes m<strong>en</strong>os)<br />

Fuerza registros A= 0, H= 0, X= 0. Invalida CC.<br />

<strong>de</strong><strong>la</strong>y= 5 + CTE2 * 9 + (CTE1-1) * (9*65536+3)<br />

(CTE1=1..256, CTE2=1..65536)<br />

"dirmem" <strong>de</strong>be estar <strong>en</strong> página 0 (pue<strong>de</strong> ser el<br />

registro <strong>de</strong> canal <strong>de</strong> un timer que no se use)<br />

Dado que no existe una instrucción "TSTHX" para ver si el registro HX, llegó a 0, <strong>en</strong> el código mostrado<br />

se graba el valor <strong>de</strong> los registros H y X <strong>en</strong> una dirección <strong>de</strong> memoria cualquiera para que actualice el<br />

registro <strong>de</strong> condición (<strong>en</strong> particu<strong>la</strong>r el bit Z) y <strong>de</strong>terminar si llegó a 0.<br />

Por supuesto estas no son <strong>la</strong>s únicas formas <strong>de</strong> g<strong>en</strong>erar <strong>de</strong>moras, sino que son algunas que utilizan<br />

muy pocos bytes <strong>de</strong> código (bi<strong>en</strong> siempre escaso!). Des<strong>de</strong> ya, si se le ocurre alguna forma más compacta<br />

<strong>de</strong> g<strong>en</strong>erar un retardo, no du<strong>de</strong> <strong>en</strong> mandarme un e-mail para agregar<strong>la</strong> a <strong>la</strong> lista.<br />

Ejemplos<br />

• Supongamos que t<strong>en</strong>emos que g<strong>en</strong>erar un retardo <strong>de</strong> 1 milisegundo con una frecu<strong>en</strong>cia <strong>de</strong><br />

bus <strong>de</strong> 8 Mhz:<br />

1. Cada ciclo <strong>de</strong> bus correspon<strong>de</strong> a: 1 / 8 Mhz = 0.125 microsegundos.<br />

2. Por lo tanto <strong>la</strong> <strong>de</strong>mora es <strong>de</strong>: 1 milisegundo / 0.125 microsegundos = 8000 ciclos <strong>de</strong> bus.<br />

3. Elegimos <strong>de</strong> <strong>la</strong> tab<strong>la</strong> el m<strong>en</strong>or código para este <strong>de</strong><strong>la</strong>y:<br />

LDA #CTE1<br />

LDX #CTE2<br />

loop: DBNZX $<br />

DBNZA loop<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

;o <strong>en</strong> formato MacAsm:<br />

lda #CTE1<br />

ldx #CTE2<br />

do{<br />

do{<br />

}while( --x != 0 )<br />

}while( --a != 0 )<br />

4. De <strong>la</strong> formu<strong>la</strong>: <strong>de</strong><strong>la</strong>y= 4 + CTE2 * 3 + (CTE1-1) * (3*256+3) (CTE1/2=1..256)<br />

<strong>de</strong>spejamos el valor <strong>de</strong> <strong>la</strong>s constantes:<br />

5. CTE1= ((8000-4)/771)+1= 11.37 => CTE1= 11<br />

CTE2= (8000-4-10*771)/3=95.33 => CTE2= 95<br />

De<strong>la</strong>y= 4+3*95+10*771= 7999<br />

6. En g<strong>en</strong>eral un error <strong>de</strong> 1 <strong>en</strong> 8000 pue<strong>de</strong> ser más que tolerable, pero para lograr el <strong>de</strong><strong>la</strong>y<br />

exacto hay que agregar un "NOP" al final o aum<strong>en</strong>tar CTE2 a 96 y obt<strong>en</strong>er un <strong>de</strong><strong>la</strong>y<br />

<strong>de</strong> 8002 ciclos si el tiempo pedido es el mínimo <strong>de</strong>seado.<br />

• Otros ejemplos los pue<strong>de</strong> <strong>en</strong>contrar <strong>en</strong> <strong>la</strong>s rutinas <strong>de</strong> grabación y borrado <strong>de</strong> <strong>la</strong> FLASH<br />

para el GP32 <strong>en</strong> particu<strong>la</strong>r <strong>la</strong> rutina "DoDe<strong>la</strong>yYStaFLCR" que realiza un <strong>de</strong><strong>la</strong>y <strong>de</strong><br />

3*X ciclos, setea el registro FLCR y produce un <strong>de</strong><strong>la</strong>y extra: cargando los registros A y X<br />

y con un RTS, g<strong>en</strong>erando el "<strong>de</strong><strong>la</strong>y TRCV" (<strong>de</strong> 1 useg.= 8 ciclos) al salir <strong>de</strong> <strong>la</strong> rutina<br />

y precargando registros para usar <strong>en</strong> otras partes <strong>de</strong>l código.<br />

Puerta serie por software<br />

A modo <strong>de</strong> ejemplo se <strong>de</strong>tal<strong>la</strong> a continuación <strong>la</strong>s rutinas para realizar una puerta serie por software a<br />

9600 bauds para frecu<strong>en</strong>cias <strong>de</strong> bus <strong>de</strong> 8MHz y 4MHz <strong>en</strong> un procesador 68<strong>HC908</strong>JL3<br />

(9600 N 8 1 = 8 bits, sin paridad y con 1 bit <strong>de</strong> stop).<br />

Para probar el sigui<strong>en</strong>te código <strong>de</strong>berá conectarse un driver <strong>de</strong> RS232 (tipo MAX232 o simi<strong>la</strong>r)<br />

<strong>de</strong> <strong>la</strong> sigui<strong>en</strong>te forma:<br />

• PORTD.7 a driver TX (salida <strong>de</strong>l micro)<br />

• PORTD.6 a driver RX (<strong>en</strong>trada al micro)<br />

Para seleccionar <strong>la</strong> frecu<strong>en</strong>cia <strong>de</strong> bus se utiliza el switch BUS8MEGA (com<strong>en</strong>tar <strong>la</strong> línea que no<br />

corresponda) <strong>de</strong> modo que el código funcione para ambas frecu<strong>en</strong>cias <strong>de</strong> bus (si utiliza otra<br />

frecu<strong>en</strong>cia, <strong>de</strong>berá ajustar <strong>la</strong>s constantes <strong>de</strong> los <strong>retardos</strong>).<br />

El formato serie RS232 utilizado incluye los sigui<strong>en</strong>tes bits a g<strong>en</strong>erar (TX) o leer (RX):<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

Don<strong>de</strong> cada uno <strong>de</strong> los bits dura: 1 / 9600 bauds = 104.16 microsegundos que a 8MHz son 833.33 ciclos<br />

y a 4MHz son 416.66 ciclos.<br />

Transmisión: <strong>la</strong> rutina itera 10 veces para <strong>en</strong>viar los 8 bits, el "start" y el "stop". El bit <strong>de</strong> "start"<br />

es g<strong>en</strong>erado forzando TX a 0 antes <strong>de</strong> <strong>en</strong>trar al loop. El bit <strong>de</strong> "stop" es g<strong>en</strong>erado con <strong>la</strong> instrucción "sec"<br />

para que luego <strong>de</strong>l 8vo bit salga el stop <strong>en</strong> "1".<br />

Las instrucciones que se ejecutan antes <strong>de</strong> <strong>en</strong>trar al <strong>la</strong>zo (psha, pshx, ldx) <strong>de</strong>moran 6 ciclos al igual<br />

que <strong>la</strong>s que hay <strong>en</strong>tre que se setea el bit a transmitir y se vuelve a iterar (bra o brn y dbnzx),<br />

lo cual asegura que los anchos <strong>de</strong> todos los bits sean iguales. Estos 6 ciclos más los <strong>de</strong> <strong>la</strong>s operaciones<br />

<strong>de</strong>l <strong>la</strong>zo (sin contar el <strong>de</strong><strong>la</strong>y) suman 21 ciclos. Por lo tanto los <strong>de</strong><strong>la</strong>ys <strong>de</strong> ajustan para que <strong>de</strong>mor<strong>en</strong> 812<br />

o 316 ciclos y obt<strong>en</strong>er así los 833 o 417 ciclos totales por bit.<br />

Recepción: <strong>la</strong> rutina espera "eternam<strong>en</strong>te" a que baje RX (comi<strong>en</strong>zo <strong>de</strong>l bit <strong>de</strong> "start") y realiza un<br />

<strong>de</strong><strong>la</strong>y inicial <strong>de</strong> 1 bit y medio, esto es todo el bit <strong>de</strong> "start" y medio "D0", <strong>de</strong> forma <strong>de</strong> leer los bits <strong>en</strong><br />

su c<strong>en</strong>tro para obt<strong>en</strong>er una mayor inmunidad a <strong>la</strong>s variaciones <strong>de</strong> cristal <strong>de</strong>l transmisor y <strong>de</strong>l procesador.<br />

La rutina luego lee los 8 bits e "ignora el stop" (esto es para utilizar ese tiempo para procesar el caracter<br />

recibido, ya que inmediatam<strong>en</strong>te luego <strong>de</strong>l "stop" pue<strong>de</strong> v<strong>en</strong>ir otro "start"). La rutina pres<strong>en</strong>tada no es<br />

óptima <strong>de</strong>s<strong>de</strong> el punto <strong>de</strong> vista <strong>de</strong>l filtrado <strong>de</strong> <strong>la</strong>s lecturas (sólo realiza una lectura por bit). No le<br />

incorporé filtrado mediante varias lecturas para mant<strong>en</strong>er el código lo más c<strong>la</strong>ro posible pero pue<strong>de</strong><br />

agregarlo dividi<strong>en</strong>do el tiempo <strong>de</strong> iteración, por ejemplo, a <strong>la</strong> décima parte, realizando 10 lecturas<br />

y <strong>de</strong>terminando si es "1" o "0" según <strong>la</strong> mayor cantidad <strong>de</strong> lecturas obt<strong>en</strong>idas.<br />

;$SET BUS8MEGA ;BUS <strong>de</strong> 8 MHZ requiere cristal <strong>de</strong> 32MHZ<br />

$SETNOT BUS8MEGA ;BUS <strong>de</strong> 4 MHZ requiere cristal <strong>de</strong> 16MHZ<br />

;==============================================================================<br />

; TXByte:<br />

; Transmite un byte por <strong>la</strong> puerta serie simu<strong>la</strong>da a 9600 (como caracter)<br />

; REQUIERE BUS <strong>de</strong> 8 MHZ. (<strong>de</strong><strong>la</strong>y= 833 ciclos x bit)<br />

; o BUS <strong>de</strong> 4 MHZ. (<strong>de</strong><strong>la</strong>y= 416-417 ciclos x bit)<br />

;<br />

; Requiere:<br />

; A= byte a <strong>en</strong>viar. (MANTIENE A,X,H)<br />

;==============================================================================<br />

TxByte:<br />

sei ;TAPA INTS (para no arruinar tiempos)<br />

sta COPCTL ;reset COP<br />

bclr 7,PORTD ;TX=0 (START)<br />

psha ;manti<strong>en</strong>e A y X<br />

pshx<br />

ldx #!10 ;X=numero <strong>de</strong> bits a <strong>en</strong>viar<br />

do{<br />

pshx<br />

$IF BUS8MEGA<br />

ldx #!203 ;<strong>de</strong><strong>la</strong>y= 812 + 21= 833<br />

do{<br />

nop<br />

}while( --x != 0 ) ;DELAY= X * 4 ciclos<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

$ELSEIF<br />

ldx #!132 ;<strong>de</strong><strong>la</strong>y= 396 + 21= 417<br />

do{<br />

}while( --x != 0 ) ;DELAY= X * 3 ciclos<br />

$ENDIF<br />

pulx<br />

sec ;CY=1 (STOP)<br />

rora ;<strong>en</strong>via bits 0,1,2... al carry<br />

if( cy == 1 ){ ;hace TX= CY<br />

bset 7,PORTD ;TX=1<br />

}else{<br />

bclr 7,PORTD ;TX=0<br />

brn $ ;<strong>de</strong><strong>la</strong>y <strong>de</strong> 3 ciclos (igual al branch <strong>de</strong>l else)<br />

}<br />

}while( --x != 0 )<br />

pulx<br />

pu<strong>la</strong><br />

cli ;DESTAPA INTS<br />

sta COPCTL ;reset COP<br />

rts<br />

;==============================================================================<br />

; RXByte:<br />

; Espera y RECIBE un byte por <strong>la</strong> puerta serie.<br />

; Espera INFINITA.<br />

;<br />

; Requiere:<br />

; OUT: A= byte recibido. (MANTIENE H,X)<br />

;==============================================================================<br />

RXByte:<br />

pshx ;salva X<br />

sei ;TAPA INTS (para medir los bits)<br />

do{<br />

sta COPCTL ;reset COP<br />

}while( PORTD.6 == 1 ) ;espera el START<br />

$IF BUS8MEGA<br />

ldx #!249 ;espera tiempo <strong>de</strong> 1+1/2 bit= 1251 ciclos<br />

do{<br />

sei ;<strong>de</strong><strong>la</strong>y <strong>de</strong> 2 ciclos<br />

}while( --x != 0 )<br />

$ELSEIF<br />

ldx #!206 ;espera tiempo <strong>de</strong> 1+1/2 bit= 625 ciclos<br />

do{<br />

}while( --x != 0 )<br />

$ENDIF<br />

lda #$80 ;<strong>de</strong>tecta RX completa (8bits)<br />

while(1){<br />

if( PORTD.6 == 0 ){ ;CY=DATA BIT<br />

}<br />

rora<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar


Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />

if( cy == 1 ){ ;ya leyo los 8 (ignora el STOP)<br />

cli ;DESTAPA INTS<br />

pulx ;manti<strong>en</strong>e X<br />

sta COPCTL ;reset COP<br />

rts<br />

}<br />

$IF BUS8MEGA<br />

ldx #!205 ;espera tiempo <strong>de</strong> 1 bit= 834 ciclos<br />

do{<br />

nop<br />

}while( --x != 0 ) ;205x4= 820<br />

$ELSEIF<br />

ldx #!134 ;espera tiempo <strong>de</strong> 1 bit= 416 ciclos<br />

do{<br />

}while( --x != 0 ) ;134x3= 402<br />

$ENDIF<br />

} ;leer otro bit<br />

Pue<strong>de</strong> <strong>de</strong>scargar el ejemplo <strong>de</strong> <strong>la</strong> puerta serie para <strong>HC908</strong>JL3 que incluye el uso <strong>de</strong> <strong>la</strong><br />

memoria FLASH para grabar<strong>la</strong> <strong>de</strong> a 1 byte por vez. El archivo ZIP ti<strong>en</strong>e el código <strong>en</strong> formato MacAsm<br />

(archivo MAS) y ya preprocesado (archivo ASM) al igual que todos los programas necesarios para usar<br />

el utilitario.<br />

El código <strong>de</strong> ejemplo <strong>en</strong>vía por <strong>la</strong> puerta serie: "Ho<strong>la</strong> mundo!", borra una página <strong>de</strong> FLASH (64 bytes),<br />

graba el string "HOLA" <strong>en</strong> <strong>la</strong> FLASH y transmite lo grabado (<strong>de</strong>bería ser: "HOLA"),<br />

luego se pone <strong>en</strong> modo "eco" (repite todo lo que recibe).<br />

Conclusión<br />

En el pres<strong>en</strong>te artículo se han visto distintas formas <strong>de</strong> g<strong>en</strong>erar <strong>retardos</strong> mediante instrucciones.<br />

La lista pres<strong>en</strong>tada está lejos <strong>de</strong> ser exhaustiva ya que cualquier código realiza una <strong>de</strong>mora<br />

al ejecutarse y <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong> <strong>la</strong> aplicación particu<strong>la</strong>r pue<strong>de</strong> que un método sea mejor que otro.<br />

Por ejemplo <strong>en</strong> <strong>la</strong> nota <strong>de</strong> aplicación AN1831 <strong>de</strong> Freescale se pue<strong>de</strong> observar el código <strong>de</strong> <strong>la</strong><br />

ROM <strong>de</strong> los procesadores <strong>HC908</strong> mo<strong>de</strong>los GR8, KX8, JL3, JK3 y JB8 que para obt<strong>en</strong>er los <strong>de</strong><strong>la</strong>ys<br />

<strong>de</strong> grabación y borrado <strong>de</strong> <strong>la</strong> FLASH ajustados con una única constante a <strong>la</strong> frecu<strong>en</strong>cia <strong>de</strong> bus,<br />

todos los <strong>de</strong><strong>la</strong>y se g<strong>en</strong>eran <strong>en</strong> base a <strong>la</strong> rutina "DELNUS" (que produce un <strong>de</strong><strong>la</strong>y <strong>de</strong> X * 12 microseg),<br />

lo cual requiere más código que ajustar <strong>la</strong>s rutinas para una frecu<strong>en</strong>cia <strong>de</strong> bus <strong>en</strong> particu<strong>la</strong>r,<br />

pero es más flexible (opción correcta para una ROM).<br />

Para verificar que los ciclos <strong>de</strong> <strong>la</strong>s instrucciones correspon<strong>de</strong>n con lo calcu<strong>la</strong>do, convi<strong>en</strong>e activar<br />

<strong>la</strong> opción "ver cu<strong>en</strong>ta <strong>de</strong> ciclos" <strong>en</strong> el <strong>en</strong>samb<strong>la</strong>dor para que g<strong>en</strong>ere un archivo <strong>de</strong> listado como<br />

el que se ve a continuación (con <strong>la</strong> opción "C" <strong>en</strong> <strong>la</strong> línea <strong>de</strong> comandos <strong>de</strong> "CASM08Z.EXE" o marcando <strong>en</strong> WIN<br />

IDE: "Show Cycles in Listing" <strong>de</strong>ntro <strong>de</strong> "Setup Environm<strong>en</strong>t..") :<br />

....<br />

EC58 [04] 1F03 201 bclr 7,PORTD ;TX=0<br />

EC5A [03] 21FE 202 brn $ ;<strong>de</strong><strong>la</strong>y <strong>de</strong> 3<br />

Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!