Tengo un ATMEGA324P que controla un circuito de controlador de motor dual. Estoy usando el contador de tiempo de 16 bits 1 en el modo de corrección de fase y frecuencia para crear (2) salidas PWM usando el ICR1 como el valor SUPERIOR y el OCR1A y OCR1B para generar las señales PWM en los pines de salida. El problema persiste igual en OCR1A y OCR1B, por lo que he desactivado OCR1A para simplificar la solución de problemas.
El problema que estoy experimentando es que cuando se dispara cualquier otra interrupción en el sistema, como UART o PCINT, el ciclo de trabajo de PWM se invertirá. Por ejemplo, si el ciclo de trabajo se establece en 75 %, se invertirá al 25 % y cambiará de un lado a otro mientras otras interrupciones se activan, lo que hace que la salida sea extremadamente errática. Las tomas de alcance a continuación muestran la salida deseada en la parte superior y la invertida en la parte inferior. Pude activar esta inversión mediante UART RX ISR, Pin change interrupt interrupt ISR y Timer Counter 0 and 2 Compare A & B ISR's. Por ejemplo, enviar un carácter al UART hará que se invierta.
Todo parece funcionar en mi código (a continuación) excepto por este problema. Probé una nueva placa de circuito y exhibió exactamente el mismo comportamiento, lo que sugiere que no es un problema de hardware. Lo que creo que podría estar sucediendo es que la interrupción OCR1B se activa de alguna manera cuando se activa la otra interrupción, lo que provoca una alternancia adicional de OCR1B en el pin de salida. Una vez que esto sucede, sigue funcionando como debería, alternando el pin pero en un estado invertido. Esto se ilustra en el siguiente diagrama de tiempo.
Es posible que tenga algún error con mi pila y que la dirección ISR esté dañada. Las direcciones que probé se muestran a continuación con la X y la dirección de destino con la flecha. Agradezco cualquier ayuda.
#define SS_Hi() PORTB |= _BV(4)
#define SS_Lo() PORTB &= ~ _BV(4)
#define SS_IN() (PINB&_BV(PINB4))
void init_TCNT1(void) {
// setup timer counter 1
// PWM, Phase Frequency Correct 8-bit. TOP = ICR1
TCCR1A |= _BV(WGM11);
TCCR1B |= _BV(WGM13);
TCCR1B |= _BV(CS11);
ICR1 = 40;
TIMSK1 |= _BV(OCIE1A);
// TIMSK1 |= _BV(OCIE1B);
OCR1A = 10;
OCR1B = 10;
TCNT1 = 0;
}
ISR(TIMER1_COMPA_vect) {
if ((EnA_1() != 0) && (EnB_1() != 0)) { // only if both enable pins are high
// if (PWM_PIN_1() == 0) PWMIN_1_Hi(); else PWMIN_1_Lo();
}
else PWMIN_1_Lo();
} // End Timer 1 Compare A ISR
ISR(TIMER1_COMPB_vect) {
// ISR For Motor 2
if (SS_IN() == 0) SS_Hi(); else SS_Lo();
} // End Timer 1 Compare B ISR
Con la ayuda de los comentarios y la publicación a continuación, pude determinar la causa del problema.
La causa del problema no es una interrupción adicional, ya que originalmente pensé que se está perdiendo una porque las interrupciones globales se deshabilitaron para manejar otra ISR. Pude verificar esto agregando un sei(); instrucción al comienzo de todos los demás controladores ISR y el problema de inversión desapareció. Volver a habilitar las interrupciones globales en todos los demás ISR no es una solución ideal y causa más problemas, especialmente con el UART. La mejor solución sería usar los pines OCR1A/B en PD4 y PD5; sin embargo, estos pines se usan para otra cosa, por lo que no es realmente una opción. La solución que se me ocurrió es usar la interrupción de desbordamiento del temporizador 1 para borrar el pin de salida que se dispara en la PARTE INFERIOR en el modo PWM de fase y frecuencia.
#define SS_Hi() PORTB |= _BV(4)
# define SS_Lo() PORTB &= ~_BV(4)
# define SS_IN()(PINB & _BV(PINB4))
void init_TCNT1(void) {
// setup timer counter 1
// PWM, Phase and Frequency Correct 8-bit. TOP = ICR1
TCCR1A |= _BV(WGM11);
TCCR1B |= _BV(WGM13);
TCCR1B |= _BV(CS11);
ICR1 = 40;
TIMSK1 |= _BV(OCIE1A);
TIMSK1 |= _BV(OCIE1B);
TIMSK1 |= _BV(TOIE1);
OCR1A = 10; //Set the top value
OCR1B = 10; // Set the compare value
TCNT1 = 0; // intitilize the start value
}
ISR(TIMER1_COMPA_vect) {
if ((EnA_1() != 0) && (EnB_1() != 0))
} // End Timer 1 Compare A ISR
ISR(TIMER1_COMPB_vect) {
// ISR For Motor 2
if (SS_IN() == 0) SS_Hi();
else SS_Lo();
} // End Timer 1 Compare B ISR
ISR(TIMER1_OVF_vect) {
SS_Lo();
}
Dado que está alternando manualmente los pines en el isr, está expuesto a rmw. Así que lo que has experimentado es posible.
Configure los bits COMx en su lugar.
Los Frijoles
Neelix
Los Frijoles
bruce abbott
Neelix