Hola a todos, os explico un poco el problema.
Tengo este Codigo que genera 3 PWM con diferentes Timer y controlando la variación de frecuencia con una trama CAN BUS, Funciona bien, pero tengo dos problemas:
1.- Nada mas iniciar Arduino sin inyectar ninguna trama, ya tengo una PWM,
2.- Cuando lanzo la trama can para variar la frecuencia funciona perfecto, pero en cuanto quito la trama CAN, se queda la PWM hay estática con el ultimo valor sesteado por el CAN
Necesito que al iniciar Arduio no tenga ninguna PWM y al desconectar el CAN esta PWM desaparezca.
#include <TimerOne.h>
#include <TimerThree.h>
#include <TimerFour.h>
#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10); // Inicializar MCP2515 CAN bus (CS pin 10)
// Variables para la lectura de CAN
unsigned char len = 0;
unsigned char buf[8];
unsigned char canId = 0;
// Configuracion de las PWM
int freq1 = 0; // Variable para almacenar la frecuencia del pin 11
int freq2 = 0; // Variable para almacenar la frecuencia del pin 3
int freq3 = 0; // Variable para almacenar la frecuencia del nuevo pin
int dutyCycle1 = 50; // Duty cycle fijo para el pin 11
int dutyCycle2 = 50; // Duty cycle fijo para el pin 3
int dutyCycle3 = 50; // Duty cycle fijo para el nuevo pin
void setup() {
pinMode(11, OUTPUT); // Configurar el pin 11 como salida para la PWM
pinMode(3, OUTPUT); // Configurar el pin 3 como salida para la PWM
pinMode(6, OUTPUT); // Configurar el pin 6 como salida para la PWM
Timer1.initialize(); // Inicializar Timer1 para la PWM del pin 11
Timer1.attachInterrupt(timerISR1); // Adjuntar la función de interrupción del temporizador 1
Timer1.pwm(11, 512); // Configurar el pin 11 para la PWM con un duty cycle del 50%
Timer3.initialize(); // Inicializar Timer3 para la PWM del pin 3
Timer3.attachInterrupt(timerISR3); // Adjuntar la función de interrupción del temporizador 3
Timer3.pwm(3, 512); // Configurar el pin 3 para la PWM con un duty cycle del 50%
Timer4.initialize(); // Inicializar TimerFour para la tercera PWM
Timer4.attachInterrupt(timerISR4); // Adjuntar la función de interrupción del temporizador 4
Timer4.pwm(6, 512); // Configurar el nuevo pin para la PWM con un duty cycle del 50%
CAN.begin(CAN_500KBPS) == CAN_OK; // Inicializar el bus CAN a una velocidad de 500 kbps
}
void loop() {
// Comprobar si hay un mensaje recibido
if (CAN_MSGAVAIL == CAN.checkReceive()) {
CAN.readMsgBuf(&len, buf); // Leer el mensaje CAN
canId = CAN.getCanId();
switch (canId) {
case 0x001:
// Obtener el valor del primer byte del buffer y mapearlo al rango deseado para la frecuencia del pin 11
freq1 = map(buf[0], 0, 255, 20, 3200); // Mapea la can de 0 a 255 (00 a FF) para variar la frecuencia de la PWM
periodMicros1 = 1000000 / freq1;
Timer1.setPeriod(periodMicros1 - 1);
Timer1.setPwmDuty(11, periodMicros1 * dutyCycle1 / 100);
break;
case 0x002:
// Obtener el valor del primer byte del buffer y mapearlo al rango deseado para la frecuencia del pin 3
freq2 = map(buf[0], 0, 255, 5, 4000);
periodMicros2 = 1000000 / freq2;
Timer3.setPeriod(periodMicros2 - 1);
Timer3.setPwmDuty(3, periodMicros2 * dutyCycle2 / 100);
break;
case 0x003:
// Obtener el valor del primer byte del buffer y mapearlo al rango deseado para la frecuencia del pin 6
freq3 = map(buf[0], 0, 255, 5, 4000);
periodMicros3 = 1000000 / freq3;
Timer4.setPeriod(periodMicros3 - 1);
Timer4.setPwmDuty(6, periodMicros3 * dutyCycle3 / 100);
break;
default:
break;
}
}
}
// Función de interrupción del temporizador 1 (pin 11)
void timerISR1() {
static boolean state1 = HIGH;
digitalWrite(11, state1);
state1 = !state1;
}
// Función de interrupción del temporizador 3 (pin 3)
void timerISR3() {
static boolean state2 = HIGH;
digitalWrite(3, state2);
state2 = !state2;
}
// Función de interrupción del temporizador 4 (nuevo pin)
void timerISR4() {
static boolean state3 = HIGH;
digitalWrite(6, state3);
state3 = !state3;
}
void loop() {
// Comprobar si hay un mensaje recibido
if (CAN_MSGAVAIL == CAN.checkReceive()) {
CAN.readMsgBuf(&len, buf); // Leer el mensaje CAN
canId = CAN.getCanId();
switch (canId) {
case 0x001:
// Obtener el valor del primer byte del buffer y mapearlo al rango deseado para la frecuencia del pin 11
freq1 = map(buf[0], 0, 255, 20, 3200); // Mapea la can de 0 a 255 (00 a FF) para variar la frecuencia de la PWM
periodMicros1 = 1000000 / freq1;
Timer1.setPeriod(periodMicros1 - 1);
Timer1.setPwmDuty(11, periodMicros1 * dutyCycle1 / 100);
break;
case 0x002:
// Obtener el valor del primer byte del buffer y mapearlo al rango deseado para la frecuencia del pin 3
freq2 = map(buf[0], 0, 255, 5, 4000);
periodMicros2 = 1000000 / freq2;
Timer3.setPeriod(periodMicros2 - 1);
Timer3.setPwmDuty(3, periodMicros2 * dutyCycle2 / 100);
break;
case 0x003:
// Obtener el valor del primer byte del buffer y mapearlo al rango deseado para la frecuencia del pin 6
freq3 = map(buf[0], 0, 255, 5, 4000);
periodMicros3 = 1000000 / freq3;
Timer4.setPeriod(periodMicros3 - 1);
Timer4.setPwmDuty(6, periodMicros3 * dutyCycle3 / 100);
break;
default:
break;
}
} else {
// Detener las salidas PWM si no hay msgs CAN
Timer1.stop();
Timer3.stop();
Timer4.stop();
digitalWrite(11, LOW);
digitalWrite(3, LOW);
digitalWrite(6, LOW);
}
}
He probado con una variable tipo boleana, de esta manera la PWM se para, pero no desaparece se queda estática y es lo miso que si para el CAN, con lo cual estoy en las mismas
#include <TimerOne.h>
#include <TimerThree.h>
#include <TimerFour.h>
#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10); // Inicializar MCP2515 CAN bus (CS pin 10)
// Variables para la lectura de CAN
unsigned char len = 0;
unsigned char buf[8];
unsigned char canId = 0;
bool canReceived = false; // Bandera para indicar si se ha recibido una señal CAN
// Configuracion de las PWM
int freq1 = 0; // Variable para almacenar la frecuencia del pin 11
int freq2 = 0; // Variable para almacenar la frecuencia del pin 3
int freq3 = 0; // Variable para almacenar la frecuencia del nuevo pin
int dutyCycle1 = 50; // Duty cycle fijo para el pin 11
int dutyCycle2 = 50; // Duty cycle fijo para el pin 3
int dutyCycle3 = 50; // Duty cycle fijo para el nuevo pin
unsigned long periodMicros1 = 0; // Variable para almacenar el período en microsegundos del pin 11
unsigned long periodMicros2 = 0; // Variable para almacenar el período en microsegundos del pin 3
unsigned long periodMicros3 = 0; // Variable para almacenar el período en microsegundos del nuevo pin
void setup() {
pinMode(11, OUTPUT); // Configurar el pin 11 como salida para la PWM
pinMode(3, OUTPUT); // Configurar el pin 3 como salida para la PWM
pinMode(6, OUTPUT); // Configurar el pin 6 como salida para la PWM
Timer1.initialize(); // Inicializar Timer1 para la PWM del pin 11
Timer1.attachInterrupt(timerISR1); // Adjuntar la función de interrupción del temporizador 1
Timer3.initialize(); // Inicializar Timer3 para la PWM del pin 3
Timer3.attachInterrupt(timerISR3); // Adjuntar la función de interrupción del temporizador 3
Timer4.initialize(); // Inicializar TimerFour para la tercera PWM
Timer4.attachInterrupt(timerISR4); // Adjuntar la función de interrupción del temporizador 4
CAN.begin(CAN_500KBPS) == CAN_OK; // Inicializar el bus CAN a una velocidad de 500 kbps
}
void loop() {
// Comprobar si hay un mensaje recibido
if (CAN_MSGAVAIL == CAN.checkReceive()) {
CAN.readMsgBuf(&len, buf); // Leer el mensaje CAN
canId = CAN.getCanId();
canReceived = true; // Indicar que se ha recibido una señal CAN
switch (canId) {
case 0x001:
freq1 = map(buf[0], 0, 255, 20, 3200);
periodMicros1 = 1000000 / freq1;
Timer1.setPeriod(periodMicros1 - 1);
Timer1.setPwmDuty(11, periodMicros1 * dutyCycle1 / 100);
break;
case 0x002:
freq2 = map(buf[0], 0, 255, 5, 4000);
periodMicros2 = 1000000 / freq2;
Timer3.setPeriod(periodMicros2 - 1);
Timer3.setPwmDuty(3, periodMicros2 * dutyCycle2 / 100);
break;
case 0x003:
freq3 = map(buf[0], 0, 255, 5, 4000);
periodMicros3 = 1000000 / freq3;
Timer4.setPeriod(periodMicros3 - 1);
Timer4.setPwmDuty(6, periodMicros3 * dutyCycle3 / 100);
break;
default:
break;
}
} else {
canReceived = false; // Indicar que no se ha recibido una señal CAN
}
}
// Función de interrupción del temporizador 1 (pin 11)
void timerISR1() {
if(canReceived) {
static boolean state1 = HIGH;
digitalWrite(11, state1);
state1 = !state1;
}
}
// Función de interrupción del temporizador 3 (pin 3)
void timerISR3() {
if(canReceived) {
static boolean state2 = HIGH;
digitalWrite(3, state2);
state2 = !state2;
}
}
// Función de interrupción del temporizador 4 (nuevo pin)
void timerISR4() {
if(canReceived) {
static boolean state3 = HIGH;
digitalWrite(6, state3);
state3 = !state3;
}
}
¿Por qué haces con interrupciones lo mismo que ya hace la función pwm()?
Revisa el ejemplo FanSpeed de la librería y verás que no usa rutinas de manejo de interrupciones "personalizadas".
Sobre tu pregunta inicial, tienes señal ni bien alimentas la placa porque en setup() llamas a la función pwm() con lo cual inicias la generación de la señal PWM.
Para detener un timer y, obviamente, la generación de la PWM está la función stop(). Por otro lado lo inicias o reinicias con start() o resume().
Respecto a que las señales continúen aunque no se reciban nuevas tramas, podrías definir un tiempo luego del cual, si no hay nuevas tramas, se detenga el timer correspondiente.
Y con este consejo tuyo, probé hacer lo que me aconsejas y funciona perfecto. Aqui dejo el Codigo. Gracias
#include <TimerOne.h>
#include <TimerThree.h>
#include <TimerFour.h>
#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10); // Inicializar MCP2515 CAN bus (CS pin 10)
// Variables para la lectura de CAN
unsigned char len = 0;
unsigned char buf[8];
unsigned char canId = 0;
// Bandera para indicar si se ha recibido una señal CAN para cada PWM
bool canReceivedPWM1 = false;
bool canReceivedPWM2 = false;
bool canReceivedPWM3 = false;
// Variables para almacenar el tiempo de la última recepción CAN para cada PWM
unsigned long lastCanReceivedTimePWM1 = 0;
unsigned long lastCanReceivedTimePWM2 = 0;
unsigned long lastCanReceivedTimePWM3 = 0;
// Tiempo de espera en milisegundos antes de detener las PWM para cada canal
const unsigned long canTimeout = 1000;
// Configuracion de las PWM
int freq1 = 0; // Variable para almacenar la frecuencia del pin 11
int freq2 = 0; // Variable para almacenar la frecuencia del pin 3
int freq3 = 0; // Variable para almacenar la frecuencia del pin 6
int dutyCycle1 = 50; // Duty cycle fijo para el pin 11
int dutyCycle2 = 50; // Duty cycle fijo para el pin 3
int dutyCycle3 = 50; // Duty cycle fijo para el nuevo pin
unsigned long periodMicros1 = 0; // Variable para almacenar el período en microsegundos del pin 11
unsigned long periodMicros2 = 0; // Variable para almacenar el período en microsegundos del pin 3
unsigned long periodMicros3 = 0; // Variable para almacenar el período en microsegundos del pin 6
void setup() {
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);
pinMode(6, OUTPUT);
Timer1.initialize(); // Inicializar Timer1 para la PWM del pin 11
Timer1.attachInterrupt(timerISR1); // Adjuntar la función de interrupción del temporizador 1
Timer3.initialize(); // Inicializar Timer3 para la PWM del pin 3
Timer3.attachInterrupt(timerISR3); // Adjuntar la función de interrupción del temporizador 3
Timer4.initialize(); // Inicializar TimerFour para la tercera PWM
Timer4.attachInterrupt(timerISR4); // Adjuntar la función de interrupción del temporizador 4
CAN.begin(CAN_500KBPS) == CAN_OK; // Inicializar el bus CAN a una velocidad de 500 kbps
}
void loop() {
// Comprobar si hay un mensaje recibido
if (CAN_MSGAVAIL == CAN.checkReceive()) {
CAN.readMsgBuf(&len, buf); // Leer el mensaje CAN
canId = CAN.getCanId();
switch (canId) {
case 0x001:
canReceivedPWM1 = true;
lastCanReceivedTimePWM1 = millis();
freq1 = map(buf[0], 0, 255, 20, 3200);
periodMicros1 = 1000000 / freq1;
Timer1.setPeriod(periodMicros1 - 1);
Timer1.setPwmDuty(11, periodMicros1 * dutyCycle1 / 100);
break;
case 0x002:
canReceivedPWM2 = true;
lastCanReceivedTimePWM2 = millis();
freq2 = map(buf[0], 0, 255, 5, 4000);
periodMicros2 = 1000000 / freq2;
Timer3.setPeriod(periodMicros2 - 1);
Timer3.setPwmDuty(3, periodMicros2 * dutyCycle2 / 100);
break;
case 0x003:
canReceivedPWM3 = true;
lastCanReceivedTimePWM3 = millis();
freq3 = map(buf[0], 0, 255, 5, 4000);
periodMicros3 = 1000000 / freq3;
Timer4.setPeriod(periodMicros3 - 1);
Timer4.setPwmDuty(6, periodMicros3 * dutyCycle3 / 100);
break;
default:
break;
}
}
// Verificar si ha pasado el tiempo de espera desde la última recepción CAN para cada PWM
unsigned long currentTime = millis();
if (currentTime - lastCanReceivedTimePWM1 > canTimeout) {
canReceivedPWM1 = false;
}
if (currentTime - lastCanReceivedTimePWM2 > canTimeout) {
canReceivedPWM2 = false;
}
if (currentTime - lastCanReceivedTimePWM3 > canTimeout) {
canReceivedPWM3 = false;
}
}
// Función de interrupción del temporizador 1 (pin 11)
void timerISR1() {
if (canReceivedPWM1) {
static boolean state1 = HIGH;
digitalWrite(11, state1);
state1 = !state1;
}
}
// Función de interrupción del temporizador 3 (pin 3)
void timerISR3() {
if (canReceivedPWM2) {
static boolean state2 = HIGH;
digitalWrite(3, state2);
state2 = !state2;
}
}
// Función de interrupción del temporizador 4 (nuevo pin)
void timerISR4() {
if (canReceivedPWM3) {
static boolean state3 = HIGH;
digitalWrite(6, state3);
state3 = !state3;
}
}
Eso es Surbyte, mientras que no hay CAN no deben de funcionar los timers, pero la duda es por que si ponemos estas líneas, no funciona nada. No entiendo el porque, debería de funcionar.
No fue lo que escribí en el código.
Yo puse que si no tenés ninguna TRAMA CAN entonces que apague los timers. Eso como primera cosa. Luego CAN requiere tal vez que pongas el bit de salida en determinado estado. Eso te lo dejo a vos. Supuse que
lo haría, si quieres que tenga 12 ponelos en HIGH.
Entonces TimerX.Stop no detecta nada. Detiene el timer 1,2 o 3. Punto.
Llegamos ahi porque no hubo tramas CAN.
Antes estas lineas las habilitaste.
Asi que si no funcionan y requieres CAN en una linea independiente hablilita con la contraparte