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

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

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!