Tuesday, February 14, 2017

Programación del microatmega328p en ensamblador

Como cargar programas de Atmel Studio 7 a Arduino UNO y ejemplo en ensamblador

Este instructivo es útil cuando necesitamos pdesarrollar porgramas que utilizan caracteristicas mas avanzadas y poder programarlo en lenguaje ensamblador. 
Se integra las capacidades de programacion mediante USB de nuestra tarjeta. Para hacer eso utilizaremos "avrdude.exe" y la opción "external tools" de Atmel Studio

Primero debemos instalar 

Paso 1: Configurando Atmel Studio

Ahora conecta tu Arduino UNO a tu PC y espera a que se instalen los controladores.Cuando termine, toma nota de cual puerto está utilizando. Para mi caso es el COM4.
Ahora:
  1. Una vez abierto Atmel Studio de click en el menú "toos/external tools" y se abrirá un cuadro de dialogo donde se nos pedirá llenar algunos parámetros.
  2. En title escribir "Send to Arduino UNO" o el nombre que quieras.
  3. En command escribir "C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe"
  4. En arguments escribir "   -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -p atmega328p -c arduino -P COM5 -b 115200 -U flash:w:"$(ProjectDir)Debug\$(TargetName).hex":i   " En este caso necesitas reemplazar el puerto COM por el que estes empleando.

Programación en lenguaje ensamblador

Lenguaje ensamblador

El lenguaje ensamblador, o assembler (en inglés assembly language y la abreviación asm), es un lenguaje de programación de bajo nivel. Consiste en un conjunto de mnemónicos que representan instrucciones básicas para los computadoresmicroprocesadoresmicrocontroladores y otros circuitos integrados programables. Implementa una representación simbólica de los códigos de máquina binarios y otras constantes necesarias para programar una arquitectura de procesador y constituye la representación más directa del código máquina específico para cada arquitectura legible por un programador. Cada arquitectura de procesador tiene su propio lenguaje ensamblador que usualmente es definida por el fabricante de hardware, y está basada en los mnemónicos que simbolizan los pasos de procesamiento (las instrucciones), los registros del procesador, las posiciones de memoria y otras características del lenguaje. Un lenguaje ensamblador es por lo tanto específico de cierta arquitectura de computador física (o virtual). Esto está en contraste con la mayoría de los lenguajes de programación de alto nivel, que idealmente son portátiles.

.DEVICE 
La directiva device permite al usuario decir al Ensamblador que dispositivo y sobre que código se va a ejecutar.
Syntax: .
        DEVICE atmega328p

.ORG 
La directiva org  es usada para indicar el comienzo de la dirección, puede ser empleada tanto para código como para dato.
Syntax: 
       .ORG  exprasión

Ejemplo
       .ORG 0x00


.INCLUDE
La directiva include le dice al lenguaje ensambladro AVR que agregue el contenido de un archivo a nuestro programa.

Ejemplo
      include "m328pdef.inc"

.EQU

Ésta es utilizada para dar un valor constante a una dirección fija.
Syntax: 
            .EQU etiqueta = exprasión


El valor de la expresión puede ser en hexadecimal, ejemplo:

             .EQU DATO1 = 0x39    ;numero en hexadecimal

El valor de la expresión puede ser en binario, ejemplo:

             .EQU DATO2 = 0b00110101    ;Binario (35 en hexadecimal)

El valor de la expresión puede ser en decimal, ejemplo:

             .EQU DATO3 = 39    ;numero decimal  (27 en  hexadecimal)

El valor de la expresión puede ser en caracter, ejemplo:

             .EQU DATO4 = '2'     ;caracter ASCII


Puertos de entrada salida (configuraciones)


Ejemplos de código en ensamblador  

Cambiar de estado una salida cada 500 milisegudos (la librería de los delay viene mas abajo)


;
; blink_led.asm
;
; Created: 15/02/2017 08:56:19 a. m.
; Author : NoeAdrian
;

