PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6Control M32: Rechteck-Generator



Dirk
07.03.2010, 16: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
*
* ************************************************** **************************
*/

/************************************************** ***************************/

TrainMen
07.03.2010, 17:06
Hi,
ein Programmcode mit Deutschem Bemerkungen. Sollte es doch Programmierer geben die Wissen wo ihr Code gelesen wird. Da könnte sich so mancher ein Beispiel dran nehmen. Danke
Trainmen

Virus
07.03.2010, 17:52
danke, gute idee.

du könntest noch die .hex posten aber sonst ists jut!

Dirk
07.03.2010, 18:04
Hallo Leute,

ich hatte noch die RP6uart_2 Lib vergessen. Die wird von dem Programm gebraucht und muss auch ins makefile mit:
SRC += $(RP6_LIB_PATH)/RP6common/RP6uart_2.c
... eingetragen werden.

RP6uart_2.h:

#ifndef RP6UART_2_H
#define RP6UART_2_H
#include "RP6uart.h"
#define PRECISION 6
#define DTOSTR_ALWAYS_SIGN 0x01
#define DTOSTR_PLUS_SIGN 0x02
#define DTOSTR_UPPERCASE 0x04
char receiveBuffer[UART_RECEIVE_BUFFER_SIZE + 1];
void writeLong(int32_t number, uint8_t base);
void writeLongLength(int32_t number, uint8_t base, uint8_t length);
void writeDouble(double number, uint8_t width, uint8_t prec);
void writeDoubleExp(double number, uint8_t prec, uint8_t flags);
uint8_t getInputLine(void);
void enterString(void);
#endif

RP6uart_2.c:

#include "RP6uart_2.h"
void writeLong(int32_t number, uint8_t base) {char buffer[33]; ltoa(number, &buffer[0], base); writeString(&buffer[0]);}
void writeLongLength(int32_t number, uint8_t base, uint8_t length) {char buffer[33]; ltoa(number, &buffer[0], base); int8_t cnt = length - strlen(buffer); if(cnt > 0) {for(; cnt > 0; cnt--, writeChar('0')); writeString(&buffer[0]);} else writeStringLength(&buffer[0], length, -cnt);}
void writeDouble(double number, uint8_t width, uint8_t prec) {char buffer[width + 1]; dtostrf(number, width, prec, &buffer[0]); writeString(&buffer[0]);}
void writeDoubleExp(double number, uint8_t prec, uint8_t flags) {char buffer[prec + 8]; dtostre(number, &buffer[0], prec, flags); writeString(&buffer[0]);}
uint8_t getInputLine(void) {static uint8_t buffer_pos = 0; if(getBufferLength()) {receiveBuffer[buffer_pos] = readChar(); if((receiveBuffer[buffer_pos] == '\n') || (receiveBuffer[buffer_pos] == '\r')) {receiveBuffer[buffer_pos] = '\0'; buffer_pos = 0; return 1;} else if(buffer_pos >= UART_RECEIVE_BUFFER_SIZE) {receiveBuffer[UART_RECEIVE_BUFFER_SIZE] = '\0'; buffer_pos = 0; return 2;} buffer_pos++;} return 0;}
void enterString(void) {while(!getInputLine());}

In dieser Lib sind einige UART-Funktionen ausgelagert.

Gruß Dirk

Virus
07.03.2010, 18:12
die .hex und man ist das Problem los.

auserdem braucht man für die von dir genannten Zecke den Quellcode nicht, naja geht auch so.

Dirk
07.03.2010, 18:16
die .hex und man ist das Problem los. auserdem braucht man für die von dir genannten Zecke den Quellcode nicht,...

Nachteil:
Nur mit HEX lernt man NIX! O:)

Gruß
Dirk

Virus
07.03.2010, 19:40
da hast du natürlich absolut recht

radbruch
07.03.2010, 20:20
Hallo


Nur mit HEX lernt man NIX!Das stimmt wohl schon im Prinzip, aber bei "manchmal braucht man eine bestimmte Frequenz" mag wohl keiner wissen, wie die erzeugt wird.


du könntest noch die .hex postenWenn du sie jetzt hast könnest du sie auch selbst posten ;)

Und wen wirklich interessiert, wie das funktioniert, der läd sich die Hex-Datei eh nicht runter.

Gruß

mic