Hallo Zusammen,
ich habe mir hier schon so manchen Tip geholt, komme aber an einer
Stelle nicht weiter.Manchmal fehlt einfach das richtige Suchwort und da
wäre ich um jeden Tip dankbar. Ich finde jede Menge zu Midi senden, aber
kaum etwas zum Empfangen.
Ich baue eine Midi-Steuerung für Gitarrenverstärker, das empfängt
Programm Change und schaltet dann entsprechend ein paar Relais.
Ich habe einen fertigen Bausatz, der Funktioniert auch gut, jedoch war
ich mit der Programmierung nicht einverstanden und so fing das Theater
an :-)
Ich habe bisher ein Programm gebaut, das an PD2 und PD3 per Taster 4
Relais hoch bzw. runter schaltet. Das funktioniert einwandfrei soweit.
Es ist immer ein Relais geschaltet.
Dann habe ich eine Uart mit IRQ Steurung eingebaut und im AVR Simulator
IDE getestet, da sende ich 0xCX 0x01, das wäre Programmchange auf Kanal
X und Programmnummer 1. Funktioniert.
Nun habe ich das Ganze auf den Chip geflusht und da klemmt es irgendwo
:-)
Da ich noch keinen Weg gefunden habe, auf dem Chip zu debuggen, habe ich
folgendes gemacht. Immer wenn ein Zeichen anliegt, schalte ein Relais
weiter und schreibe das Zeichen in den eeprom und wenn nichts mehr
kommt, schreibe eine 0 ins eeprom (als terminator).
Beim Testen passiert folgendes: Bei jedem Programmchange, wird nur
einmal geschaltet (ich hätte zweimal erwartet) Also bekomme ich immerhin
mit, das was am Midi passiert.
Das steht im eeprom: 0000EA00F200F200F200FA00, ich habe Programm
50,51,52 usw gesendet.
Hier mal der testcode Ausschnitt:
(das uart_putc ist für den Simulator)
1
intmain(void)
2
{
3
4
program=0;
5
gotChange=0;
6
uart_init();
7
sei();
8
9
while(1){
10
if(uart_data_received()){
11
switchChannel(UP);//schaltet eine Relais weiter -> klack
Urban M. schrieb:> Hier mal der testcode Ausschnitt:> (das uart_putc ist für den Simulator)
Der hilft dir nicht viel.
Denn im Simulator ist immer alles perfekt: Die Taktfrequenz ist genau
die, die du eingestellt hast, etc. etc.
Meines erachtens ist es ein Fehler, wenn man bei der UART gleich mit dem
Empfang loslegt.
Die andere Richtung (unter mithilfe eines PC mit einem Terminalprogramm
drauf) ist viel sinnvoller als erstes in Betrieb zu nehmen.
Meine Empfehlung wäre:
Sieh zu, dass du vom AVR aus per UART etwas wegschickst und sieh zu,
dass du am PC mit einem Terminalprogramm das dann auch sichtbar kriegst.
Und solange du am PC nicht genau das siehst, was am AVR weggeschickt
wird (zb ein simples 'x'), solange hast du ein Problem mit der Baudrate,
welches in den meisten Fällen auf eine falsche Taktversorgung des µC
zurückzuführen ist.
Wenn das dann klappt, dann klappt auch die Gegenrichtung im Regelfall
sofort.
Alles andere ist stochern im Nebel.
Alternativ könnte man versuchen, erst mal abzuklären, ob die
Taktfrequenz des AVR auch wirklich die ist, mit der man die Faktoren bei
der UART Initialisierung berechnet hat.
Ob der Takt 1Mhz ist, oder 4Mhz oder 8 Mhz oder 16Mhz kann man mit einem
einfach _delay_ms ermitteln. Schwieriger wird es zwischen 11Mhz und
12Mhz zu unterscheiden. Aber den Fall hat man eigentlich nicht. Denn man
weiss ja, was auf dem Quarz drauf steht und die Alternative ist ja dann
nur, ob der AVR noch mit den Default 1Mhz läuft, oder ob der Quarz aktiv
ist und der AVR mit 11Mhz läuft. Das wiederrum lässt sich mit einer LED
und delay-gesteuertem Delay leicht überprüfen.
Erst mal danke für die schnelle Antwort, ich programmiere das Teil im
Moment mit der internen 1Mhz Frequenz und habe das in den Optionen und
Fuses eingestellt, bzw belassen. Der Uart rechnet so:
Kann aber gut sein, das da noch etwas nicht stimmt. ich habe mir die
Terminal.exe gesaugt und bekomme immerhin eine Verbindung, empfangen tue
ich erst mal nix :-)....da muss ich mich noch mit beschäftigen.
Gibt es da Standard Unix Tools, die ggf besser geeignet sind? Ich habe
hier OSX und bekomme auch fast all Pinguinableger zum Laufen.
Denk auch bitte daran, dass das Schreiben ins EEPROM langsam ist.
Beim Mega32 (das Datenblatt hab ich gerade offen) gibt Atmel an, dass es
rund 8400 Takzyklen dauert. Bei 1Mhz sind das immerhin ca 8.5ms. Da
muss die Baudrate gar nicht so hoch sein, dass dir die UART Übertragung
das Programm 'überläuft'.
Ev. das empfangene lieber erst mal im SRAM zwischenspeichern und dann zb
auf Knopfdruck ins EEPROM transfierieren, damit du mit dem Brenner da
rann kommst.
So, ich habe mal weiter gegoogelt und das ist vermutlich mein
Gedankenfehler gewesen......Empfangen :-)
Mit Deinen Infos: UART - Terminal - Senden - Problem, finde ich nun eine
ganze Menge und werde mich da erst mal langsam durchwurschteln, und ein
Testprogramm bauen, was ausschließlich mit einem Terminal quasselt.
Wenn das klappt, habe ich wohl die Baudrate gefunden und einen kleinen
Schritt weiter gemacht.
Ich verkrieche mich mal in die Testhöhle, I'll keep u updated.
Danke, Deine Antwort kam als ich geschrieben habe :-)
Das eeprom Schreiben habe ich erst später eingebaut, ist aber ein Tip,
die empfangenen Zeichen erst mal zu Puffern und dann auf Knopfdruck ins
eeprom schreiben.
Ich bin wohl ein Stück weiter und denke es liegt an der Baudrate. Midi
spielt mit 9600 und das bekommt man mit 1MHz offensichtlich nicht hin.
Der Bausatz läuft mit 7.3728 MHz, also werde ich einen entsprechenden
Ozi dranhängen. Da kann man aber viel falsch machen, ergo werde ich viel
Spaß haben :-)
Um mit einem Terminal zu quasseln benötige ich wohl andere Hardware,
daher habe ich das erst mal verworfen. Grundsätzlich bekomme ich ja Midi
Signale...eben nur unsinnige....
Diese Links sind brauchbar für mein Projekt und will sie hier auch
teilen, falls noch jemand über diesen thread stolpert.
Midi Controller:
http://www.oldcrows.net/~patchell/smb1/midi.pdf
Das Gegenstück, das Program Change Fussbrett:
https://github.com/eepp/avr-midi-footswitch/blob/master/main.c
Baudratenrechner:
http://www.gjlay.de/helferlein/avr-uart-rechner.html
Der Midi Bausatz:
http://www.tube-town.net/ttstore/Bausaetze/Sonstige-Bausaetze/Kit-Midi-Kanalumschalter::6193.html
Der Bausatz ist sehr gut, lediglich die Tastersteuerung gefällt mir
nicht so gut.
Die Midi Quellcodes muss ich mir Stückweise zu Gemüte führen, aber mit
dem Uart Tutorial hier, klappt das schon. Sobald ich was habe, melde ich
mich noch mal.
So ein dröges "Nö" enttäuscht mich aber lach
Die Richtigkeit meiner Quellen konnte ich noch nicht prüfen, jedenfalls
bekomme ich 31250 noch weniger sauber hin mit 1MHz
Hi
>Die Richtigkeit meiner Quellen konnte ich noch nicht prüfen, jedenfalls>bekomme ich 31250 noch weniger sauber hin mit 1MHz
31250Bd bei 1MHz bekommst du sogar mit einem Fehler von genau 0% hin.
MfG Spess
Der schlaue Baudrechner sagt alles was über 4800 liegt, geht
nicht...sauber :-).....aber das werde ich noch mal testen.
Mit den oben geposteten Quellen werde ich mein Midi Geraffelt noch mal
neu bauen und mir für die Baudraten mal einen Test machen, dass ich die
ggf on the fly ändern kann....egal ob das klappt oder nicht...hinterher
bin sogar ich schlauer :-)
Hi
>Der schlaue Baudrechner sagt alles was über 4800 liegt, geht>nicht...sauber :-).....aber das werde ich noch mal testen.
Dann tauge er nichts. Midi hat eine Bitlänge von 32 µs. Da die UART 16
mal pro Bit abtastet geschieht das alle 2µs, also mit einer Freqenz von
500kHz. Und 500kHz sind nunmal 1MHz/2. Macht beim AVR ein UBRR von 1.
MfG Spess
Et funzt nu, ich habe alles richtig gemacht, bis auf...
1
#define BAUD 9600UL
Getreut dem Motto, real men never read a manual, habe ich das nie in
Frage gestellt. :-)
Hätte Jonas gleich gesagt: Hau dir mal eine selber rein und mach das:
1
#define BAUD 31250UL
wäre alles gut gewesen.
Ich habe das ganze uart Geraffelt noch mal neu geschrieben und mir alle
Zeilen die ich nicht kapiert habe noch mal nachgelesen....nun bin sogar
ich schlauer.
Ich teste noch an Optimierungen und werde dann mein Beispiel mal
anhängen.
Besten Dank für die Tips.
So, ich habe das Programm nun soweit, das ich es hier anhängen
kann....falls noch Jemand über das Problem stolpert, sollte ja auch eine
Lösung zu finden sein.
Midi Program_Change empfangen und darauf reagieren, sowie passend zum
Programm die Daten speichern......es ist jedoch nicht durchgetestet, da
ich aus meinem Ungetüm einfach alles was nicht hierher passt entfernt
habe.
(ich meine die Variable midiEnabled) ist den Aufwand nicht wert. Die
ganze Abfragerei dieser Variablen bzw. Setzen derselben kostet dich
mehr, als wie wenn du ganz einfach in den Registern die Bits setzt. Der
UART Einheit ist das sowieso egal, wenn du bereits gesetzte Bits nochmal
setzt.
1
voidenableIRQ(unsignedcharreceiveOnly)
2
{
3
UCSRB=(1<<RXCIE)|(1<<RXEN);
4
if(!receiveOnly)
5
UCSBR|=(1<<TXEN);
6
}
selbiges beim disablen.
Den Funktionsnamen find ich nicht so prickelnd. Denn eigentlich wird ja
hier die UART als ganzes aktiviert und nicht nur der IRQ.
Hier
1
unsignedcharreadByte(void)
2
{
3
unsignedcharnewTail;
4
5
newTail=(UART_RxTail+1)&UART_RX_BUFFER_MASK;
6
UART_RxTail=newTail;
7
8
returnUART_RxBuf[newTail];// return buffer byte
9
}
hast du eine Race Condition. Du setzt UART_RxTail zu früh auf den neuen
Wert. Wenn dir zwischen der Zuweisung an UART_RxTail und dem abholen der
Daten aus dem Array ein UART Empfangs Interrupt dazwischenknallt UND der
Ringbuffer bereits voll ist, dann überschreibt dir der Empfangsinterrupt
genau das eine Byte im Array, das du gerade im Begriff bist zu holen.
OK. der Fall wird bei dir wahrscheinlich so nicht vorkommen und wenn der
Ringbuffer voll ist, hast du ganz andere Probleme. Trotzdem ist es eine
Racecondition.
1
SIGNAL(SIG_UART_RECV)
2
{
SIGNAL ist seit vielen, vielen Jahren veraltet.
1
voidcheckEeprom()
2
{
3
....
4
byte=0x00;
5
eeprom_write_byte((uint8_t*)ADR_GLOBAL,byte);
du verschleierst hier mehr, als du gut machst. Warum nicht einfach
1
eeprom_write_byte((uint8_t*)ADR_GLOBAL,0x00);
und warum nicht den cast gleich in das ADR_GLOBAL Makro mit integrieren?
1
#define ADR_GLOBAL ((uint8_t*)128) //adress where globals are saved
2
#define ADR_DETECT ((uint8_t*)129) //test byte, if eeprom is init
für etwas anderes als die Adressierung ins EEPROM kannst du die beiden
Makros sowieso nicht gebrauchen (zumindest in der überwiegenden Mehrzahl
der Fälle)
1
//show write effect clean blinks
2
for(inti=1;i<5;i++){
3
clean(true);
4
_delay_ms(PAUSE-100);
5
clean(false);
6
}
wozu der int?
Abgesehen davon: das da was blinkt ist theoretisch. Wenn du nicht gerade
Superman bist, wirst du da nichts blinken sehen. Da fehlt ein 2.ter
delay. Blinken besteht nun mal aus 2(!) Zuständen. Und beide müssen
entsprechend lange anliegen, damit langsame Menschen die beiden auch
sehen können.
Klaro bin ich an Kritik interessiert, immer feste druff :-)
Grundsätzlich optimiere ich noch an dem Code und Hilfe kann nie schaden.
midiEnabled habe ich eingeführt, weil mir nicht ganz klar ist ob und wie
viel Zeit das setzen der Bits kostet. Ich mache sonst GUI Programme und
bin paranoid, wenn etwas unnötig verzögert und ggf. die GUI einfriert
:-)
Das ist auch nur drin, weil ich alle PIN's für Schalter brauche und
eigentlich gar nicht senden will. Luft nach oben ist immer vorhanden...
readByte hast Du uneingeschränkt recht :-)
Dem Signal geht es wie mir....völlig veraltet....muss ausgetauscht
werden. Das ist never change a running code....Wie und wann welcher ISR
aufgerufen wird, ist mir noch nicht so ganz klar, da ich das so gewohnt
bin: connect(ptrUart,SIGNAL(sig_MidiDaten()), this, SLOT(onMidiDaten())
);
defines verbessern, ja...ich gelobe Besserung.
Die Loop zum Blinken ist tatsächlich Müll...habe ich so herunter
getippt....da war vorher was Anderes, was aber das Textprogramm nur
verkompliziert hätte...ein delay noch am Ende und gut ist, der int ist
auch Gewohnheit ....ich tippe fast täglich for(int i =...... Das geht
dann automatisch :-)
Danke
So ich habe noch mal ein Update gemacht und mich um die kleinen
Problemchen oben gekümmert. Das
1
#define ADR_GLOBAL 128
habe ich belassen, weil ich das an anderer Stelle noch mal als Zahl
brauche und dann müsste ich zurückcasten.....nee :-)
Es ist jetzt jedoch eine gute Basis für meine 3 Projekte..
Kann man den Anhang oben löschen, ich kann das leider nicht mehr
editieren?