domingo, 16 de marzo de 2014

MUESTREO DE SEÑALES CON MATLAB



                     En el siguiente programa realizado en conjunto con MATLAB presentare una forma sencilla de muestreo de señales, en esta ocasión para posteriormente presentar un programa realizado igualmente en MATLAB del control de las articulaciones de un robot diseñado en MATLAB con ayuda del ADC, claro sera un ejemplo demostrativo por lo que el diseño del robot no sera del todo bueno pero es una forma de mostrar el uso del programa.

                    Es importante aclarar que el software MATLAB no es recomendable para muestreo de señales en tiempo real debido a sus procesamiento de datos, este programa tiene la finalidad únicamente de proporcionar una manera de obtener datos mediante este software para poder utilizarlo posteriormente en usos prácticos.



DESARROLLO:

                          Comenzaremos explicando el programa realizado para el microcontrolador AVR y en seguida el código en MATLAB.                    



MICROCONTROLADOR:  
                           Para la ejecución del programa se utilizo el software VIRTUAL SERIAL PORT DRIVER el cual crea puertos seriales virtuales, se mostrara al final una imagen.
                          El código en sí es muy sencillo consta de tres partes principales, las cuales se describirán a continuación:

ISR(USART_RX_vect):

                          Realiza la recepción de los datos, únicamente lee el dato adquirido y asigna el valor de 1 a la variable habilitar, esto para realizar el envió de datos incluido en la función enviar.


ENVIAR:

                        Esta función realiza el envió de los datos adquiridos por el modulo ADC en especifico el ADC0, para esto, se envían datos cada vez que la variable habilitar es igual a uno, una vez leído el dato se pregunta si se recibió el carácter 'x' de ser así lee el valor de la señal  y la procesa para enviar el valor leído en unidades, decenas y centenas en su correspondiente carácter en ASCII para que MATLAB pueda interpretar los datos y manipularlos, ademas se envía un byte el cual es el valor 0x0A indicando el termino de la cadena.
                            Cabe aclarar que esta función deshabilita la interrupción global al inicio para evitar que se dispare la interrupción mientras se envían los datos, al finalizar el envió se vuelve a habilitar la interrupción global y se asigna a la variable habilitar el valor cero para que únicamente se ejecute la función cuando suceda una interrupción.
                   

MAIN:

                               Realiza la declaración de las funciones a utilizar y las inicializa. En esta ocasión el baudrate del USART sera de 19200 para que el muestreo sea rápido.

WHILE(1):
                             
                               Envía los datos cada vez que surge una interrupción.

DESCONCATENAR(unsigned char dato):


                              Realiza la asignación del valor correspondiente de las unidades, decenas y centenas en su correspondiente carácter ASCII para ser tratados por el software MATLAB.




MATLAB:

                                El código en MATLAB realiza lo siguiente:


  1. Cierra y limpia para que no haya ningún conflicto en la ejecución del programa.
  2. Declara las variables a usar y designa los datos a capturar siendo el máximo de 2001, donde el ultimo es el carácter 0x0A que es un salto de linea.
  3. Configuración del puerto serial.
  4. Envió de carácter que permite leer los datos.
  5. Recepción de datos.
  6. Tratamiento de los datos adquiridos para poder manipularlos.
  7. Presentación en una gráfica los datos adquiridos








                  


NOTA:
             
                          Alguna duda o aclaración puede ingresarla en los comentarios. Dejo al final los links para que pueda descargar los programas.


PROGRAMAS:

MICROCONTROLADOR:


/*
 * MUESTREO_MATLAB_2.c
 *
 * Created: 16/03/2014 11:44:53
 *  Author: TERRAFORMARS
 */ 


#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 8000000UL // XTAL de 8 MHz
#endif
#include "InitADC.h"
#include "UARTAiNit.h"
#include <util/delay.h>
#include <avr/interrupt.h>

#define setbit(sfr,bit) (_SFR_BYTE(sfr)|=(_BV(bit)))
#define clearbit(sfr,bit) (_SFR_BYTE(sfr)&=~(_BV(bit)))
#define bittoggle(sfr,bit)(_SFR_BYTE(sfr)^=_BV(bit))

