Hallo zusammen, ich würde gerne ein Frequenzmoduliertes Signal mit einem ATxmega32A4U erzeugen und weiß nicht so recht wie ich da herangehen soll. Das Signal soll wie folgt aussehen: Die Periodendauer der Grundrechteckfrequenz ist T = 105ms (ca. 9,5Hz). Tein beträgt 5ms und Taus 100ms. Nun würde ich gerne in Tein, also in den 5ms eine Frequenz von 39kHz bis 40kHz (Tastgrad 50%) hochlaufen lassen. Dann 100ms Taus und in dem nächsten Tein die Frequenz von 40kHz wieder auf 39kHz runterlaufen lassen. Das dann immer im Wechsel. Ich denke ich brauche hierfür zwei Timer. Einen für die Grundfrequenz und einen für die Frequenz die in Tein der Grundfrequenz herauf- bzw. herunterläuft. Den Ersten Timer würde ich im „phase correct PWM mode“ laufen lassen um den Tastgrad zu erreichen. Den zweiten im „fast PWM mode“ da ich ja keinen Tastgrad benötige“. Die Nächste Überlegung von mir wäre, dass ich die Reloadwerte für die 39kHz-40kHz in eine Tabelle lege und diese dann immer im Timerinterrupt nachlade um so die 100kHz von 39kHz bis 40kHz zu erreichen. Bei einer Oszillatorfrequenz von 16MHz und einem Prescaler von 1, komme ich auf Reloadwerte (OCR1A) für 39kHz auf 204 und für 40kHz auf 199. Das wären ja dann in viel zu große Schritte. Ich würde gerne die 100kHz möglichst klein in den 5ms herauf- bzw. herunterlaufen. Ich wäre sehr dankbar für jegliche Tipps wie ich so etwas realisieren könnte. Grüße Robert
39 kHz ~= 410 Clk-Zyklen bei 16 MHz 40 kHz ~= 400 Clk-Zyklen bei 16 MHz das sind 10 Steps Wenn es symmetrisch sein soll: 39 kHz ~= 2 * 205 Clk-Zyklen bei 16 MHz 40 kHz ~= 2 * 200 Clk-Zyklen bei 16 MHz Zwischenwerte sind noch möglich: 205 - 205 204 - 205 204 - 204 ... 200 - 200 Das sind 10 Schritte. Zwischen- Zwischenwerte sind aber auch noch möglich: 8 * 205 7 * 205 + 1 * 204 = 204,875 6 * 205 + 2 * 204 = 204,750 5 * 205 + 3 * 204 = ... usw. Kämen schon mal 40 Zwischenschritte bei raus. Lässt sich aber noch verfeinern mit: 16 * 205, 15 * 205 + 1 * 204, ... DDS macht es auch nicht viel besser. ;-)
Jacko schrieb: > DDS macht es auch nicht viel besser. ;-) Gutes Stichwort. Ein DDS "mischt" die unterschiedlich langen Intervalle per Prinzip gut durch und man hat damit im uC keine Scherereien. Für die 3€, die ein Modul mit einem AD9833 kostet, hat man das nicht selber gestrickt. Per Timer braucht man dem nur die Werte auf der Frequenzrampen zuzuschieben, muss sich aber keine Sorgen um Phasenstetigkeit und Periodenmittelwert mehr machen. Bei 5ms Rampenlänge wird man allerdings sowieso nicht beliebig viele 39..40kHz Schwingungen unter kriegen und die Anwendung muss mit dem Phasenjitter leben können.
Hallo, vielen Dank für die Antworten. Ich habe nun mal etwas programmiert, was mir in den 5ms die Frequenzen erzeugt. Wie gesagt eben leider nur in 200 Hz Schritten, da 16MHz. Bei 32MHz könnte ich 100Hz Schritte realisieren. Den AD9833 muss ich mir noch genau anschauen. Hier müsste ich ja denn immer über die serielle Schnittsctelle mit diesem kommunizieren. Geht da nicht zu viel Zeit verloren? Hier ist mein Code in C für einen Atmega256. Bin dankbar für jede Hilfe wie ich das Program besser bzw. effizienter mache. Funktionieren tuts.
1 | /*
|
2 | * MEGA2560_R3.c
|
3 | *
|
4 | * Created: ...
|
5 | * Author : ...
|
6 | */
|
7 | |
8 | #define F_CPU 16000000UL // 16Mhz
|
9 | |
10 | #include <avr/io.h> |
11 | #include <util/delay.h> |
12 | #include <avr/interrupt.h> |
13 | |
14 | |
15 | //================================================================================
|
16 | // pin- and portdefinition
|
17 | //================================================================================
|
18 | #define CLK_STOP_HI TCCR1A &= ~(1<<COM1A0);PORTB |= (1<<PORTB5) // Portpin von Timer abgekoppelt => high
|
19 | #define CLK_STOP_LO TCCR1A &= ~(1<<COM1A0);PORTB &= ~(1<<PORTB5) // Portpin von Timer abgekoppelt => low
|
20 | #define CLK_TOGGLE PINB |= (1<<PINB5) // Portpin von Timer abgekoppelt => toggle
|
21 | #define CLK_START TCCR1A |= (1<<COM1A0) // Portpin an Timer angekoppelt => fclk
|
22 | |
23 | //================================================================================
|
24 | // frequenzen
|
25 | //================================================================================
|
26 | #define OCR_39000Hz 204 //39024,39024 Hz
|
27 | #define OCR_39200Hz 203 //39215,68627 Hz
|
28 | #define OCR_39400Hz 202 //39408,867 Hz
|
29 | #define OCR_39600Hz 201 //39603,9604 Hz
|
30 | #define OCR_39800Hz 200 //39800,99502 Hz
|
31 | #define OCR_40000Hz 199 //40000 Hz
|
32 | |
33 | |
34 | uint16_t count_100us = 0; |
35 | |
36 | void clk_init (void) |
37 | {
|
38 | unsigned char reg_help; |
39 | |
40 | DDRB |= (1<<DDB5); // CLK-Pin Port B, Bit 5 -> OUTPUT |
41 | CLK_STOP_LO; |
42 | |
43 | TCCR1A = 0x00; |
44 | TCCR1B = 0x00; |
45 | |
46 | reg_help = TCCR1A; |
47 | reg_help |= ((1<<WGM11) | (1<<WGM10)); // Timer 1: Fast PWM |
48 | TCCR1A = reg_help; |
49 | |
50 | reg_help = TCCR1B; |
51 | reg_help |= ((1<<WGM13) | (1<<WGM12) | (1<<CS12)); // Timer 1: Fast PWM / Prescale: 256 |
52 | TCCR1B = reg_help; |
53 | |
54 | TCCR1B &= ~(1<<CS12); // Timer 1: Fast PWM / Prescale: 1 |
55 | TCCR1B |= (1<<CS10); |
56 | }
|
57 | |
58 | void timer3_init (void) |
59 | {
|
60 | TCCR3A = 0x00; |
61 | TCCR3B = 0x00; |
62 | |
63 | TIMSK3 |= (1<<OCIE3A); |
64 | |
65 | OCR3A = 1600; |
66 | |
67 | TCCR3A |= ((1<<WGM31) | (1<<WGM30)); // Timer 3: Fast PWM |
68 | TCCR3B |= ((1<<WGM33) | (1<<WGM32) | (1<<CS30)); // Timer 3: Fast PWM / Prescale: 1 |
69 | }
|
70 | |
71 | // 100us
|
72 | ISR (TIMER3_COMPA_vect) |
73 | {
|
74 | count_100us++; |
75 | |
76 | if (count_100us == 10) |
77 | {
|
78 | OCR1A = OCR_39800Hz; |
79 | }
|
80 | else if (count_100us == 20) |
81 | {
|
82 | OCR1A = OCR_39600Hz; |
83 | }
|
84 | else if (count_100us == 30) |
85 | {
|
86 | OCR1A = OCR_39400Hz; |
87 | }
|
88 | else if (count_100us == 40) |
89 | {
|
90 | OCR1A = OCR_39200Hz; |
91 | }
|
92 | else if (count_100us == 50) |
93 | {
|
94 | OCR1A = OCR_39000Hz; |
95 | CLK_STOP_LO; |
96 | }
|
97 | else if (count_100us == 1000) |
98 | {
|
99 | OCR1A = OCR_40000Hz; |
100 | CLK_START; |
101 | count_100us = 0; |
102 | }
|
103 | }
|
104 | |
105 | int main (void) |
106 | {
|
107 | |
108 | clk_init (); |
109 | timer3_init (); |
110 | |
111 | OCR1A = OCR_40000Hz; |
112 | |
113 | sei(); |
114 | |
115 | while(1) |
116 | {
|
117 | ;
|
118 | }
|
119 | }
|
Gruß Robert
Robert schrieb: > Hier ist mein Code in C für einen Atmega256. Bin dankbar für jede Hilfe > wie ich das Program besser bzw. effizienter mache. Jacko hat dir die Grundidee für eine bessere Lösung quasi auf dem Silbertablett präsentiert, sogar die wesentliche Einschränkung mit aufgeführt und damit gezeigt, dass er definitiv weiss, wovon er redet. Diese Einschränkung betrifft im übrigen zumindest prinzipiell den Ansatz mit dem AD9833 ganz genauso. Warum nutzt du also nicht zumindest erst einmal Jackos Grundidee? Die läßt sich doch wirklich noch recht einfach umsetzen. Wenn das läuft und der sowieso unvermeidliche Phasenjitter ein wenig zu regulär ist, kann man die Grundidee variieren und dann tatsächlich das erreichen, was eine mit 16MHz getaktete DDS überhaupt zu erreichen in der Lage ist. Sprich: den unvermeidlichen Phasenjitter so stochastisch wie möglich zu machen, damit der Beschiss weniger auffällt. Das genau ist die Grundidee auch des AD9833, ja das Konzept einer DDS überhaupt...
Hallo, ich würde die Grundidee von Jacko (vielen Dank Jacko!) sehr gerne versuchen programmtechnisch umzusetzen. Leider weiß ich nicht genau wie. Benötige ich Timer und ISR? Soll ich es irgendwie mit Schleifen nur im Hauptprogramm laufen lassen. Einzelne Befehle brauchen dann ja auch wieder eine bestimmte zeit. Vielleicht könnte mir jemand erklären wie das Program dann aussehen soll bzw. wie es aufgebaut sein soll. Grüße
Robert schrieb: > Benötige ich Timer und ISR? Ja, genau das. Allerdings genügt ein Timer. Der wird dann halt in der ISR dynamisch umprogrammiert und kann so sowohl den 5ms-Sweep erzeugen als auch die 100ms Wartezeit zwischen den Sweeps. Der sinnvollste Timermodus für den Sweep ist übrigens Fast-PWM. Die Ablaufsteuerung kann man mittels Tabelle machen oder algorithmisch. Tabelle ist einfacher umzusetzen, braucht aber halt auch mehr Flash, die algorithmische Umsetzung braucht dafür mehr Rechenzeit in der ISR. Könnte in C umgesetzt eventuell schon etwas knapp werden. Die Tabellenlösung hingegen sollte auf jeden Fall ganz entspannt möglich sein. > Soll ich es irgendwie mit Schleifen nur im > Hauptprogramm laufen lassen. Einzelne Befehle brauchen dann ja auch > wieder eine bestimmte zeit. Kann man auch machen, aber nur dann, wenn das die einzige Aufgabe des µC sein soll. Ich würde es hier nicht empfehlen. Es macht hier nichts einfacher, eher ist das Gegenteil der Fall.
Hallo, ich glaube weitestgehend habe ich das so in meinem Program realisiert. Der Timer mit der ISR erzeugt mein 5ms tein und meine 100ms taus. Der zweite Timer erzeugt meine 5 verschiedenen Frequenzen welche immer in 1ms gewechselt werden. Wie funktioniert das aber nur mit einem Timer? Wie genau erzeuge ich dann den Sweep? Grüße
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.