-
Notifications
You must be signed in to change notification settings - Fork 0
/
Generador_PWM_Arduino.ino
157 lines (142 loc) · 5 KB
/
Generador_PWM_Arduino.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*=============================================================
Control Directo de PWM para Arduinos basados en AVR de 8 bits
=============================================================
Este sketch permite generar una señal PWM con frecuencia y ciclo de
trabajo arbitrarios mediante el pin 9 (Uno, lilypad, etc.) o bien el
pin 11 (Mega y Mega ADK).
Los parametros son establecidos mediante comandos enviados por el
puerto serie. La misma terminal de Arduino IDE puede ser usada
para este proposito.
Parametros de terminal de arduino:
- Velocidad: 9600 baudios
- Retorno de linea: CR ó CR/LF
Parametros adicionales (automatico si se usa la terminal de arduino)
- Bits de datos: 8
- Paridad: ninguna
- Bits de parada: 1
Comandos:
f (enter) : permite cambiar la frecuencia (Hz)
d (enter) : permite cambiar el ciclo de trabajo (%)
numero (enter) : establece el nuevo valor de frecuencia o ciclo
de trabajo
*/
//Cadena de texto que guarda el comando a medida llega por el puerto
String comando;
//Modo de comando. Indica con 'f' que se establece frecuencia y con
//'d' que se establece ciclo de trabajo
char modoCmd = 0;
//Valores de los registros de periodo y ciclo de trabajo
word reg_periodo = 0;
word reg_ciclo = 0;
//Valores de frecuencia (Hz) y ciclo de trabajo (%)
long freq = 1000;
byte ciclo = 50;
void setup() {
Serial.begin(9600);
//Se habilita el pin de I/O asociado al canal de PWM utilizado,
//que sera el canal A del timer 1 (OC1A), segun la tarjeta de
//arduino empleada
#if defined(__AVR_ATmega328P__)
//En las tarjetas basadas en ATMega328 (Uno, lilypad,
//duemilanove, etc.), la señal PWM se emite por el pin 9
pinMode(9, OUTPUT);
digitalWrite(9, LOW);
#elif defined(__AVR_ATmega2560__)
//En las tarjetas basadas en ATMega2560 se emplea el pin 11
pinMode(11, OUTPUT);
digitalWrite(11, LOW);
#else
#error "Tarjeta no soportada"
#endif
}
void loop() {
char caracter;
//La logica se efectua siempre que ingresa un caracter
if (Serial.available()) {
caracter = Serial.read();
if (caracter == 0x0D || caracter == 0x0A) {
//Si el caracter es de fin de linea, intenta procesar el comando
if (comando == "f") {
//El comando "f" indica que los datos ingresados son de
//frecuencia (en hertz)
modoCmd = 'f';
Serial.println("[OK]");
}
else if (comando == "d") {
//El comando "d" indica que los datos ingresados son de ciclo
//de trabajo (porcentaje)
modoCmd = 'd';
Serial.println("[OK]");
}
//El resto de comandos se intentan interpretar como numeros
else if (comando == "0" || comando.toInt() != 0) {
long valor = comando.toInt();
//Si se interpreto como numero exitosamente, se actualiza
//uno de los valores segun el modo de comando
switch (modoCmd) {
case 'f':
//En modo de frecuencia, se verifica que la misma sea
//lograble con el contador
if (valor < 245 && valor < 1000000) {
//Si no es lograble, se emite un mensaje de error
Serial.println("[ERROR]");
break;
}
//Si es realizable, se actualiza la frecuencia
freq = valor;
actualizarPWM();
break;
case 'd':
//En modo de ciclo de trabajo, se verifica que el mismo no
//exceda 100%
if (valor > 100) {
//Si excede 100% se emite un mensaje de error
Serial.println("[ERROR]");
break;
}
//Si es valido, actualiza el ciclo de trabajo
ciclo = valor;
actualizarPWM();
break;
default:
//Si no se ha establecido un modo de comando, se emite un
//mensaje de error
Serial.println("[ERROR]");
break;
}
}
else {
//Si el comando no se pudo interpretar como numero, reporta un
//mensaje de error
if (comando.length() != 0)
Serial.println("[ERROR]");
}
//Tras interpretar el comando, limpia la cadena
comando = "";
}
else if (comando.length() < 16)
//Todos los demas caracteres se almacenan hasta un maximo de 16
comando += caracter;
}
}
void actualizarPWM() {
//Activa el modulo en modalidad PWM rapido, utilizando ICR1L como
//registro de cuenta tope (periodo)
TCCR1A = 0x82;
TCCR1B = 0x19;
//Calcula los valores de los registros de acuerdo a las variables
//de estado
reg_periodo = F_CPU / freq;
reg_ciclo = long(ciclo) * reg_periodo / 100;
//Escribe los registros correspondientes con la nueva configuracion
OCR1AH = reg_ciclo >> 8;
OCR1AL = reg_ciclo & 0xFF;
ICR1H = reg_periodo >> 8;
ICR1L = reg_periodo & 0xFF;
//Imprime los valores verdaderos implementados (en caso de errores de
//aproximacion, se hacen evidentes)
Serial.print("F = ");
Serial.println(float(F_CPU) / reg_periodo);
Serial.print("DC = ");
Serial.println(float(reg_ciclo) / reg_periodo * 100);
}