unsigned char i,n,valor[3]={0},envio[4]={0},recibido,unidad,habilitar=0;
int j;
unsigned char desconcatenar(unsigned char dato);

ISR (USART_RX_vect){
recibido=ReceiveUART0();

if (recibido=='x')
{
habilitar=1;

}

}

void enviar(){

if (habilitar==1)
{
cli();
for (j=0;j<500;j++)
{

n=convADC();
valor[0]=n/100;
valor[1]=(n-100*valor[0])/10;
valor[2]=n-100*valor[0]-10*valor[1];
for (i=0;i<3;i++)
{
envio[i]=desconcatenar(valor[i]);
}
envio[3]=0;
for (i=0;i<4;i++)
{
TransmiteUART0(envio[i]);
}
}
envio[3]=10;
TransmiteUART0(envio[3]);
habilitar=0;
sei();
}

}
int main(void)
{
canalADC(0);
initADC(2,1,5);

initializeUART0(19200,0,8,2,2);
setbit(UCSR0B,RXCIE0);
sei();

    while(1)
    {
        //TODO:: Please write your application code
enviar();
    }
}


unsigned char desconcatenar(unsigned char dato){

switch(dato){

case 0:
unidad='0';
break;
case 1:
unidad='1';
break;
case 2:
unidad='2';
break;
case 3:
unidad='3';
break;
case 4:
unidad='4';
break;
case 5:
unidad='5';
break;
case 6:
unidad='6';
break;
case 7:
unidad='7';
break;
case 8:
unidad='8';
break;
case 9:
unidad='9';
break;
}
return unidad;
}


MATLAB

close all
clear all
clc
n=2001;
n2=(n-1)/4;
temp=zeros(1,n);
B=zeros(n2,4);
x=0:n-1;
b=0;
%configuracion de puerto serial
s2 = serial('COM2','BaudRate',19200,'DataBits',8,'StopBits',2);
set(s2,'Parity','none'); % se configura sin paridad
set(s2,'InputBufferSize' ,n); % ”n” es el número de bytes a recibir
set(s2,'Timeout',2); % 1 segundos de tiempo de espera a recibir los datos
set(s2,'FlowControl','none');        %sin control de flujo
set(s2,'Terminator','LF');             %el carácter que indica la terminación de la cadena
%abrir puerto
fopen(s2);
fprintf(s2,'%c','x');                 %Manda el carácter 'x'
A=fread(s2,n,'uchar');            %Lee los caracteres en el buffer
%cerrar puerto
fclose(s2);
delete(s2);
clear s2
instrfind
for i=1:n2-1
    if i==1            %si i es igual a 1 entonces b es igual a 1
    b=1;
    else                %sino b es igual a 4
    b=4;
    end
    
      for l=1:4
          s=b*i+l-1;
        B(i,l)=A(s);               %asigna los datos en A a la variable B
      end 
end
C=char(B);                       %convierte los datos en B en datos tipo char y los guarda en C
for i=1:n2                           
    D=cat(2,C(i,1),C(i,2),C(i,3),C(i,4));           %Guarda la concatenación de C en D 
    temp(i)=str2double(D);                               %Convierte el valor de D a tipo double y lo guarda en temp.
end    

y1=5*temp/255;                       %Preescala el valor de temp de 0 a 255 en 0 a 5
plot(x,y1)                                  %grafica el valor de x e y1
axis([0 n2 0 5])                          %Manipula las propiedades de los ejes para visualizar la grafica de forma                                                    %adecuada

VÍDEO DE FUNCIONAMIENTO:




IMÁGENES:

PROGRAMA EN ISIS:



EJECUCIÓN DE ISIS Y MATLAB 1:


PROGRAMA EN ISIS 2:


EJECUCIÓN DE ISIS Y MATLAB 2: 


GRÁFICA DE SEÑAL DIENTE DE SIERRA:


CÓDIGO EN MATLAB:



