Autor Tema: Invertir pwm en Atmega 8515 asembler  (Leído 23912 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado esteban_k

  • PIC10
  • *
  • Mensajes: 18
Invertir pwm en Atmega 8515 asembler
« en: 29 de Julio de 2015, 17:39:29 »
Hola como andan, quiero ver si me pueden dar una mano, de programación se muy poco , solo hago retoques y nada mas.. digamos que casi nada..
,Quiero invertir la fase del pwm del codigo que adjunto, mi problema es que si uso un mosfet canal n me queda al revés en la consola dmx  (cuando el potenciometro esta al maximo el pwm esta en 0, y cuando el potenciometro esta al minimo el pwm esta en valos 255) , lo soluciones agregando un CD4069, pero bueno se que se puede invertir, estoy buscando información pero mayormente es en lenguaje C....  si me pueden ayudar muchas gracias... igual sigo buscando...

Saludos

Código: [Seleccionar]
include "m8515def.inc"

;Register and Pin definitions

.def tempL = r16
.def tempH = r17
.def Flags = r18
.def DMXstate = r19
.def null = r2
.def status = r21
.def ind_count = r3
.def blink = r4
.def PwmCnt = r20
.def SREGbuf = r5
.def ChaseFine = r6
.def ChaseRes = r7

.equ StrobeFreqH = 0x80
.equ StrobeFreqL = 0x81
.equ StrobeBuf = 0x82

.equ OldStepH = 0x83
.equ OldStepL = 0x84
.equ NewStepH = 0x85
.equ NewStepL = 0x86
.equ StepCnt = 0x87
.equ ChaseCnt = 0x88
.equ ChaseSeed = 0x89

.equ LED1= PD7
.equ LED2= PE0
.equ BIT9= PE2

.equ DMX_FIELD=      0x60 ;SRAM-Beginn
.equ DMX_CHANNELS=   5
.equ PWM_FIELD=      0x70
.equ F_OSC=          8000
.equ FLASH_DURATION= 400
.equ IND_OFFSET=     12 ;Offset für indicator-Timer (14Hz)

#define CHS_SPD (0x600)
#define RATE         (0x500)
#define PAT0 (0x400)
#define PAT1         (PAT0 +0xA)
#define PAT2 (PAT1 +0xA)
#define PAT3 (PAT2 +0xA)
#define PAT4 (PAT3 +0xA)
#define PAT5         (PAT4 +0xA)
#define PAT6         (PAT5 +0xA)
#define PAT7         (PAT6 +0xA)


;***** special Flags

#define  VALID_DMX     (0)
#define  SIGNAL_COMING  (1)

#define  doIND (5)
#define  BLACK_OUT (6)
#define  DATA_REFRESHED (7)


;interrupt vectors
.org 0
rjmp init ;reset vector address
reti ;External Interrupt0 Vector Address
reti ;External Interrupt1 Vector Address
reti ;Input Capture1 Interrupt Vector Address
rjmp strobe ;Output Compare1A Interrupt Vector Address
reti ;Output Compare1B Interrupt Vector Address
reti ;Overflow1 Interrupt Vector Address
rjmp pwm ;Overflow0 Interrupt Vector Address
reti ;SPI Interrupt Vector Address
rjmp get_byte ;UART Receive Complete Interrupt Vector Address
reti ;UART Data Register Empty Interrupt Vector Address
reti ;UART Transmit Complete Interrupt Vector Address
reti ;Analog Comparator Interrupt Vector Address
reti ;External Interrupt2 Vector Address
reti ;Output Compare0 Interrupt Vector Address
reti ; EEPROM Interrupt Vector Address
reti ; SPM complete Interrupt Vector Address
reti ; SPM complete Interrupt Vector Address

; INIT

init:

; Stack
ldi tempH,high(RAMEND)
ldi tempL,low(RAMEND)
out SPH,tempH
out SPL,tempL

; WATCHDOG
wdr
ldi tempL, (1<<WDE)|(1<<WDCE)
out WDTCR, tempL
ldi tempL, (1<<WDE)|(1<<WDCE)|(1<<WDP2)|(1<<WDP1)
out WDTCR, tempL
wdr ;set prescaler @0,5s

; PortA
ser tempL
out DDRA, tempL
clr tempL
out PortA, tempL ;low Outputs

; PortB
ldi tempL, 0b00000011
out DDRB, tempL
ldi tempL, 0b11110100
out PortB, tempL

; PortD
ldi tempL, 0b10000100
out DDRD, tempL
ldi tempL, 0b01111000
out PortD, tempL ;DMX & Spare , LED1 on

; PortE
ldi tempL, 0b00000001
out DDRE, tempL
ser tempL
out PortE, tempL ;LED2 off, BIT9 & OPTION Pullup

; Timers
ldi tempL, (1<<CS01) ;set counter0 @clock/8 frequency
out TCCR0, tempL
clr tempL
out TCCR1A, tempL
ldi tempL, (1<<CS12)|(1<<WGM12) ;set counter1 @clock/256 frequency, CTCmode
out TCCR1B, tempL
ldi tempL, (1<<TOIE0) ;aktivate overflow interrupt
out TIMSK, tempL

rcall init_dmx


; set Register
clr null
clr blink
com blink
mov ChaseFine, blink
ldi tempL, IND_OFFSET
mov ind_count, tempL
ldi PwmCnt, 0xFF
ldi Flags, 0 ;clear Flags

sts StepCnt, null
sts NewStepH, null
sts NewStepL, null
ldi tempL, 1
sts ChaseCnt, tempL
sts ChaseSeed, tempL
mov ChaseRes, tempL

wdr
sei

main: sbrc Flags, doIND
rcall indicate

rcall   eval_strobe_freq
;rcall chase
rjmp main



;****************************** LED INDICATOR ***********************************
indicate:
cbr Flags, (1<<doIND) ;clear flag
rcall chase
dec ind_count
breq ind_a
ret
     
  ind_a:
wdr ;reset Watchdog
;working LED
sbrc Flags, DATA_REFRESHED ;should flash?
rjmp data_flash
sbi PortE, LED2 ; LED off

Error_LED:
sbrc  blink, 0 ;wenn erstes bit HI
rjmp  on
sbi    PortD, LED1
rjmp  ind_tst
on:
cbi  PortD, LED1

     ind_tst:
    lsr    blink
ldi tempL, 1
cp blink, tempL
brne no_ind

;wenn durchrotiert (blink = 0)
ldi tempL, 0b10000000
sbrs Flags, VALID_DMX
ldi tempL, 0b10001010
sbrs Flags, SIGNAL_COMING
ldi tempL, 0b10000010
mov  blink, tempL

cbr Flags, (1<<VALID_DMX)|(1<<SIGNAL_COMING)

no_ind:
ldi tempL, IND_OFFSET
mov ind_count, tempL ;plant prescaler
ret
data_flash:
cbr Flags, (1<<DATA_REFRESHED)
    sbis PortE,LED2 ;blinken grün
rjmp off
cbi PortE,LED2
rjmp Error_LED
off:
sbi PortE,LED2
rjmp Error_LED




;****************************** strobe frequency ***********************************
eval_strobe_freq:
lds tempL, DMX_FIELD ;get 1st DMX ch
cpi tempL, 246
brlo esf_1
ldi tempL, 245
       esf_1:
lds tempH, StrobeBuf
cp tempL, tempH
brne esf_2 ;only eval if changed
ret
esf_2:
sts StrobeBuf, tempL
cpi tempL, 30
brlo esf_no_strobe
cpi tempL, 245
brsh esf_sync

subi tempL, 30 ;0-200 allowed
ldi ZL, low(RATE*2) ;get freq from table
ldi ZH, high(RATE*2)
add ZL, tempL
adc ZH, null
add ZL, tempL
adc ZH, null
lpm tempL, Z+
lpm tempH, Z
cli
sts StrobeFreqL, tempL ;atomic store
sts StrobeFreqH, tempH

in tempL, TIMSK
sbr tempL, (1<<OCIE1A) ;enable irq
out TIMSK, tempL
in tempL, TIFR
sbr tempL, (1<<OCF1A) ;enable irq
out TIFR, tempL
reti


esf_no_strobe:
in tempL, TIMSK
cbr tempL, (1<<OCIE1A) ;disable irq
out TIMSK, tempL
cbr Flags, (1<<BLACK_OUT) ;enable pwm
ret

esf_sync:
in tempL, TIMSK
sbrs tempL, OCIE1A ;only when strobing
ret
cli
sbr Flags, (1<<BLACK_OUT) ;blank!
lds ZH, StrobeFreqH
lds ZL, StrobeFreqL
out OCR1AH, ZH
out OCR1AL, ZL
sbiw ZH:ZL, 20
out TCNT1H, ZH
out TCNT1L, ZL
reti


;****************************** manual chaser mode ***********************************
chase: ;called by indicator
sbis PinE, PE1
rjmp chs_a
sbic UCSRB,RXEN
ret ;enable DMX reception
sbi UCSRB, RXEN
clr DMXstate
ret

chs_exit:
sts ChaseCnt, tempH
ret

    chs_a:
cbi UCSRB,RXEN ;disable DMX
sbr Flags, (1<<VALID_DMX)|(1<<SIGNAL_COMING)
lds tempH, ChaseCnt ;load prescaler
dec tempH
brne chs_exit
lds tempL, ChaseSeed ;reseed prescaler
sts ChaseCnt, tempL

add ChaseFine, ChaseRes ;up-fade val
adc tempH, null ;(tempH was 0)
mov tempL, ChaseFine
com tempL ;down-fade val

tst tempH
brne chs_step
  chs_step_ret:
ldi XL, low(DMX_FIELD +1)
ldi XH, high(DMX_FIELD)
ldi ZL, 1
   chase_fade: ;ch1..8
clr tempH
lds ZH, OldStepL
and ZH, ZL
breq cf_no_old
mov tempH, tempL
   cf_no_old:
    lds ZH, NewStepL
and ZH, ZL
breq cf_no_new
        add tempH, ChaseFine
       cf_no_new:
    st X+, tempH
lsl ZL
brne chase_fade

clr tempH ;9th ch
lds ZH, OldStepH
sbrc ZH, 0
mov tempH, tempL
lds ZH, NewStepH
sbrc ZH, 0
add tempH, ChaseFine
st X, tempH

ret


chs_step:
sbr Flags, (1<<DATA_REFRESHED)
clr ChaseFine ;reset fader
ser tempL

lds tempH, NewStepL ;change steps
sts OldStepL, tempH
lds tempH, NewStepH
sts OldStepH, tempH

ldi ZH, high(CHS_SPD*2) ;get speed
in ZL, PinC
com ZL
swap ZL
andi ZL, 0b00001111 ;isolate pattern
lpm ZH, Z
ldi tempH, 1

cpi ZL, 5 ;switch between resolution and prescale
brsh chs_decres
mov ChaseRes, tempH
sts ChaseSeed, ZH
rjmp chs_strb
       chs_decres:
    mov ChaseRes, ZH
sts ChaseSeed, tempH
   chs_strb:

clr ZH ;add strobe
sbis PinE, PE2
ldi ZH,  220
sts DMX_FIELD, ZH

ldi ZH, high(PAT0*2) ;get next step
lds tempH, StepCnt
mov ZL, tempH
lsl ZL
inc tempH
sts StepCnt, tempH
lpm tempH, Z+
sts NewStepL, tempH
lpm tempH, Z
sts NewStepH, tempH

sbrs tempH, 1 ;reset pattern?
rjmp chs_step_ret

in ZL, PinC
com ZL
andi ZL, 0b00000111 ;isolate pattern
ldi tempH, 10
mul ZL, tempH
sts StepCnt, r0 ;save pattern

rjmp chs_step_ret






; ***************************9ch 8bitpwm-Ausgabe ****************************************
pwm:
in      SREGbuf, SREG
push tempL

  sbrc Flags, BLACK_OUT ;blanked by strobe?
rjmp pwm_bo_exit

lds tempL, PWM_FIELD
cp tempL, PwmCnt
ror status
 
  lds tempL, (PWM_FIELD+1)
cp tempL, PwmCnt
ror status

lds tempL, (PWM_FIELD+2)
cp tempL, PwmCnt
ror status

lds tempL, (PWM_FIELD+3)
cp tempL, PwmCnt
ror status

lds tempL, (PWM_FIELD+4)
cp tempL, PwmCnt
ror status

  lds tempL, (PWM_FIELD+5)
cp tempL, PwmCnt
ror status
 
lds tempL, (PWM_FIELD+6)
cp tempL, PwmCnt
ror status

  lds tempL, (PWM_FIELD+7)
cp tempL, PwmCnt
ror status
    ;9th bit
    sbis PinD, PD4 ;invert option
  rjmp pwm9_pos ; no invert

lds tempL, (PWM_FIELD+8)
sbi PortB, 0
cp tempL, PwmCnt
brlo pwm_exit
cbi PortB, 0
rjmp pwm_exit

   pwm9_pos:
    com status
  lds tempL, (PWM_FIELD+8)
cbi PortB, 0
cp tempL, PwmCnt
brlo pwm_exit
sbi PortB, 0
rjmp pwm_exit

pwm_bo_exit:
sbis PinD, PD4 ;invert option
  rjmp pwm_bo_pos ; no invert
ser status ;all ch off (inverted)
sbi PortB, 0
rjmp pwm_exit
   pwm_bo_pos:
    clr status ;all ch off
cbi PortB, 0

pwm_exit:
out PortA, status ;output
mov tempL, PwmCnt ;set next compare time
lsr tempL
lsr tempL
lsr tempL
ldi status, 250
sub status, tempL
out TCNT0, status

inc PwmCnt
tst PwmCnt
brne pwm_no_reload
lds tempL, (DMX_FIELD+1) ;refresh channels
sts PWM_FIELD, tempL
lds tempL, (DMX_FIELD+2)
sts (PWM_FIELD+1), tempL
lds tempL, (DMX_FIELD+3)
sts (PWM_FIELD+2), tempL
lds tempL, (DMX_FIELD+4)
sts (PWM_FIELD+3), tempL
lds tempL, (DMX_FIELD+5)
sts (PWM_FIELD+4), tempL
lds tempL, (DMX_FIELD+6)
sts (PWM_FIELD+5), tempL
lds tempL, (DMX_FIELD+7)
sts (PWM_FIELD+6), tempL
lds tempL, (DMX_FIELD+8)
sts (PWM_FIELD+7), tempL
lds tempL, (DMX_FIELD+9)
sts (PWM_FIELD+8), tempL
ldi PwmCnt, 1 ;reseed counter
sbr Flags, (1<<doIND) ;indicate in main
 
  pwm_no_reload:
  pop tempL
out     SREG, SREGbuf
reti



; ***************************Strobo function ****************************************
strobe:
in      SREGbuf, SREG
push tempL
push tempH

sbrs Flags, BLACK_OUT
rjmp str_blank
cbr Flags, (1<<BLACK_OUT) ;enable pwm
ldi tempL,  low(FLASH_DURATION) ;load flash time
ldi tempH, high(FLASH_DURATION)
rjmp str_exit

str_blank:
sbr Flags, (1<<BLACK_OUT)
lds tempL, StrobeFreqL
lds tempH, StrobeFreqH

str_exit:
out OCR1AH, tempH
out OCR1AL, tempL
pop tempH
pop tempL
out     SREG, SREGbuf
reti


.include "lib_dmx_in.asm"

nix: rjmp nix

// Strobo frequency table (damped logarithmic)
.org RATE
.dw 65532, 60407, 56368, 53017, 50170, 47708, 45546, 43626, 41904, 40345, 38925, 37623, 36423, 35311, 34277, 33311
.dw 32406, 31555, 30753, 29996, 29278, 28596, 27948, 27331, 26741, 26177, 25637, 25120, 24623, 24145, 23685, 23242
.dw 22814, 22402, 22003, 21617, 21244, 20882, 20531, 20191, 19861, 19540, 19228, 18924, 18629, 18341, 18061, 17788
.dw 17521, 17261, 17007, 16760, 16517, 16281, 16049, 15823, 15601, 15384, 15172, 14964, 14760, 14560, 14364, 14172
.dw 13983, 13798, 13617, 13438, 13263, 13091, 12922, 12756, 12593, 12432, 12274, 12119, 11966, 11815, 11667, 11522
.dw 11378, 11237, 11098, 10960, 10825, 10692, 10561, 10431, 10304, 10178, 10054, 9931,  9811,  9691,  9574,  9458
.dw 9343,  9230,  9119,  9008,  8899,  8792,  8686,  8581,  8477,  8375,  8273,  8173,  8074,  7976,  7880,  7784
.dw 7690,  7596,  7504,  7412,  7322,  7232,  7144,  7056,  6969,  6884,  6799,  6715,  6631,  6549,  6467,  6387
.dw 6307,  6227,  6149,  6071,  5994,  5918,  5843,  5768,  5694,  5620,  5548,  5475,  5404,  5333,  5263,  5193
.dw 5125,  5056,  4988,  4921,  4855,  4789,  4723,  4658,  4594,  4530,  4466,  4404,  4341,  4279,  4218,  4157
.dw 4097,  4037,  3978,  3919,  3860,  3802,  3744,  3687,  3631,  3574,  3518,  3463,  3408,  3353,  3299,  3245
.dw 3191,  3138,  3085,  3033,  2981,  2929,  2878,  2827,  2777,  2726,  2677,  2627,  2578,  2529,  2480,  2432
.dw 2384,  2337,  2289,  2242,  2196,  2149,  2103,  2057,  2012,  1967,  1922,  1877,  1833,  1789,  1745,  1701
.dw 1658,  1615,  1572,  1530,  1488,  1446,  1350,  1250,  1100,  1050,  1000,  950,   900,   850,   800,   750
.dw 700,   650,   600,   550,   500,   450,   400,   350,   300,   250,   200,   150


.org PAT0 ;on
.dw 0b0111111111
.dw 0b1111111111

.org PAT1 ;Lauflicht
.dw 0b0000000001
.dw 0b0000000010
.dw 0b0000000100
.dw 0b0000001000
.dw 0b0000010000
.dw 0b0000100000
.dw 0b0001000000
.dw 0b0010000000
.dw 0b1100000000

.org PAT2 ;ping pong
.dw 0b0000010000
.dw 0b0000100000
.dw 0b0000001000
.dw 0b0001000000
.dw 0b0000000100
.dw 0b0010000000
.dw 0b0000000010
.dw 0b0100000000
.dw 0b1000000001

.org PAT3 ;ping pong
.dw 0b0000011000
.dw 0b0000100100
.dw 0b0001000010
.dw 0b1010000001

.org PAT4 ;pfeil
.dw 0b0000011000
.dw 0b0000111100
.dw 0b0001111110
.dw 0b0011111111
.dw 0b0011100111
.dw 0b0011000011
.dw 0b1010000001

.org PAT5 ;RGB
.dw 0b0001001001
.dw 0b0011011011
.dw 0b0010010010
.dw 0b0110110110
.dw 0b0100100100
.dw 0b1101101101

.org PAT6 ;RGB spread
.dw 0b0100010001
.dw 0b0101110011
.dw 0b0001100010
.dw 0b0011101110
.dw 0b0010001100
.dw 0b1110011101

.org PAT7
.dw 0b0001001001 ;RGB single change
.dw 0b0001001011
.dw 0b0001011011
.dw 0b0011011011
.dw 0b0011011010
.dw 0b0011010010
.dw 0b0010010010
.dw 0b0010010110
.dw 0b0010110110
.dw 0b0110110110
.dw 0b0110110100
.dw 0b0110100100
.dw 0b0100100100
.dw 0b0100100101
.dw 0b0100101101
.dw 0b0101101101
.dw 0b0101101001
.dw 0b1101001001


.org CHS_SPD
.db 25, 10, 3, 2, 1, 2, 3, 5, 8, 12, 17, 22, 27, 35, 40, 48



 
« Última modificación: 30 de Julio de 2015, 12:04:42 por stk500, Razón: puesto como debe ser!! »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 7802
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #1 en: 30 de Julio de 2015, 01:44:10 »
Es un PWM por software, no trabaje nunca con micros de Atmel, pero el ASM es parecido en todo, solo cambia la forma de los nombres y la arquitectura, se me ocurren 4 cosas a probar:

1-
Parece que ya tiene incorporado algo para invertirlo, supuestamente el pin D4 sirve para invertir la señal de salida. Podrias probarlo, para empezar.

2-
Tal ves la mas compleja por que requiere tener en cuenta varias cosas, y sea mucho mas facil la otra opcion

Cambiar el formato del PWM, en ves de incrementar la variable que la reste, pero esto requiere el cambio de 3 lineas de codigo.
Lo bueno de este metodo es que no se agregan instrucciones ni ciclos. Las instrucciones a cambiar son:

Código: ASM
  1. inc      PwmCnt
  2. ldi PwmCnt, 0xFF
  3. ldi      PwmCnt, 1                     ;reseed counter


3-
La opcion mas simple (ya que se encuentra confinado en un bloque y no en diversas partes del codigo) y no creo que afecte demasiado el cambio.
Ya esto deberias de agregar un par de instrucciones mas, en ves de contar a la inversa, deberias invertir lo guardado, en ves de modificar el index. simplemente haces el complemento y deberias cambiar:

Código: ASM
  1.       lds      tempL, (DMX_FIELD+1)            ;refresh channels
  2.       sts      PWM_FIELD, tempL
  3.       lds      tempL, (DMX_FIELD+2)
  4.       sts      (PWM_FIELD+1), tempL
  5.       lds      tempL, (DMX_FIELD+3)
  6.       sts      (PWM_FIELD+2), tempL
  7.       lds      tempL, (DMX_FIELD+4)
  8.       sts      (PWM_FIELD+3), tempL
  9.       lds      tempL, (DMX_FIELD+5)
  10.       sts      (PWM_FIELD+4), tempL
  11.       lds      tempL, (DMX_FIELD+6)
  12.       sts      (PWM_FIELD+5), tempL
  13.       lds      tempL, (DMX_FIELD+7)
  14.       sts      (PWM_FIELD+6), tempL
  15.       lds      tempL, (DMX_FIELD+8)
  16.       sts      (PWM_FIELD+7), tempL
  17.       lds      tempL, (DMX_FIELD+9)
  18.       sts      (PWM_FIELD+8), tempL

Por:

Código: ASM
  1.       lds      tempL, (DMX_FIELD+1)            ;refresh channels
  2.       com      tempL
  3.       sts      PWM_FIELD, tempL
  4.       lds      tempL, (DMX_FIELD+2)
  5.       com      tempL
  6.       sts      (PWM_FIELD+1), tempL
  7.       lds      tempL, (DMX_FIELD+3)
  8.       com      tempL
  9.       sts      (PWM_FIELD+2), tempL
  10.       lds      tempL, (DMX_FIELD+4)
  11.       com      tempL
  12.       sts      (PWM_FIELD+3), tempL
  13.       lds      tempL, (DMX_FIELD+5)
  14.       com      tempL
  15.       sts      (PWM_FIELD+4), tempL
  16.       lds      tempL, (DMX_FIELD+6)
  17.       com      tempL
  18.       sts      (PWM_FIELD+5), tempL
  19.       lds      tempL, (DMX_FIELD+7)
  20.       com      tempL
  21.       sts      (PWM_FIELD+6), tempL
  22.       lds      tempL, (DMX_FIELD+8)
  23.       com      tempL
  24.       sts      (PWM_FIELD+7), tempL
  25.       lds      tempL, (DMX_FIELD+9)
  26.       com      tempL
  27.       sts      (PWM_FIELD+8), tempL


De esa forma cuando lo llegado del DMX le indique que es de 250, lo que luego se compara es con 255 - 250 = 5, es decir 5, cuando tu potenciometro este en 205, tu pwm va a usar el valor de 50.
Es decir ahi estarias invirtiendolo, no se si lo que recibe ya lo invierte y lo guarda en DMX_FIELD, pero con este caso, lo estariamos invirtiendo de nuevo.
De todas formas no tuve en cuenta el tiempo, pero solo llevaria mas tiempo el momento en que comienze en 0 pwmCnt ya que necesitaria recargar, y en tiempo me refiero a 8 ciclos mas de reloj.

4-
Buscar donde cambia el valor del puerto e invertirlo antes, es decir esto:

Código: ASM
  1.    pwm_exit:
  2.       out      PortA, status                  ;output

Por

Código: ASM
  1.    pwm_exit:
  2.       com     status
  3.       out      PortA, status                  ;output
  4.       com     status

Agregando 2 instrucciones, Y todo lo demas internamente funcionaria de la misma forma, es decir solo toco lo que va al puerto. invierto e invierto nuevamente por que luego se hace uso de "status" entonces debe mantener el valor sin invertir.
Sino habria que revisar todo el programa. Si solo quisiera invertirlo una ves


------------------------

De recomendar te recomiendo la primera opcion, luego la 4ta, luego la 3era y luego la 2da.

PD: Esto sin conocer los atmega ya que nunca trabaje con ellos, solo mire su set de intrucciones.
« Última modificación: 30 de Julio de 2015, 07:23:17 por KILLERJC »

Desconectado esteban_k

  • PIC10
  • *
  • Mensajes: 18
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #2 en: 30 de Julio de 2015, 12:01:52 »
Buenas....
Te comento que use la Opción nº 4 y anduvo perfecto!!!!!!..

Muchas gracias por la información, soy muy duro para esto de la programación...

Mil Gracias!!!!..

Desconectado locodelafonola

  • PIC10
  • *
  • Mensajes: 42
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #3 en: 31 de Julio de 2015, 19:23:52 »
hola
Es un PWM por software, no trabaje nunca con micros de Atmel, pero el ASM es parecido en todo, solo cambia la forma de los nombres y la arquitectura, se me ocurren 4 cosas a probar:

1-
Parece que ya tiene incorporado algo para invertirlo, supuestamente el pin D4 sirve para invertir la señal de salida. Podrias probarlo, para empezar.

2-
Tal ves la mas compleja por que requiere tener en cuenta varias cosas, y sea mucho mas facil la otra opcion

Cambiar el formato del PWM, en ves de incrementar la variable que la reste, pero esto requiere el cambio de 3 lineas de codigo.
Lo bueno de este metodo es que no se agregan instrucciones ni ciclos. Las instrucciones a cambiar son:

Código: ASM
  1. inc      PwmCnt
  2. ldi PwmCnt, 0xFF
  3. ldi      PwmCnt, 1                     ;reseed counter


3-
La opcion mas simple (ya que se encuentra confinado en un bloque y no en diversas partes del codigo) y no creo que afecte demasiado el cambio.
Ya esto deberias de agregar un par de instrucciones mas, en ves de contar a la inversa, deberias invertir lo guardado, en ves de modificar el index. simplemente haces el complemento y deberias cambiar:

Código: ASM
  1.       lds      tempL, (DMX_FIELD+1)            ;refresh channels
  2.       sts      PWM_FIELD, tempL
  3.       lds      tempL, (DMX_FIELD+2)
  4.       sts      (PWM_FIELD+1), tempL
  5.       lds      tempL, (DMX_FIELD+3)
  6.       sts      (PWM_FIELD+2), tempL
  7.       lds      tempL, (DMX_FIELD+4)
  8.       sts      (PWM_FIELD+3), tempL
  9.       lds      tempL, (DMX_FIELD+5)
  10.       sts      (PWM_FIELD+4), tempL
  11.       lds      tempL, (DMX_FIELD+6)
  12.       sts      (PWM_FIELD+5), tempL
  13.       lds      tempL, (DMX_FIELD+7)
  14.       sts      (PWM_FIELD+6), tempL
  15.       lds      tempL, (DMX_FIELD+8)
  16.       sts      (PWM_FIELD+7), tempL
  17.       lds      tempL, (DMX_FIELD+9)
  18.       sts      (PWM_FIELD+8), tempL

Por:

Código: ASM
  1.       lds      tempL, (DMX_FIELD+1)            ;refresh channels
  2.       com      tempL
  3.       sts      PWM_FIELD, tempL
  4.       lds      tempL, (DMX_FIELD+2)
  5.       com      tempL
  6.       sts      (PWM_FIELD+1), tempL
  7.       lds      tempL, (DMX_FIELD+3)
  8.       com      tempL
  9.       sts      (PWM_FIELD+2), tempL
  10.       lds      tempL, (DMX_FIELD+4)
  11.       com      tempL
  12.       sts      (PWM_FIELD+3), tempL
  13.       lds      tempL, (DMX_FIELD+5)
  14.       com      tempL
  15.       sts      (PWM_FIELD+4), tempL
  16.       lds      tempL, (DMX_FIELD+6)
  17.       com      tempL
  18.       sts      (PWM_FIELD+5), tempL
  19.       lds      tempL, (DMX_FIELD+7)
  20.       com      tempL
  21.       sts      (PWM_FIELD+6), tempL
  22.       lds      tempL, (DMX_FIELD+8)
  23.       com      tempL
  24.       sts      (PWM_FIELD+7), tempL
  25.       lds      tempL, (DMX_FIELD+9)
  26.       com      tempL
  27.       sts      (PWM_FIELD+8), tempL


De esa forma cuando lo llegado del DMX le indique que es de 250, lo que luego se compara es con 255 - 250 = 5, es decir 5, cuando tu potenciometro este en 205, tu pwm va a usar el valor de 50.
Es decir ahi estarias invirtiendolo, no se si lo que recibe ya lo invierte y lo guarda en DMX_FIELD, pero con este caso, lo estariamos invirtiendo de nuevo.
De todas formas no tuve en cuenta el tiempo, pero solo llevaria mas tiempo el momento en que comienze en 0 pwmCnt ya que necesitaria recargar, y en tiempo me refiero a 8 ciclos mas de reloj.

4-
Buscar donde cambia el valor del puerto e invertirlo antes, es decir esto:

Código: ASM
  1.    pwm_exit:
  2.       out      PortA, status                  ;output

Por

Código: ASM
  1.    pwm_exit:
  2.       com     status
  3.       out      PortA, status                  ;output
  4.       com     status

Agregando 2 instrucciones, Y todo lo demas internamente funcionaria de la misma forma, es decir solo toco lo que va al puerto. invierto e invierto nuevamente por que luego se hace uso de "status" entonces debe mantener el valor sin invertir.
Sino habria que revisar todo el programa. Si solo quisiera invertirlo una ves


------------------------

De recomendar te recomiendo la primera opcion, luego la 4ta, luego la 3era y luego la 2da.

PD: Esto sin conocer los atmega ya que nunca trabaje con ellos, solo mire su set de intrucciones.
bueno yo use ese codigo tal cual esta ., y no tube problemas de invercion en la consola
 
pero eso si ., segui la sujerencias del autor ., para conectar los led y use de 5W (que talvez alli este el problema del amigo )
 
yo lo que siempre intente ., pero no pude lograrlo es copiar o pasr las funciones de FADING o RAIMBON  a C en AVRstuduo (sin DMX)
yo solo se que ...nose nada

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 7802
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #4 en: 01 de Agosto de 2015, 00:06:58 »
Citar
yo lo que siempre intente ., pero no pude lograrlo es copiar o pasr las funciones de FADING o RAIMBON  a C en AVRstuduo (sin DMX)

Realmente yo jamas trabaje con un atmel (ni en C ni en ASM), asi que mi codigo solo fue por curiosidad de ver como era el ASM de los atmega. Debido a que todos los ASM manejan binario no fue dificil entenderlo
Tampoco trabaje con DMX para saber que es o cuales son las funciones FADING y RAIMBON ( o RAINBOW?) como para intentar decirte como pasarlo, lo que si veo es que los efectos parecen estar programados al final del codigo.

Si pasas el codigo en ASM e indicas cual es la parte se podria pasar tranquilamente creo.

Desconectado locodelafonola

  • PIC10
  • *
  • Mensajes: 42
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #5 en: 02 de Agosto de 2015, 16:06:44 »
hola  ., y desde ya muchas gracias por enseñar
Si pasas el codigo en ASM e indicas cual es la parte se podria pasar tranquilamente creo.
bueno aca te paso el codigo de ASM que probe (el anterior ya tambien esta probado y funcionan los dos perfectamente )
esta parte esta solamente los efectos FADING y RAINBOW(corregido su  escritura gracias ) pero todo esto sin DMX
tambien habria que aclarar que las funciones  de FADING de la libreria anterior funcionan si se coloca la llave minidips numero 10 en ON (conectada) adjunto foto del montaje fisico por si tiene dudas
de esa manera desabilita la funcion DMX y queda en modo programado
este codigo que pongo solo es para tres (3) led o sea RGB ., el anterior es para nueve (9) divididos en RGB (8 del puerto A y 1 del puerto B )
y vuelvo a repetir., he probado los dos codigos originales .,  el anterior y el simplificado (este) !!!! y funciona los dos perfectamente ¡¡¡
este es la configuracion que uso (montaje )
Código: [Seleccionar]
; ***********************************************************************************************
; * RGB atenuador + mix colores + stroboscopico + luz discoteca-intermitente *
; * *
; * para ATMega 8515 *
; * *
; * Versión 3.0 - 22/03/2008 *
; * LED en el interruptor MOSFET al puerto B *
; * *
; * *
; * PortB0 = Rojo, PortB1 = Verde, PortB2 = Azul  *
; ***********************************************************************************************

.include "m8515def.inc"

; ------------------------------------------------------------------------------------------------
;           Definir los registros, etc.
; ------------------------------------------------------------------------------------------------

.def temp0 = R16 ;Definir registro
.def temp1 = R17
.def temp2 = R18
.def temp_ZL = R1
.def temp_ZH = R2
.def temp_Sreg = R3
.def Speed = R19
.def R  = R20
.def V  = R21
.def A  = R22
.def R_Out = R4
.def V_Out  = R5
.def A_Out = R6
.def PWM_Count = R23

.equ XTAL = 8000000 ; Sólo para información

; ------------------------------------------------------------------------------------------------
;            Tabla de vectores de interrupción Mega8515
; ------------------------------------------------------------------------------------------------

.CSEG

.org 0x0000

rjmp    Inicio  ; Restablecer controlador
reti ; Interrupción externa Solicitud 0
reti ; Interrupción externa Solicitud 1
reti ; Temporizador / Captura de Counter1
reti ; Timer / Counter1 Comparar Partido A
reti ; Timer / Counter1 Comparar Partido B
reti ; Timer / Counter1 desbordamiento (overflow)
rjmp    ISR_PWM ; Timer / Counter0 desbordamiento (Overflow) -> rutina PWM
reti ; Transferencia serial completa
reti ; Rx completa
reti ; Registro de datos vacía
reti ; Tx completa
reti ; Comparador analógico
reti ; Interrupción externa Solicitud 2
reti ; Timer / Counter0 Comparar Partido (match)
reti ; EEPROM Ready
reti ; almacenado memoria Ready Programa

; ------------------------------------------------------------------------------------------------
;                Puntero de pila , puertos establecidos
; ------------------------------------------------------------------------------------------------

Inicio:

ldi temp0, LOW(RAMEND);Byte bajo de dirección superior RAM BAJA
out SPL, temp0
ldi temp0, HIGH(RAMEND);Byte alto de dirección superior RAM ALTA
out SPH, temp0

ldi     temp0, 0b00000001;Conjunto CS00: 1 divisor
out     TCCR0, temp0

ldi     temp0, (1<<TOIE0);TOIE0: interrumpir el desbordamiento del temporizador
out     TIMSK, temp0

sei          ;Habilitar las interrupciones

ldi temp0, 0
out DDRC, temp0 ;Puerto C en la entrada (interruptor DIP)

ldi temp0, 0b00000001
out DDRE, temp0 ;PortE0 en la salida (LED), 1 y 2 en la entrada
sbi PORTE, 1 ;Pull-up resistencias
sbi PORTE, 2         ;Pull-up resistencias

ldi temp0, 0xff
out DDRB, temp0 ;PortA para establecer la salida (salida PWM)
out PORTC, temp0 ;Habilitar resistencias pull-up en PORTC

sbi DDRD, 7 ;PortD7 en la salida ("On" LED)

; ------------------------------------------------------------------------------------------------
; "Estado fundamental" - Colores y Strobo, ajustables mediante interruptores DIP switch
; ------------------------------------------------------------------------------------------------

Interruptor_Loop:    ;Comprobar el interruptor DIP

sbis PINC, 6   ;El interruptor 7 está apagado, más
rcall RGB_Fader  ;Cambie a -> RGB atenuador

sbis PINC, 5   ;El interruptor 6 está apagado, más
rcall Disco   ;Cambie a -> Indicador de Disco

cbi PORTE, 0  ;LED de estado encendido

sbic PINC, 3   ;Comprobar el interruptor 4 (medio Verde / corrección de color rosa)
rjmp Mixcolores   ;No se requiere corrección, "lo más normal"

in temp1, PINC ;Comprobar dip switch
andi temp1, 0b00000111 ;Caso especial "blanco"
brne Mixcolores   ;no todos los interruptores (no blanco), por lo que otros colores

ldi R, 220   ;menos rojo porque ajustado a rosa rebelde
ldi V, 255
ldi A, 255
rcall Dimmercurva ;Corrección y de salida Brillo

rjmp Strobo ;Saltarse la configuración del color, además Strobo

Mixcolores:

ldi R, 255 ;encendido de rojo
sbic PINC, 0 ;Comprobar el interruptor 1 (Rojo)
ldi R, 0 ;El interruptor está apagado,apagado de rojo

ldi V, 0 ;apagado de verde
sbic PINC, 1 ;Comprobar el interruptor 2 (Verde)
rjmp azul ;El interruptor está apagado, más
ldi V, 255 ;encendido de verde
sbis PINC, 3 ;Comprobar el interruptor 4 (media Verde / corrección de color de rosa)
ldi V, 128 ;si el interruptor encendido , la mitad verde

azul:

ldi A, 255 ;encendido de Azul
sbic PINC, 2 ;Comprobar el interruptor 3 (azul)
ldi A, 0 ;El interruptor está apagado, apagado de azul

rcall Dimmercurva ;Corrección y de salida Brillo

Strobo:

sbic PINC, 4 ;Revise el interruptor 5 (estroboscópico)
rjmp Interruptor_Loop ;no Apagar, 

;// ------------------------------------------------------------------------------------------------//
;              Strobo - estroboscópica
;// ------------------------------------------------------------------------------------------------//
ldi Speed, 255 ;Strobo velocidad básica

sbic PINC, 7 ;Interruptor 8 chequea (Rojo / Azul Strobe)
rjmp Strobo_normal ;interuptor apagado, Strobo normales

ldi R, 255 ;Rojo
ldi V, 0    ;verde
ldi A, 0    ;azul
rcall Dimmercurva ;Corrección y de salida Brillo

cbi PORTE, 0 ;LED de estado encendido

ldi temp1, 2 ;durante 2 ciclos rojo

Strobo_rojo:

rcall esperar

dec temp1
brne Strobo_rojo


ldi R, 0 ;rojo apagado
ldi v, 0    ;verde apagado
ldi A, 0    ;azul apagado
rcall Dimmercurva ;Corrección y de salida Brillo

sbi PORTE, 0 ;LED de estado apagado

ldi temp1, 10 ;y 10 ciclos de apagado

Strobo_rojo_desde:

rcall esperar

dec temp1
brne Strobo_rojo_desde

ldi R, 0 ;rojo apagado
ldi V, 0    ;verde apagado
ldi A, 255  ;azul encendido
rcall Dimmercurva ;Corrección y de salida Brillo

cbi PORTE, 0 ;LED de estado encendido

ldi temp1, 2 ;durante 2 ciclos azul

Strobo_azul:

rcall esperar

dec temp1
brne Strobo_azul

ldi R, 0 ;rojo apagado
ldi V, 0    ;verde apagado
ldi A, 0    ;azul apagado
rcall Dimmercurva ;Corrección y de salida Brillo

sbi PORTE, 0 ;LED de estado apagado

ldi temp1, 10 ;y 10 ciclos de apagado

Strobo_azul_desde:

rcall esperar

dec temp1
brne Strobo_azul_desde

rjmp Interruptor_Loop

Strobo_normal:

ldi temp1, 2 ;durante 2 ciclos

Strobo_a:

rcall esperar

dec temp1
brne Strobo_a


ldi R, 0 ;rojo apagado
ldi V, 0    ;verde apagado
ldi A, 0    ;azul apagado
rcall Dimmercurva ;Corrección y de salida Brillo

sbi PORTE, 0 ;LED de estado apagado

ldi temp1, 10 ;y 10 ciclos de apagado

Strobo_desde:

rcall esperar

dec temp1
brne Strobo_desde

rjmp Interruptor_Loop

; ------------------------------------------------------------------------------------------------
;      Atenuacion o Fader General sin cambiar el valor del brillo(fading) rutina 1
; ------------------------------------------------------------------------------------------------

RGB_Fader:

ldi Speed, 127 ;Velocidad del módo básico en espera

RGB_Loop:

ldi R, 255 ;rojo encendido
ldi V, 0    ;verde apagado
ldi A, 0    ;azul apagado
rcall Dimmercurva ;Corrección y de salida Brillo

cbi PORTE, 0 ;LED de estado encendido

rojo_amarillo: ;verde apagado -> pasa a amarillo

sbic PINC, 6 ;Interruptor 7 encendido continuar con Fader
rjmp RGB_fin ;interuptor apagado -> Detener RGB atenuador

sbis PINC, 7 ;Revise el interruptor 8 ("Fader 2")?
rcall Rainbow_Fader ;Cambie a seguir el programa 2

rcall esperar

sbi PORTE,0 ;LED de estado apagado

inc V
rcall Dimmercurva ;Corrección y de salida Brillo
cpi V, 255
brlo rojo_amarillo

cbi PORTE, 0 ;LED de estado encendido

amarillo_verde: ;amarillo apagado -> pasa a Verde

sbic PINC, 6 ;Interruptor 7 encendido continuar con Fader
rjmp RGB_fin ;interuptor apagado -> Detener RGB atenuador

sbis PINC, 7 ;Revise el interruptor 8 ("Fader 2")?
rcall Rainbow_Fader ;Cambie a seguir el programa 2

rcall esperar

sbi PORTE,0    ;LED de estado apagado

dec R
rcall Dimmercurva ;Corrección y de salida Brillo
brne amarillo_verde

cbi PORTE, 0 ;LED de estado encendido

verde_cyan: ;verde apagado -> pasa a Cyan

sbic PINC, 6 ;Interruptor 7 encendido continuar con Fader
rjmp RGB_fin ;interuptor apagado -> Detener RGB atenuador

sbis PINC, 7 ;Revise el interruptor 8 ("Fader 2")?
rcall Rainbow_Fader ;Cambio, a seguir el programa 2

rcall esperar

sbi PORTE,0 ;LED de estado apagado

inc A
rcall Dimmercurva ;Corrección y de salida Brillo
cpi A, 255
brlo verde_cyan

cbi PORTE, 0     ;LED de estado encendido

cyan_azul: ;cyan apagado -> pasa a Azul

sbic PINC, 6 ;Interruptor 7 encendido continuar con Fader
rjmp RGB_fin ;interuptor apagado -> Detener RGB atenuador

sbis PINC, 7 ;Revise el interruptor 8 ("Fader 2")?
rcall Rainbow_Fader ;Cambio a seguir el programa 2

rcall esperar

sbi PORTE,0 ;LED de estado apagado

dec V
rcall Dimmercurva ;Corrección y de salida Brillo
brne cyan_azul

cbi PORTE, 0     ;LED de estado en

azul_magenta: ;azul apagado -> pasar a Magenta

sbic PINC, 6 ;Interruptor 7 encendido continuar con Fader
rjmp RGB_fin ;interuptor apagado -> Detener RGB atenuador

sbis PINC, 7 ;Revise el interruptor 8 ("Fader 2")?
rcall Rainbow_Fader ; Cambio , a seguir el programa 2

rcall esperar

sbi PORTE,0 ;LED de estado apagado

inc R
rcall Dimmercurva ;Corrección y de salida Brillo
cpi R, 255
brlo azul_magenta

cbi PORTE, 0 ;LED de estado en

magenta_rojo: ;magenta apagado -> pasa a rojo

sbic PINC, 6 ;Interruptor 7 encendido continuar con Fader
rjmp RGB_fin ;interuptor apagado -> Detener RGB atenuador

sbis PINC, 7 ;Revise el interruptor 8 ("Fader 2")?
rcall Rainbow_Fader ;Cambio , a seguir el programa 2

rcall esperar

sbi PORTE,0 ;LED de estado apagado

dec A
rcall Dimmercurva ;Corrección y de salida Brillo
brne magenta_rojo

rjmp RGB_Loop ;Fader-ciclo repetitivo desde el principio

RGB_fin:

ret

; ------------------------------------------------------------------------------------------------
;           Rainbow-Fader 2 -- "funcion Rainbow" atenuador 2
; ------------------------------------------------------------------------------------------------

Rainbow_Fader:

mov temp0, R  ;definicion de Colores fijos para diferentes atenuaciones
mov temp1, V  ;definicion de Colores fijos para diferentes atenuaciones
mov temp2, A  ;definicion de Colores fijos para diferentes atenuaciones

ldi Speed, 254 ;Velocidad del módo básico en espera

Rainbow_Loop:

ldi R, 255 ;primero ,tiempo del colr rojo encendido
ldi V, 0        ;tiempo de verde CERO
ldi A, 0        ;tiempo de azul CERO
rcall Dimmercurva ;Corrección y de salida Brillo

cbi PORTE, 0 ;LED de estado encendido

rojo_verde: ;Ocultar Rojo, Mostrar Verde

sbic PINC, 7 ;Interruptor 8 está encendido, continúe con el fader 2
rjmp Rainbow_fin ;Switch -> volver a RGB-faders 1

rcall esperar

sbi PORTE,0 ;LED de estado apagado

dec R
inc V
rcall Dimmercurva ;Corrección y de salida Brillo
cpi V, 255
brlo rojo_verde

cbi PORTE, 0 ;LED de estado encendido

verde_azul: ;Ocultar Verde, mostrar Azul

sbic PINC, 7 ;Interruptor 8 está encendido, continúe con el fader 2
rjmp Rainbow_fin ;interuptor apagado -> volver a RGB-faders 1

rcall esperar

sbi PORTE,0 ;LED de estado apagado

dec V
inc A
rcall Dimmercurva ;Corrección y de salida Brillo
cpi A, 255
brlo verde_azul

cbi PORTE, 0 ;LED de estado encendido

azul_rojo:              ;Ocultar Azul, Mostrar Rojo

sbic PINC, 7 ;Interruptor 8 está encendido, continúe con el fader 2
rjmp Rainbow_fin ;iteruptor apagado -> volver a faders RGB 1

rcall esperar

sbi PORTE,0 ;LED de estado apagado

dec A
inc R
rcall Dimmercurva ;Corrección y de salida Brillo
cpi R, 255
brlo azul_rojo

cbi PORTE, 0   ;LED de estado encendido

rjmp Rainbow_Loop  ;LED de Estado encendido

Rainbow_fin:

mov R, temp0 ;Restaurar colores para diferentes atenuaciones
mov V, temp1    ;Restaurar colores para diferentes atenuaciones
mov A, temp2    ;Restaurar colores para diferentes atenuaciones

ret

; ------------------------------------------------------------------------------------------------
;         "Disco-Blink"-Routine -- Rutina "Disco Blink"
; ------------------------------------------------------------------------------------------------

Disco:

in temp1, PINC ;Comprobar el interruptor DIP-swch
andi temp1, 0b00000011 ;sólo está interesado en los dos primeros, PC0 y PC1
mov temp2, temp1 ;lamado ,para ver si el interruptor cambió su estado

cpi temp1, 0b00000011 ;Programa 1
brne Disco_P2
ldi     ZL, LOW(Disco_Mixcolores_1*2) ;Z-puntero, Cargar programa 1
        ldi     ZH, HIGH(Disco_Mixcolores_1*2)
rjmp Disco_Loop

Disco_P2:

cpi temp1, 0b00000001 ;Programa 2
brne Disco_P3
ldi     ZL, LOW(Disco_Mixcolores_2*2) ;Z-puntero, Cargar programa 2
        ldi     ZH, HIGH(Disco_Mixcolores_2*2)
rjmp Disco_Loop

Disco_P3:

cpi temp1, 0b00000010 ;Programa 3
brne Disco_P4
ldi     ZL, LOW(Disco_Mixcolores_3*2) ;Z-puntero, Cargar programa 3
        ldi     ZH, HIGH(Disco_Mixcolores_3*2)
rjmp Disco_Loop

Disco_P4:

ldi     ZL, LOW(Disco_Mixcolores_4*2) ;Cargar programa Z-puntero 4
        ldi     ZH, HIGH(Disco_Mixcolores_4*2)

Disco_Loop:

lpm Speed, Z+ ;Compruebe la velocidad / "bandera final"
tst Speed ;Se ha llegado al final de la muestra de la mesa?
breq Disco ;Sí, empezar de nuevo

in temp1, PINC ;Comprobar el interruptor DIP
andi temp1, 0b00000011 ;sólo está interesado en los dos primeros
cp temp2, temp1 ;Si cambia el interruptor DIP?
brne Disco ;Sí, reiniciar con un nuevo programa

cbi PORTE, 0 ;LED de estado encendido

lpm R, Z+ ;Elija los colores de la tabla
lpm V, Z+
lpm A, Z+
rcall Dimmercurva ;Corrección de brillo

ldi temp0, 64 ;tiempo de la funcion Discoteca Básica intermitente

Disco_esperar:

sbic PINC, 5 ;El interruptor 6 está encendido, continúe con funcion "disco"
ret ;interuptor apagado -> Detener Disco

rcall esperar

sbi PORTE,0 ;LED de estado apagado

dec temp0
brne Disco_esperar

rjmp Disco_Loop ;Color siguiente

; ------------------------------------------------------------------------------------------------
; Las tablas de colores para los colores del indicador Disco
; Byte primero = velocidad / extremo (255), los bytes 2-4 = R, G, B
; ------------------------------------------------------------------------------------------------

Disco_Mixcolores_1:

.db 128,255,0,0 ;Rojo
.db 128,0,255,0 ;Verde
.db 128,0,0,255 ;Azul
.db 128,255,0,0 ;Rojo
.db 128,0,255,0 ;Verde
.db 128,0,0,255 ;Azul
.db 64,255,0,0 ;Rojo
.db 64,0,255,0 ;Verde
.db 64,0,0,255 ;Azul
.db 64,255,0,0 ;Rojo
.db 64,0,255,0 ;Verde
.db 64,0,0,255 ;Azul
.db 128,0,255,255 ;Cyan
.db 128,255,0,255 ;Magenta
.db 128,255,255,0 ;Amarillo
.db 128,0,255,255 ;Cyan
.db 128,255,0,255 ;Magenta
.db 128,255,255,0 ;Amarillo
.db 64,0,255,255 ;Cyan
.db 64,255,0,255 ;Magenta
.db 64,255,255,0 ;Amarillo
.db 64,0,255,255 ;Cyan
.db 64,255,0,255 ;Magenta
.db 64,255,255,0 ;Amarillo
.db 0,0 ;Fin de la Tabla

Disco_Mixcolores_2:

.db 128,255,0,0 ;Rojo
.db 128,0,0,255 ;Azul
.db 128,210,255,255 ;Blanco
.db 128,255,0,0 ;Rojo
.db 128,0,0,255 ;Azul
.db 128,210,255,255 ;Blanco
.db 64,255,0,0 ;Rojo
.db 64,0,0,255 ;Azul
.db 64,210,255,255 ;Blanco
.db 64,255,0,0 ;Rojo
.db 64,0,0,255 ;Azul
.db 64,210,255,255 ;Blanco
.db 128,255,0,0 ;Rojo
.db 128,0,0,255 ;Azul
.db 128,210,255,255 ;Blanco
.db 128,255,0,0 ;Rojo
.db 128,0,0,255 ;Azul
.db 128,210,255,255 ;Blanco
.db 64,255,0,0 ;Rojo
.db 64,0,0,255 ;Azul
.db 64,210,255,255 ;Blanco
.db 64,255,0,0 ;Rojo
.db 64,0,0,255 ;Azul
.db 64,210,255,255 ;Blanco
.db 128,255,0,0 ;Rojo
.db 128,210,255,255 ;Blanco
.db 128,0,0,255 ;Azul
.db 128,210,255,255 ;Blanco
.db 128,255,0,0 ;Rojo
.db 128,210,255,255 ;Blanco
.db 128,0,0,255 ;Azul
.db 128,210,255,255 ;Blanco
.db 0,0 ;Fin de la Tabla

Disco_Mixcolores_3:

.db 255,255,90,0 ;Naranja
.db 255,0,0,255 ;Azul
.db 255,255,128,0 ;Naranja
.db 255,0,255,255 ;Cyan
.db 255,255,128,0 ;Naranja
.db 255,0,255,0 ;Verde
.db 255,255,128,0 ;Naranja
.db 255,255,0,255 ;Magenta
.db 255,0,0,255 ;Azul
.db 255,255,0,255 ;Magenta
.db 255,0,255,255 ;Cyan
.db 255,255,0,255 ;Magenta
.db 255,255,255,0 ;Amarillo
.db 255,0,255,0 ;Verde
.db 0,0 ;Fin de la Tabla

Disco_Mixcolores_4:

.db 64,255,0,0 ;Rojo
.db 64,0,0,0 ;empieza
.db 64,0,255,255 ;Cyan
.db 64,0,0,0 ;empieza
.db 64,255,128,0 ;Naranja
.db 64,0,0,0 ;empieza
.db 64,0,255,0 ;Verde
.db 64,0,0,0 ;empieza
.db 64,255,0,255 ;Magenta
.db 64,0,0,0 ;empieza
.db 64,255,255,0 ;Amarillo
.db 64,0,0,0 ;empieza
.db 64,0,0,255 ;Azul
.db 64,0,0,0 ;empieza
.db 64,255,255,0 ;Amarillo
.db 64,0,0,0 ;empieza
.db 0,0 ;Fin de la Tabla

; ------------------------------------------------------------------------------------------------
;              ISR para PWM por software
; ------------------------------------------------------------------------------------------------

ISR_PWM:    ;Salida PWM
 
        push temp0
        in    temp0, SREG
        push temp0

        ldi     temp0, 0b00000111 ;Estado fundamental 1 = LED encendido, 0 = LED apagado (porque FET)

inc     PWM_Count         ;el contador de PWM de 0 a ++++
 
 
        cp      PWM_Count, R_Out  ;Si se alcanza el límite para el rojo?
        brlo    PWM_V   ;no, pase a verde
        andi    temp0, 0b00000110 ;sí, LED rojo apagado

PWM_V:
 
        cp      PWM_Count, V_Out  ;Si se alcanza el límite para el verde?
        brlo    PWM_A   ;no, pase a azul
        andi    temp0, 0b00000101 ;Sí, LED verde apagado

PWM_A:

        cp      PWM_Count, A_Out  ;Si se alcanza el límite para el azul?
        brlo    PWM_edicion   ;Si no es así, seguir emitiendo
        andi    temp0, 0b00000011 ;sí, LED azul desde
 
PWM_edicion:                    ;Emisión de nueva asignación de bits

        out     PORTB, temp0
 
pop temp0
        out SREG, temp0 ;Restaurar el registro de estado + temp0
pop temp0

reti

; ------------------------------------------------------------------------------------------------
;                 Conversión dimmer transferencia curva en el registro PWM
; ------------------------------------------------------------------------------------------------

Dimmercurva:

push temp0
in temp0, SREG ;Guardar registros
push temp0
mov temp_ZL, ZL
mov temp_ZH, ZH

ldi     ZL, LOW(DC_Data*2) ;Carga Z-puntero empezar valores dimmer bajo
        ldi     ZH, HIGH(DC_Data*2)  ;Carga Z-puntero empezar valores dimmer alto

add     ZL, R ;Añadir valor de rojo, de 16 bit+
    ldi     temp0,0                   
    adc     ZH,temp0

lpm R_Out, Z ;Obtener el valor de la tabla

ldi     ZL, LOW(DC_Data*2) ;Carga Z-puntero empezar valores dimmer bajo
        ldi     ZH, HIGH(DC_Data*2) ;Carga Z-puntero empezar valores dimmer alto

add     ZL, V ;Añadir valor verde, 16 bits
    ldi     temp0,0                   
    adc     ZH,temp0

lpm V_Out, Z ;Obtener el valor de la tabla

ldi     ZL, LOW(DC_Data*2) ;Carga Z-puntero empezar valores dimmer bajo
        ldi     ZH, HIGH(DC_Data*2) ;Carga Z-puntero empezar valores dimmer alto

add     ZL, A ;Añadir valor azul, 16 bit
    ldi     temp0,0                   
    adc     ZH,temp0

lpm A_Out, Z ;Obtener el valor de la tabla

pop temp0
out SREG, temp0 ;Restaurar registro
pop temp0
mov ZL, temp_ZL
mov ZH, temp_ZH

ret

; ------------------------------------------------------------------------------------------------
;       Los datos para la curva de dimmer -DIMERCURVA
; ------------------------------------------------------------------------------------------------

DC_Data:

.db     0,   0,   1,   1,   1,   1,   1,   2
.db     2,   2,   2,   3,   3,   3,   4,   4
.db     4,   5,   5,   5,   6,   6,   7,   7
.db     8,   8,   9,   9,  10,  10,  11,  11
.db    12,  12,  13,  13,  14,  14,  15,  15
.db    16,  16,  17,  17,  18,  18,  19,  19
.db    20,  20,  21,  21,  22,  22,  23,  23
.db    24,  24,  25,  25,  26,  27,  28,  29
.db    30,  30,  31,  32,  33,  34,  35,  36
.db    36,  37,  38,  39,  40,  41,  42,  43
.db    43,  44,  45,  46,  47,  48,  49,  50
.db    51,  52,  52,  53,  54,  55,  56,  57
.db    58,  59,  60,  61,  62,  63,  64,  65
.db    66,  67,  68,  69,  70,  71,  72,  73
.db    74,  75,  76,  77,  78,  79,  80,  81
.db    82,  83,  84,  85,  86,  88,  89,  90
.db    91,  92,  93,  94,  95,  96,  97,  98
.db    99, 100, 102, 103, 104, 105, 106, 107
.db   108, 109, 110, 112, 113, 114, 115, 116
.db   117, 119, 120, 121, 122, 123, 124, 126
.db   127, 128, 129, 130, 132, 133, 134, 135
.db   136, 138, 139, 140, 141, 142, 144, 145
.db   146, 147, 149, 150, 151, 152, 154, 155
.db   156, 158, 159, 160, 161, 162, 164, 165
.db   167, 168, 169, 171, 172, 173, 174, 176
.db   177, 178, 180, 181, 182, 184, 185, 187
.db   188, 189, 191, 192, 193, 195, 196, 197
.db   199, 200, 202, 203, 204, 206, 207, 208
.db   210, 211, 213, 214, 216, 217, 218, 220
.db   221, 223, 224, 226, 227, 228, 230, 231
.db   233, 234, 236, 237, 239, 240, 242, 243
.db   245, 246, 248, 249, 251, 252, 254, 255

; ------------------------------------------------------------------------------------------------
;          Bucle de temporisacion de espera (delay)
; ------------------------------------------------------------------------------------------------

esperar:    ;3 loops de espera (delay)

        push temp2 ;Registro de estado Temp + asegurar
        push temp1
        push temp0
in    temp0, SREG
        push temp0

mov temp0, Speed ;Velocidad de registro "Speed"

loop0:

ldi temp1, 255 ;255 repeticiones
sbis PINE, 2 ;Dip en 9? -> Duración maxima
ldi temp1, 64

loop1:

ldi temp2, 2 ;2 repeticiones
sbis PINE, 1 ;Dip en 10? -> Duracion Medio tiempo
ldi temp2, 1

loop2:                         

dec     temp2
brne    loop2

dec     temp1
brne    loop1

dec     temp0
brne    loop0

        pop temp0
out SREG, temp0 ;Estado del registro + Restaurar Temporizador
        pop temp0
pop temp1
pop temp2

ret

; ------------------------------------------------------------------------------------------------
;               ternminacion de programa y Cierre
; ------------------------------------------------------------------------------------------------

fin: rjmp fin

 
las funciones que tiene con las llaves son
  • DIP 1-3: rojo, verde, azul, respectivamente, de encendido / apagado - es decir, 7 colores (. Incl Blanco) - (DIP 1 y 2)usados tambien en lafuncion  "Disco", ver más abajo
  • DIP 4: En colores mezclados aquí el verde se reduce para producir naranja, es en blanco ., de modo conmutado la corrección es a deshacerse .,  del tinte rosado del rojo intenso principal (las líneas se comentan en el programa) , aquí puede introducir otros valores si, por ejemplo (como se muestra a continuación) si el led es de 5 mm .,con un débil el rojo ., tiene similares resultados .... resultado llegado más tarde: puede ser ell "  Rosa blanco" ., de hecho se puede ajustar, y luego cambiar a este interruptor, por ejemplo, entre el blanco cálido y blanco frío ....
  • DIP 5: Entra en el "Strobe" a - el color actualmente ajustado parpadea / parpadea en la velocidad establecida ... con un valor fijo de encendido / apagado proporción de 02:10, por lo que el "parpadeo" más es mas lento , podría cambiar, pero me ha gustado mucho como queda alli  ...
    Recuadro: aquí esta la funcion por si alguien quiere construir un Strobo con LEDs, este ejemplo se puede usar , que es probablemente demasiado débil por la potencia de los led  (pero con varios juntos queda muy bien) - pero tengo que decir que los dos led RGB Estrella., en 200 mA puede mantener fácilmente un Strobo, por ejemplo, 3 de 750 mA debe ser lo suficientemente fácil para la sala de fiestas - de esta manera ., entonces sigue siendo facil que usted pueda "parpadear" ese color ....
  • DIP 6: Cambia el "disco-programas" - con DIP 1 y 2 a continuación, puede seleccionar varios (4 combinaciones )
  • DIP 7: se enciende el fader RGB
  • DIP 8: si el fader RGB se activa , es por este contacto que se activa el "Time Adjust" (tiempo de ajuste ) - cuando el estrobo está funcionando, puede aquí (rojo y azul parpadean alternativamente) en un interruptor "programa especial" - que tenia que ser el modo fácil ... 
  • DIP 9 + 10: Velocidad (para Fader, Strobo, indicadores Disco) - ambos de = "velocidad de avance", 10 = el doble de rápido, a las 9 = 4x, 8x, tanto a =
« Última modificación: 02 de Agosto de 2015, 16:09:30 por locodelafonola »
yo solo se que ...nose nada

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 7802
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #6 en: 02 de Agosto de 2015, 19:18:23 »
No pase todo a C solo, la parte del fading y rainbow_fading, tampoco pase la parte del PWM por software, ya que eso es hacerlo con una interrupcion cada X tiempo ( dado por el valor que se le carga al timer ) y ahi usar V_out,R_out y A_out, para comparar con el PWM por soft


un poco burdo el programa y seguro que se puede mejorar mas:
Código: C
  1. const short int arraydimmer[256]={0,0,1,1,......,251,252,254,255};  // Lo que aparece como DC_Data
  2. Short int velocidad,Rojo,Verde,Azul,V_out,R_out,A_out;
  3.  
  4.  
  5.  
  6. void main() {
  7.  
  8.         if(!PINC6){ fading();}
  9.         if(!PINC5){ disco();}
  10.         /*
  11.         Aca mas codigo que realmente no influye en nada
  12.         */
  13. }
  14.  
  15.  
  16.  
  17. void fading() {
  18.  
  19.         Velocidad = 127;
  20.  
  21.         while(!PINC6)
  22.         {
  23.                 Rojo = 255;
  24.                 Verde = 0;
  25.                 Azul = 0;
  26.  
  27.                 DimmerCurva()
  28.                 PORTE0 = 0;
  29.  
  30.         //rojo_amarillo
  31.                 while(Verde!=255 && !PINC6)
  32.                 {
  33.                         if(PINC7) { rainbow_fader();}
  34.                         delay(velocidad);
  35.                         PORTE0 = 1;
  36.                         Verde++;
  37.                         DimmerCurva();
  38.                 }
  39.                 PORTE0 = 0;
  40.  
  41.         //amarillo_verde
  42.                 while(Rojo && !PINC6)
  43.                 {
  44.                         if(PINC7) { rainbow_fader();}
  45.                         delay(velocidad);  //esperar
  46.                         PORTE0 = 1;
  47.                         Rojo--;
  48.                         DimmerCurva();
  49.                 }
  50.                 PORTE0 = 0;
  51.  
  52.         //verde_cyan
  53.                 while(Azul!=255 && !PINC6)
  54.                 {
  55.                         if(PINC7) { rainbow_fader();}
  56.                         delay(velocidad);  //esperar
  57.                         PORTE0 = 1;
  58.                         Azul++;
  59.                         DimmerCurva();
  60.                 }
  61.                 PORTE0 = 0;
  62.  
  63.         //cyan_azul
  64.                 while(Verde && !PINC6)
  65.                 {
  66.                         if(PINC7) { rainbow_fader();}
  67.                         delay(velocidad);  //esperar
  68.                         PORTE0 = 1;
  69.                         Verde--;
  70.                         DimmerCurva();
  71.                 }
  72.                 PORTE0 = 0;
  73.  
  74.         //azul_magenta
  75.                 while(Rojo!=255 && !PINC6)
  76.                 {
  77.                         if(PINC7) { rainbow_fader();}
  78.                         delay(velocidad);  //esperar
  79.                         PORTE0 = 1;
  80.                         Rojo++;
  81.                         DimmerCurva();
  82.                 }
  83.                 PORTE0 = 0;
  84.        
  85.         //magenta_rojo
  86.                 while(Azul && !PINC6)
  87.                 {
  88.                         if(PINC7) { rainbow_fader();}
  89.                         delay(velocidad);  //esperar
  90.                         PORTE0 = 1;
  91.                         Azul--;
  92.                         DimmerCurva();
  93.                 }
  94.                 PORTE0 = 0;
  95.         }
  96. }
  97.  
  98. void delay(int velocidad) {
  99.  
  100.         delay_ciclos();  // La cantida de ciclos va a depender de los siwthc que estan conectados a PINE2 y PINE1
  101.                          // Si podes simularlo con velocidad = 1 para saber que valor tenes que multiplicar a velocidad, es por que no se la cantidad de ciclos que consume cada instruccion
  102.  
  103. //temp2 = 1  si PINE1 = 0 sino temp2=2
  104. //temp1 = 64 si PINE2 = 0 sino temp1=255
  105.  
  106. /*
  107.  
  108. Ciclos a esperar
  109.  
  110. temp2=1 temp1=255
  111. 11445 * (velocidad-1) +28
  112.  
  113. temp2=1 temp1=64
  114. 2895 * (velocidad -1) +28
  115.  
  116. temp2=2 temp1=255
  117. 18303 * (velocidad-1) +28
  118.  
  119. temp2=2 temp1=64
  120. 4551 * (velocidad-1) +28
  121. */
  122. }
  123.  
  124.  
  125. void rainbow_fader(){
  126.  
  127.         int Temp_R,Temp_A,Temp_V;
  128.         Velocidad = 254;
  129.         Temp_R = Rojo;
  130.         Temp_A = Azul;
  131.         Temp_V = Verde;
  132.  
  133.         while(PINC7)
  134.         {
  135.                 Rojo = 255;
  136.                 Verde = 0;
  137.                 Azul = 0;
  138.                 DimmerCurva();
  139.                 PORTE0 = 0;
  140.  
  141.         //rojo_verde
  142.                 while(Verde!=255 && PINC7)
  143.                 {
  144.                         delay(velocidad);
  145.                         PORTE=1;
  146.                         Rojo--;
  147.                         Verde++;
  148.                         DimmerCurva();
  149.                 }
  150.                 PORTE0=0;
  151.  
  152.         //verde_azul
  153.                 while(Azul!=255 && PINC7)
  154.                 {
  155.                         delay(velocidad);
  156.                         PORTE=1;
  157.                         Verde--;
  158.                         Azul++;
  159.                         DimmerCurva();
  160.                 }
  161.                 PORTE0=0;
  162.  
  163.         //azul_rojo
  164.                 while(Rojo!=255 && PINC7)
  165.                 {
  166.                         delay(velocidad);
  167.                         PORTE=1;
  168.                         Azul--;
  169.                         Rojo++;
  170.                         DimmerCurva();
  171.                 }
  172.                 PORTE0=0;
  173.         }
  174.  
  175.         Rojo = Temp_R;
  176.         Azul = Temp_A;
  177.         Verde = Temp_V;
  178.  
  179. }
  180.  
  181. void DimmerCurva(){
  182.  
  183.         R_out=arraydimmer[Rojo];
  184.         V_out=arraydimmer[Verde];
  185.         A_out=arraydimmer[Azul];
  186.  
  187. }

Si observas ahi donde puse el delay, eso depende de las llaves, el cual van a cambiar el valor de temp1 y temp2, si no me equivoque eso son los ciclos que requieren segun cada caso.

Código: ASM
  1. esperar:                ;3 loops de espera (delay)
  2.  
  3.                 push    temp2           ; 3 ciclos rcall
  4.                 push    temp1
  5.                 push    temp0
  6.                 in      temp0, SREG
  7.                 push    temp0
  8.  
  9.                 mov     temp0, Speed    ; 10 ciclos
  10.  
  11. loop0:
  12.  
  13.                 ldi     temp1, 255      ; 3 ciclos
  14.                 sbis    PINE, 2         ;
  15.                 ldi     temp1, 64
  16.  
  17. loop1:
  18.  
  19.                 ldi     temp2, 2        ; 3 ciclos
  20.                 sbis    PINE, 1         ;
  21.                 ldi     temp2, 1
  22.  
  23. loop2:                          
  24.  
  25.                 dec     temp2           ; (temp2-1)*3+2
  26.                 brne    loop2
  27.  
  28.                 dec     temp1           ; (temp1-1)*3+2 ( acumulado esto multiplicado por lo de temp2)
  29.                 brne    loop1
  30.  
  31.                 dec     temp0           ; (temp0-1)*3+2
  32.                 brne    loop0
  33.  
  34.                 pop     temp0
  35.                 out     SREG, temp0     ; 9 ciclos
  36.                 pop     temp0
  37.                 pop     temp1
  38.                 pop     temp2
  39.  
  40.                 ret                     ; 4 ciclos

Hacer una formula para eso se llenaria de parentesis, asi que no la pongo.
« Última modificación: 02 de Agosto de 2015, 19:21:50 por KILLERJC »

Desconectado locodelafonola

  • PIC10
  • *
  • Mensajes: 42
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #7 en: 04 de Agosto de 2015, 01:04:04 »
 hola y gracias
No pase todo a C solo, la parte del fading y rainbow_fading, tampoco pase la parte del PWM por software, ya que eso es hacerlo con una interrupcion cada X tiempo ( dado por el valor que se le carga al timer ) y ahi usar V_out,R_out y A_out, para comparar con el PWM por soft
un poco burdo el programa y seguro que se puede mejorar mas:
Código: C
  1. const short int arraydimmer[256]={0,0,1,1,......,251,252,254,255};  // Lo que aparece como DC_Data
  2. Short int velocidad,Rojo,Verde,Azul,V_out,R_out,A_out;
  3.  
  4.  
  5.  
  6. void main() {
  7.  
  8.         if(!PINC6){ fading();}
  9.         if(!PINC5){ disco();}
  10.         /*
  11.         Aca mas codigo que realmente no influye en nada
  12.         */
  13. }
  14.  
  15.  
  16.  
  17. void fading() {
  18.  
  19.         Velocidad = 127;
  20.  
  21.         while(!PINC6)
  22.         {
  23.                 Rojo = 255;
  24.                 Verde = 0;
  25.                 Azul = 0;
  26.  
  27.                 DimmerCurva()
  28.                 PORTE0 = 0;
  29.  
  30.         //rojo_amarillo
  31.                 while(Verde!=255 && !PINC6)
  32.                 {
  33.                         if(PINC7) { rainbow_fader();}
  34.                         delay(velocidad);
  35.                         PORTE0 = 1;
  36.                         Verde++;
  37.                         DimmerCurva();
  38.                 }
  39.                 PORTE0 = 0;
  40.  
  41.         //amarillo_verde
  42.                 while(Rojo && !PINC6)
  43.                 {
  44.                         if(PINC7) { rainbow_fader();}
  45.                         delay(velocidad);  //esperar
  46.                         PORTE0 = 1;
  47.                         Rojo--;
  48.                         DimmerCurva();
  49.                 }
  50.                 PORTE0 = 0;
  51.  
  52.         //verde_cyan
  53.                 while(Azul!=255 && !PINC6)
  54.                 {
  55.                         if(PINC7) { rainbow_fader();}
  56.                         delay(velocidad);  //esperar
  57.                         PORTE0 = 1;
  58.                         Azul++;
  59.                         DimmerCurva();
  60.                 }
  61.                 PORTE0 = 0;
  62.  
  63.         //cyan_azul
  64.                 while(Verde && !PINC6)
  65.                 {
  66.                         if(PINC7) { rainbow_fader();}
  67.                         delay(velocidad);  //esperar
  68.                         PORTE0 = 1;
  69.                         Verde--;
  70.                         DimmerCurva();
  71.                 }
  72.                 PORTE0 = 0;
  73.  
  74.         //azul_magenta
  75.                 while(Rojo!=255 && !PINC6)
  76.                 {
  77.                         if(PINC7) { rainbow_fader();}
  78.                         delay(velocidad);  //esperar
  79.                         PORTE0 = 1;
  80.                         Rojo++;
  81.                         DimmerCurva();
  82.                 }
  83.                 PORTE0 = 0;
  84.        
  85.         //magenta_rojo
  86.                 while(Azul && !PINC6)
  87.                 {
  88.                         if(PINC7) { rainbow_fader();}
  89.                         delay(velocidad);  //esperar
  90.                         PORTE0 = 1;
  91.                         Azul--;
  92.                         DimmerCurva();
  93.                 }
  94.                 PORTE0 = 0;
  95.         }
  96. }
  97.  
  98. void delay(int velocidad) {
  99.  
  100.         delay_ciclos();  // La cantida de ciclos va a depender de los siwthc que estan conectados a PINE2 y PINE1
  101.                          // Si podes simularlo con velocidad = 1 para saber que valor tenes que multiplicar a velocidad, es por que no se la cantidad de ciclos que consume cada instruccion
  102.  
  103. //temp2 = 1  si PINE1 = 0 sino temp2=2
  104. //temp1 = 64 si PINE2 = 0 sino temp1=255
  105.  
  106. /*
  107.  
  108. Ciclos a esperar
  109.  
  110. temp2=1 temp1=255
  111. 11445 * (velocidad-1) +28
  112.  
  113. temp2=1 temp1=64
  114. 2895 * (velocidad -1) +28
  115.  
  116. temp2=2 temp1=255
  117. 18303 * (velocidad-1) +28
  118.  
  119. temp2=2 temp1=64
  120. 4551 * (velocidad-1) +28
  121. */
  122. }
  123.  
  124.  
  125. void rainbow_fader(){
  126.  
  127.         int Temp_R,Temp_A,Temp_V;
  128.         Velocidad = 254;
  129.         Temp_R = Rojo;
  130.         Temp_A = Azul;
  131.         Temp_V = Verde;
  132.  
  133.         while(PINC7)
  134.         {
  135.                 Rojo = 255;
  136.                 Verde = 0;
  137.                 Azul = 0;
  138.                 DimmerCurva();
  139.                 PORTE0 = 0;
  140.  
  141.         //rojo_verde
  142.                 while(Verde!=255 && PINC7)
  143.                 {
  144.                         delay(velocidad);
  145.                         PORTE=1;
  146.                         Rojo--;
  147.                         Verde++;
  148.                         DimmerCurva();
  149.                 }
  150.                 PORTE0=0;
  151.  
  152.         //verde_azul
  153.                 while(Azul!=255 && PINC7)
  154.                 {
  155.                         delay(velocidad);
  156.                         PORTE=1;
  157.                         Verde--;
  158.                         Azul++;
  159.                         DimmerCurva();
  160.                 }
  161.                 PORTE0=0;
  162.  
  163.         //azul_rojo
  164.                 while(Rojo!=255 && PINC7)
  165.                 {
  166.                         delay(velocidad);
  167.                         PORTE=1;
  168.                         Azul--;
  169.                         Rojo++;
  170.                         DimmerCurva();
  171.                 }
  172.                 PORTE0=0;
  173.         }
  174.  
  175.         Rojo = Temp_R;
  176.         Azul = Temp_A;
  177.         Verde = Temp_V;
  178.  
  179. }
  180.  
  181. void DimmerCurva(){
  182.  
  183.         R_out=arraydimmer[Rojo];
  184.         V_out=arraydimmer[Verde];
  185.         A_out=arraydimmer[Azul];
  186.  
  187. }

Si observas ahi donde puse el delay, eso depende de las llaves, el cual van a cambiar el valor de temp1 y temp2, si no me equivoque eso son los ciclos que requieren segun cada caso.
Hacer una formula para eso se llenaria de parentesis, asi que no la pongo.
Bueno amigo tome tu codigo y le agrege lo que me parece que falta ., y aclaro que la parte fisica esta armada
solo armar esta libreria ., para que compile y probar ., yo uso el wachdog por que si te fijas el esquematico no esta conectado el "reset"
aca te muestro para que veas y revices si esta bien 
Código: [Seleccionar]
#define F_CPU 8000000
#include<util\delay.h>

#include<stdio.h>
#include<stdlib.h>

#include <avr/wdt.h>
 //*********************************//
const short int arraydimmer[256]={0,0,0.0.0.0.0.0.0.0.0.1.1.1.1.1.1.1.1.1,1,1,1,1,2.2,2,2,3,3,3,4,4.4,5,5,5,6,6,7,7.8,8,9,9,10,10,11,11.12,12,13,13,14,14,15,15.16,16,17,17,18,18,19,19.20,20,21,21,22,22,23,23.24,24,25,25,26,27,28,29.30,30,31,32,33,34,35,36.36,37,38,39,40,41,42,43.43,44,45,46,47,48,49,50.51,52,52,53,54,55,56,57.58,59,60,61,62,63,64,65.66,67,68,69,70,71,72,73.74,75,76,77,78,79,80,81.82,83,84,85,86,88,89,90.91,92,93,94,95,96,97,98.99,100,102,103,104,105,106,107.108,109,110,112,113,114,115,116,117,119,120,121,122,123,124,126.127,128,129,130,132,133,134,135.136,138,139,140,141,142,144,145.146,147,149,150,151,152,154,155.156,158,159,160,161,162,164,165.167,168,169,171,172,173,174,176.177,178,180,181,182,184,185,187.188,189,191,192,193,195,196,197.199,200,202,203,204,206,207,208.210,211,213,214,216,217,218,220.221,223,224,226,227,228,230,231.233,234,236,237,239,240,242,243.245,246,248,249,251,252,254,255 }; // Lo que aparece como DC_Data
                                   
Short int velocidad,Rojo,Verde,Azul,V_out,R_out,A_out;
//************* Inicialización pines / port *****************//
void init_pinouts(){                   
    //#ifdef USE_DIP
 
    DDRC  = 0; // establecer DIPs
    PORTC  = 0xFF;
    DDRE  &= ~((1<<PE2)|(1<<PE1));
    PORTE |=   (1<<PE2)|(1<<PE1);
 
  //  #endif
   
DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2); // Salida pin LED
PORTB= 0;
DDRE  |= (1<<PE0); //LED2 azul indicador
    PORTE |= (1<<PE0);
    }     
