Dirk
07.03.2010, 17:52
Hallo RP6-Fans,
manchmal braucht man eine bestimmte Frequenz (symmetrisches Rechteck-Signal, keine PWM), um ein eigenes Programm auf einem anderen uC zu testen oder um einen uC ohne Quarz wieder zu beleben.
Dieser Rechteck-Generator erzeugt Frequenzen am OC1A Pin der M32 (I/O-Stecker Pin 9 = PD5).
Der Generator startet mit 1kHz Rechteck. Man kann dann über das Terminal eine neue Frequenz im Bereich 0,12 bis 4000000 Hz eingeben.
Diese Frequenz wird möglichst genau eingestellt (Timer1 im CTC Modus) und an OC1A ausgegeben. Die Abweichung der erzeugten von der gewünschten Frequenz gibt das Programm in Promille am Terminal aus.
Leider kann nicht jede Frequenz mit diesem Programm erzeugt werden!
Viel Spaß damit!
Dirk
/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 TESTS
* ************************************************** **************************
* Beispiel: Rechteckgenerator
* Autor(en): Dirk
* ************************************************** **************************
* Beschreibung:
*
* Mit diesem Programm kann eine symmetrische Rechteck-Frequenz am OC1A Pin
* der M32 (PD5, I/O-Stecker Pin 9) erzeugt werden.
* Du kannst die gewünschte Frequenz am Terminal eingeben. Das Programm ver-
* sucht, diese Frequenz so gut wie möglich einzustellen und gibt die
* Ausgabe-Frequenz und die Abweichung von der gewünschten Frequenz in
* Promille [o/oo] am Terminal aus.
* Die gewählte Frequenz wird an OC1A ausgegeben, bis du eine neue Frequenz
* auswählst.
* Das Programm ist KEIN DDS, daher kann nicht jede Frequenz eingestellt
* werden.
*
* Technische Daten:
* -----------------
* Frequenzbereich: 0,12 [Hz] ... 4,0 [MHz]
* Start-Frequenz: 1000 [Hz]
* Generator Stop: Gib 0 ein
* Generator Start: Gib eine neue Frequenz ein
*
* ################################################## ##########################
* Der Roboter bewegt sich NICHT in diesem Beispiel! Du kannst ihn einfach auf
* einen Tisch neben deinen PC stellen und solltest ihn mit dem PC über das
* USB-Interface verbinden!
* ################################################## ##########################
* ************************************************** **************************
*/
/************************************************** ***************************/
// Einzufügende Dateien:
#include "RP6ControlLib.h"
#include "RP6uart_2.h"
/************************************************** ***************************/
// Definitionen:
#define INFO // Zeige zusätzliche Informationen
/************************************************** ***************************/
// Variablen:
double freq_target; // Gewünschte Frequenz
double freq_actual; // Aktuelle Frequenz
double deviation; // Abweichung [Promille]
const uint16_t prescalers[5] = {1, 8, 64, 256, 1024}; // Alle Vorteiler
uint8_t psindex; // Vorteiler Index
uint16_t prescaler; // Aktueller Vorteiler
uint16_t topvalue; // Aktueller OCR1A Spitzenwert
/************************************************** ***************************/
// Funktionen:
/**
* SETZE NEUE FREQUENZ
*
* Ruf diese Funktion auf, wenn du eine neue Frequenz einstellen willst.
*
*/
void setNewFrequency(double f_target)
{uint32_t topvalue32 = 0; double temp;
if (f_target == 0) {
TCCR1A &= ~(1 << COM1A0); // OC1A nicht verbunden
PORTD &= ~IO_PD5; // und PD5 auf Nullpegel
topvalue = 0;
return;
}
else {
temp = (double) F_CPU / 4;
if (f_target > temp) f_target = temp;
temp = (double) F_CPU / (2 * 1024 * 65535);
if (f_target < temp) f_target = temp;
TCCR1A |= (1 << COM1A0); // OC1A verbunden
}
for (psindex = 0; psindex < 5; psindex++) {
prescaler = prescalers[psindex];
temp = (double) F_CPU / (2 * prescaler * f_target) - 1;
topvalue32 = temp + 0.5; // Runde zum Integer-Wert
if (topvalue32 < 65535) break;
}
topvalue = (uint16_t) topvalue32;
cli();
switch (prescaler) {
case 1 :
TCCR1B = (0 << WGM13) // Vorteiler 1
| (1 << WGM12)
| (0 << CS12)
| (0 << CS11)
| (1 << CS10);
break;
case 8 :
TCCR1B = (0 << WGM13) // Vorteiler 8
| (1 << WGM12)
| (0 << CS12)
| (1 << CS11)
| (0 << CS10);
break;
case 64 :
TCCR1B = (0 << WGM13) // Vorteiler 64
| (1 << WGM12)
| (0 << CS12)
| (1 << CS11)
| (1 << CS10);
break;
case 256 :
TCCR1B = (0 << WGM13) // Vorteiler 256
| (1 << WGM12)
| (1 << CS12)
| (0 << CS11)
| (0 << CS10);
break;
case 1024 :
TCCR1B = (0 << WGM13) // Vorteiler 1024
| (1 << WGM12)
| (1 << CS12)
| (0 << CS11)
| (1 << CS10);
}
OCR1A = topvalue;
sei();
}
/************************************************** ***************************/
// Haupt Funktion - Das Programm beginnt hier:
int main(void)
{uint8_t i;
initRP6Control();
initLCD();
showScreenLCD("Rechteck-Gener. ", " Version 1.00 ");
writeString_P("\n\n _______________________\n");
writeString_P(" \\| RP6 ROBOT SYSTEM |/\n");
writeString_P(" \\_-_-_-_-_-_-_-_-_-_/\n\n");
writeString_P("################\n");
writeString_P("<<RP6 Control>>\n");
writeString_P("Rechteck-Gener. \n");
writeString_P(" Version 1.00 \n");
writeString_P("################\n\n");
mSleep(2500);
setLEDs(0b111111);
mSleep(500);
setLEDs(0b000000);
// Initialisiere den M32 OC1A Pin (PD5) als Ausgang:
DDRD |= IO_PD5;
// Initialisiere den M32 Timer1 "Lösche Timer
// bei Vergleichs-Übereinstimmung" (CTC) Modus:
cli();
// Timer 1:
// Kein Vorteiler, Modus 4 (CTC, Spitzenwert OCR1A),
// schalte OC1A um bei Vergleichs-Übereinstimmung.
TCCR1A = (0 << COM1A1)
| (1 << COM1A0)
| (0 << FOC1A)
| (0 << WGM11)
| (0 << WGM10);
TCCR1B = (0 << WGM13)
| (1 << WGM12)
| (0 << CS12)
| (0 << CS11)
| (1 << CS10);
OCR1A = F_CPU / 2000 - 1; // 1 kHz beim Start
// Schalte Ausgabe-Vergleichs-Übereinstimmungs A Interrupts aus:
TIMSK &= ~(1 << OCIE1A);
sei();
while(true)
{
writeString_P("\n\n\n\n\n\n\n\n");
writeString_P("\n|============================|");
writeString_P("\n| Rechteck - Generator V1.0 |");
writeString_P("\n|============================|");
writeString_P("\n| Zielfrequenz [Hz] eingeben |\n");
enterString();
i = 0;
while (receiveBuffer[i]) { // Ersetze ',' durch '.'
if (receiveBuffer[i] == ',') receiveBuffer[i] = '.';
i++;
}
writeString_P("|============================|\n");
freq_target = atof(&receiveBuffer[0]);
writeString_P("| F-Ziel ");
writeDouble(freq_target, 11, 3);
writeString_P(" [Hz]");
writeString_P("\n|============================|");
setNewFrequency(freq_target);
if (topvalue) {
#ifdef INFO
writeString_P("\n| Neue OCR1A Spitze ");
writeLong(topvalue, DEC);
writeString_P("\n| Neuer Vorteiler ");
writeLong(prescaler, DEC);
writeString_P("\n|============================|");
#endif
freq_actual = (double) 2 * prescaler * (1 + topvalue);
freq_actual = (double) F_CPU / freq_actual;
writeString_P("\n| F-Aktuell ");
writeDouble(freq_actual, 11, 3);
writeString_P(" [Hz]");
writeString_P("\n|============================|");
#ifdef INFO
deviation = (freq_actual - freq_target) / freq_target * 1000;
writeString_P("\n| Abweichung ");
writeDouble(deviation, 7, 3);
writeString_P(" [o/oo]");
writeString_P("\n|============================|");
#else
writeString_P("\n\n\n\n\n");
#endif
}
else {
writeString_P("\n| Generator ist jetzt aus!!! |");
writeString_P("\n|============================|");
writeString_P("\n\n\n\n\n");
}
}
return 0;
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 07.03.2010 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
manchmal braucht man eine bestimmte Frequenz (symmetrisches Rechteck-Signal, keine PWM), um ein eigenes Programm auf einem anderen uC zu testen oder um einen uC ohne Quarz wieder zu beleben.
Dieser Rechteck-Generator erzeugt Frequenzen am OC1A Pin der M32 (I/O-Stecker Pin 9 = PD5).
Der Generator startet mit 1kHz Rechteck. Man kann dann über das Terminal eine neue Frequenz im Bereich 0,12 bis 4000000 Hz eingeben.
Diese Frequenz wird möglichst genau eingestellt (Timer1 im CTC Modus) und an OC1A ausgegeben. Die Abweichung der erzeugten von der gewünschten Frequenz gibt das Programm in Promille am Terminal aus.
Leider kann nicht jede Frequenz mit diesem Programm erzeugt werden!
Viel Spaß damit!
Dirk
/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 TESTS
* ************************************************** **************************
* Beispiel: Rechteckgenerator
* Autor(en): Dirk
* ************************************************** **************************
* Beschreibung:
*
* Mit diesem Programm kann eine symmetrische Rechteck-Frequenz am OC1A Pin
* der M32 (PD5, I/O-Stecker Pin 9) erzeugt werden.
* Du kannst die gewünschte Frequenz am Terminal eingeben. Das Programm ver-
* sucht, diese Frequenz so gut wie möglich einzustellen und gibt die
* Ausgabe-Frequenz und die Abweichung von der gewünschten Frequenz in
* Promille [o/oo] am Terminal aus.
* Die gewählte Frequenz wird an OC1A ausgegeben, bis du eine neue Frequenz
* auswählst.
* Das Programm ist KEIN DDS, daher kann nicht jede Frequenz eingestellt
* werden.
*
* Technische Daten:
* -----------------
* Frequenzbereich: 0,12 [Hz] ... 4,0 [MHz]
* Start-Frequenz: 1000 [Hz]
* Generator Stop: Gib 0 ein
* Generator Start: Gib eine neue Frequenz ein
*
* ################################################## ##########################
* Der Roboter bewegt sich NICHT in diesem Beispiel! Du kannst ihn einfach auf
* einen Tisch neben deinen PC stellen und solltest ihn mit dem PC über das
* USB-Interface verbinden!
* ################################################## ##########################
* ************************************************** **************************
*/
/************************************************** ***************************/
// Einzufügende Dateien:
#include "RP6ControlLib.h"
#include "RP6uart_2.h"
/************************************************** ***************************/
// Definitionen:
#define INFO // Zeige zusätzliche Informationen
/************************************************** ***************************/
// Variablen:
double freq_target; // Gewünschte Frequenz
double freq_actual; // Aktuelle Frequenz
double deviation; // Abweichung [Promille]
const uint16_t prescalers[5] = {1, 8, 64, 256, 1024}; // Alle Vorteiler
uint8_t psindex; // Vorteiler Index
uint16_t prescaler; // Aktueller Vorteiler
uint16_t topvalue; // Aktueller OCR1A Spitzenwert
/************************************************** ***************************/
// Funktionen:
/**
* SETZE NEUE FREQUENZ
*
* Ruf diese Funktion auf, wenn du eine neue Frequenz einstellen willst.
*
*/
void setNewFrequency(double f_target)
{uint32_t topvalue32 = 0; double temp;
if (f_target == 0) {
TCCR1A &= ~(1 << COM1A0); // OC1A nicht verbunden
PORTD &= ~IO_PD5; // und PD5 auf Nullpegel
topvalue = 0;
return;
}
else {
temp = (double) F_CPU / 4;
if (f_target > temp) f_target = temp;
temp = (double) F_CPU / (2 * 1024 * 65535);
if (f_target < temp) f_target = temp;
TCCR1A |= (1 << COM1A0); // OC1A verbunden
}
for (psindex = 0; psindex < 5; psindex++) {
prescaler = prescalers[psindex];
temp = (double) F_CPU / (2 * prescaler * f_target) - 1;
topvalue32 = temp + 0.5; // Runde zum Integer-Wert
if (topvalue32 < 65535) break;
}
topvalue = (uint16_t) topvalue32;
cli();
switch (prescaler) {
case 1 :
TCCR1B = (0 << WGM13) // Vorteiler 1
| (1 << WGM12)
| (0 << CS12)
| (0 << CS11)
| (1 << CS10);
break;
case 8 :
TCCR1B = (0 << WGM13) // Vorteiler 8
| (1 << WGM12)
| (0 << CS12)
| (1 << CS11)
| (0 << CS10);
break;
case 64 :
TCCR1B = (0 << WGM13) // Vorteiler 64
| (1 << WGM12)
| (0 << CS12)
| (1 << CS11)
| (1 << CS10);
break;
case 256 :
TCCR1B = (0 << WGM13) // Vorteiler 256
| (1 << WGM12)
| (1 << CS12)
| (0 << CS11)
| (0 << CS10);
break;
case 1024 :
TCCR1B = (0 << WGM13) // Vorteiler 1024
| (1 << WGM12)
| (1 << CS12)
| (0 << CS11)
| (1 << CS10);
}
OCR1A = topvalue;
sei();
}
/************************************************** ***************************/
// Haupt Funktion - Das Programm beginnt hier:
int main(void)
{uint8_t i;
initRP6Control();
initLCD();
showScreenLCD("Rechteck-Gener. ", " Version 1.00 ");
writeString_P("\n\n _______________________\n");
writeString_P(" \\| RP6 ROBOT SYSTEM |/\n");
writeString_P(" \\_-_-_-_-_-_-_-_-_-_/\n\n");
writeString_P("################\n");
writeString_P("<<RP6 Control>>\n");
writeString_P("Rechteck-Gener. \n");
writeString_P(" Version 1.00 \n");
writeString_P("################\n\n");
mSleep(2500);
setLEDs(0b111111);
mSleep(500);
setLEDs(0b000000);
// Initialisiere den M32 OC1A Pin (PD5) als Ausgang:
DDRD |= IO_PD5;
// Initialisiere den M32 Timer1 "Lösche Timer
// bei Vergleichs-Übereinstimmung" (CTC) Modus:
cli();
// Timer 1:
// Kein Vorteiler, Modus 4 (CTC, Spitzenwert OCR1A),
// schalte OC1A um bei Vergleichs-Übereinstimmung.
TCCR1A = (0 << COM1A1)
| (1 << COM1A0)
| (0 << FOC1A)
| (0 << WGM11)
| (0 << WGM10);
TCCR1B = (0 << WGM13)
| (1 << WGM12)
| (0 << CS12)
| (0 << CS11)
| (1 << CS10);
OCR1A = F_CPU / 2000 - 1; // 1 kHz beim Start
// Schalte Ausgabe-Vergleichs-Übereinstimmungs A Interrupts aus:
TIMSK &= ~(1 << OCIE1A);
sei();
while(true)
{
writeString_P("\n\n\n\n\n\n\n\n");
writeString_P("\n|============================|");
writeString_P("\n| Rechteck - Generator V1.0 |");
writeString_P("\n|============================|");
writeString_P("\n| Zielfrequenz [Hz] eingeben |\n");
enterString();
i = 0;
while (receiveBuffer[i]) { // Ersetze ',' durch '.'
if (receiveBuffer[i] == ',') receiveBuffer[i] = '.';
i++;
}
writeString_P("|============================|\n");
freq_target = atof(&receiveBuffer[0]);
writeString_P("| F-Ziel ");
writeDouble(freq_target, 11, 3);
writeString_P(" [Hz]");
writeString_P("\n|============================|");
setNewFrequency(freq_target);
if (topvalue) {
#ifdef INFO
writeString_P("\n| Neue OCR1A Spitze ");
writeLong(topvalue, DEC);
writeString_P("\n| Neuer Vorteiler ");
writeLong(prescaler, DEC);
writeString_P("\n|============================|");
#endif
freq_actual = (double) 2 * prescaler * (1 + topvalue);
freq_actual = (double) F_CPU / freq_actual;
writeString_P("\n| F-Aktuell ");
writeDouble(freq_actual, 11, 3);
writeString_P(" [Hz]");
writeString_P("\n|============================|");
#ifdef INFO
deviation = (freq_actual - freq_target) / freq_target * 1000;
writeString_P("\n| Abweichung ");
writeDouble(deviation, 7, 3);
writeString_P(" [o/oo]");
writeString_P("\n|============================|");
#else
writeString_P("\n\n\n\n\n");
#endif
}
else {
writeString_P("\n| Generator ist jetzt aus!!! |");
writeString_P("\n|============================|");
writeString_P("\n\n\n\n\n");
}
}
return 0;
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 07.03.2010 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/