Este documento describe cómo programar un microcontrolador ATmega328p en lenguaje ensamblador. Explica cómo cargar programas desde Atmel Studio a un Arduino UNO y provee ejemplos básicos en ensamblador, incluyendo cómo configurar puertos, usar retardos y cambiar el estado de salidas. También incluye cómo crear subrutinas de retardo y una práctica propuesta para incrementar el valor mostrado en un display 7 segmentos al presionar un botón.
1. Programación delmicroatmega328p en ensamblador.Comocargar
programas en proteusde Atmel Studio 7 a Arduino UNO y ejemplo
en ensamblador
Este instructivoesútil cuandonecesitamos desarrollarprogramasque utilizancaracterísticasmás
avanzadasy poderprogramarloenlenguaje ensamblador.
Se integralascapacidadesde programaciónmediante USBde nuestratarjeta.Para hacereso
utilizaremos"avrdude.exe"ylaopción"external tools"de AtmelStudio
Primerodebemosinstalar
ArduinoIDE
Atmel Studio
Paso 1: ConfigurandoAtmel Studio
Ahoraconecta tu ArduinoUNOa tu PC y esperaa que se instalenloscontroladores. Cuando
termine,toma nota de cual puerto está utilizando. Para mi caso esel COM4.
Ahora:
1. Una vez abiertoAtmel Studiode clickenel menú"toos/externaltools"yse abrirá un
cuadro de dialogodonde se nospedirállenaralgunosparámetros.
2. En title escribir"Sendto ArduinoUNO"o el nombre que quieras.
3. En command escribir"C:ProgramFiles
(x86)Arduinohardwaretoolsavrbinavrdude.exe"
4. En arguments escribir" -C"C:ProgramFiles
(x86)Arduinohardwaretoolsavretcavrdude.conf"-patmega328p -carduino -P
COM5 -b 115200 -U flash:w:"$(ProjectDir)Debug$(TargetName).hex":i " En este caso
necesitasreemplazarel puertoCOMpor el que estésempleando.
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 computadores, microprocesadores, microcontroladores 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
legibleporunprogramador.Cada arquitecturade procesadortiene supropiolenguaje 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
posicionesdememoriayotrascaracterísticasdel lenguaje.Unlenguajeensambladoresporlotanto
2. 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 directivadevice permite al usuariodeciral Ensambladorque dispositivoysobre que código se
va a ejecutar.
Syntax:
DEVICEatmega328p
.ORG
La directivaorg es usadapara indicarel comienzode ladirección,puede serempleadatantopara
códigocomo para dato.
Syntax:
.ORG exprasión
Ejemplo
.ORG 0x00
.INCLUDE
La directivainclude le dice al lenguaje ensambladro AVRque agregue el contenidode unarchivoa
nuestroprograma.
Ejemplo
include "m328pdef.inc"
.EQU
Ésta es utilizadaparadar unvalorconstante a una direcciónfija.
Syntax:
.EQU etiqueta=exprasión
El valorde la expresiónpuede ser enhexadecimal,ejemplo:
.EQU DATO1 = 0x39 ;numeroenhexadecimal
El valorde la expresiónpuede seren binario,ejemplo:
.EQU DATO2 = 0b00110101 ;Binario(35 en hexadecimal)
El valorde la expresiónpuede seren decimal,ejemplo:
.EQU DATO3 = 39 ;numerodecimal (27en hexadecimal)
3. El valorde la expresiónpuede seren carácter,ejemplo:
.EQU DATO4 = '2' ;carácter ASCII
Puertosde entrada salida (configuraciones)
Ejemplosde código en ensamblador
Cambiar de estadouna salidacada 500 milisegundos(lalibreríade los delayviene más abajo)
;
; blink_led.asm
;
; Created: 15/02/2017 08:56:19 a. m.
; Author : NoeAdrian
;
.include "m328pdef.inc"
.include "delay.inc" ;Library a de retardos
.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
4. 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
Instruccionesempleadas
;K Valor
LDI Rd, K ;Carga el registro Rd con el valor K
IN Rd, PINn ;Carga el 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
5. Cambiar de estadouna salidaPD0 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 línea 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 línea si PD0
es 1
jmp escero ;Salta a escero
6. 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 subrutinade retardo
Para este caso lasubrutinaestáenotro archivoel cual nombraremosdelay.inc
1. Damos clickderechoenel nombre del proyecto
2. ClickenAdd/new ítem...
3. Seleccionamosincludefile ynombramosel archivo
4. Una vez creadahay que añadirla libreríacon .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
7. dec r17 ; 1 ciclo
brne repetir1 ; 2 ciclos
ret ; 5 ciclo
Instruccionesempleadas
;K 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ómose calculó?
Buenoenprimerlugarse utilizóunafrecuenciade trabajode 16 MHz por loque
(1/(16x10^6))(1+1+100(200(8))+4))=0.01 seg= 10 ms
Se repite primero100 vecespor 200 veces8 ciclosque sonlosnop,dec y brne.
Si se utilizaotrafrecuenciade trabajoparael micro se deberáhaceruna subrutinaparecidapero
adecuadaa la frecuenciade trabajo.
Con estopodemosrealizar una nueva rutina de 100ms repitiendo10 vecesla subrutina de 10ms
y de la misma manera podemoscrear más.
8. 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
9. 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
Realizarel unprograma que mediante unbotónconectadoal PUERTO B incremente el valorde la
salidadel PUERTO D en1, mostrandoel valorcon undisplay7SEG-BCDsegmentos que vayade 0 a
F.
El códigoserásimuladoenProteus.
Componentes
1. 7SEG-BCD
2. CAPACITOR22pF
3. ATMEGA328P
4. BUTTON
5. CRISTAL
6. RES
11. Al terminarenla práctica se deberáentregarunreporte porcada persona,seráhechoen
computadoray contendrá:
1. Portada
1. Nombre de lainstitución
2. Carrera
3. Semestre
4. Númerode lapráctica, unidadynombre de la práctica
5. Nombre del Alumno
6. Nombre del profesor
7. Lugar y fecha
2. Introducción
3. Objetivos
4. Desarrollo
1. Códigodel programacon comentarios.
2. Fotografíasde los resultadosde lasimulación
12. 5. Conclusiónpersonal
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