domingo, 5 de junio de 2011

Input Capture Unit


El timer1 incorpora una unidad de captura la cual puede capturar eventos externos y darnos un tiempo referencial en el cual estos ocurrieron.
La señal que indica el evento puede ser aplicado al pin ICP1 o vía la unidad de comparación analógica. El tiempo que es capturado puede ser usado para medir frecuencia, duty-cycle u alguna otra característica de la señal aplicada.

En el siguiente gráfico de muestra el diagrama de bloques de la unidad de captura.

bloques

Se puede ver que las entradas pueden ser el pin ICP1 o el comparador analógico. LA unidad también cuenta con un modulo de cancelación de ruido el cual tomará 4 muestras de la señal y si las 4 son iguales la señal será valida. También ésta el modulo de detección de flanco que nos permite seleccionar entre los flancos de subida(‘1’) o bajada(‘0’).
Cuando el evento ocurre los 16bits del contador TCNT1 son escritos al registro ICR1, también  en éste mismo instante se generará un interrupción( siempre que se activen los flag’s TICIE1 en el registro TIMSK y I en SREG.

En éste post usaré la unidad de captura para medir la frecuencia de una señal cuadrada.
El principio de medición consiste en capturar el valor de cuenta del timer1 (TCNT1) en un periodo de la señal a medir, luego con el valor de la captura , la frecuencia a la que trabaja el uC y conociendo el pre-escaler usado podremos fácilmente encontrar la frecuencia de la señal.

Por ejemplo: Si se trabaja con una F_CPU=16MHz, el valor capturado es ICR1=0x08BB y el pre-escaler usado es 64, entonces la frecuencia de la señal es:

image

Aplicando los datos a la formula:

image

Ahora pasaré a mostrar el código. Hay algunas macros y rutinas que ya he mostrado en post anteriores pero las estoy volviendo a mostrar.

Primero mostrare las macros.






m24

Ahora mostraré la rutinas de conversión de binario a ascii.

binascii1

binascii2

Ahora la rutinas para manejo del LCD.

lcd1

lcd2

lcd3

Las rutina de retardo que es usado junto a las macros delay_ms y delay_us.

retardo

La rutina para efectuar la división.

div1

div2

Y por último el código principal.






main23


main24

El funcionamiento del programa es como sigue.
  • Se configura los periféricos, se habilita la interrupción y se espera a que ésta ocurra.

  • Cuando ocurra la interrupción por captura el programa saltará a la rutina “CAPTURA_EVEN”, aquí tomará el valor capturado y lo pondrá en dos registros(R19:R18=ICR1H:ICR1L).
  • Se verificara si el timer se ha desbordado, en caso de ser así se mostrará un mensaje indicado que aquella es una frecuencia que no se puede medir(“fuera de rango”).

  • Si no se ha desbordado se calculará la frecuencia, con la formula ya antes mostrada, y se guardará en FRECASCII.

  • Luego del calculo de mostrará la frecuencia en el LCD.

  • Se espera 300ms y luego se espera al siguiente flanco de subida para iniciar la siguiente captura de datos (la medida de la frecuencia se toma entre dos francos de subida).
Hay que tener presente que con este método no se puede medir frecuencias muy altas, mientras mayor es la frecuencia mayor es el error en la medición. En un próximo post  mostraré como usar el mismo timer para hacer medidas de frecuencias mas altas.
Espero este pequeño ejemplo le ayude..!!!

Ahora un video del programa en funcionamiento.


lunes, 30 de mayo de 2011

TIMER 1

En éste post mostraré un pequeño ejemplo de como configurar el timer 1 (16 bits) para tener una gran variedad de bases de tiempo, las cuales pueden ser usadas para generar retardos, pulsos a una determinada frecuencia, etc.

Programa : TIMER

Sin mas preámbulo pasaré a mostrar las macros usadas.


A ésta macro solamente hay que indicarle el tiempo con el cual se quiere configurar el timer (en ms).
El pre-escaler del timer se puede cambiar modificando CSN.

macros2

MOVIF pone un inmediato en la RAM, ya sea en el espacio de datos o en el espacio de registro especiales.

El programa principal es el siguiente:

main1

Esta parte configura dos pines como salidas (PB0 y PB1), también configura el TIMER 1 a 100ms, configura el pre-escaler del timer y por ultimo habilita la interrupción por desborde u overflow.

main2

Cada vez que el timer se desborda se conmutará los pines PB0 y PB1, y también hay que volver a configurar el timer.

En el siguiente video se muestra el funcionamiento del programa.


sábado, 21 de mayo de 2011

Manejo del WDT

A diferencia de otros uC’s en los ATmega el WDT se puede habilitar y deshabilitar por programa, pudiendo cambiar el tiempo de reset a voluntad.

En éste post mostraré como habilitar y deshabilitar el Watch Dog Timer en cualquier ATmega.

En nuestro archivo de macros tenemos que agregar el siguiente codigo. (Link al programa)

wdt1

Estas definiciones no son aplicables a todos los ATmega, en un ATmega8 solamente de puede llegar a 2 segundos mientras que en un ATmega324P se puede llegar hasta 8 segundos.

wdt2

La macro anterior permite habilitar el wdt.

wdt3

La macro anterior permite deshabilitar el wdt.

Ahora mostrare en sencillo ejemplo de su uso.

wdt4

sábado, 2 de abril de 2011

I2C en ATmega8

En éste post mostrare un par de ejemplos de como usar el bus i2c para escribir y leer datos en una memoria EEPROM serial (24C16).
La memoria 24C16 tiene una capacidad de 2048 bytes agrupados en 8 páginas de 256 bytes cada una.
Todos los esclavos del bus i2c tienen una dirección la cual les permite ser seleccionados; en el caso de estas memorias seriales la dirección es en parte configurable o fija, esto dependerá del fabricante. En el siguiente gráfico se muestra dos memorias de fabricantes distintos.

Programas

eeproms

La primera es una memoria de ATMEL, la cual permite configurar parte de la dirección mediante los pines A2, A1 y A0; los bits B2B1B0 son usados para seleccionar la pagina de la dentro de la memoria.
La otra es una memoria de FAIRCHILD, ésta ya trae parte de dirección fija(1010), los bit A2A1A0 permiten seleccionar la pagina de la memoria a la cual se accederá.
La velocidad del reloj para esto dispositivos se indica en sus hojas de datos, en los ejemplos usaremos 100KHz. Para configurar dicha velocidad se usa la siguiente formula, la cual se puede encontrar en el manual de del uC que se usara, yo la obtuve del manual del ATmega8.
 formula

La forma de escribir  datos es la siguiente:

write

Se inicia la transmisión con un “START”, luego se selecciona el esclavo “DEVICE ADDRESS” en modo de escritura “0”, después del “ACK” enviado por el esclavo se enviara la dirección donde se escribirá “WORD ADDRESS”, por último se envía el dato a escribir. Hay que cada ciclo de escritura tiene una duración, éste tiempo dependerá del dispositivo.

La forma de leer datos es la siguiente:

read

Se inicia la transmisión con un “START”, luego se selecciona el esclavo “DEVICE ADDRESS” en modo de escritura “0”, después del “ACK” enviado por el esclavo se enviara la dirección donde se leerá “WORD ADDRESS”, nuevamente se envía un “START” o también conocido como “RESTART”, por último se lee el dato.

Bueno, como ya es costumbre mostrare las macros que usare en estos ejemplos.

macros

Ahora mostrare las rutinas para iniciar y usar el bus i2c.

rutinasi2c1

rutinasi2c2

rutinasi2c3

Ahora el un sencillo ejemplo se escritura y lectura de algunos datos en una EEPROM.

i2c1

El ejemplo no hace otra cosa que escribir algunos datos a partir de la dirección 0x05 de la pagina 0, luego los leerá.

El circuito es el siguiente:

simu_0

Con el uso de debuger i2c se puede ver la transferencia de datos:

simu_2

El final la memoria debe quedar así:

simu_1

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

El segundo ejemplo consiste en enviarle al ATmega8, por el uart, un comando para que éste lea o escriba en la EEPROM.

‘W’+PAGINA+DIRECCIÓN+DATO se usara para escribir en la EEPROM.
‘R’+PAGINA+DIRECCIÓN se usara para leer en la EEPROM.

Por ejemplo si se envía por el uart ‘W’ 0x06 0x66 0x99 el uC escribirá en la dirección 0x66 de la pagina 6 el dato 0x99. Y si enviamos ‘R’ 0x03 0x79 estaremos leyendo el datos que esta guardado en la posición 0x79 de la pagina 3.

Agregaremos algunas rutinas al archivo RUTINAS_I2C.asm:

rutinasi2c4

Las rutinas usadas en el uart son las siguientes:

uart1

uart2

El programa principal es mostrado a continuación.

i2c2

Ahora les mostrare un vídeo con el funcionamiento del programa anterior.

En el vídeo se escribe 0x99 en la dirección 0x66 de la página 6 (dirección absoluta en la memoria es 6*0x100 + 0x66 = 0x666), luego éste dato es leído. También se escribe 0x58 en la posición 0x67 de la misma página.

viernes, 18 de marzo de 2011

Manejando Display 7-seg

Ahora mostrare un sencillo programa que muestra una cuenta ascendente de cuatro dígitos, que se almacenan en memoria (CUENTA1:CUENTA2:CUENTA3:CUENTA4), en 4 displays de 7-segmentos.

Link Programa

Agregaremos una macro más a nuestro archivo macros.inc:

MACRO

MOVIF toma un inmediato (@1) y lo guarda en una posición de memoria (@0).

El programa tiene dos rutinas, una llamada muestra y otra llamada incrementa.

Muestra toma cada dígito y lo envía a su respectivo display. También genera un retardo antes de pasar el siguiente display, ya que esto permite visualizar el dígito.

Incrementa va aumentando en 1 el valor de la cuenta, la cuenta será de 0-9999.

prog1

prog2

El circuito en el cual se usan displays con ánodo común es el mostrado abajo.

DISPLAY

En el siguiente vídeo se muestra la simulación del programa, aunque no se aprecia muy bien debido al programa de captura.


lunes, 7 de marzo de 2011

ADC - Analog-to-digital Converter

El ADC en los ATmega, cómo en otros uC´s de 8bits, tiene una resolución máxima de 10bits. Dependiendo de el uC se encontrara un número diferente de canales simples o diferenciales.
La formula clásica para convertir el valor que se obtiene de los registros ADCH:ADCL es:

Vin=5*(ADCH:ADCL )/1024

5/1042 es aproximadamente 48828e-7, entonces Vin=((ADCH:ADCL )*48828)e-7.

Ahora mostrare un ejemplo de la configuración del ADC en un ATmega324P.
Agregaremos unas macros a las nuestro archivo macros.inc:

macros

La macro “PUTM” no hace otra cosa que obtener el valor de una posición de la ram y enviarlo al LCD.
Las otras dos macros realizan una multiplicación como es indicado. Estas se usan para multiplicar ((ADCH:ADCL )*48828).
También se ha usado una rutina para convertir el resultado de la multiplicación a código ascii, esto es para poderlo mostrar en el lcd.

ascii

Antes de llamar a esta rutina Z debe apuntar al dato que se quiere convertir (LSB), Y debe apuntar a la posición de la ram donde se quiere guardar los datos en ascii (MSB).

El programa principal es el siguiente:





SELEC_CH recibe en R16 el canal que se muestreara, luego de escoger el canal se habilita el conversor (ADEN) y se inicia la conversión (ADSC).
ESPERA_ADC esperará hasta el final de la conversión.
CALCULA_VOL obtiene los 10 bits de la conversión en R17:R16 y lo multiplica con R19:R18=48828, luego ese valor convertido la convierte a código ascii y lo pone en la ram (Y=0x0100).
El resultado de la simulación es el mostrado:

fig1

En la ram se puede ver uno de los valores en ascii (000023486268=23486268). La coma decimal debe correr 7 posiciones (debido al factor e-7), entonces el voltaje es 2.34862.


martes, 1 de marzo de 2011

“delay_ms(ms)” y “delay_us(us)” para cualquier frecuencia

En un post anterior mostré como generar una rutina de retardos en milisegundos, ésta rutina funcionaba muy bien pero el problema era volver a calcular valores para una frecuencia diferente.
Ahora mostrare otra rutina que junto con sus macros permiten tener retardos en milisegundos y microsegundos, pero a diferencia de la anterior ya no hay que calcular valores para generar los retardos, solamente se deberá cambiar la frecuencia a la cual se trabajara (F_CPU).

Esta rutinas pueden soportar valores de 0-65535. Descarga

Las rutinas y las macros son las siguientes:

macros

retardo

Su uso es muy sencillo, aquí se muestra:

main

Los resultados los puede ver en la parte izquierda del simulador.

cpu

Espero éste sencillo ejemplo les sea útil.