CONFIGURACIÓN DE COMPIM


CONFIGURACIÓN DE VIRTUAL SERIAL PORT DRIVER:



LINKS:


MATLAB:
https://mega.co.nz/#!Fx0HQRLZ!zN6FnXMNwuuvUPVHVWm6EqbnfEcwRMo8MPRY3Cj4jhE
MICROCONTROLADOR:
https://mega.co.nz/#!508FUKrR!dYeL91engG0F7aYaBxGFrk_nLdc6kCyQgwHtllkFp0E


domingo, 9 de marzo de 2014

RELOJ CON MICROCONTROLADOR AVR

                          El siguiente programa a realizar se trata sobre la implementación de un reloj mostrado en displays de siete segmentos de cátodo común donde ademas de mostrar hora, minutos y segundos se agrego la capacidad de cambiar horas y minutos con ayuda de las interrupciones INT0 e INT1. Ademas de todo esto se agrego un botón el cual dependiendo su estado (HIGH o LOW), incrementa o decrementa  las horas y minutos cada vez que se cambien con las interrupciones correspondientes.

DESCRIPCIÓN:

                            Se comenzara ha explicar el programa en el orden en el que se encuentra dando a mencionar primero lo que realizan las interrupciones y después se explicará lo que realizan las funciones y el programa principal.


ISR(INT0_vect):

                           Cada vez que se genera una interrupción esta rutina realiza el incremento/decremento de horas dependiendo del estado del pin PB7 el cual determina lo que realizará la función, ademas identifica si el valor de la variable horas es igual a cero no decrementa su valor.

