salidas - Programando un PWM en un microcontrolador Arduino Mega ATmega2560
pwm arduino mega (4)
Mirando www.atmel.com/Images/doc2549.pdf página 136, veo una nota:
"El bit de Reducción de potencia / Contador3, PRTIM3, en" PRR1 - Registro de reducción de potencia 1 "en la página 57 debe escribirse en cero para habilitar el módulo de temporizador / contador3".
Puede ser relevante?
No sé cuáles son los valores predeterminados para los regs de administración de energía, y no he usado el 2560.
El resto se ve bien para mí, aunque he usado las librerías de temporizador avr-timer0.adb, etc. en el 328p en lugar de hacer las mías.
Estoy tratando de habilitar un PWM en un Arduino Mega ( ATmega2560 ), pero estoy enfrentando algunos problemas.
Primero, estoy tratando de programar esto en Ada . Deseo utilizar los tres canales Timer3 con FastPWM, así que escribí
procedure Main is
begin
-- Nullify Timer3 buffers
TCCR3A := 0;
TCCR3B := 0;
TCCR3C := 0;
-- Waveform Generation Mode
-- Fast PW, 8-bit, TOP = 0x00FF, Update OCR3x at BOTTOM, TOV3 Flag Set on TOP
-- => WGM33|WGM32|WGM31|WGM30 = 0|1|0|1
TCCR3A := TCCR3A or TCCR3A_WGM30;
TCCR3B := TCCR3B or TCCR3B_WGM32;
-- Compare Output Mode:
-- Fast PWM, non-inverting mode
-- => COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0
TCCR3A := TCCR3A or TCCR3A_COM3A1 or TCCR3A_COM3B1 or TCCR3A_COM3C1;
-- Clock Select: clk/1024 => CS32|CS31|CS30 = 1|1|1
TCCR3B := TCCR3B or TCCR3B_CS32 or TCCR3B_CS31 or TCCR3B_CS30;
-- Set Timer3 pins as output :
-- Channel A : Digital Pin 5 / Chip Pin 5 (PE3/OC3A/AIN1)
-- Channel B : Digital Pin 2 / Chip Pin 6 (PE4/OC3B/INT4)
-- Channel C : Digital Pin 3 / Chip Pin 7 (PE5/OC3C/INT5)
DDRE := DDRE_DDE3 or DDRE_DDE4 or DDRE_DDE5;
OCR3AH := 0;
OCR3AL := 250;
OCR3BH := 0;
OCR3BL := 250;
OCR3CH := 0;
OCR3CL := 250;
end Main;
Las conexiones de hardware están bien; Lo probé usando un código simple en el Arduino IDE. Entonces, para mí, está muy claro que el código carece de algo o está haciendo algo mal, y esto debería ser causado por un problema en la inicialización de PWM. ¿Podría alguien explicarme dónde cometí tal error?
Gracias por adelantado.
Actualizar
Si Ada puede ser difícil de obtener toda la lógica, el código equivalente en C es (puedes construirlo usando AS6 , el resultado es el mismo, es decir, no se genera ninguna señal):
int main(void){
TCCR3A = 0;
TCCR3B = 0;
TCCR3C = 0;
/* Waveform Generation Mode
Fast PW, 8-bit, TOP = 0x00FF, Update OCR3x at BOTTOM, TOV3 Flag Set on TOP
=> WGM33|WGM32|WGM31|WGM30 = 0|1|0|1 */
TCCR3A = TCCR3A|(1<<WGM30);
TCCR3B = TCCR3B|(1<<WGM32);
/* Compare Output Mode:
Fast PWM, non-inverting mode
=> COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0*/
TCCR3A = TCCR3A|(1<<COM3A1)|(1<<COM3B1)|(1<<COM3C1);
/* Clock Select: clk/1024 => CS32|CS31|CS30 = 1|1|1 */
TCCR3B = TCCR3B|(1<<CS32)|(1<<CS31)|(1<<CS30);
/* Set Timer3 pins as output :
Channel A : Digital Pin 5 / Chip Pin 5 (PE3/OC3A/AIN1)
Channel B : Digital Pin 2 / Chip Pin 6 (PE4/OC3B/INT4)
Channel C : Digital Pin 3 / Chip Pin 7 (PE5/OC3C/INT5)*/
DDRE = DDRE|(1<<DDE3)|(1<<DDE4)|(1<<DDE5);
/* Set PWM Duty Cycles */
OCR3AH = 0;
OCR3AL = 250;
OCR3BH = 0;
OCR3BL = 250;
OCR3CH = 0;
OCR3CL = 250;
}
No estoy seguro, pero si olvida el bucle infinito al final de su función principal, el programa se detiene, todas las interrupciones se desactivarán y los controladores entrarán en un bucle vacío.
Y sin interrupciones no PWM.
int main(void){
....
while (1) {
}
return 0;
}
Debe establecer el indicador SEI en SREG para habilitar interrupciones y agregar bucle infinito en main. Los programas Avr no terminan ni se cuelgan después de alcanzar el final de la función principal, sino que comienzan todo de nuevo. http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html
Una observación aparece a la vez, casi seguro de que esto no es correcto:
-- => COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0
TCCR3A := TCCR3A or TCCR3A_COM3A1 or TCCR3A_COM3B1 or TCCR3A_COM3C1;
¿Por qué? Porque las constantes con nombre como COM3A0
son solo alias para enteros que indican la posición del bit (0 a 7). En C, cuando configuramos hacemos algo como:
REGISTER |= (1<<COM3A0);
y COM3A0 = 3, luego se convierte en (1 << 3) u 8 que está ORed.
Que desplaza un 1 el número de lugares hacia la izquierda antes de ORing con el valor de registro actual. Entonces, a menos que su COM3A0, por ejemplo, ya haya cambiado de bit, todo lo que esta instrucción está haciendo es ORing varios unos y ceros y asignando el único resultado a TCCR3A.