// ***** inicializacion del timer****//
void init_timer(){
TCCR0|= (1<<CS02) ; // Precontador 256
TIMSK|= (1<<TOIE0); // desbordamientos de la interrupción

}     
     
    void main()
     {
 //***** Watchdog *****//
wdt_reset();
wdt_enable(WDTO_500MS); // Habilitar el watchdog (timeout = 0.5s)
wdt_reset();
cli();
init_pinouts(); // Establecer los puertos de E / S
init_timer(); // Establecer el temporizador
   
sei();     // habilitar las interupciones globales  ???
int PWM_timer;  // inicializar el timer PWM

      for (PWM_timer=0; PWM_timer<255 ; PWM_timer++)  // Loop timer general en un ciclo de llenado
{
    if(!PINC6){ fading();}
    if(!PINC5){ disco();}
    /*
    Aca mas codigo que realmente no influye en nada
    */
    }
     
     
     
    void fading() {
     
    Velocidad = 127;
     
    while(!PINC6)
    {
    Rojo = 255;
    Verde = 0;
    Azul = 0;
     
    DimmerCurva()
    PORTE0 = 0;
     
    //rojo_amarillo
    while(Verde!=255 && !PINC6)
    {
    if(PINC7) { rainbow_fader();}
    delay(velocidad);
    PORTE0 = 1;
    Verde++;
    DimmerCurva();
    }
    PORTE0 = 0;
     
    //amarillo_verde
    while(Rojo && !PINC6)
    {
    if(PINC7) { rainbow_fader();}
    delay(velocidad);  //esperar
    PORTE0 = 1;
    Rojo--;
    DimmerCurva();
    }
    PORTE0 = 0;
     
    //verde_cyan
    while(Azul!=255 && !PINC6)
    {
    if(PINC7) { rainbow_fader();}
    delay(velocidad);  //esperar
    PORTE0 = 1;
    Azul++;
    DimmerCurva();
    }
    PORTE0 = 0;
     
    //cyan_azul
    while(Verde && !PINC6)
    {
    if(PINC7) { rainbow_fader();}
    delay(velocidad);  //esperar
    PORTE0 = 1;
    Verde--;
    DimmerCurva();
    }
    PORTE0 = 0;
     
    //azul_magenta
    while(Rojo!=255 && !PINC6)
    {
    if(PINC7) { rainbow_fader();}
    delay(velocidad);  //esperar
    PORTE0 = 1;
    Rojo++;
    DimmerCurva();
    }
    PORTE0 = 0;
   
    //magenta_rojo
    while(Azul && !PINC6)
    {
    if(PINC7) { rainbow_fader();}
    delay(velocidad);  //esperar
    PORTE0 = 1;
    Azul--;
    DimmerCurva();
    }
    PORTE0 = 0;
    }
    }
     
    void delay(int velocidad) {
     
    delay_ciclos();  // La cantida de ciclos va a depender de los siwthc que estan conectados a PINE2 y PINE1
    // Si podes simularlo con velocidad = 1 para saber que valor tenes que multiplicar a velocidad, es por que no se la cantidad de ciclos que consume cada instruccion
     
    //temp2 = 1  si PINE1 = 0 sino temp2=2
    //temp1 = 64 si PINE2 = 0 sino temp1=255
     
    /*
     
    Ciclos a esperar
     
    temp2=1 temp1=255
    11445 * (velocidad-1) +28
     
    temp2=1 temp1=64
    2895 * (velocidad -1) +28
     
    temp2=2 temp1=255
    18303 * (velocidad-1) +28
     
    temp2=2 temp1=64
    4551 * (velocidad-1) +28
    */
    }
     
     
    void rainbow_fader(){
     
    int Temp_R,Temp_A,Temp_V;
    Velocidad = 254;
    Temp_R = Rojo;
    Temp_A = Azul;
    Temp_V = Verde;
     
    while(PINC7)
    {
    Rojo = 255;
    Verde = 0;
    Azul = 0;
    DimmerCurva();
    PORTE0 = 0;
     
    //rojo_verde
    while(Verde!=255 && PINC7)
    {
    delay(velocidad);
    PORTE=1;
    Rojo--;
    Verde++;
    DimmerCurva();
    }
    PORTE0=0;
     
    //verde_azul
    while(Azul!=255 && PINC7)
    {
    delay(velocidad);
    PORTE=1;
    Verde--;
    Azul++;
    DimmerCurva();
    }
    PORTE0=0;
     
    //azul_rojo
    while(Rojo!=255 && PINC7)
    {
    delay(velocidad);
    PORTE=1;
    Azul--;
    Rojo++;
    DimmerCurva();
    }
    PORTE0=0;
    }
     
    Rojo = Temp_R;
    Azul = Temp_A;
    Verde = Temp_V;
     
    }
     
    void DimmerCurva(){
     
    R_out=arraydimmer[Rojo];
    V_out=arraydimmer[Verde];
    A_out=arraydimmer[Azul];
     
    }
te vuelvo a agradecer y espero tus comentarios
yo solo se que ...nose nada

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 7802
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #8 en: 04 de Agosto de 2015, 04:54:05 »
Ojo que faltan cosas...

Cosas que imagino que van a fallar:

1-

PINC6
PINC7
PORTE0

PINC6 es en ASM, pero en C tal ves debas hacer un (PINC & (1<<6)) , que es lo mismo que PINC & 0x20
De la misma forma que si quiero cambiar el bit 0 del PORTE:

Para ponerlo a 0
PORTE &= 0xFE;
PORTE &= ~(1<<0);

Para ponerlo a 1
PORTE |= 0x01;
PORTE |= (1<<0);

Para hacer un toggle
PORTE ^= 0x01;
PORTE ^= (1<<0);

No se si C tiene acceso directo a esos pines como para llamarlos PINC6 y PORTE0, recorda que yo no se del entorno de programacion de los ATmega.

2-
Este estoy seguro que va a fallar
En mi codigo "faltaron" unas cosas

if(!PINC5){ disco();}

Esa parte deberia quitarse, solo lo hice por que asi era el ASM, pero no hice la funcion disco() ya que me dijiste de las otras 2 funciones nomas.

3-
La funcion delay() esta incompleta, yo ahi di las formulas para sacar cuantos ciclos de espera son segun las opciones y la velocidad. No se si hay uan libreria que permita hacer un delay de ciclos en ves de tiempo. Por eso mismo no la escribi.
Sino vas a tener que pasar esos ciclos a tiempos y seguir usando la formula.

4-
El array posee puntos ( . ) en ves  de comas ( , ) en algunos valores

5-
Falta el PWM por software el cual pense que ya estaba implementado, pero que eso se puede buscar en cualquier otro lado.
Jusatmente en la interrupcion del timer se cambia los valores del los puertos segun V_out,R_out y A_out.

Desconectado locodelafonola

  • PIC10
  • *
  • Mensajes: 42
Re: Invertir pwm en Atmega 8515 asembler
« Respuesta #9 en: 05 de Agosto de 2015, 06:53:39 »
hola amigo ¡¡¡¡¡ muchisimas gracias por enceñarme!!!!!
Ojo que faltan cosas...

Cosas que imagino que van a fallar:

1-

PINC6
PINC7
PORTE0

PINC6 es en ASM, pero en C tal ves debas hacer un (PINC & (1<<6)) , que es lo mismo que PINC & 0x20
De la misma forma que si quiero cambiar el bit 0 del PORTE:

Para ponerlo a 0
PORTE &= 0xFE;
PORTE &= ~(1<<0);

Para ponerlo a 1
PORTE |= 0x01;
PORTE |= (1<<0);

Para hacer un toggle
PORTE ^= 0x01;
PORTE ^= (1<<0);

No se si C tiene acceso directo a esos pines como para llamarlos PINC6 y PORTE0, recorda que yo no se del entorno de programacion de los ATmega.

2-
Este estoy seguro que va a fallar
En mi codigo "faltaron" unas cosas

if(!PINC5){ disco();}

Esa parte deberia quitarse, solo lo hice por que asi era el ASM, pero no hice la funcion disco() ya que me dijiste de las otras 2 funciones nomas.

3-
La funcion delay() esta incompleta, yo ahi di las formulas para sacar cuantos ciclos de espera son segun las opciones y la velocidad. No se si hay uan libreria que permita hacer un delay de ciclos en ves de tiempo. Por eso mismo no la escribi.
Sino vas a tener que pasar esos ciclos a tiempos y seguir usando la formula.

4-
El array posee puntos ( . ) en ves  de comas ( , ) en algunos valores

5-
Falta el PWM por software el cual pense que ya estaba implementado, pero que eso se puede buscar en cualquier otro lado.
Jusatmente en la interrupcion del timer se cambia los valores del los puertos segun V_out,R_out y A_out.
bueno amigo ., yo arme esto pero todavia no compile., porque se que hay muchos errores
bueno muchos de ellos son los que tu amablemente me señalas
pero tranquilo ., el C para atmega no difiere mucho del C para pic ., basicamente son los cambio de nombres par las sentencias
  • 1° . si te fijas en lo que agregue  ., estan definidos los MINIDIPS  en el inicio de PINOUTS
Código: [Seleccionar]
//************* Inicialización pines / port *****************//
void init_pinouts(){                   
    //#ifdef USE_DIP
 
    DDRC  = 0; // establecer DIPs
    PORTC  = 0xFF;
    DDRE  &= ~((1<<PE2)|(1<<PE1));
    PORTE |=   (1<<PE2)|(1<<PE1);
 
  //  #endif
a tener en cuenta que la sentencia USE_DIP la comente y asi la desbilite bueno en mis compilaciones se puede llamar ala lectura de los MINI-DIPS con esta sentencia get_dips();
de esa manera podemos leer todas las llaves de los 10 puertos (los 8 de C y los  de E ., tal cual esta en la compilacion de ASM
eso tendrias que fiajarte si es correto a tu modo de ver

  • 2° :
    bueno en cuanto ala definicion de los puerto y su manejo me parece que esta correcto ., si no te es mucha molestia fijate por aca http://www.todopic.com.ar/foros/index.php?topic=44207.msg366067#msg366067 ese proyecto lo arme yo con las librerias base de  H.Hölscher
    claro que con la diferencia que alli manejo DMX pero las formas del compilador par atmega son iguales (el mismo compilador maneja ASM y C) o seatiene que andar lode ASM en C (basicamente claro)
    tambien tome en cuenta que la parte de 
    Código: [Seleccionar]
    if(!PINC5){ disco();} no va afuncionar porque no tiene nigundesarrollo del programa ., pero la deje igual (se comenta y con eso arreglado el asunto )
  • 3° : por eso inclui  la libreria util_ delay ., en la compilacion ., en ASM la toma ., pero no se si en C ., no hay que cambiar los atributos
  • 4° : no me di cuenta de eso., yo para no cambiar nada ., tome el DC_data como estaba y sacque las leyendas db en cada renglon , pero como soy una persona mayor .,  ya no veo bien ., he confundido el punto con la coma ya lo arreglare en la proxima edicion (mis 53 años no vienen solos jajajajajajaja)
  • 5° : yo implemente y defini un timer por si no lo viste
Código: [Seleccionar]
// ***** inicializacion del timer****//
void init_timer(){
TCCR0|= (1<<CS02) ; // Precontador 256
TIMSK|= (1<<TOIE0); // desbordamientos de la interrupción
y tambien un PWM por sofware
Código: [Seleccionar]
int PWM_timer;  // inicializar el timer PWM for (PWM_timer=0; PWM_timer<255 ; PWM_timer++)  // Loop timer general en un ciclo de llenado
    pero obiamente no lo implemente en la compilacion ., ademas ya tiene  los pin de salidas declarados del puerto B y el LED  del puero E

    • 6° : en la compilacion actual yo implemente el timerO asi TCCR0|= (1<<CS02) ; ahora en la compilacion ASM esta asi
    Código: [Seleccionar]
           ldi     temp0, 0b00000001;     Conjunto CS00: 1 divisor
    out     TCCR0, temp0
          
    o sea tendria que ser  CS00 y yo lo cabie por CS02., porque habia un pequeño "parpadeo" en los led., en las compilaciones que yo usaba antes en C ., y con esta configuracion CS02.,  casi no se nota
    yo no se como cambiar esa sentencia o sea  "0b00000001" en binario para aplicarla por la que yo cambie CS02 ., y probarla en ASM
    y vuelvo a repetir.,  muchas gracias por tu tiempo y tus ganas de enseñarme ., espero tus comentarios 


    yo solo se que ...nose nada

    Desconectado KILLERJC

    • Colaborador
    • DsPIC33
    • *****
    • Mensajes: 7802
    Re: Invertir pwm en Atmega 8515 asembler
    « Respuesta #10 en: 05 de Agosto de 2015, 07:49:50 »
    Como te habia adelantado jamas programe en C/ASM ni un ATmega, ni un arduino, por lo cual estoy un poco perdido.

    No sabia que hacer:

    variable = (PINC & (1<<6));

    era equivalente a

    variable = PINC6;

    Y cuando habia que cambiar o leer unicamente un pin, pense que podria haber problemas, por eso lo nombre.

    -----------------------------------

    Con respecto a los delays, ahi vi que usas esa libreria y que posee 2 funciones

    _delay_ms();
    _delay_us();

    Tomando la tabla que deje donde se cuentan los ciclos, y tomando en consideracion que 1 ciclo es justamente 1 / Fosc, entonces el ciclo de reloj es de 0.125us (Para 8 Mhz)
    teniendo en cuenta eso

    Citar
    PINE1 => temp2  , si 0 temp2=1 , si 1 temp2=2
    PINE2 => temp1  , si 0 temp1=64 si 1 temp2=255

        temp2=1 temp1=255
        11445 * (velocidad-1) +28
        
        temp2=1 temp1=64
        2895 * (velocidad -1) +28
        
        temp2=2 temp1=255
        18303 * (velocidad-1) +28
        
        temp2=2 temp1=64
        4551 * (velocidad-1) +28

    Podemos hacer la funcion de espera (o delay como habia puesto):

    Código: C
    1. void espera(short int velocidad){
    2.         int tiempo;
    3.         switch((PINE&0x06))
    4.         {
    5.         case 0x00:
    6.                 tiempo=((362 * (velocidad-1)+3)/1000);
    7.                 _delay_ms(tiempo);
    8.                 break;
    9.         case 0x02:
    10.                 tiempo=((568 * (velocidad-1)+3)/1000);
    11.                 _delay_ms(tiempo);
    12.                 break;
    13.         case 0x04:
    14.                 tiempo=((1430 * (velocidad-1)+3)/1000);
    15.                 _delay_ms(tiempo);
    16.                 break;
    17.         case 0x06:
    18.                 tiempo=((2287 * (velocidad-1)+3)/1000);
    19.                 _delay_ms(tiempo);
    20.                 break;
    21.         default:
    22.                 break;
    23.         }
    24. }

    Citar
    6° : en la compilacion actual yo implemente el timerO asi TCCR0|= (1<<CS02) ; ahora en la compilacion ASM esta asi

    La traduccion directa del ASM al C de esas intrucciones que me pasaste es:

    TCCR0 = 0x01;

    Pero supongamos que no queres afectar a los otros bits, entonces mejor un:
    TCCR0 &= 0x7;  // Para limpiar si habia otro valor
    TCCR0 |=0x1;   // Escribimos el bit CS0

    o directamente:

    TCCR0 = ((TCCR0 & 0x7) | 0x01);

    Lo que me parece raro. Por que como esta significa que el Timer no posee preescaler y por eso mismo se va a producir la interrupcion mas rapido, es decir los ultimos 3 bits del TCCR0 corresponden a CSn2:0, estos indican que preescaler va encima. Y esto va afectar al PWM por software, Mientras mas rapido, quiere decir que es mas rapida la frecuencia del PWM, por lo que no deberias notar nunca un parpadeo, Haber si me explico..
    Tu PWM por soft usa una interrupcion, en esa interrupcion incrementa el valor del PWM en 1 hasta llegar a 255 y volver a comenzar de 0. entonces cuando pasa 255, es decir 255 interrupciones la señal subio y bajo. es decir hizo un ciclo completo.
    Si vos agrandas el preescaler (dividis mas la señal del clock) quiere decir que va a contar mucho mas lento, por lo tanto mas tiempo para la interrupcion y en consecuencia va a estar mucho mas tiempo encendido y tambien apagado la salida.

    Segun el datasheet con un valor de 001b de esos bits la frecuencia del reloj entra directamente al timer. Mientras que si pones un 100b como vos queres la frecuencia del reloj se encuentra disminuida por 256.

    De todas formas si queres poner el preescaler asi:
    TCCR0|= (1<<CS02)

    es equivalente a
    TCCR0 &= 0x7; // Limpio los bits por si otra instruccion antes los cambio, esto detiene el timer
    TCCR0 |= 0x4;  // Activo el bit CS02 el cual le da reloj al timer con un preescaler de 1/256

    Citar
    y tambien un PWM por sofware
    Citar
    int PWM_timer;  // inicializar el timer PWM   for (PWM_timer=0; PWM_timer<255 ; PWM_timer++)  // Loop timer general en un ciclo de llenado

    Eso no es un PWM por software y esta mal realizado. No deberias tener nunca un for ahi. Ni si quiera en la interrupcion, solamente en la interrupcion deberia quedarte algo asi:

    Código: C
    1. // *************** Soft PWM ****************
    2. ISR (TIMER0_OVF_vect)
    3. {
    4.         salida=0x7;
    5.         if (R_out>=PWM_timer) { salida &= 0x06; }   // Esta es la traduccion directa del ASM , por eso lo puse asi.
    6.         if (V_out>=PWM_timer) { salida &= 0x05; }
    7.         if (A_out>=PWM_timer) { salida &= 0x03; }
    8.         PORTB = salida;
    9. }

    Y tu main como dije no deberia tener el for, sino que simplente el while y estar continuamente llamando a las funciones que debe.

    El por que no deberias tener un for actuando de PWM en el main, es por que tenes delays involucrados. esto hace que cada cuenta del PWM_timer (PWMCnt en el ASM) sea distinto, y la idea es que cada seccion de las 256 secciones ( al contar de 0 a 255 ) tengan el mismo tiempo, asi tener una buena definicion de duty cicle
    « Última modificación: 05 de Agosto de 2015, 08:03:03 por KILLERJC »

    Desconectado locodelafonola

    • PIC10
    • *
    • Mensajes: 42
    Re: Invertir pwm en Atmega 8515 asembler
    « Respuesta #11 en: 09 de Agosto de 2015, 17:32:33 »
    ¡¡¡¡¡¡ MUCHISIMAS GRACIAS !!!!!!
    Como te habia adelantado jamas programe en C/ASM ni un ATmega, ni un arduino, por lo cual estoy un poco perdido.

    No sabia que hacer:

    variable = (PINC & (1<<6));

    era equivalente a

    variable = PINC6;

    Y cuando habia que cambiar o leer unicamente un pin, pense que podria haber problemas, por eso lo nombre.

    -----------------------------------

    Con respecto a los delays, ahi vi que usas esa libreria y que posee 2 funciones

    _delay_ms();
    _delay_us();

    Tomando la tabla que deje donde se cuentan los ciclos, y tomando en consideracion que 1 ciclo es justamente 1 / Fosc, entonces el ciclo de reloj es de 0.125us (Para 8 Mhz)
    teniendo en cuenta eso

    Citar
    PINE1 => temp2  , si 0 temp2=1 , si 1 temp2=2
    PINE2 => temp1  , si 0 temp1=64 si 1 temp2=255

        temp2=1 temp1=255
        11445 * (velocidad-1) +28
         
        temp2=1 temp1=64
        2895 * (velocidad -1) +28
         
        temp2=2 temp1=255
        18303 * (velocidad-1) +28
         
        temp2=2 temp1=64
        4551 * (velocidad-1) +28

    Podemos hacer la funcion de espera (o delay como habia puesto):

    Código: C
    1. void espera(short int velocidad){
    2.         int tiempo;
    3.         switch((PINE&0x06))
    4.         {
    5.         case 0x00:
    6.                 tiempo=((362 * (velocidad-1)+3)/1000);
    7.                 _delay_ms(tiempo);
    8.                 break;
    9.         case 0x02:
    10.                 tiempo=((568 * (velocidad-1)+3)/1000);
    11.                 _delay_ms(tiempo);
    12.                 break;
    13.         case 0x04:
    14.                 tiempo=((1430 * (velocidad-1)+3)/1000);
    15.                 _delay_ms(tiempo);
    16.                 break;
    17.         case 0x06:
    18.                 tiempo=((2287 * (velocidad-1)+3)/1000);
    19.                 _delay_ms(tiempo);
    20.                 break;
    21.         default:
    22.                 break;
    23.         }
    24. }

    Citar
    6° : en la compilacion actual yo implemente el timerO asi TCCR0|= (1<<CS02) ; ahora en la compilacion ASM esta asi

    La traduccion directa del ASM al C de esas intrucciones que me pasaste es:

    TCCR0 = 0x01;

    Pero supongamos que no queres afectar a los otros bits, entonces mejor un:
    TCCR0 &= 0x7;  // Para limpiar si habia otro valor
    TCCR0 |=0x1;   // Escribimos el bit CS0

    o directamente:

    TCCR0 = ((TCCR0 & 0x7) | 0x01);

    Lo que me parece raro. Por que como esta significa que el Timer no posee preescaler y por eso mismo se va a producir la interrupcion mas rapido, es decir los ultimos 3 bits del TCCR0 corresponden a CSn2:0, estos indican que preescaler va encima. Y esto va afectar al PWM por software, Mientras mas rapido, quiere decir que es mas rapida la frecuencia del PWM, por lo que no deberias notar nunca un parpadeo, Haber si me explico..
    Tu PWM por soft usa una interrupcion, en esa interrupcion incrementa el valor del PWM en 1 hasta llegar a 255 y volver a comenzar de 0. entonces cuando pasa 255, es decir 255 interrupciones la señal subio y bajo. es decir hizo un ciclo completo.
    Si vos agrandas el preescaler (dividis mas la señal del clock) quiere decir que va a contar mucho mas lento, por lo tanto mas tiempo para la interrupcion y en consecuencia va a estar mucho mas tiempo encendido y tambien apagado la salida.

    Segun el datasheet con un valor de 001b de esos bits la frecuencia del reloj entra directamente al timer. Mientras que si pones un 100b como vos queres la frecuencia del reloj se encuentra disminuida por 256.

    De todas formas si queres poner el preescaler asi:
    TCCR0|= (1<<CS02)

    es equivalente a
    TCCR0 &= 0x7; // Limpio los bits por si otra instruccion antes los cambio, esto detiene el timer
    TCCR0 |= 0x4;  // Activo el bit CS02 el cual le da reloj al timer con un preescaler de 1/256

    Citar
    y tambien un PWM por sofware
    Citar
    int PWM_timer;  // inicializar el timer PWM   for (PWM_timer=0; PWM_timer<255 ; PWM_timer++)  // Loop timer general en un ciclo de llenado

    Eso no es un PWM por software y esta mal realizado. No deberias tener nunca un for ahi. Ni si quiera en la interrupcion, solamente en la interrupcion deberia quedarte algo asi:

    Código: C
    1. // *************** Soft PWM ****************
    2. ISR (TIMER0_OVF_vect)
    3. {
    4.         salida=0x7;
    5.         if (R_out>=PWM_timer) { salida &= 0x06; }   // Esta es la traduccion directa del ASM , por eso lo puse asi.
    6.         if (V_out>=PWM_timer) { salida &= 0x05; }
    7.         if (A_out>=PWM_timer) { salida &= 0x03; }
    8.         PORTB = salida;
    9. }

    Y tu main como dije no deberia tener el for, sino que simplente el while y estar continuamente llamando a las funciones que debe.

    El por que no deberias tener un for actuando de PWM en el main, es por que tenes delays involucrados. esto hace que cada cuenta del PWM_timer (PWMCnt en el ASM) sea distinto, y la idea es que cada seccion de las 256 secciones ( al contar de 0 a 255 ) tengan el mismo tiempo, asi tener una buena definicion de duty cicle
    bueno amigaso ., por empezar., aunque parezca que se mucho ., no se engañe ., NO es asi
    Y viendo eso ., esperando que no lo tome a mal ., " lo declaro mi  maestro " ., soy una persona que por cuestiones de la vida ., no pudo ir ala escuela.,
    el aprender aleer y escribir ., aun mas el manejo de la informatica ., lo aprendi solo y por mis propios medios
    yo empece con los micros a mediados del 2013 ., y al contrario de la mayoria ., directamente con atmega
    intente aprender ASM .,(y puse mucho empeño ) ., tengo tres tutoriales traducidos al español por mi ., pero no hay caso no entiendo muchisimas cosas
    En cambio con C (aunque todavia hay cosas que me confunden ) me llevo mejor ., es mas entendible ( para mi )
    esto lo cuento par que sepa que tipo de persona "esta" ., enfrente
    bueno como a mi me encanta el DMX ., "juego" con los led y motorcitos PAP 
    Vi y acepte que en estos casos para tener multifunciones ., se debe implementar el PWM por sotfware., y no por hardware
    pues el PWM ., se puede usar en mas de una funcion ( ¿¿¿ o estoy equivocado ??? ) ., igual menra que la IRS
    por el simple hecho ., que por lo general se controlan todas las salidas de un PORT
    como en este caso que tengo 3 PORT ( portb ) .,  para los led y me quedan 5 libres ( que podria colocar un motor tranquilamente y que funcione con otro timer )
    por eso uso el PWM asi
    en la compilacion DMX., que indique mas arriba ., funciona con las dos configuraciones de timer ( TCCR0|= (1<<CS00 )  y  TCCR0|= (1<<CS02) )
    L e pido mil perdones , por no entenderlo ., pero se me hace dificil comprender cuando usa definiciones asi
    Código: [Seleccionar]
    int tiempo;
    switch((PINE&0x06))
    {
    case 0x00:
    tiempo=((362 * (velocidad-1)+3)/1000);
    _delay_ms(tiempo);
    break;
    case 0x02:
    tiempo=((568 * (velocidad-1)+3)/1000);
    _delay_ms(tiempo);
    break;
    case 0x04:
    tiempo=((1430 * (velocidad-1)+3)/1000);
    _delay_ms(tiempo);
    break;
    case 0x06:
    tiempo=((2287 * (velocidad-1)+3)/1000);
    _delay_ms(tiempo);
    break;
    concretamente cuando usa por ejemplo: "" case 0x04:" ., la definicion CASE si la entiendo pero 0x04 ., no
    bueno aca le publico lo que mas o menos arme ( no esta compilado todavia ) solo el bosquejo
    tambien prepare las llaves MINI-DIPS para poder poner alli las escala de tiempos y demas
    con la llave N° 10 ( PINE=1) en ON tendriamos funcionamiento ., en OFF apagado
    de alli nos pasa a otra funcion (PINE=2) ., en ON es fading y en OFF es rainbow
    aparte en las que quedan (PINC=0 a PINC=7) se puede agregar las velocidades u otra funcion que nesesites ., ( por ahora esta definido los valores DMX ) ., pero eso se puede cambiar y tenes 8 posisciones.,  que tambien se suman
    el valor de la suma o resultado lo puede alojar en ADRRESTEMP
    tambien esta la posibilidad que nesesitas otra funcion de las MINI-DIPS la numero 10 (PINE=1) en OFF ., tenga otras funciones a definir  .,
    bueno aca te pongo lo que arme y vamos viendo
    Código: [Seleccionar]
    #define F_CPU 8000000
    #include<util\delay.h>

    #include<stdio.h>
    #include<stdlib.h>

    #include <avr/wdt.h>
     // *** establecer valor de WHILE  ***//
    enum {FALSE=0, TRUE=1};   //*********************************//
    uint8_t count= 1; // contador del soft PWM
    enum {FADING,RAINBOW_FADER,} mode;
     //*********************************//
    const short int arraydimmer[256]={0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1.1,1,1,1,1,1,1,2.2,2,2,3,3,3,4,4.4,5,5,5,6,6,7,7,8,8,9,9,10,10,11,11.12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19.20,20,21,21,22,22,23,23.24,24,25,25,26,27,28,29.30,30,31,32,33,34,35,36.36,37,38,39,40,41,42,43,43,44,45,46,47,48,49,50,51,52,52,53,54,55,56,57,58,59,60,61,62,63,64,65.66,67,68,69,70,71,72,73.74,75,76,77,78,79,80,81,82,83,84,85,86,88,89,90,91,92,93,94,95,96,97,98,99,100,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,119,120,121,122,123,124,126,127,128,129,130,132,133,134,135.136,138,139,140,141,142,144,145,146,147,149,150,151,152,154,155.156,158,159,160,161,162,164,165,167,168,169,171,172,173,174,176,177,178,180,181,182,184,185,187,188,189,191,192,193,195,196,197,199,200,202,203,204,206,207,208,210,211,213,214,216,217,218,220,221,223,224,226,227,228,230,231,233,234,236,237,239,240,242,243,245,246,248,249,251,252,254,255 }; // Lo que aparece como DC_Data
                                       
    Short int velocidad,Rojo,Verde,Azul,V_out,R_out,A_out;
    //************* Inicialización pines / port *****************//
    void init_pinouts(){                   
        #ifdef USE_DIP
     
        DDRC  = 0; // establecer DIPs
        PORTC  = 0xFF;
        DDRE  &= ~((1<<PE2)|(1<<PE1));
        PORTE |=   (1<<PE2)|(1<<PE1);
     
        #endif
       
    DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2); // Salida pin LED
    PORTB= 0;
    DDRE  |= (1<<PE0); //LED2 azul indicador
        PORTE |= (1<<PE0);
        }     
    // ***** inicializacion del timer****//
    void init_timer(){
    TCCR0|= (1<<CS02) ; // Precontador 256
    TIMSK|= (1<<TOIE0); // desbordamientos de la interrupción
    TCNT0= OV_SIZE;
    }
     // ****** Temporizador de inicialización para evitar efecto estroboscópico *****//
    #define OV_COUNT 14 // 161 , 7  = 0.25ms
    #define OV_SIZE 161 // comenzando Contador inicial
    volatile int timer_counter=0;// Contador del temporizador
     // ************* obtener DMX dirección de inicio **************
    void get_dips(void)
    {
    #ifdef USE_DIP
    uint16_t Temp;
     
    if (!(PINE &(1<<PE1))){ // Modo FADING / RAINBOW_FADER
    Temp=   // DMXAdress = tiempo de retardo
    (!(PINC &(1<<PC0)) *1) +
    (!(PINC &(1<<PC1)) *2) +
    (!(PINC &(1<<PC2)) *4) +
    (!(PINC &(1<<PC3)) *8) +
    (!(PINC &(1<<PC4)) *16) +
    (!(PINC &(1<<PC5)) *32) +
    (!(PINC &(1<<PC6)) *64) +
    (!(PINC &(1<<PC7)) *128);
    Address= Temp;
    if (!(PINE &(1<<PE2))) // MODO FADING / OFF RAINBOW_FADER
         {
    mode= FADING;
    }else{
    mode= RAINBOW_FADER;

         }
    return;
    }
    //mode= xxx; // ACA PUEDE IR OTRA FUNCION CON LOS DIPS
    //Temp=
    // (!(PINC &(1<<PC0)) *1) +
    // (!(PINC &(1<<PC1)) *2) +
    // (!(PINC &(1<<PC2)) *4) +
    // (!(PINC &(1<<PC3)) *8) +
    // (!(PINC &(1<<PC4)) *16) +
    // (!(PINC &(1<<PC5)) *32) +
    // (!(PINC &(1<<PC6)) *64) +
    // (!(PINC &(1<<PC7)) *128) +
    // (!(PINE &(1<<PE2)) *256);
     
     
    //if (Temp != 0)
    // {
    // Address= Temp;

    // }
     
    #endif
    }
             
       int main(void)
         {
     //***** Watchdog *****//
    wdt_reset();
    wdt_enable(WDTO_500MS); // Habilitar el watchdog (timeout = 0.5s)
    wdt_reset();
    cli();
    init_pinouts(); // Establecer los puertos de E / S
    init_timer(); // Establecer el temporizador
       
    sei();     // habilitar las interupciones globales  ???
    int PWM_timer;  // inicializar el timer PWM
      while(1) // bucle principal (LOOP)
        {

            get_dips(); // Comprobar dip-switch y habilitar la funcion

          for (PWM_timer=0; PWM_timer<255 ; PWM_timer++)  // Loop timer general en un ciclo de llenado
    {

    // if(!PINC6){ fading();}
        // if(!PINC5){ disco();}
        /*
        Aca mas codigo que realmente no influye en nada
        */
        }
         
         
         
        void fading() {
         
        Velocidad = 127;
         
        while(!PINC6)
        {
        Rojo = 255;
        Verde = 0;
        Azul = 0;
         
        DimmerCurva()
        PORTE0 = 0;
         
        //rojo_amarillo
        while(Verde!=255 && !PINC6)
        {
        if(PINC7) { rainbow_fader();}
        delay(velocidad);
        PORTE0 = 1;
        Verde++;
        DimmerCurva();
        }
        PORTE0 = 0;
         
        //amarillo_verde
        while(Rojo && !PINC6)
        {
        if(PINC7) { rainbow_fader();}
        delay(velocidad);  //esperar
        PORTE0 = 1;
        Rojo--;
        DimmerCurva();
        }
        PORTE0 = 0;
         
        //verde_cyan
        while(Azul!=255 && !PINC6)
        {
        if(PINC7) { rainbow_fader();}
        delay(velocidad);  //esperar
        PORTE0 = 1;
        Azul++;
        DimmerCurva();
        }
        PORTE0 = 0;
         
        //cyan_azul
        while(Verde && !PINC6)
        {
        if(PINC7) { rainbow_fader();}
        delay(velocidad);  //esperar
        PORTE0 = 1;
        Verde--;
        DimmerCurva();
        }
        PORTE0 = 0;
         
        //azul_magenta
        while(Rojo!=255 && !PINC6)
        {
        if(PINC7) { rainbow_fader();}
        delay(velocidad);  //esperar
        PORTE0 = 1;
        Rojo++;
        DimmerCurva();
        }
        PORTE0 = 0;
       
        //magenta_rojo
        while(Azul && !PINC6)
        {
        if(PINC7) { rainbow_fader();}
        delay(velocidad);  //esperar
        PORTE0 = 1;
        Azul--;
        DimmerCurva();
        }
        PORTE0 = 0;
        }
        }
         
        void delay(int velocidad) {
         
        delay_ciclos();  // La cantida de ciclos va a depender de los siwthc que estan conectados a PINE2 y PINE1
        // Si podes simularlo con velocidad = 1 para saber que valor tenes que multiplicar a velocidad, es por que no se la cantidad de ciclos que consume cada instruccion
         
        //temp2 = 1  si PINE1 = 0 sino temp2=2
        //temp1 = 64 si PINE2 = 0 sino temp1=255
         
        /*
         
        Ciclos a esperar
         
        temp2=1 temp1=255
        11445 * (velocidad-1) +28
         
        temp2=1 temp1=64
        2895 * (velocidad -1) +28
         
        temp2=2 temp1=255
        18303 * (velocidad-1) +28
         
        temp2=2 temp1=64
        4551 * (velocidad-1) +28
        */
        }
         
         
        void rainbow_fader(){
         
        int Temp_R,Temp_A,Temp_V;
        Velocidad = 254;
        Temp_R = Rojo;
        Temp_A = Azul;
        Temp_V = Verde;
         
        while(PINC7)
        {
        Rojo = 255;
        Verde = 0;
        Azul = 0;
        DimmerCurva();
        PORTE0 = 0;
         
        //rojo_verde
        while(Verde!=255 && PINC7)
        {
        delay(velocidad);
        PORTE=1;
        Rojo--;
        Verde++;
        DimmerCurva();
        }
        PORTE0=0;
         
        //verde_azul
        while(Azul!=255 && PINC7)
        {
        delay(velocidad);
        PORTE=1;
        Verde--;
        Azul++;
        DimmerCurva();
        }
        PORTE0=0;
         
        //azul_rojo
        while(Rojo!=255 && PINC7)
        {
        delay(velocidad);
        PORTE=1;
        Azul--;
        Rojo++;
        DimmerCurva();
        }
        PORTE0=0;
        }
         
        Rojo = Temp_R;
        Azul = Temp_A;
        Verde = Temp_V;
         
        }
         
        void DimmerCurva(){
         
        R_out=arraydimmer[Rojo];
        V_out=arraydimmer[Verde];
        A_out=arraydimmer[Azul];
         }
         if (count == 0xFF)
       { // Llamado con 122Hz
       count= 1;
       
       }
          else count++;
           }
    }
     }
     //***** inicio del ocilador Temporizador de interrupción ****//
    ISR(TIMER0_OVF_vect){
    int count;
    switch(mode){
    case RAINBOW_FADER:
    count = OV_COUNT + Address;
    break;
    case FADING :
    count = OV_COUNT + Address * 10;
    break;
    default:
    count = OV_COUNT;
    }
    if(timer_counter>=count){
    timer_counter=0;

    if (mode==FADING){

    }
     
    }else{ timer_counter++; }

    {

    }


    bueno espero tus comentarios tan educativos para mi ., aunque no lo creas ., eres la primer persona que me explica ., algo de C ., que no usa ese lenguaje ( partiendo del conosimiento del ASM )., y para colmo no usa atmega., y eso es muy destacable ., infinitas  gracias
    « Última modificación: 09 de Agosto de 2015, 17:35:55 por locodelafonola »
    yo solo se que ...nose nada

    Desconectado KILLERJC

    • Colaborador
    • DsPIC33
    • *****
    • Mensajes: 7802
    Re: Invertir pwm en Atmega 8515 asembler
    « Respuesta #12 en: 09 de Agosto de 2015, 18:48:09 »
    Citar
    directamente con atmega intente aprender ASM .,(y puse mucho empeño )
    Tenes 2 caminos concretamente:

    Usar un lenguaje de alto nivel como C, el cual te abstrae un poco del hardware y sus funciones, hace que programar sea mas facil.
    Por otro lado tenes el ASM que es ideal en tema del provecho que le podes sacar al micro, pero que te ocupa mucho tiempo para hacer algo simple. Lo que si te lleva a aprender bien el manejar el binario y saber bien como se maneja por dentro el microcontrolador asi de esa forma luego cuando pasas a C podes aprovecharlo mas.

    Citar
    Vi y acepte que en estos casos para tener multifunciones ., se debe implementar el PWM por sotfware., y no por hardware

    Las principales razones de por que se usa un PWM por software y no uno por hardware son varias.

    Si es de elegir se prefiere siempre un PWM por Hardware y no uno por software, por que de esa forma el micro se encuentra libre ejecutando otras instrucciones mientras que el Hardware solo genera el PWM.

    Aunque esto tiene algunos problemas segun el micro que sea. Uno de estos por la cantidad de salidas. Por cada pin se requiriria el Hardware para el mismo, entonces por ahi no se tienen 8 salidas con PWM por hardware. Entonces te fuerza a usar un PWM por Software.

    Otra de las razones es que algunos PWM por Hardware no son lo suficientemente lentos. Tal ves el maximo periodo es de 1ms y vos necesitas un periodo de 20ms, entonces no queda otra que usar uno por Software a pesar que significa que el micro tenga que ponerse a hacer el PWM y no solo el programa en cuestion.

    Citar
    concretamente cuando usa por ejemplo: "" case 0x04:" ., la definicion CASE si la entiendo pero 0x04

    Hay distintas formas de expresar los numeros, ya sea binario, decimal, hexadecimal, octal(realmente nunca lo use), esto va a depender a veces del compilador usado, algunos formatos que eh visto:

    Binario (8bits):
    0b00100101
    b'00100101'

    Decimal
    30
    .30
    30d

    Hexadecimal
    0x20
    20h


    Lo interesante del Hexadecimal y el binario es que tienen una forma facil de pasar de uno a otro
                  0      4
    0x04 = 0000 0100 = 4 decimal
    0x2A = 0010 1010 = 42 decimal
                  2      A

    Si observas al numero binario de 8 bits lo separe en 4 bit, y cada 4 bits es representado por un solo valor en hexadecimal. En esa parte hago:

     (PINE&0x06)

    es igual a ( separo los bits para que sea mas legible nada mas )

     PINE & 0000 0110

    entonces eso me va a dejar los bits de los pines 1 y 2.

    Segun el valor que salga de ahi, el resultado de esa AND, va a ser donde entre el case. Si por ejemplo tengo que
    PINE = 0101 1101

    Entonces tendria ->  PINE & 0000 0110 -> 0101 1101 & 0000 0110 -> 0000 0100
    Eso en hexadecimal seria 0x04

    Citar
    bueno espero tus comentarios tan educativos para mi ., aunque no lo creas ., eres la primer persona que me explica ., algo de C ., que no usa ese lenguaje ( partiendo del conosimiento del ASM )., y para colmo no usa atmega., y eso es muy destacable ., infinitas  gracias

    El lenguaje C es igual en todos los micros, sea de microchip / atmel / renesas / ti / nxp, etc. Lo unico que cambian son los registros a configurar, y modulos. Y eso es lo bueno de C. Una funcion en un micro puede ser usada en otro, siempre y cuando no modifique registros, ya que vas a tener que buscar equivalentes entre los micros. Si haces:

    tiempo=((568 * (velocidad-1)+3)/1000);

    En cualquier micro eso va a servir. Esto no pasa con ASM ya que el manejo de memoria es distinto, las instrucciones son distintas incluso de cada marca de microcontrolador y vas a tener que aprender todo de ese micro nuevamente.

    Y una ves que viste algunos microcontroladores, vas a notar que TODOS son casi iguales, si usas un timer, tenes que buscar los registros a modificar y listo, llenas esos registros y tenes andando tu timer sea cual sea tu micro.

    Desconectado locodelafonola

    • PIC10
    • *
    • Mensajes: 42
    Re: Invertir pwm en Atmega 8515 asembler
    « Respuesta #13 en: 09 de Agosto de 2015, 22:55:44 »
    bueno amigaso ., a vuelto a responder magistralmente
     ((:-))  ((:-))  ((:-))  ((:-))
    muchisimas gracias ., por el tiempo y la voluntad puesta de manifiesto
    espero que tenga tiempo (y ganas de leer el bosquejo de programacion que hice
    viendo de esa manera mis posibles "horrores"
    aca subo varios tutos ., de ASM par atmega., (incluida la hoja de datos resumida del 8515 traducida
    si algun moderador considera que tienen que publicarce en otro lugar que lo corrija  (gracias )
    quedo ala espera de su comentario ., muchas gracias
    NOTA AL MODERADOR : quedaron sin subir 4 archivos con los tutos traducidos ., por el limite de tamaño
    « Última modificación: 09 de Agosto de 2015, 23:02:22 por locodelafonola »
    yo solo se que ...nose nada

    Desconectado stk500

    • Moderador Local
    • DsPIC33
    • *****
    • Mensajes: 4862
    Re: Invertir pwm en Atmega 8515 asembler
    « Respuesta #14 en: 10 de Agosto de 2015, 02:43:11 »
    Por lo que leo, veo que estais saliendo del Tema DMX512 y tutoriando de Lenguaje , para este caso seria mejor abrir el tema en el Subforo de Atmel.
    Querido amigo Locodelafonola, quizas te ha pasado por el Subforo de Atmel, pues alli hay muchos tutoriales de todos los lenguaje de programacion y de Assemble mas aun. por favor respectar el orden de los Subforo , asi se facilita a la hora de buscar Informaciones. para esto esta el foro Clasificado, no siendo asi seria dificil para Usuarios que usen el Buscador encontrar la Info que busquen.

    Saludos