.include "m328pdef.inc"
.include "delay.inc"              ;Librery a de retardos
.device atmega328p
;---------Configuración  de puertos ---------------
.ORG   0x00       ;Comienzo del codigo en la posición 0         
                                  ;inicializa el SP
       LDI R16, HIGH(RAMEND)      ; Carga el SPH
       OUT SPH, R16
       LDI R16, LOW(RAMEND)       ;Carga el SPL
       OUT SPL, R16

       LDI R16, 0xFF            ;R16 = 255 o 0b11111111
       OUT DDRB,R16             ;Pone como salida el Puerto B
       NOP                      ;Espera un ciclo de reloj
       LDI R16, 0b00100000      ;R16 = 0b00100000  
       OUT PORTB, R16           ;Enciende el led
      

start:
       LDI  R16, 0b00100000     ;R16 = 0b00100000  
       OUT  PORTB, R16          ; enciende el led
       call delay_500ms         ;Retado de 500 milisegundos
       LDI  R16, 0b00000000     ;R16 = 0b0000000
       OUT  PORTB, R16          ; enciende el led
       call delay_500ms         ;Retado de 500 milisegundos

    jmp start




Instrucciones empleadas

      ;Valor
LDI    Rd, K     ;Carga el registro Rd con el valor  K
IN     Rd, PINn     ;Cargael valor de un registro como PINn a Rd
OUT    PORTn, Rd     ;Carga Rd a PORTn. Es empleada para mandar algún valor a un puerto
JMP    k         ;Salta a la dirección k. En este caso la etiqueta start


Cambiar de estado una salida PD0 mediante cada que se pone en alto la entrada PB0


.include "m328pdef.inc"
.include "delay.inc"
.device atmega328p
;---------Configuración  de puertos ---------------
.ORG   0x00                ;Comienzo del código en la posición 0         
                                  ; Inicializa el SP
       LDI R16, HIGH(RAMEND)      ; Carga el SPH
       OUT SPH, R16
       LDI R16, LOW(RAMEND)       ;Carga el SPL
       OUT SPL, R16

       LDI R16, 0x00              ;R16 = 0
       OUT    DDRB,R16            ;Pone como entrada el Puerto B
       NOP                               ;Espera un ciclo de reloj
      
       LDI R16, 0xFF              ;R16 = 0x0FF
       OUT    DDRD,R16            ;Pone como salida el Puerto B
       NOP                        ;Espera un ciclo de reloj
       LDI    R16,0xFF            ;Pone resistencia de pull up     
       OUT    PORTB, R16          ;Pone en cero el puerto b
      
      

start:
       sbis   PINB,0              ;Salta la siguiente linea si PB0 es 1
       jmp    continuar1          ;salta a continuar1
            call   delay_100ms         ;espera 100 milisegundos para evitar rebotes
            call   delay_100ms         ;espera 100 milisegundos para evitar rebotes
            call   delay_100ms         ;espera 100 milisegundos para evitar rebotes
            sbis   PIND,0              ;Salta la siguiente linea si PD0 es 1
            jmp    escero              ;Salta a escero
                 ldi    r17,0b00000000      ;r17=0
                 out    PORTD,r17           ;PORTD = r17
                 jmp    continuar1          ;Salta a continuar1
      escero:
            ldi          r17,0b00000001      ;r17=1
            out          PORTD,r17           ;PORTD = r17
continuar1:
    jmp start

Como crear una subrutina de retardo

Para este caso la subrutina está en otro archivo el cual nombraremos delay.inc

  1. Damos click derecho en el nombre del proyecto 
  2. Click en Add/new item...
  3. Seleccionamos include file y nombramos el archivo
  4. Una vez creada hay que añadir la librería con  .include
;------------------------- subrutina de retardo delay_10ms --------------------------------- 


       .ORG 0x300          ;coloca la rutina de retardo en la dirección 0x300


dealy_10ms:
       ldi    r17,99       ; 1 ciclo
repetir1:
       ldi    r18,199      ; 1 ciclo
