Ich wollte mit einem ATMega8 eine oktave stummelpedale midifizieren.
etzt hab ich mir gedacht, machst die uart mal von hand...
Irgendwas funktioniert aber nicht, ich habe mir den Takt von 31,250kHz
mittels timer hergestellt (und mit oszi nachgemessen) und ein
progrämmchen geschrieben, welches ein startbit, 8 datenbits und ein
stopbit auf einen pin schickt:
______________________________________________________________
unsigned char tick=0x00;
unsigned char toggle=0x00;
const unsigned char noteon=0x09; //90
const unsigned char keynum=0x24; //24
const unsigned char velocity=0xff;
const unsigned char novelocity=0x00;
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// if (tick==0x00)
// {
tick++;
// }
// else
// {
// tick=0x00;
// }
TCNT0=0x30;
}
void midiout (unsigned char byte)
{
unsigned char busy=0x01;
unsigned char bitcount=0x00;
while (busy==0x01)
{
//write startbit
if (bitcount==0x00 && tick==0x01)
{
PORTD=0xFF;
tick=0x00;
bitcount++;
}
//write stopbit
else if(bitcount==0x09 && tick==0x01)
{
PORTD=0xFF;
tick=0x00;
bitcount++;
}
else if(bitcount==0x0a && tick==0x01)
{
PORTD=0x00;
tick=0x00;
bitcount++;
busy--;
}
//write byte
else if(tick==0x01)
{
PORTD=byte;
byte>>=1;
bitcount++;
tick=0;
}
}
PORTC.1^=1;
}
// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
// Reinitialize Timer 1 value
TCNT1H=0x70;
TCNT1L=0x00;
// Place your code here
PORTC.2^=1;
toggle++;
}
/*
// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
// Place your code here
PORTD.2^=1;
}
*/
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port B initialization
// Func0=In Func1=In Func2=In Func3=In Func4=In Func5=In Func6=In
Func7=In
// State0=P State1=P State2=P State3=P State4=T State5=T State6=P
State7=P
PORTB=0xCF;
DDRB=0x00;
// Func0=Out Func1=Out Func2=Out Func3=Out Func4=Out Func5=Out
Func6=Out
// State0=0 State1=0 State2=0 State3=0 State4=0 State5=0 State6=0
PORTC=0x00;
DDRC=0x7F;
// Port D initialization
// Func0=Out Func1=Out Func2=Out Func3=In Func4=In Func5=In Func6=In
Func7=In
// State0=0 State1=0 State2=0 State3=T State4=T State5=T State6=T
State7=T
PORTD=0x00;
DDRD=0x07;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
TCCR0=0x01;
TCNT0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0x70;
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
/*
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
// Mode: Normal top=FFh
// OC2 output: Disconnected
TCCR2=0x01;
ASSR=0x00;
TCNT2=0x00;
OCR2=0x00;
*/
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
GICR=0x00;
MCUCR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x45;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
// Analog Comparator Output: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
#asm("sei")
while (1)
{
midiout(noteon);
midiout(keynum);
midiout(velocity);
/*
if(toggle==0x01)
{
midiout(noteon); //10010000
midiout(keynum); //00100100
midiout(velocity); //11111111
toggle++;
}
else if (toggle==0x03)
{
midiout(noteon); //10010000
midiout(keynum); //00100100
midiout(novelocity); //00000000
toggle=0x00;
} */
}
}
____________________________________________________________
Irgendwo ist ein grober fehler drinne, das signal hab ich aufm oszi,
wie es eigentlich sein soll.
Wie muss ein midisignal aussehen, 1 bedeutet doch stromschleife
unterbrochen, für eine taktperiode?
wie ist das mit startbit, kommt da nochmal 0 dazwischen?
das keyboard, das ich angeschlossen hab reagiert nicht, schaltet nur
manchmal das rythmusgerät ein, ist aber definitiv ok, da es mit anderen
quellen tut.
Die Stromschleife passt von den Werten her exakt (nachgemessen)
Ist schon eine Weile her, seit dem ich mich das letzte mal mit Midi beschäftigte. Schließ doch mal statt eines Keyboards die Midi-Signale an Deine PC-Soundkarte an. Ich kann mich noch dunkel an ein Programm (Midimon?) erinnern, das die Bytes am Bildschirm anzeigte. Solche Projekte gibt es wie Sand am Meer, oft mit PIC-Prozessoren. Polarität des Midi-Signals weiß ich nicht auswendig, ich denke aber mal TTL high = V24 low = Midi no current (nur eine Vermutung, da sonst bei abgestecktem Midi immer Startbits gesehen würden). Freut mich immer, wenn jemand was mit Midi macht... Kennst Du den ZEL Midi-Compiler (www.zelsoft.com)? Super high-density-Programm für Puristen!
Danke erstmal für die Hilfe, aber die projekte, die ich bisher gesehen hab, sind alle in asm -kann ich nicht. Es tut ja an sich alles was ich will... signal hab ich ja aufm oszi. es ist irgendwie der fehler im systen... hi/lo verwechselt, byte verkehrtrum gesendet? steht doch nirgends...steht nur überall startbit datenbyte stoppbit. oder muss man da noch irgendwelche config messages bringen? aus dem keyboard seh ich immer nur die 3 bytes noteon/kanal, keynumber/ velocity...beim loslassen halt mit velocity=00
natürlich mußt du auch während der Ausgabe eines Bytes über den Soft UART dafür sorgen, daß keine weitere Interrupt Routine ausgeführt wird. Sonst kommt ja da das Bit-Timing durcheinander.
Versuche doch mal, genau die gleiche Bitfolge zu erzeugen, wie aus dem Keyboard beim Drücken einer Taste kommt. Dann muss es gehen. Habe ich von 20 Jahren schonmal gemacht: ein einfachster Sequenzer: ich zeichnete das Byte und die Zeit zum nächsten auf. Damit konnte ich gespielte Stücke wiederholt abspielen. Hast Du mal den Midimon ausprobiert? Hast Du eine Soundkarte mit Midi-In/Out?
Ich hab jetzt mal doch die USART des atmels benutzt -die bitfolge ist von der frequenz her auch so wie von meiner softuart... ich kann nur die vom keyboard schlecht angucken, weil ich kein speicheroszi hab. habs jetzt mal versucht mit der soundkarte als audio aufzuzeichen auch nicht ideal mit 44.1kHz sampling nur, mehr macht die irgendwie net. das problem ist eher dass ich nirgends gefunden hab, wie das signal aussehen soll. ich hab ein programm nahmens midispy, das hex anzeigt, was empfangen wird (nix). Ich begreif das midisignal nicht. HAb wo gelesen, dass logisch 1 strom aus und logisch null strom an sei. ist das startbit dann logisch 0? das signal vom keyboard, so gut ichs erkennen kann ist strom aus, wenn nix gesendet wird. irgendwie ist der fehler im system. signal fällt ja raus, nur das falsche, und ich weiss nicht was falsch ist.
MIDI Spezifikationen gibt´s unter http://www.midi.org unter http://www.google.de sind jede Menge Seiten mit Infos zu finden, wie die verschiedensten MIDI-Strings aufgebaut sind.
Zuerst musst Du mal klären, ob es an der HW oder der SW liegt, ich vermute mal, mit der HW stimmt was noch nicht. Kannst Du mal versuchen, das Signal im Empfänger nach dem ersten Optokoppler zu messen. Wenn Du Dein Oszi auf Single oder AUTO stellst und die Triggerung und den Slope richtig einstellst, kannst Du erreichen, dass der Strahl immer mit dem Startbit an der linken Seite der Schirms beginnt. Wenn die Umgebung dunkel ist, sieht man den Strahl immer noch ausreichend lange nachleuchten. Natürlich wäre ein Speicheroszi besser, hat ein Bekannter vielleicht eines zum Leihen? Dann kannst Du auch die Polarität und die Bit-Dauer (ca.31µs) messen. Vergleiche sie mit einem Midi-Signal (aus dem PC oder einem anderen Gerät oder mit einem Midi-Loop-Stecker sogar aus dem selben Gerät). Das sollte doch zu schaffen sein.
@ Bassti: Hast Du an Deiner Soundkarte keinen MIDI-Eingang? Falls doch, guckst Du "MIDI-OX" - kleines Programm, was Dir alles zeigt, was über MIDI ´rein kommt. In puncto Midi: Startbit (0V / 0mA), Datenbits LSB zuerst, MSB zuletzt, Stopp-Bit (5V / 5 mA). Falls Du ´nen Optokoppler benutzt, diesen über 3x 220 Ohm und ´ne Sicherheitsdiode antiparallel zu LED zwischen Port-AusgangsPin und VCC klemmen, so daß beim StopBit die LED aus ist. Am Ausgang des Optos einen PullUp und daran die MIDI-Schnittstelle der Soundkarte. Achtung, die Pegel und Anstiegs-/Abfallzeiten sind kritisch und können, falls falsch eingestellt oder verwaschen, zu Bitfehlern führen. Übrigens sind MIDI-Befehle nur sehr selten ein einziges Byte. Kanalmeldungen und Ereignismeldungen (Note/Anschlag) müssen immer mitübertragen werden, sonst reagiert der angeschlossene "Slave" nicht. Nutz doch für Testzwecke erstmal einen Hardware-Uart, bei dem Du von 4 oder 8MHz die Taktfreqens auf 31250Hz herunterteilst. Bei dem stimmen dann zwangsläufig zumindest Datenformat und Timing und Du kannst den Fehler eventuell woanders suchen.
also wie gesagt, hab ich zu hardwaredebugging mal die hardwareuart des
atmels verwendet, mit 8MHz auf die 31,250kHz eingestellt.
Passt von der frequenz her.
Mir ist das mit dem startbit nicht klar was das soll... wenn nix kommt,
dann ist doch sowieso 0 Strom??
Datenbits 1=Strom oder kein Strom? -also wirklich in der
stromschleife...
ich hab jetzt von optokopplern mal abgesehen kommt später, wenns mal
soweit tut.
versorgt potentialfrei, also keine probleme mit massen und so.
ist das alles richtig so? code vom wizzard:
_________________________________________________________________
#include <mega8.h>
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART Transmitter buffer
#define TX_BUFFER_SIZE 64
typedef unsigned char byte;
char tx_buffer[TX_BUFFER_SIZE];
unsigned char tx_wr_index,tx_rd_index,tx_counter;
const byte noteon=0x90;
const byte keynum=0x24;
const byte velocity=0x7F;
const byte novelocity=0x00;
byte toggle=0x00;
// USART Transmitter interrupt service routine
#pragma savereg-
interrupt [USART_TXC] void uart_tx_isr(void)
{
#asm
push r26
push r27
push r30
push r31
in r26,sreg
push r26
#endasm
if (tx_counter)
{
--tx_counter;
UDR=tx_buffer[tx_rd_index];
if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
};
#asm
pop r26
out sreg,r26
pop r31
pop r30
pop r27
pop r26
#endasm
}
#pragma savereg+
#ifndef DEBUG_TERMINAL_IO
// Write a character to the USART Transmitter buffer
#define ALTERNATE_PUTCHAR
#pragma used+
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
{
tx_buffer[tx_wr_index]=c;
if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
#asm("cli")
++tx_counter;
PORTC.2^=1; //schaun
#asm("sei")
}
else UDR=c;
}
#pragma used-
#endif
// Standard Input/Output functions
#include <stdio.h>
// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
// Place your code here
toggle++;
TCNT1H=0x70;
TCNT1L=0x00;
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port B initialization
// Func0=In Func1=In Func2=In Func3=In Func4=In Func5=In Func6=In
Func7=In
// State0=P State1=P State2=P State3=P State4=T State5=T State6=P
State7=P
PORTB=0xCF;
DDRB=0x00;
// Port C initialization
// Func0=Out Func1=Out Func2=Out Func3=Out Func4=Out Func5=Out
Func6=Out
// State0=0 State1=0 State2=0 State3=0 State4=0 State5=0 State6=0
PORTC=0x00;
DDRC=0x7F;
// Port D initialization
// Func0=In Func1=In Func2=In Func3=In Func4=Out Func5=In Func6=In
Func7=In
// State0=T State1=T State2=T State3=T State4=0 State5=T State6=T
State7=T
PORTD=0x00;
DDRD=0x10;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 7,813 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0x70;
TCNT1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
TCCR2=0x00;
ASSR=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
GICR=0x00;
MCUCR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x04;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 31250
UCSRA=0x00;
UCSRB=0x48;
UCSRC=0x86;
UBRRL=0x0F;
UBRRH=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
// Analog Comparator Output: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
#asm("sei")
while (1)
{
putchar(novelocity);
// Place your code here
// if(toggle==0x01)
/* {
putchar(noteon); //10010000
putchar(keynum); //00100100
putchar(velocity); //11111111
toggle++;
}
else if (toggle==0x03)
{
putchar(noteon); //10010000
putchar(keynum); //00100100
putchar(novelocity); //00000000
toggle=0x00;
} */
};
}
_____________________________________________
hab jetzt einfach nen dauersignalstrom drinne, um die frequenz mal
anzuschauen... ansonsten immer abwechlungsweise die drei / sechs
messages Noteonereignis/Kanalnummer Keynummer und velocity, mal volle
pulle, mal 0. -was anderes tut das keyboard auch nicht schicken.
das Signal hab ich dann von dem pin genommen und doppelt invertiert.
bzw. die last der 2. emitterstufe ist dann die midistromschleife.
kann man aufm oszi auch anschaun. ich bin echt am verzweifeln.
sind die einsen beim datenbyte strom oder nicht strom?
Also könntest Du bitte mal das tun, was wir dir anraten, sonst wird das nichts. Ich bin mir nicht ganz sicher: Ruhe = 0 mA Startbit = 5 mA (TravelRec behauptet das Gegenteil) Dlow = 5mA Dhigh = 0 mA Stopbit = 0mA (TravelRec behauptet das Gegenteil) Ist die Bitdauer richtig (MESSEN!) sind die Kanten scharf (MESSEN!) Ist das Signal genauso wie das Keyboard es sendet? HAST DU EINEN MIDI-EINGANG AM PC???
Ruhe = 0 mA -richtig. Startbit = 5 mA -richtig. Dlow = 5mA -richtig. Dhigh = 0 mA -richtig. Stopbit = 0mA -richtig. Ist die Bitdauer richtig (MESSEN!) -bei der hardwareusart ja, hab versucht bei der softwareusart mal die dauern zu variieren um vielleicht irgendwann mal die richtige zu treffen, denn die vom keyboard gesendeten stimmen auch nicht. sind die Kanten scharf (MESSEN!) -ja, sind sie.(imo wirklich scharf genug, scharf ist relativ) Ist das Signal genauso wie das Keyboard es sendet? nein, denn mit der hardwareusart krieg ich das mit den start/stoppbits nicht hin -dient das stopbit als platzhalter? ansonsten ja sinnlos, weil dann strom eh 0.. mit der softuart hab ich dann mal versucht das signal genausolang zu machen, wie das vom keyboard mit meinem speicheroszi (oszi + digicam) es will nicht tun. HAST DU EINEN MIDI-EINGANG AM PC??? -ja, und der empfängt genausowenig wie das keyboard
Freudentränen laufen mir über die backen... geht doch, GEHT DOCH!! Das tool, das ich verwendet hab war einfach n sch.... mit der hardwareuart tuts jetzt, einfach das falsche gesendet. das geniesse ich jetzt erstmal, bevor ich mich wieder entmutigen lass. ich melde mich dann wieder von der front, wenn ich was neues hab. Dickes DANKE erstmal für eure Hilfe! Hoffentlich kann ich das auch zurückgeben.
Na super! Ja, habe da oben ein bissi Quark geschrieben - kommt von der dauernden Invertiererei mit den Optos - irgendwann hat man dann ´nen Knoten im Hirn. Wichtig ist, es geht, bei mir tut´s ja auch alles geh´n trotz des Hirnknotens ;-). Zum Klarstellen nochmals: Das U(S)ART ist gegenüber Masse logisch HIGH, solange nix passiert, geht auf logisch 0 für das Startbit, toggelt je nach Daten zwischen 0 und 1 rum, wobei das kleinstwertige Bit zuerst gesendet wird und geht mit dem Stopp-Bit wieder auf logisch 1. Parity gibt´s dann auch noch, aber eben nicht bei MIDI - schön, daß wir uns alle einig sind :-).
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.