if (bit_is_clear(PINB,PINB7))
{
if (horas>0){ horas--; }
else
{
    horas++;
if (horas==24){ horas=0; }
}

ISR(INT1_vect):

                           Cada vez que se genera una interrupción esta rutina realiza el incremento/decremento de minutos dependiendo del estado del pin PB7 el cual determina lo que realizará la función, ademas identifica si el valor de la variable minutos es igual a cero no decrementa su valor.

ISR(INT1_vect){
if (bit_is_clear(PINB,PINB7))
{
if (minutos>0){ minutos--; }
}
else
{
minutos++;
if (minutos==60){ minutos=0; horas++; }
}
}

ISR(TIMER1_COMPA_vect):

                            En la siguiente sección del programa se realiza el incremento de las variables segundos, minutos y horas cada vez que surge una interrupción debido a la comparación del registro OCRIA y el registro TCNT1 lo cual sucede cada 1 segundo.

TCNT1=0; 
segundos++;

                             Cada vez que la interrupción sucede se reinicia el registro TCNT1 para que vuelva a contar. En seguida se incrementa la variable segundos y se pregunta con las funciones if el valor de dicha variable, si su valor es de 60 entonces se incrementa la variable minutos y se limpia segundos.

if (segundos==60)
{
minutos++;
segundos=0;
}

                             Cuando el valor de la variable minutos es igual a 60 se incrementa el valor de horas y se limpia el contenido de minutos.

if (minutos==60)
{
    horas++;
minutos=0;
 
}

                           Para finalizar se pregunta si la variable horas es igual a 24 de ser así se le asigna el valor 0.

if (horas==24)
{
horas=0;
}

INTERRUPCIÓN_CAMBIO:

                           Esta función habilita las interrupciones INT0 e INT1 del registro EIMSK, configurando la interrupción en flanco de bajada con los bits ISC11 e ISC01 del registro EICRA, ademas habilita las resistencias de pull-up y limpia las banderas de interrupción para que no se disparen de forma aleatoria.

setbit(PORTD,PD3);
setbit(PORTD,PD2);

//FLANCO DE BAJADA DE LA INTERRUPCION
setbit(EICRA,ISC01); 
setbit(EICRA,ISC11);
//PINES DE CAMBIO HORA Y MINUTO
setbit(EIMSK,INT1);
setbit(EIMSK,INT0);
setbit(EIFR,INTF0);
setbit(EIFR,INTF1);

TEMPORIZADOR:

                            Esta función configura el TIMER1 en modo CTC en particular el modo 4 con los bits WGM13:10, del registro TCCR1A. Se selecciono un preescalamiento de 256 con los bits CS12:10 del registro TCCR1B y se le asigno el valor 31249 al registro OCR1A para que la interrupción surja cada 1 segundo. Para finalizar se habilito la interrupción por comparación.

//MODO CTC WGM13:0 = 4
clearbit(TCCR1A,WGM13);
setbit(TCCR1A,WGM12);
clearbit(TCCR1A,WGM11);
clearbit(TCCR1A,WGM10);
//PREESCALER
setbit(TCCR1B,CS12);
clearbit(TCCR1B,CS11);
clearbit(TCCR1B,CS10);
//COMPARACION CADA 1 SEGUNDO
OCR1A=31249;
    setbit(TIMSK1,OCIE1A);

UNIDADES_DECENAS:

                                En esta sección se separan las unidades y decenas correspondientes de las variables segundos, minutos y horas. Son guardadas en nuevas variables que serán utilizadas para presentar los datos en los displays de siete segmentos.

dec_seg=segundos/10;
uni_seg=segundos-10*dec_seg;
dec_min=minutos/10;
uni_min=minutos-10*dec_min;
dec_hor=horas/10;
uni_hor=horas-10*dec_hor;

MAIN:

                                    Se declara el pin PB7 como entrada y se habilita su resistencia del pull-up, se realiza la configuración de INT0 e INT1 y del TIMER1 y las salidas que serán conectadas a los dispalys y se habilita la interrupción global.                        

clearbit(DDRB,DDB7);
setbit(PORTB,PB7);
INTERRUPCION_CAMBIO();
initDisplay();
temporizador();
sei();

WHILE(1):

                                    Este bucle realiza la presentación de las horas, minutos y segundos mediante lo siguiente:


  • Se determina el valor de las unidades y decenas de los segundo, minutos y horas con la función UNIDADES_DECENAS();                        
  • Primero coloca en HIGH el bit que se encontraba en LOW para no ser presentado en el display conectado en ese pin.
  • Se determina el valor que se presentara en el display correspondiente.
  • Se pone en LOW el pin conectado a ese display para visualizar su contenido.
  • Espera 2 milisegundos.
  • realiza lo mismo hasta presentar las dec_hor donde volverá a inicio del bucle.



UNIDADES_DECENAS();
//UNIDADES SEGUNDOS
setbit(Pdisp_6,disp_6);
salida_7seg(uni_seg);
clearbit(Pdisp_1,disp_1);
_delay_ms(retencion);
//DECENAS SEGUNDOS
setbit(Pdisp_1,disp_1);
salida_7seg(dec_seg);
clearbit(Pdisp_2,disp_2);
_delay_ms(retencion);
//UNIDADES MINUTOS
setbit(Pdisp_2,disp_2);
salida_7seg(uni_min);
clearbit(Pdisp_3,disp_3);
_delay_ms(retencion);
//DECENAS MINUTOS
setbit(Pdisp_3,disp_3);
salida_7seg(dec_min);
clearbit(Pdisp_4,disp_4);
_delay_ms(retencion);
//UNIDADES HORAS
setbit(Pdisp_4,disp_4);
salida_7seg(uni_hor);
clearbit(Pdisp_5,disp_5);
_delay_ms(retencion);
//DECENAS HORAS
setbit(Pdisp_5,disp_5);
salida_7seg(dec_hor);
clearbit(Pdisp_6,disp_6);
_delay_ms(retencion);

NOTA: 

                         Al final se colocara el link del programa y su simulación en proteus para que puedan descargarlo. Alguna duda o sugerencia puede ingresarla en los comentarios para que podamos realizar programas de su interés.

PROGRAMA:

/*
 * RELOJ.c
 *
 * Created: 09/03/2014 17:40:37
 *  Author: TERRAFORMARS
 */ 


#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 8000000UL // XTAL de 8 MHz
#endif
#include <avr/interrupt.h>
#include "7_segmentos.h"
#include <util/delay.h>

#define setbit(sfr,bit) (_SFR_BYTE(sfr)|=(_BV(bit)))
#define clearbit(sfr,bit) (_SFR_BYTE(sfr)&=~(_BV(bit)))
#define bittoggle(sfr,bit)(_SFR_BYTE(sfr)^=_BV(bit))
#define retencion 2

unsigned char segundos=0,minutos=0,horas=0,uni_seg,uni_min,uni_hor,dec_seg,dec_min,dec_hor;

ISR(INT0_vect){
if (bit_is_clear(PINB,PINB7))
{
if (horas>0){ horas--; }

else
{
   horas++;
if (horas==24){ horas=0; }
}

}
ISR(INT1_vect){
if (bit_is_clear(PINB,PINB7))
{
if (minutos>0){ minutos--; }
}
else
{
minutos++;
if (minutos==60){ minutos=0; horas++; }
}
}


ISR(TIMER1_COMPA_vect){
TCNT1=0; 
segundos++;
if (segundos==60)
{
minutos++;
segundos=0;
}

if (minutos==60)
{
   horas++;
minutos=0;
 
}

if (horas==24)
{
horas=0;

}

}

void INTERRUPCION_CAMBIO(){
setbit(PORTD,PD3);
setbit(PORTD,PD2);

//FLANCO DE BAJADA DE LA INTERRUPCION
setbit(EICRA,ISC01); 
setbit(EICRA,ISC11);
//PINES DE CAMBIO HORA Y MINUTO
setbit(EIMSK,INT1);
setbit(EIMSK,INT0);
setbit(EIFR,INTF0);
setbit(EIFR,INTF1);

}
//CONFIGURACION DE TIMER1
void temporizador(){
//MODO CTC WGM13:0 = 4
clearbit(TCCR1A,WGM13);
setbit(TCCR1A,WGM12);
clearbit(TCCR1A,WGM11);
clearbit(TCCR1A,WGM10);

//PREESCALER
setbit(TCCR1B,CS12);
clearbit(TCCR1B,CS11);
clearbit(TCCR1B,CS10);
//COMPARACION CADA 1 SEGUNDO
OCR1A=31249;
    setbit(TIMSK1,OCIE1A);
};

void UNIDADES_DECENAS(){
dec_seg=segundos/10;
uni_seg=segundos-10*dec_seg;

dec_min=minutos/10;
uni_min=minutos-10*dec_min;

dec_hor=horas/10;
uni_hor=horas-10*dec_hor;

}

int main(void)
{
clearbit(DDRB,DDB7);
setbit(PORTB,PB7);
INTERRUPCION_CAMBIO();
initDisplay();
temporizador();
sei();

    while(1)
    {
        //TODO:: Please write your application code 
UNIDADES_DECENAS();
//UNIDADES SEGUNDOS
setbit(Pdisp_6,disp_6);
salida_7seg(uni_seg);
clearbit(Pdisp_1,disp_1);
_delay_ms(retencion);
//DECENAS SEGUNDOS
setbit(Pdisp_1,disp_1);
salida_7seg(dec_seg);
clearbit(Pdisp_2,disp_2);
_delay_ms(retencion);
//UNIDADES MINUTOS
setbit(Pdisp_2,disp_2);
salida_7seg(uni_min);
clearbit(Pdisp_3,disp_3);
_delay_ms(retencion);
//DECENAS MINUTOS
setbit(Pdisp_3,disp_3);
salida_7seg(dec_min);
clearbit(Pdisp_4,disp_4);
_delay_ms(retencion);
//UNIDADES HORAS
setbit(Pdisp_4,disp_4);
salida_7seg(uni_hor);
clearbit(Pdisp_5,disp_5);
_delay_ms(retencion);
//DECENAS HORAS
setbit(Pdisp_5,disp_5);
salida_7seg(dec_hor);
clearbit(Pdisp_6,disp_6);
_delay_ms(retencion);

    }
}


VÍDEO:




IMÁGENES:

SIMULACIÓN EN ISIS PROTEUS:


PROGRAMA EN ATMEL STUDIO:


LINK:

https://mega.co.nz/#!V4kClC5Q!B5Q-CudJuH_Qr-dFyc-kOLpBPidvTYJimHP4SINOcIE



sábado, 8 de marzo de 2014

INT0 EN ENSAMBLADOR EJEMPLO DEMOSTRATIVO

                           Desde el año pasado he mostrado el uso de las interrupciones y como todos sabrán, las interrupciones son secciones de un programa que se ejecuta cada vez que son llamadas es decir cada vez que la bandera de la interrupción se activa deteniendo temporalmente la ejecución del programa principal y ejecutando el programa realizado en la rutina de interrupción.
                           Para este caso se presentará un programa el cual muestra el funcionamiento de las interrupciones en general de forma visual en una simulación realizada en ISIS PROREUS utilizando para ello la interrupción INT0 y que el usuario pueda comprobar en realidad como funciona una interrupción.

DESCRIPCIÓN:

DEFINICIÓN DE VARIABLES:

                             En esta sección del código se definen los registros que se utilizaran para las acciones de operaciones lógicas, mover datos e inicializar bits en registros de entrada y salida así como los registros de configuración, los cuales en este caso son los de enmascaramiento de la interrupción INT0.

 .equ EIMSKreal48=0x3d  ;posicion real del registro EIMSK

                                Para aquellos que programen en ensamblador el microcontrolador ATMEGA48 declara la localización de su registro EIMSK en la localización 0x1D lo cual es incorrecto, la localización es 0x3D, el datasheet menciona que se debe sumar 0x20.


INICIALIZACIÓN DEL PROGRAMA:

                          En esta parte del código se establece el Stack Pointer al principio de la RAM:

 ldi pila, high(RAMEND); Main program start
       out SPH,pila ; Set Stack Pointer to top of RAM
       ldi pila, low(RAMEND)
       out SPL,pila

                          En seguida se declara como salida los PORTB y PORTC, y como entrada el PORTD:

 ;declaracion de salidas en puerto B
       ldi ES,0xff
   out DDRB,ES      ;declara al puerto B como salidas
   out PORTD,ES     ;habilita resistencias de pull-up del puerto D
   out DDRC,ES      ;declara al puerto C como salidas 
   com ES           ;complemento 1 de la variable ES
   out DDRD,ES      ;declara al puerto D como entradas

                          Se habilita la interrupción:

;habilitacion de interrupciones
   clr temp                     ;limpia el contenido de la variable temp
   ldi temp,(1<<INT0)           ;setea el bit 0 de la variable temp
   sts EIMSKreal48,temp         ;habilita la mascara de interrupcion INT0
   
   clr temp                     ;limpia la variable temp
   ldi temp,(1<<ISC01)          ;setea el bit 1 de la variable temp
   sts EICRA,temp               ;configuracion de interrupciones en flanco de bajada

   sei                          ;habilita la interrupcion global

PROGRAMA PRINCIPAL BUCLE INFINITO:

                         La función de esta sección es la de presentar el valor guardado en el registro temp por medio del PORTC desplazando a la derecha el contenido del mismo con un retraso declarado con la subrutina rcall delay_1, una vez que la variable temp esta vacía coloca su contenido en el PORTC y retorna al inicio del bucle con la subrutina infinito.

RUTINA DE INTERRUPCIÓN:

                              La interrupción realiza el decremento de la variable ES, y la presenta por medio del PORTB y a continuación espera un tiempo y decremento el valor de ES, pregunta si se encuentra vacía la variable de ser así sale de la interrupción y continua con el programa exactamente donde fue interrumpido.


NOTA:
                                Se colocara el link del programa y la simulación a final para que pueda descargarlo, al realizar la simulación podrá notar de forma clara como funciona una interrupción para reducir las dudas que se tenga sobre todo si es es nuevo en la programación de microcontroladores. Alguna duda o sugerencia puede ingresarla en los comentarios para que pueda mejorar la forma de presentación de los programas.





PROGRAMA:

/*
 * INTRRUPCION0.asm
 *
 *  Created: 02/03/2014 18:04:19
 *   Author: TERRAFORMARS
 */ 
 .include "m48def.inc"


 ;DEFINICION DE VARIABLES
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 .def temp=r16
 .def pila=r17
 .def ES=r18
 .def delay=r19
 .def retraso_0=r20
 .def retraso_1=r21
 .equ EIMSKreal48=0x3d  ;posicion real del registro EIMSK
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 .org 0x000      ;origen del programa
 rjmp start      ;salto a principio del programa

 .org INT0addr   ;direccion de la interrrupcion INT0
 rjmp int_0      ;salto a rutina de interrupcion

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;INICIALIZACION DEL PROGRAMA
 start:

       ldi pila, high(RAMEND); Main program start
       out SPH,pila ; Set Stack Pointer to top of RAM
       ldi pila, low(RAMEND)
       out SPL,pila

  ;declaracion de salidas en puerto B
       ldi ES,0xff
  out DDRB,ES      ;declara al puerto B como salidas
  out PORTD,ES     ;habilita resistencias de pull-up del puerto D
  out DDRC,ES      ;declara al puerto C como salidas 
  com ES           ;complemento 1 de la variable ES
  out DDRD,ES      ;declara al puerto D como entradas
  
  ;habilitacion de interrupciones
  clr temp                     ;limpia el contenido de la variable temp
  ldi temp,(1<<INT0)           ;setea el bit 0 de la variable temp
  sts EIMSKreal48,temp         ;habilita la mascara de interrupcion INT0
  
  clr temp                     ;limpia la variable temp
  ldi temp,(1<<ISC01)          ;setea el bit 1 de la variable temp
  sts EICRA,temp               ;configuracion de interrupciones en flanco de bajada

  sei                          ;habilita la interrupcion global



  ;PROGRAMA PRINCIPAL BUCLE INFINITO
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  infinito:                    

  ldi temp,0x3F                ;carga temp con el valor 0b01111111

       desplazamiento_R:        ;realiza el desplazamiento de la salida a la derecha
          
       out PORTC,temp               ;coloca el valor de temp en el puerto C
  
  rcall delay_1                ;realiza un delay
  lsr temp                     ;desplaza el contenido de temp
  brne desplazamiento_R        ;comprueba si la opeacion seteo la bandera Z, de no ser asi realiza el salto 
 
  out PORTC,temp               ;coloca el valor de temp en el puerto C
  rcall delay_1                ;realiza un delay
  rjmp infinito                ;realiza un salto 
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


  ;RUTINA DE INTERRUPCION
  int_0:
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        push temp
in temp,SREG
ldi ES,0xe3          ;carga la variable ES con 0xe3
decremento:                  ;rutina de reduccion de la variable ES
        out PORTB,ES         ;coloca ES en el puerto B
 
;DELAY
;;;;;;;;;;;;;;;;;
        ldi delay,0xff       
loop_1:
    ldi pila,0xff
loop_2:  
        dec pila
             brne  loop_2
dec delay
brne loop_1
;;;;;;;;;;;;;;;;;;
dec ES               ;decrementa a ES en 1
brne decremento      ;salto a decremento si ES es diferente de 0, Z=0       


clr delay            ;limpia la variable delay
out PORTB,delay      ;limpia el puerto B
out SREG,temp
pop temp
reti                 ;retorna al programa principal
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;DELAY
delay_1:
            ldi retraso_1,0xff
retrasar_1:
    ldi retraso_0,0xff
espera_1:  
        dec retraso_0
             brne  espera_1
dec retraso_1
brne retrasar_1
ret

IMÁGENES:

SIMULACIÓN EN PROTEUS:

EJECUCIÓN DE PROGRAMA EN BUCLE 


EJECUCIÓN DE RUTINA DE INTERRUPCIÓN:


ATMEL STUDIO:


LINK:

https://mega.co.nz/#!8g1BlQ6B!CN5YYpCh-NNFHXjpH-tZZ_bL7bKZcgdppbIxSZ3x_GI