repetir:
       nop    ; 1 ciclo
       nop    ; 1 ciclo
       nop    ; 1 ciclo
       nop    ; 1 ciclo
       nop    ; 1 ciclo
       dec    r18    ; 1 ciclo
       brne repetir  ; 2 ciclos
       dec    r17    ; 1 ciclo
       brne repetir1 ; 2 ciclos

       ret           ; 5 ciclo  

Instrucciones empleadas



      ;Valor
LDI    Rd, K     ;Carga el registro Rd con el valor  K.
NOP              ;No hace ninguna operación.
DEC    Rd        ;Carga Rd = Rd-1.
BRNE   k         ;Salta a la dirección k +1. En si el valor no es cero o z=0.
RET              ;regresa a la dirección donde fue llamada + 1.


¿Cómo se calculó?

Bueno en primer lugar se utilizó una frecuencia de trabajo de 16 MHz por lo que 

(1/(16x10^6))(1+1+100(200(8))+4))=0.01 seg = 10 ms
se repite primero 100 veces por 200 veces 8 ciclos que son los nop, dec y brne.

Si se utiliza otra frecuencia de trabajo para el micro se deberá hacer una subrutina parecida pero adecuada a la frecuencia de trabajo.

Con esto podemos realizar una nueva rutina de 100ms repitiendo 10 veces la subrutina de 10ms y de la misma manera podemos crear mas. 

Ejemplo


      
/*
 * delay.inc
 *
 *  Created: 15/02/2017 12:17:22 p. m.
 *   Author: NoeAdrian
 */

;----------------------Esta es la subrutina de retardo dalay_500ms  -------------------------

       .ORG 0x300          ;coloca la rutina de retardo en la dirección 0x300

delay_500ms:
  call delay_100ms
  call delay_100ms
  call delay_100ms
  call delay_100ms
  call delay_100ms
  ret
;----------------------Esta es la subrutina de retardo delay_100ms  -------------------------

      
delay_100ms:
       call delay_10ms
       call delay_10ms
       call delay_10ms
       call delay_10ms
       call delay_10ms
       call delay_10ms
       call delay_10ms
       call delay_10ms
       call delay_10ms
       call delay_10ms
       ret

      
;----------------------Esta es la subrutina de retardo delay_10ms  -------------------------

      
delay_10ms:
       ldi    r17,99 ; 1 ciclo
repetir1:
ldi    r18,199      ; 1 ciclo
repetir:
       nop
       nop
       nop
       nop
       nop
       dec    r18                 ; 1 ciclo
       brne repetir ; 2 ciclos
       dec    r17                 ; 1 ciclo
       brne repetir1 ; 2 ciclos

       ret

Practica 1

Realizar el un programa que mediante un botón conectado al PUERTO B incremente el valor de la salida del PUERTO D en 1, mostrando el valor con un display 7SEG-BCD segmentos  que vaya de 0 a F.
El código será simulado en Proteus.

Componentes

  1. 7SEG-BCD
  2. CAPACITOR 22pF
  3. ATMEGA328P
  4. BUTTON
  5. CRISTAL
  6. RES


Configuración del microcontrolador (revisar su configuración, que corresponda con la imagen).



Al terminar el la practica se deberá entregar un reporte por cada persona, será hecho en computadora y contendrá:
  1. Portada
    1. Nombre de la institución 
    2. Carrera
    3. Semestre
    4. Numero de la practica, unjidad y nombre de l a práctica
    5. Nombre del Alumno
    6. Nombre del profesor
    7. Lugar y fecha
  2. Introducción
  3. Objetivos
  4. Desarrollo
    1. Código del programa con comentarios.
    2. Fotografías de los resultados de la simulación
  5. Conclusión personal
Ayuda 
ldi    r17,16                      ;Se debe poner este registro a 16 para compararlo con el valor del                            :puerto D
inc    r18                 ;r18 = r18+1
cp     r18,r17             ;compara r18 con r17
breq   mayora15            ;si es igual salta a mayora15