Hallo Zusammen,
momentan versuche ich mit einem ATMEGA16 ein Rechtecksignal zu erzeugen,
das von einem Midikeyboard angesteuert wird.
Das Ganze soll später mal ein Oszillator für einen Synthesizer werden,
der die vier grundlegenden Wellenformen (Sinus, Dreieck, Sägezahn,
Rechteck) generieren kann.
Das Erzeugen der Frequenz ist nicht das Problem, sondern die
Midi-Schnittstelle will nicht so, wie ich will:
Ich habe mit erstmal ein Programm geschrieben, das wenn ich auf dem
Keyboard das A4 drücke den entsprechenden Ton mit 440Hz generieren soll.
Das klappt bis zu einem gewissen Grad auch gut, allerdings nur, so lange
ich die Taste nicht zu schnell drücke und wieder loslasse.
Dann scheint der ATMEGA nicht mehr schnell genug zu sein und somit
manche Midi-Messages zu verpassen.
Zur Hardware:
Das Keyboard habe ich über die standart Midi-In Schaltung angeschlossen,
die ich auch in den Anhang geladen habe.
Allerdings habe ich hinter den Optokoppler noch einen Schmitt-Trigger
gesetzt, da die Signale am Optokoppler noch nicht sehr sauber waren.
Die Midi-Schnittstelle am Keyboard funktioniert an meinem PC
einwandfrei, da liegt das Problem also nicht.
An PORTC liegt dann das generierte Signal an, wo ich dann zwei einfache
PC Speaker angeschlossen habe.
Zur Software:
Das Programm wartet auf einen UART-Interrupt, prüft dann ob es sich um
die Note-On Nachricht handelt und setzt dann einen int auf 1 oder 0, der
dann in der Hauptschleife die Tonerzeugung ein - oder ausschaltet.
Ich habe mich bemüht alles gut zu kommentieren und leserlich zu
gestalten, weshalb es einfach sein sollte das Program zu verstehen.
1
#define F_CPU 20000000UL
2
3
#include<avr/interrupt.h>
4
5
#include"uart.h"
6
7
8
voidgenerate_sound(uint8_tnote,uint8_tvelocity);
9
voidsilence();
10
voiddelay_us(uint16_tzeit);
11
12
13
uint8_tmessage=0,rcvd=0,note_on=0,data_rcvd=0;
14
uint8_tdata_buf[2];
15
volatileuint8_tplay_note=0;
16
volatileuint16_tdauer=0;
17
18
19
ISR(USART_RXC_vect)
20
{
21
rcvd=UDR;// Empfangsregister auslesen
22
23
if(rcvd>0x7F)// Status-Byte
24
{
25
message=rcvd>>4;// Die Nachricht = die oberen 4 Bit
26
27
if(message==0b1001)// Note On
28
{
29
// Die nächsten beiden Interrupts sind die zwei Datenbytes
30
// Also für die Aufzeichnung sorgen
31
note_on=1;
32
}
33
}
34
else// Daten-Byte
35
{
36
if(note_on)// Gehört das Daten-Byte zur Note On Nachricht?
37
{
38
data_buf[data_rcvd]=rcvd;// Daten-Byte ins Array schreiben
39
data_rcvd++;// Array-Index erhöhen
40
41
if(data_rcvd==2)// Beide Daten-Bytes empfangen?
42
{
43
note_on=0;// Note On Nachricht zu Ende
44
data_rcvd=0;// Array-Index resetten
45
46
if(data_buf[1])// velocity größer Null?
47
{
48
// Einen Klang mit der Note data_buf[0] und der
49
// velocity data_buf[1] erzeugen
50
generate_sound(data_buf[0],data_buf[1]);
51
}
52
else
53
{
54
// Sonderfall velocity = Null bedeutet Note Off
55
// Also still sein!
56
silence();
57
}
58
}
59
}
60
}
61
}
62
63
voidgenerate_sound(uint8_tnote,uint8_tvelocity)
64
{
65
uint16_tfreq;
66
67
play_note=1;
68
69
switch(note)
70
{
71
case69:// Kammerton A4 = 440Hz
72
freq=440;
73
break;
74
default:
75
play_note=0;
76
}
77
78
dauer=(1000000/freq)/2;// Periodendauer / 2 in µS berechnen;
79
80
}
81
82
voidsilence()
83
{
84
play_note=0;
85
}
86
87
88
// Wartet bei 20MHz Takt die vorgegebende Anzahl an µS
Synthbastler schrieb:> Das klappt bis zu einem gewissen Grad auch gut, allerdings nur, so lange> ich die Taste nicht zu schnell drücke und wieder loslasse.> Dann scheint der ATMEGA nicht mehr schnell genug zu sein und somit> manche Midi-Messages zu verpassen.
Das möchte ich mal ausschließen. Wenn es etwas nicht schafft, dann Dein
Programm.
Synthbastler schrieb:> Allerdings habe ich hinter den Optokoppler noch einen Schmitt-Trigger> gesetzt, da die Signale am Optokoppler noch nicht sehr sauber waren.
Ich denke, dass hier (auch) der Hase im Pfeffer liegt. Schalte an den
Optokoppler einen solch niederohmigen Arbeitswiderstand (470R...1k),
dass die Signale am Kollektor sauber sind und lass den Schmitt-Trigger
weg, der verändert nur das Tastverhältnis der Bits.
EDIT:
Anstelle des 6N138 tut es ein normaler PC817 oder CNY17-1.
Synthbastler schrieb:> while(play_note)> {> PORTC = 0xFF;> delay_us(dauer);> PORTC = 0x00;> delay_us(dauer);> }
Mit diesem Ansatz wirst du nicht über einen Kanal hinwegkommen. Für
mehrere Kanäle braucht man fast zwingend einen Timer. Die Tonerzeugung
für mehrere Kanäle gibt es übrigens recht effektiv hier:
AVR-Synthesizer
@Hobbyorganist
Ganz ehrlich.
Ich habe den Eindruck du solltest erst mal mit viel grundlegenderen
Dingen anfangen.
Dein Projekt in allen Ehren, aber du übernimmst dich. So wird das
nichts. Dein Können ist noch lange nicht an dem Punkt angelangt, an dem
man einigermassen sinnvoll ein derartiges Projekt anfangen kann, wobei
einige Dinge dann erst on-the-job gelernt werden.
Nix für ungut.
Der Anfang jedes µC-Progammierers besteht in
LED einschalten, LED ausschalten, LED blinken lassen.
Erst mit Zeitschleifen, dann mit Timern.
dann kommt irgendwann UART dazu, möglicherweise ein LCD
Und dann, erst dann, ist man auf einem Level, auf dem man sinnvoll
darüber nachdenken kann, wie man eigentlich Tonerzeugung auf einem AVR
macht. Wobei es dann immer noch viel zu lernen gibt. Die vorgenannten
Punkte sind sozusagen die Einstiegshürde. Solange die nicht beherrscht
werden (und natürlich die Programmiersprache einigermassen sicher
beherrscht wird), braucht man über ein Synthi-Midi-Projekt gar nicht
erst nachdenken.
Hallo,
ich habe mich auch schon mit MIDI beschäftigt. Um einen analogen
Synthesizer an MIDI-Keyboards zu betreiben, braucht man einen MIDI-to-CV
Konverter.
Wenn man diesen selbst baut, spart man eine Menge Geld und lernt
Assemblern (oder C), umd den Mikrocontroller zu betreiben. Es empfiehlt
sich, ein Flußdiagramm anzulegen, und diesen dann in Code umzusetzen.
Dafür eignet sich das kostenlose Programm "Diagramm Designer"
http://www.chip.de/downloads/Diagram-Designer_46463345.html.
Bei youtube
http://www.youtube.com/watch?v=qOInnuqfsS0&list=UUnJGkAU29GWN9MdDnQ3zNWA
kann man unter Anderem auch den Aufbau meines MIDI-to-CV Konverters
Marke Eigenbau sehen.
Ich habe den 80C31, 74HC573, 27C512, DAC0808LCN, µA741 und 4N35 dafür
verwendet. Taktfrequenz 12 MHz.
Gruß Thomas