TUTORIAL DE ATMEL AVR´s de 8-bits

Anuncio
TUTORIAL DE ATMEL AVR´s de 8-bits
Logo propiedad de Atmel
Ensamblador
Autor: Luis Antonio Méndez Soto
PARTE 1
Libre distribución.
Solo pongan de donde lo obtuvieron y referencias bibliográficas.
Atmel®, the Atmel logo and combinations thereof, and others are the registered trademarks or
trademarks of Atmel Corporation of its subsidiaries
"AVR®" and "AVR is a registered trademark of Atmel Corporation".
Introducción.
Decidí hacer este tutorial por que yo aprendí a programar los Avr´s en c++ y quería
aprender en ensamblador, estuve buscando y nunca encontré un tutorial que en realidad
le entendiera entonces decidí aprender por mi cuenta. Tengo conocimientos sobre
ensamblador de Z80 y como funciona un sistema mínimo conecte uno en una protoboard
que ya no era tan sistema mínimo estaba bastante grande todavía lo tengo por ahí
armado de hecho no lo quiero desarmar, no lo uso por que que no tengo programador de
memorias paralelas. Y pues se poco ensamblador de PIC16F84 pero pues aquí tratamos
de aprender ensamblador de los Avr´s. En general el ensamblador es lo mismo en todos
los Avr´s no como en los PIC que cada uno tiene un ensamblador diferente. Desde mi
punto de vista y lo poco que conozco al arquitectura del uC Pic no fue muy bien pensada
en comparación con la de los Avr´s. Pero eso ya es decisión de cada uno.
Dedico este pequeño tutorial a todas las personas que me apoyan y me dicen que siga
adelante que cumpla con mis sueños a mis papas que siempre han sido la base de mi de
mi crecimiento como persona y que sin ellos no sabría todo esto, los quiero mucho. A mi
novia que siempre me apoya y mas que nada por el tiempo que no le dedico a ella y se lo
dedico a estas actividades que tanto me gustan.
Conocimientos Necesarios.
1. Electrónica básica(conexiones)
2. Programación ya sea en c o algún otro lenguaje.
3. Ganas de Aprender bien y hacer preguntas.
Componentes Necesarios.
1.-Programador de Avr´s cualquiera que funcione.
2.-uC Atmel Serie Avr Attiny 461, Atmega8(cualquier Avr funciona por que va a
ser en ensamblador y todo ensamblador de Avr es muy parecido)
3.-Protoboard
4.-Pequeña fuente de 5 Volts
5.-Resistencias (variadas)
6.-Led´s Varios
Software necesario
Avr Studio 4
Avr Dude (dependiendo de el programador)
Pony Prog (dependiendo de el programador)
Sobre los componentes.
1.-Programador de Avr´s, yo tengo el Avr Dragon pero cualquiera que tengan y que
funcione debe de funcionar bien y servirnos y si no tiene chequeen paginas como
http://www.pictronico.com/shop/osc/index.php?cPath=33
que tienen desde $ 300 pesos
Aquí en Celaya Voltix vende el Avr Dragon que cuesta aproximadamente $1000
En Queretaro esta Advandix ahi venden también
En la Ciudad de México en el Centro en la calle de República de el Salvador deben de
encontrar yo e visto en al plaza con el numero 24 en la parte de arriba es cosa de que
pregunten.
O otra opción es hacerlo en lo personal yo no los e probado pero les dejo varios links.
Miren
http://www.obdev.at/products/vusb/prjprog.html
http://www.forosdeelectronica.com/f24/diagrama-programador-atmel-atmega16-32-a16274/
http://www.foroselectronica.es/f65/programador-atmega32-16pi-745.html
Mas adelante haber si agarramos un tutorial de estos y los probamos haber que pasa, si
alguien ve alguno y le funciono pues que nos diga
2.-Aquí en Celaya en Voltix los venden o pueden ponerse en contacto conmigo por
correo electrónico [email protected] y [email protected] y yo se los puedo
vender.
3.- Esta las pueden conseguir en Voltix o en Steren en cualquier tienda que venda
componentes electrónicos como para hobistas
4.-Pues esto pueden usar la de un cargador de celular una computadora o varias cosas así
o hacer una pequeña fuente con LM7805 y un transformador ahí esta el diagrama.
5.- Igualmente en Voltix o en cualquier Steren si quiere me pueden contactar y yo
también se las puedo vender.
6.- Igualmente en Voltix o en cualquier Steren si quiere me pueden contactar y yo
también se las puedo vender.
Software necesario
Pues el Avr Studio lo pueden conseguir directo de la pagina de Atmel www.atmel.com
este software es gratuito solo hace falta registrarse y si quieren aprender pues con este
basta por que también es simulador y para programas simples como con los que vamos a
empezar con este software basta.
El Avr dude y el pony prog también son gratuitos esos hay que echarle una buscada en
google.
Les recomiendo también tener la hoja de datos de su uC que quieren programar la
pueden buscar directo en Atmel tiene todo muy bien organizado y las instrucciones de
ensamblador de loa Avr´s también están en Atmel pero a esa si les dejo el link seria
http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf
Estas son las instrucciones de los Avr´s de 8 bits
Inicio y pura teoria.
Que es un Microcontrolador?De Wikipedia: Un circuito Integrado o chip que incluye en
sus interior las tres unidades básicas de una computadora: Unidad central de
procesamiento (CPU) , Memoria y unidades de E/S.
Desde mi punto de vista: es una computadora en un circuito integrado. Pueden tener mas
dispositivos dentro de ellos mismo como: Convertidores DAC, ADC, timers, PWM,
USART, UART, SPI, Comparadores, Interfaz usb, Ethernet, Controladores de LCD, etc..
Dependiendo de los módulos extras que tenga es su precio y complejidad. Existen
muchos fabricantes como: Atmel, Microchip, Motorola, Parallax, Hitachi, National
Instruments, Texas Instruments, Zilog , etc...
Aplicaciones: Pues sus aplicaciones son prácticamente infinitas, imaginate cuantos
aparatos conoces que tiene una pantalla ya sea de leds, touch, lcd como hornos,
celulares,cámaras, refrigeradores, relojes, aires acondicionados, lavadoras, controles
remotos, etc... Los aparatos que traen botones para interactuar con nosotros, los aparatos
con leds pequeños y así muchos mas. Todo este tipo de aparatos necesita un controlador,
generalmente es una computadora pero son muy caras para tenerlas dentro, ahí es donde
entra el uC. Un carro es un buen ejemplo, sin temor a equivocarme un carro moderno
trae cerca de 50 uC, casi casi uno por sensor por que van interconectados a un una
computadora central que controla todo pero algo necesita enviar los datos de una manera
para que los entienda el CPU principal esto lo hace el uC. El bus que usan generalmente
los carros se llama Bus CAN.
Pues bueno nosotros vamos a usar el Attiny461 pero como ya lo dije y lo vuelvo a
repetir es ensamblador y pues sirve para casi todos los microcontroladores Atmel de la
seria AVR tiny y Avr Mega no se decirles de los Xmega nunca e usado uno pero espero y
pronto poder usarlo.
Ejecución de instrucciones
Todos los uC tiene arquitectura Harvard al menos todos los que conozco esto quiere
decir tiene una memoria diferente para programa y para datos mientras que una
arquitectura Von Neuman es la misma memoria para datos y programa. Tener
arquitectura Harvard es mejor por que es mas rápido de accesar. Veamos lo así mientras
en Harvard yo lee el programa y también obtengo los datos al mismo tiempo en el
mismo ciclo de reloj en el de Von Neuman necesito dos ciclos de reloj uno para leer la
acción a hacer y la otra para el dato.
Les dejo una figura de como se lee los datos y el programa en los Avr´s
Imagen propiedad de Atmel
Figura 1 de la hoja de datos del Attiny461
Como se alcanza a ver en el primer ciclo de reloj se decodifica la primera instrucción y
en el segundo ciclo ya se sabe que tiene que hacer y ejecuta la primera instrucción,
mientras que en ese mismo ciclo la segunda instrucción se decodifica y al tercer ciclo se
ejecuta esa segunda instrucción y se obtiene la 3er instrucción y así sucesivamente, todo
esto es gracias a las dos memorias separadas para datos y para programa.
Un poco de la arquitectura.
Les dejo una imagen de la arquitectura y explicación de los componentes que vamos a
usar en esta primera parte de el tutorial.
Contiene 32 Registros de propósito general de 8 bits con un tiempo de acceso de un
ciclo de reloj.
El flujo de el programa es proveído por saltos condicionados y no condicionados la
función Call o llamada a subrutina y esto es capaz de accesorio a toda la memoria de el
uC.
Imagen propiedad de Atmel
ALU
Este esta conectado a los 32 registros de propósito general.se ejecutan instrucciones
entre los registros en un solo ciclo de reloj puede ser con otro registro o con otro dato.
Se divide en tres categorías :operaciones aritméticas, operaciones lógicas y operaciones
de tipo bit.
Statur register.(SREG)
Contiene información de la operación aritmética ejecutada mas recientemente.
Este registro no se guarda automáticamente cuando entras a una subrutina, hay que
guardarlo automáticamente.
Imagen propiedad de Atmel
Esta parte es muy importante es la que nos dice como debe de seguir el programa o las
condiciones apréndansela o impriman la es muy importante les explico cada bit.
Bit 7 Global Interupt enable (GIE)
Cuando este bit es 1 están habilitadas la interrupciones del uC, si no esta habilitado y en
los otros registros se habilitan no va a pasar nada por que este no esta habilitado. Se
cambia a 0 automáticamente por hardware cuando ocurre alguna interrupción. Y puede
ser puesto a uno de nuevo con la instrucción RETI. Puede ser puesto a 1 o 0 con las
instrucciones SEI y CLI.
Bit 6 Bit Copy Storage (BCS)
Este se usa para copiar un bit de el SREG a un registro o de un registro al SREG no se
usa mucho en programación.
Bit 5 Half Carry Flag (HCF)
Indica si hay medio carry en la ultima operación. O si la operación anterior fue mayor a
15.
Bit 4 Sign Bit (SB)
Siempre es una operación exclusive or con la bandera de negativo y la de complemento
a dos y sobre flujo
Bit 3 Two complements overflow flag
Esta la Explico un poco mas adelante
Bit 2 Negative flag (NF)
Indica si el resultado de la ultima operación fue menor que cero. Tambien podemos
checarla y ver que el numero es 128 o mayor
Bit 1 Zero flag(ZF)
Indica si la ultima operación fue cero.
Bit 0 Carry flag (CF)
Indica si el resultado de la ultima operación fue mas de 255.
Sobre los registros.
Los registros son una especie de memoria Ram pero no lo son estos están conectados
directo al ALU y todas las operaciones pasan por el ALU. Para un programa pequeño no
necesita Ram pero si necesita guardar información para esto nos sirven los registros
como lo dice son 32 registros les dejo una pequeña imagen de como están.
Imagen propiedad de Atmel
Como se alcanza a ver aquí los registro del 26 al 31 de pueden usar como registros de 16
bits para lograr accesar a toda la memoria del uC.
Las operaciones que se pueden hacer son:
Una entrada de 8 bits de entrada y el resultado ser de 8 bits.
Dos entradas de 8 bits y un resultado de 8 bits.
Dos entradas de 8 bits y una salida de 16 bits.
Una entrada de 16 bits y una salida de 16 bits.
Pues eso seria toda la teoria por este primera parte de el tutorial ahora si viene lo mismo
espero y ya tengamos al menos instalado el Avr Studio todos en nuestra maquina.
Si no recuerden descargarlo de la pagina de Atmel www.atmel.com
INICIO
Esta es la imagen con la que empezamos
Aquí le tenemos que dar click en new project y esta es la imagen que sale
Aquí seleccionamos Atmel Avr Assembler esto nos habilita el nombre de el proyecto y
el nombre de el archivo con extensión .asm y le damos en Next y sale esto.
ASEGURENSE TAMBIEN DE PONER CREATE INITIAL FILE.
Aquí seleccionamos Avr Simulator y en mi caso Selecciono Attiny461 si ustedes tiene
otro uC seleccionen el modelo de el uC que tiene si no aparece en Avr Simulator
seleccionen el Avr Simulator 2 y ahí de seguro debe aparecer y damos click en Finish.
Pues ahora si viene lo bueno no se si recuerden el Sreg que tiene un numero en
hexadecimal a la hora de programar no existe el Sreg y los demás registros del timer, adc
usart y demás cosas cada uno tiene un numero pero pues así es un poco mas difícil
recordarlo por ejemplo el que les digo el Sreg tiene el numero hexadecimal 0x3F de
ahora en adelante cuando vean 0xA0 va a ser un numero en hexadecimal es mas fácil
aprender que es el Sreg que el registro 0x3F. Entonces lo que podemos hacer es que
escribamos.
De ahora en adelante todo texto en cursiva y negritas es parte de el programa
.equ Sreg = 0x3F
y así para todos los demás registros que vayamos a y usar.
Pero esta la otra opción que se me hace mas fácil, donde se instalo el Avr Studio en mi
caso C:\Program Files\Atmel hay una carpeta que dice Avr Tools le damos click ahí
después hay una que dice Avr Assembler click y por fin en la que dice Appnotes.
Vemos que nos aparece cosas así : m32def, m48def, tn2313def, tn45def, etc... abramos
uno el que sea en este caso les pego una parte de lo que tiene el tn2313def aquí lo tienen:
;***************************************************************************
;* A P P L I C A T I O N N O T E F O R T H E A V R F A M I L Y
;* Number
:AVR000
;* File Name
:"tn2313def.inc"
;* Title
:Register/Bit Definitions for the ATtiny2313
;* Date
:03.06.17
;* Version
:1.00
;* Support E-mail :[email protected]
;* Target MCU
:ATtiny2313
;* DESCRIPTION
;* When including this file in the assembly program file, all I/O register names and I/O register bit names appearing in the data book can
be used.In addition, the two registers forming the data pointer Z have been assigned names ZL - ZH.
;* The Register names are represented by their hexadecimal address.
;* The Register Bit names are represented by their bit number (0-7).
;* Please observe the difference in using the bit names with instructions such as "sbr"/"cbr" (set/clear bit in register) and "sbrs"/"sbrc"
(skip if bit in register set/cleared). The following example illustrates this:
;* in r16,PORTB
;read PORTB latch
;* sbr r16,(1<<PB6)+(1<<PB5) ;set PB6 and PB5 (use masks, not bit#)
;* out PORTB,r16
;output to PORTB
;* in r16,TIFR
;read the Timer Interrupt Flag Register
;* sbrc r16,TOV0
;test the overflow flag (use bit#)
;* rjmp TOV0_is_set ;jump if set
;* ...
;otherwise do something else
;***************************************************************************
;***** Specify Device
.device ATtiny2313
;*****************************************************************************
; I/O Register Definitions
;*****************************************************************************
.equ SREG = 0x3F
.equ SPL = 0x3D
.equ OCR0B = 0x3C
.equ GIMSK = 0x3B
.equ EIFR = 0x3A
.equ GIFR = 0x3A ; for compatibility purpose
.equ TIMSK = 0x39
.equ TIFR = 0x38
.equ SPMCSR = 0x37
.equ OCR0A = 0x36
.equ MCUCR = 0x35
.equ MCUSR = 0x34
.equ TCCR0B = 0x33
.equ TCCR0 = 0x33 ; for compatibility purpose
.equ TCNT0 = 0x32
.equ OSCCAL = 0x31
.equ TCCR0A = 0x30
.equ TCCR1A = 0x2F
.equ TCCR1B = 0x2E
.equ TCNT1H = 0x2D
.equ TCNT1L = 0x2C
.equ OCR1AH = 0x2B
.equ OCR1AL = 0x2A
.equ OCR1BH = 0x29
.equ OCR1BL = 0x28
.equ CLKPR = 0x26
.equ ICR1H = 0x25
.equ ICR1L = 0x24
.equ GTCCR = 0x23
.equ SFIOR = 0x23 ; for compatibility purpose
.equ TCCR1C = 0x22
.equ WDTCR = 0x21
.equ PCMSK = 0x20
.equ EEAR = 0x1E ; for compatibility purpose
.equ EEARL = 0x1E
.equ EEDR = 0x1D
.equ EECR = 0x1C
.equ PORTA = 0x1B
.equ DDRA = 0x1A
.equ PINA = 0x19
.equ PORTB = 0x18
.equ DDRB = 0x17
.equ PINB = 0x16
.equ GPIOR2 = 0x15
.equ GPIOR1 = 0x14
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
.equ
GPIOR0 = 0x13
PORTD = 0x12
DDRD = 0x11
PIND = 0x10
USIDR = 0x0F
USISR = 0x0E
USICR = 0x0D
UDR = 0x0C
UCSRA = 0x0B
USR = 0x0B ; for compatibility purpose
UCSRB = 0x0A
UCR = 0x0A ; for compatibility purpose
UBRRL = 0x09
UBRR = 0x09 ; for compatibility purpose
ACSR = 0x08
UCSRC = 0x03
UBRRH = 0x02
DIDR = 0x01
Se alcanza a ver que son puras definiciones y pues así están todos en este caso buscamos la que
diga tn461def para el uC que voy a usar si tiene el Atmega8 usan la que dice mega8def y así.
Pero notamos que no esta el tn461def buscamos el uC mas parecido y pues es el Attiny2113
usamos este solo en unos caso va a haber que definir mas cosas por ejemplo este Attiny2113 no
tiene ADC y el Attiny461 si los tiene pues ya cuando los usemos vemos como le hacemos por
lo pronto no hay que preocuparnos entonces en lugar de todas esas declaraciones al inicio de le
programa ponemos
.include “tn2313def.inc”
Esto hará que todas las definiciones que tenemos en esa hoja queden en nuestro programa
cuando se este ensamblando y el ensamblador vea Sreg lo va a sustituir por el numero que
pusimos y no usamos mas memoria eso se hace a la hora de ensamblar.
Entonces tenemos algo que se ve como esto.
Ahora pues esto no hace nada incluso si se trata de ensamblar nos manda errores por que no
tiene nada este primer programa vamos a hacer que un led prenda y apague cada cierto tiempo
de hecho no se va a alcanzar a ver por que el uC lo va a hacer muy muy rápido.
El uC no sabe por donde queremos sacar el dato en esta caso hacer que se prenda o se apague el
led. Vamos a la hoja de datos y vemos tiene dos puertos de 8 bits pues que podemos hacer
sacamos todo el dato por un puerto en este caso voy a seleccionar el puerto B de alguna manera
tengo que decirle al uC que por el puerto B voy a sacar mi dato aquí es donde voy a usar mi
primera instrucción tengo que decirle al puerto B que sea salida para eso tengo que poner un
numero en el registro DDRB este numero es un 1 para que sea el bit 0 como salida pero no
puedo poner DDRB=1 tengo que cargárselo antes aun registro de propósito general para esto
vamos a hacer esto es lo que llevamos de el programación
.include “tn2313def.inc”
//definiciones
LDI R16,0x01
//carga un uno al registro 16
OUT DDRB,R16
//selecciona el bit0 del puerto b como salida
Bien ahora no falta decirle que se prenda y se apague cada X tiempo para eso volvemos a usar
la instrucción OUT pero en lugar de DDRB que dice si el puerto es entrada o salida ponemos
PORTB que dice cuanto va a valer el PORTB quedando
OUT PORTB,R16
//aqui saco el valor de el R16 por el puertoB
Bien ahora solo falta que se haga o para ver que si funciona entonces seria poner en un registro
un cero y usar la otra vez la instrucción out quedando de esta manera.
LDI R16,0x00
//uso de nuevo el R16 para que este un poco tiempo prendido
OUT PORTB,R6
//saco el cero que tiene el registro r16
Esto seria en si nuestro programa básico miren
.include “tn2313def.inc”
//definiciones
LDI R16,0x01
//carga un uno al registro 16
OUT DDRB,R16
//selecciona el bit0 del puerto b como salida
OUT PORTB,R16
//aqui saco el valor de el R16 por el puertoB
LDI R16,0x00
//uso de nuevo el R16 para que este un poco tiempo prendido
OUT PORTB,R6
//saco el cero que tiene el registro r16
Pero nuestro aparato no se puede decir que es inteligente por que queremos que lo haga por
siempre y si lo dejamos así lo va a hacer una vez y ya no va a hacer mas entonces hay que
encontrar una manera para que lo repita por siempre y para eso usamos la función RJMP que
brinca a una parte de el programa que queramos nosotros. El problema aquí es decidir a donde
regresar podríamos regresar a la primera linea la de LDI R16,0x01y quedaría bien pero pues en
cada nuevo ciclo declararíamos otra vez que el bit0 de el puerto B es salida entonces yo mejor
agrego una linea de que diga LDI R16,0x01 y después el RJMP quedando todo el programa
como:
.include “tn2313def.inc” //definiciones
LDI R16,0x01
//carga un uno al registro 16
OUT DDRB,R16
//selecciona el bit0 del puerto b como salida
INICIO:
OUT PORTB,R16
//aqui saco el valor de el R16 por el puertoB
LDI R16,0x00
//uso de nuevo el R16 para que este un poco tiempo prendido
OUT PORTB,R6
//saco el cero que tiene el registro r16
LDI R16,0x01
//cargo de nuevo un uno en el R16
RJMP INICIO
// salto a inicio
Después de RJMP pongo a donde quiero saltar puedo usar cualquier palabra o dirección de
memoria pero es mas fácil la palabra aquí tendríamos un led apagándose y prendiendo.
Solo falta compilar y correr el programa para esto podemos usar la tecla F7 o usar en la barra
de herramientas donde dice build darla “build” o “build and run” la diferencia es que build solo
lo compila y build and run lo compila y corre usemos build and run para ver que pasa ok
En al parte de los errores no debe de aparecer esto para decir que todo nuestro programa esta
bien. Quedamos que le ibamos a dar en build and run para simularlo entonces el programa ya
debe de estar corriendo esperando a que le digamos que ejecute la siguiente operacion debe de
estar algo asi.
Quiero que en el panel de salida seleccionemos el que dice PORTB lo podemos hacer mas
grande con el botón de + que tiene ahí o con seleccionarlo basta. Y donde quedamos que
estaban los archivos de el proyecto ya no están ahora hay una que dice Processor bien ahi dicen
varias cosas dice Program Counter, Stack Pointes ,....., Sreg y al final Registers hacemos mas
grande la de Registers.
Aprieten la tecla F10 para ir paso a paso en la ejecución de instrucciones o Alt+F5 vaya sola la
computadora e ligan lo que quieran y después hagan lo siguiente
Ok ya que hicieron eso necesito que se fijen en 4 cosas en el panel de salida de el uC abajo va a
salir DDRB, PINB y PORTB y vena como PORTB y PINB cambia a la hora de que pasamos
por la instrucción “OUT PORTB,R16” y ahora ne la parte de Processor quiero que vean como
el R16 cambia con las instrucciones “LDI R16,0x00” y LDI R16,0x01” y se pone con el
numero que decimos en el registro. Fíjense como la parte de hasta arriba el Program Counter va
incrementando de uno en uno hasta que llega a la instrucción RJMP y cambia a 0x0002 y si se
fijan el tan famoso Sreg nunca cambia esto quiere decir las instrucciones que estamos
ejecutando no lo afectan. Otra cosa importante a ver las instrucciones abran las instrucciones de
los Avr´s que bajaron antes y búsquenlas. Esto seria el primer programa. El siguiente es hacer
un contador que implica un poco mas de instrucciones.
Si tienen dudas sobre esto no duden en escribirme a mis dos correos [email protected] y
a [email protected] o dejen un comentario en www.mecatronicamexicana.blogspot.com
Esto es lo que se ve en el osciloscopio pero agregue unas instrucciones llamadas NOP para
alargar tiempo de encendido. No les posteo el otro programa por que no vale la pena.
Aquí la imagen
Les dejo también el link al video espero y les guste perdón por la cámara ya esta mal y no
enfoca bien prometo comprar una que sirva bien lo mas rápido posible.
Vean el video de youtube de este programa.
http://www.youtube.com/watch?v=39gZ2sCYfFU
Programa numero 2
Para este segundo programa omitiré todo lo que ya vimos de el primer programa. Solo que
debemos de crear un nuevo proyecto. Abordemos el problema es un Contador espero que
sepamos todos que es un contador esto quiere decir que empieza en cero y va contando hasta
que llena los 8 bits y se hace 255 aquí en este punto veremos algo interesante con el Sreg aun
no lo usaremos pero veremos algo interesante pues lo principal de nuevo usaremos el puerto b
como nuestra salida entonces lo principal sera
.include “tn2313def.inc” //definiciones
LDI R16,0xff
//carga un 255 al registro 16
OUT DDRB,R16
//selecciona todo el puerto b como salida
Aquí quiero que aprendan esto si el registro DDRB tiene 0 es entrada si tiene unos es salida y si
quiero los primeros cuatro como entradas pues debo de poner los primeros cuatro en 0 y los
otros cuatro como salidas los debo de poner en uno seria este ejemplo:
De ahora en adelante lo que esta en cursiva y rojo es un ejemplo y no es parte de el programa
que estamos haciendo
include “tn2313def.inc” //definiciones
LDI R16,0xf0
//carga un 240 al registro 16
OUT DDRB,R16
//selecciona la parte alta del puerto b como salida y la baja como entrada
Espero y se allá entendido bien lo siguiente aquí seria hacer que cuente y para eso buscamos en
nuestra hoja de instrucciones y encontramos la instrucción INC que incremente un registro en 1
entonces pues si ya tengo un registro el R16 aquí vale decir que puedo usar cualquier registro
bueno no cualquiera en las hojas de instrucciones dice que registros acepta cada instrucción
entonces le agregaríamos a nuestro programa.
INC R16
// incrementa el registro 16 en 1
OUT PORTB,R16
//pone en el puerto b el valor de el R16
cabe mencionar que el R16 valía 255 antes de ejecutar INC R16 cuando se ejecuta la
instrucción cambia a 0 y aquí viene lo interesante noten que en el Sreg a la hora de compilarlo
y correrlo y se ejecuta el primer INC R16 la bandera de cero(ZF) pasa a ser uno que significa
que la ultima operación resulto ser cero y que cuando es mayor de 128 están activas las
banderas de signo y de negativo aunque esto no nos interesa ahorita. Lo único que nos faltaría
en el programa seria hacer que regrese y pues para eso tenemos la instrucción que ya
aprendimos de RJMP pero pues donde se debe de poner a donde regresa pues se pone a INC
R16 para que regrese e incremente en 1 y vuelva a sacar el dato de el puerto. Quedándonos
todo el programa como se muestra a continuación.
.include "tn2313def.inc" //definiciones
LDI R16,0xff
//carga un uno al registro 16
OUT DDRB,R16
//selecciona el puerto b como salida
REGRESO: INC R16
//incremento R16 en uno
OUT PORTB,R16
NOP
//esto es una nop no importa no sirve de nada ahorita
NOP
//nada mas insertan tiempo muerto y gastan memoria
RJMP REGRESO
Si lo alcanzan a ver este programa es mas pequeño que el otro por que el otro había que poner
un registro a cero y aqui solo se incremente no necesitamos 2 outs.
No les pongo imagen de osciloscopio por que no puedo ver todas las señales pero pues les dejo
una foto de la protoboard
Como se ve es muy simple solo 8 leds y hacer un contador de 8bits con integrados usas muchos
mínimo 2 y este puedes hacer muchas mas cosas los leds no tiene resistencia por que son leds
que aguantan los 5 volts si tiene leds que aguanten menos voltaje si pónganles una resistencia
mínimo de 100 ohmsy máximo de 330 de ahí en mas cualquiera esta bien. Y aquí el video de
youtube. http://www.youtube.com/watch?v=wl3x5gncOPU
Sobre el video que digo que el bit mas significativo no prende tendré que investigar voy a ver
si es internamente le uC por que el programa esta bien luego alguna vez me paso que estaba
programando un Atmega32 por Isp y cuando programas por Isp un puerto de Atmega32 se
deshabilita y pensaba que no servia el puerto y leyendo encontré que no pues hay que
deshabilitar un fusible, puede estar pasando lo mismo aquí. Otra cosa que me pareció
interesante sin tener que ver con los uC se fijan como se ve morado y como rayitas eso es luz
infrarroja que detecta la cámara y el filtro no la elimina bien supongo que las rayas por que esta
espaciado es el tiempo en encendido y apagado nunca lo había notado aquí podemos aprender
de todo.
Sobre el error ya vi el error ese pin es el reset y como les dije es cosa de deshabilitar el fusible
y ya este tercer programa vamos a ver como programo físicamente el uC.
Tercer programa
Este programa va a ser un poco mas difícil por que ya va llevar toma de decisiones del uC con
el Sreg y las banderas. Va a llevar un salto y varios retardos de tiempo se podría hacer con el
Stack Pointer y la memoria Ram pero eso prefiero dejarlo para la siguiente parte de el tutorial.
Abordemos el problema pues este consiste básicamente en hacer un contador ascendente y
cuando llegue a 255 se vuelve descendente. Otro punto importante aquí si vamos a usar los 8
bits ya cheque cual era el problema como les dije un fusible con desactivarlo funciona bien y
cuando vean como lo programa pues ya con eso quedara entendido creo yo pues como siempre
empezamos igual la librería de definiciones y declarar al puerto B como salida sale.
.include "tn2313def.inc" //definiciones
LDI R16,0xff
//carga un uno al registro 16
OUT DDRB,R16
//selecciona el puerto b como salida
Después de esto queremos que se incremente el R16 se detenga un tiempo para que alcanzamos
a ver como cuenta entonces tendríamos algo así
INC R16
//incremento R16
LDI R30,0x00
//cargo 0 en r30
LDI R31,0xFF
//cargo 255 en R31
Aquí tenemos LDI R30,0x00 y LDI R31,0xFF esta operación ya la conocemos pero pues mas
adelante nos va a servir para hacer comparaciones recuerdan que nuestro programa va a contar
de 0, 1, 2, 3, ........, 254, 255 y después de 255, 254, 253, 252, ........, 1, 0 esos nos van a servir
para hacer eso saber cuando esta en 255 y cuando en cero.
MAS:
INC R16
//muy fácil incremento R16
OUT PORTB,R16
//saco R16 por el puerto B
RJMP RETARDO
//salto a retardo pero que hay en retardo
PRINCIPAL:CP R16,R31
//esto hace R16-R31 abajo lo explico
BREQ MENOS
//dependiendo de las banderas salta a menos
RJMP MAS
//salta a MAS que es la parte de hasta arriba de este código
Pues bueno aquí tenemos dos instrucciones nuevas CP R16,R31 y BREQ MENOS.
CP es de comparación esta hace una resta entre R16 menos R31 sin alterar el contenido de
ningún registro lo único que nos modifica son las famosas banderas o el SREG explico solo las
banderas que nos interesan
Bandera de Cero (ZF) esta se pone a uno si R16 y R31 son iguales si no es cero.
Bandera de Carry (CF)esta se pone a uno solo si R31 es mayor que R16
Aquí la bandera que vamos a usar es la de cero, no nos interesa saber si uno es mayor o menor
que otro solo si son iguales el uno a otro sale.
BREQ (Branch if equal) checa la bandera de cero si es uno salta a donde dice en nuestro
programa. Esto quiere decir que cuando R16 y R31 son iguales CP pone la bandera de cero a
uno y BREQ checa la bandera y si es uno salta a menos en el otro caso si no son iguales no
salta y continua su ejecución normal. Si recuerdan R31 contiene 0xFF esto quiere decir que
cuando llega a 255 es cuando se hace cero este ciclo es el que cuenta ascendente mente y
cuando llega a 255 salta a menos que es el que cuenta descendente mente y pues retardo se los
explico ahorita un poco mas adelante.
Aquí otra parte de el código
MENOS:
DEC R16
//no hay mucho que decir decremento en uno R16
OUT PORTB,R16
RJMP RETARDO1
//Salta a Retardo1 ahorita vemos que es retardo1
PRINCIPAL1:CP R16,R30
//comparo R16 con R30
BREQ MAS
//dependiendo de las banderas salta a mas
RJMP MENOS
//Salta a menos
Pues primero voy a empezar a omitir la partes que ya vimos mas bien no las voy a explicar.
Aquí tenemos una nueva instrucción DEC es muy fácil es como INC pero en lugar de sumar
uno resta uno. Aquí se fijan tengo RJMP RETARDO1 es el mismo código que RETARDO sin
el 1 pero como el Avr no recuerda en donde estaba por eso dos rutinas de retardo si usáramos la
función CALL y el Stack Pointer (SP) no necesitaremos dos pero eso sera para la siguiente
parte de el tutorial. Y pues para lo demas seria los mismo que el otro Resto R16-R30 si el
resultado es cero salta a MAS si no salta a menos.
Ahora si el tan famoso retardo.
RETARDO:LDI R25,0x00
REGRESO:INC R25
CP R25,R31
//aquí comparo R25 con R31 deben de ser 255
BREQ ACABO
//si son iguales se va acabo y de acabo salta a
RJMP REGRESO
//principal que es la parte que cuenta hacia arriba
ACABO:
RJMP PRINCIPAL
//si no a acabado salta a regreso y sigue contando
RETARDO1:LDI R25,0x00
REGRESO1:INC R25
CP R25,R31
BREQ ACABO1
// es lo mismo pero para la parte de cuenta hacia
RJMP REGRESO1
//abajo espero y lo entiendan
ACABO1: RJMP PRINCIPAL1
Espero y se entienda es muy parecido al contador aquí si yo quiero mas tiempo puedo agregar
NOP entre INC R25 y BREQ ACABO aquí el ejemplo:
REGRESO1:INC R25
NOP
//Inserto tiempo muerto
NOP
//Inserto tiempo muerto
CP R25,R31
BREQ ACABO1
// es lo mismo pero para la parte de cuenta hacia
RJMP REGRESO1
//abajo espero y lo entiendan
ACABO1: RJMP PRINCIPAL1
Para aproximar el tiempo de retardo aquí hay que ver dos cosas el lazo o el ciclo que se hace
que vendría siendo todo lo que esta entre INC R y RJMP REGRESO vemos las instrucciones
que seria en este caso 6 y vemos cuantos ciclos de reloj toma cada una aquí todas toman una
menos RJMP que lleva dos y BREQ cuando salta también son dos esa la podemos agregar al
final por que solo salta una vez. Y pues se hacen 255 veces esas siete por que cuenta hasta 255
que serian 1785 instrucciones Y debemos agregarle dos ciclos de reloj por el RJMP
REGRESO, RJMP PRINCIPAL1 y el ciclo que nos faltaba serian 5 ciclos mas entonces
tomamos 1790 ciclos. Suponiendo que nuestro uC corre a 8MHZ eso hace que haga 8 millones
de ciclos por segundo entonces hacemos la simple regla de tres 8 millones es a un segundo
como 1790 es a cuanto que serian 0.00022375 s que es un retardo muy pequeño lo que
podemos hacer es añadir mas NOP o podemos poner un ciclo dentro de esos lo cual nos daría
un retardo mucho mas grande. Aquí les dejo tal cual el programa que yo le puse al uC de el
video.
.include "tn2313def.inc" //definiciones
LDI R16,0xff
//carga un uno al registro 16
OUT DDRB,R16
//selecciona el puerto b como salida
INC R16
LDI R30,0x00
LDI R31,0xFF
MAS: INC R16
OUT PORTB,R16
RJMP RETARDO
PRINCIPAL:CP R16,R31
BREQ MENOS
RJMP MAS
MENOS:
DEC R16
OUT PORTB,R16
RJMP RETARDO1
PRINCIPAL1:CP R16,R30
BREQ MAS
RJMP MENOS
RETARDO:LDI R25,0x00
REGRESO:INC R25
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
CP R25,R31
BREQ ACABO
RJMP REGRESO
ACABO:
RJMP PRINCIPAL
RETARDO1:LDI R25,0x00
REGRESO1:INC R25
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
CP R25,R31
BREQ ACABO1
RJMP REGRESO1
ACABO1: RJMP PRINCIPAL1
Como ven es mucho mas grande por las NOP y tiene un retardo no muy grande de 0.00047875
s o 4.7875 mili segundos.
Les dejo el diagrama de conexión eléctrico para estos últimos dos programas si conocen algún
programa para hacerlos mas bonitos díganme por que no me gusto mucho como quedo si no
pues los haré a mano y los escaneo.
Vean los videos de youtube el de como programar con Avr Studio y el de este tercer programa
funcionando aquí están los links. O visiten www.mecatronciamexicana.blogspot.com
Programar http://www.youtube.com/watch?v=p58QXXSYgXc
Tercer Programa http://www.youtube.com/watch?v=FaVF6jDs74o
Cabe Recordar aqui que si quiero usar el puerto a como salida o sacar mi dato por el puerto a
en lugar de usar DDRB pongo DDRA en todo caso sera la letra de el puerto donde esta la X
DDRX, PINX y PORTX espero y esto les sirva.
Espero y les allá gustado este tutorial es para ustedes para aprender en la siguiente parte de el
tutorial vamos a ver como se usan las entradas se me ocurre un contador cada vez que yo apreté
un botón , como se usa la Ram y el satck pointer y como leer un dato analógico desde los ADC
internos que trae el micro. Manden sus dudas quejas sugerencias comentarios a
[email protected] y a [email protected] o dejen
www.mecatronicamexicana.blogspot.com si les gusto o no el tutorial.
Muchas gracias por tomarse el tiempo para leer esto suerte.
LUIS ANTONIO MÉNDEZ SOTO
www.mecatronicamexicana.blogspot.com
"AVR®" and "AVR is a registered trademark of Atmel Corporation".
un
comentario
en
Descargar