martes, 1 de enero de 2013

PWM Variable con ATMega16


Generar una señal PWM configurable en frecuencia y ciclo útil es de lo más básico, es por eso que en esta entrada mostramos como hacerlo con un microcontrolador ATMega16 en esamblador.

Señal PWM generada (Línea amarilla).

Para lograr esta señal, vamos a hacer un contador ascendente/descendete y vamos a compararlo con una señal de referencia. Para fines ilustrativos, en el circuito se han puesto convertidores DAC del contador (línea azul) y la referencia (línea morada) cuya salidas son conectadas al osciloscopio virtual, sin embargo, esto no es necesario porque todo el proceso se realiza dentro del microcontrolador y podría solo salir la señal PWM deseada por el pin 4 (PB3).

Esquemático del circuito.

Para configurar la señal en tiempo de ejecución, usamos la terminal virtual de ISIS, la cual se comunica de manera serial con el microcontrolador, los comandos usados son:
W: Incrementa la señal de referencia.
S: Disminuye la señal de referencia.
E: Disminuye a frecuencia de operación.
D: Aumenta la frecuencia de operación.

Configurando la señal PWM.


Código en ASM:

.include "m16def.inc"
.device ATmega16

.def temp = R16
.def fre  = R17
.def ref  = R18
.def dato = R19

.cseg
.org 0x000

reset:
ldi temp,0x04;ubica apuntador de la pila
out sph,temp
ldi temp,0x5f
out spl,temp

ldi temp,0xff
out DDRB,temp
out DDRA,temp
out DDRC,temp

ldi temp,  0x71
out TCCR0, temp
ldi temp,  0x00
out TCNT0, temp

ldi temp, 128
out OCR0, temp

rcall conf_usart;configurar la usart
ldi zh, high(2*duty)
ldi zl, low(2*duty)

ldi fre, 1
ldi ref, 5

main:
in temp, TCNT0
out PORTA, temp
in temp, OCR0
out PORTC, temp
sbis ucsra,rxc
rjmp main

rcall recibe
rjmp main

recibe:
in dato,udr
rcall transmite
cpi dato, $57 // W
brne baja_ref
inc ref
mov temp, ref
rcall transmite_temp
cpi ref, 10
brne baja_ref
ldi ref, 1
baja_ref:
cpi dato, $53 // S
brne sube_frec
dec ref
cpi ref, 0
brne sube_frec
ldi ref, 9
sube_frec:
cpi dato, $45 // E
brne baja_frec
inc fre
cpi fre, 6
brne baja_frec
ldi fre, 1
baja_frec:
cpi dato, $44 // D
brne final
dec fre
cpi fre, 0
brne final
ldi fre, 5
final:
ldi zh, high(2*duty)
mov zl, ref
lpm temp, z
out OCR0, temp
ldi zh, high(2*frec)
mov zl, fre
lpm temp, z
out TCCR0, temp
ret

transmite:
sbis ucsra, udre
rjmp transmite
out udr,dato
ret

transmite_temp:
sbis ucsra, udre
rjmp transmite
out udr, temp
ret

conf_usart:
clr r16;valor de recarga para una velocidad de 9600 bps
out ubrrh,r16
ldi r16,12
out ubrrl,r16

ldi r16,0x02;
out ucsra,r16

ldi r16,0x18;habilita receptor y trasmisor
out ucsrb,r16;sin interrupciones

ldi r16,0x86; 1 bit de paro,sin paridad y datos de 8 bits
out ucsrc,r16
ret

.org 0x200
duty: .db 00, 00, 32, 64, 96, 128, 160, 192, 224, 255
.org 0x300
frec: .db $71, $71, $72, $73, $74, $75


Descarga código y simulación aquí.

2 comentarios:

  1. buenos dias
    quiero saber si puedo colocarle pulsadores a este pwm, con el fin de poder modificar frecuencia y ciclo de trabajo mediante pulsadores

    ResponderEliminar
    Respuestas
    1. Claro que sí, es el mismo principio y, de hecho, es más sencillo.
      En este ejemplo se ha tenido que configurar el USART (puerto serial) para recibir los caracteres en código ASCII y compararlos con las constantes que esperamos (W, S, E y D), en tu caso podrías usar un puerto para tus botones y hacer las comparaciones contra el valor de tu puerto.
      Las comparaciones se hacen en las líneas semejantes a esta:

      cpi dato, $57 // W

      Como puedes ver hay una para cada botón esperado.
      Suerte. :)

      Eliminar