Forum: Mikrocontroller und Digitale Elektronik 5 zeilen C code


von newbi (Gast)


Lesenswert?

Hallo Zusammen,

eine kurze Frage:
Ist es möglich den unten stehende C code einfacher zu schreiben ?
Oder so zu schreiben das er schneller vom µC abgearbeitet werden kann?

in der Schleife soll perm. der IO Pin 6.0 abgefragt werden und nach 
seinem Zustand (high / low) auf den IO Pin 1.2 gesetzt werden.

 while(UCA1IFG == 0x02) // mache solange , bis was im rx Puffer ist
  {
     if (P6IN & (1 << 0)) // ist 6.0 high
     {
        P1OUT |= 0x04; // dann setze 1.2 auf high
     }
     else
     {
        P1OUT &=~ 0x04;  // oder eben auf "low"
     }


vielen Dank

newbi

von Vlad T. (vlad_tepesch)


Lesenswert?

welcher µC?

ein bit toggelt man mit

P1OUT ^= 0x04;

von HenningW (Gast)


Lesenswert?

In C kannst du nicht wissen wie schnell der Code abgearbeitet wird, 
dafür bräuchstest du Assembler und wissen über die µC Type.

Vielleicht ist es schneller wenn du 3 while Schleifen hast und du somit 
nur ein if und kein else hast.

Das setzen des Bits ist soweit richtig, du kannst das so machen und 
musst nicht Toggeln.

von C Vergesser (Gast)


Lesenswert?

Kann man nicht einfach Portpind gleichsetzen, in der Form
Pin6.0 = Pin1.2 ???

von newbi (Gast)


Lesenswert?

ich will mich mit dem code (unter anderen) vorbereiten auf das nächste 
Semester.
hab mir dazu in der uni eine Evalboard von Ti ausgeliehen mit einem 
msp430f5506

@ Vlad Tepesch

ich will nicht toggeln, ich will den Zustand des pins 1.2 anhand des 
Zustands von pin 6.0 setzen

@ HenningW

kannst du das mit den 3 while schleifen skizzieren ?

von Vlad T. (vlad_tepesch)


Lesenswert?

newbi schrieb:
> ich will nicht toggeln, ich will den Zustand des pins 1.2 anhand des
> Zustands von pin 6.0 setzen

oh, sorry, hab übersehen, dass das ein anderer Pin ist der Abgefragt 
wird.

von Vlad T. (vlad_tepesch)


Lesenswert?

Tip:
wenn man portablen Code schreiben will, kapselt man Hardwarezugriffe.
Zb in eigene (inline) Funktionen.
Das hat den Vorteil, dass der Code auch viel verständlicher ist:
1
inline void StatusLedEin()
2
{
3
 P1OUT |= 0x04; // dann setze 1.2 auf high
4
}
5
6
inline void StatusLedAus()
7
{
8
 P1OUT &= ~0x04; // dann setze 1.2 auf high
9
}
10
11
inline bool isActive()
12
{
13
  return P6IN & (1 << 0);
14
}
15
16
17
...
18
     if (isActive())
19
     {
20
        StatusLedEin();
21
     }
22
     else
23
     {
24
        StatusLedAus()// oder eben auf "low"
25
     }
26
...
keine Angst, der Compiler optimiert das schon vernünftig

von Karl H. (kbuchegg)


Lesenswert?

newbi schrieb:
> Hallo Zusammen,
>
> eine kurze Frage:
> Ist es möglich den unten stehende C code einfacher zu schreiben ?
> Oder so zu schreiben das er schneller vom µC abgearbeitet werden kann?

Auf C Ebene ist das erst mal alles.
Jetzt kommt man in die Phase in der man sich die Frage stellt

* muss es schneller sein?
  wie schnell bin ich überhaupt? Welche Vorgaben habe ich, wie schnell
  ich sein muss?

* Was hat der Comiler da draus gemacht und habe ich alle meine
  Compileroptionen bereits ausgeschöpft?
  Ist zb der Optimizer eingeschaltet?

* Wie sieht der Assemblercode aus?
  Gibt es im Assemblercode noch Verbesserungspotential und wenn ja
  wie könnte ich das von C aus nutzen?

* Gehe ich die Sache vielleicht überhaupt falsch an?
  Welche anderen Möglichkeiten gibt es diese Funktionalität zu
  erreichen? Operationen aus der Schleife rausschaufeln? Interrupts
  nutzen?

* Reissen alle Stricke und muss ich vielleicht überhaupt auf
  Assembler ausweichen? Inline-Assembler?

von HenningW (Gast)


Lesenswert?

vor while ersten zustand setzen
wenn erster zustand high
while(UCA1IFG == 0x02)
 while(UCA1IFG == 0x02 && pin aktiv){}
 if uca1fg == 2 pin low
 while(UCA1IFG == 0x02 && pin aktiv){}
 if uca1fg == 2  pin high
bei low analog dazu

Dann im Assemblercode prüfen obs mit weniger Takten abgearbeitet wird. 
Du kommst für solche Optimierungen und Zeitkritischen Sachen nicht an 
Assembler herum.

von newbi (Gast)


Lesenswert?

erstmal vielen Dank für die Tipps.

Ich arbeite mich seit einigen Tagen erstmal in C ein. Assembler ist mir 
seit dem zwar schon einige Male über den Weg gelaufen, aber parallel 
damit arbeiten und wirklich nutzen liegt noch in weiter ferne.

Wenn ich am Eingang (Pin 6.0 ) einen Taster anschließe und an Pin 1.2 
eine LED an und aus mache, spielt Zeit eher eine Nebenrolle

Ich versuche über einen Tongenerator (LVTTL Signal ist eingstellt) eine 
Frequenz bis 1MHZ einzuzspeisen und am Ausgang (Pin 1.2) zu messen.
Das klappt bis etwa 200 KHz
Testweise hatte ich vorher in der while Schleife den Ausgang getoggelt 
da habe  2,4 MHz gemessen.

In den code Beispielen Von TI tauchte immer wieder das hoch setzen der 
CLk bis 25 Mhz auf.
Wäre das nicht auch ein Lösung um mein Problem?

von Helmut L. (helmi1)


Lesenswert?

newbi schrieb:
> In den code Beispielen Von TI tauchte immer wieder das hoch setzen der
> CLk bis 25 Mhz auf.
> Wäre das nicht auch ein Lösung um mein Problem?

Auch wenn TI das hin und wieder macht laeuft der uC ausserhalb seiner 
Specs. Sowas macht man nicht weil es nicht garantiert ist das er das 
unter allen Umstaenden (Temperatur , Spannung etc.) macht.
Die Beispiele von TI sind nicht das verbindliche Datenblatt und nur was 
dort drin steht wird auch garantiert.

von newbi (Gast)


Lesenswert?

ok, vielen Dank, das eval board sollte ich nicht kaputt machen, sonst 
gibts nen "duchgefallen" für die Prüfung und den Zorn des Profs.   ;-)

Ich werde alle Vorschläge jetzt durcharbeiten.
vielen Dank an alle

von Michel (Gast)


Lesenswert?

newbi schrieb:
> Oder so zu schreiben das er schneller vom µC abgearbeitet werden kann?

Wenn es schnell und unabhängig von Compilerumsetzung/-optimierungsstufe 
sein soll, wäre Inline-Assembler wohl die richige Wahl.
1
$asm (...)

Die Details hängen von deinem Prozessor und eingesetzten Assember ab.

Falls du die Problem, dass du ohne C nicht hättest, unbedingt in C lösen 
möchtest, solltest du einfach einen Blick in den erzeugten ASM-Code 
werfen, um zu gucken, was noch optimiert werden kann und so lange am C 
Code und der Oprimierung feilen, bis die gewünchte Assemblerzeile da 
steht.

von Helmut L. (helmi1)


Lesenswert?

newbi schrieb:
> ok, vielen Dank, das eval board sollte ich nicht kaputt machen, sonst
> gibts nen "duchgefallen" für die Prüfung und den Zorn des Profs.   ;-)

Kaputt geht er dabei nicht. Nur die Stabilitaet deines Programm laesst 
dann zu wuenschen ueberig.

von Peter (Gast)


Lesenswert?

@newbi

Dein Codebeispiel ist gut so: Kurz und übersichtlich und der Compiler 
hat die Möglichkeit, das optimal in Assambler umzusetzen. Ob er das 
wirklich tut hängt vom Compiler und den eingestellten Optionen (z.B. 
Optimierung) ab.


@HenningW
Die Version mit den While Schlaufen ist viel unübersichtlicher bzw. 
schwerer durchschaubar, sowas würde ich nicht empfehlen! Ich bin mir 
auch zimlich sicher, dass der Compiler dies weniger effizient übersetzen 
wird...

von Helmut L. (helmi1)


Lesenswert?

Die kuerzeste Version der inneren "if" Abfrage:
mit IAR Compiler

//  142   if(P6IN & 1)
        BIT.B   #0x1, &0x34
        JNC     ??main_1
//  143   {
//  144     P1OUT |= 0x04;
        BIS.B   #0x4, &0x21
        JMP     ??main_2
//  145   } else
//  146   {
//  147     P1OUT &= 0x04;
??main_1:
        AND.B   #0x4, &0x21
//  148   }
??main_2:

von Meister E. (edson)


Lesenswert?

1
void foo(void)
2
{
3
   while(UCA1IFG==0x02)
4
      {
5
         P1OUT=(P6IN&1)?0x04:(P1OUT&0xFB);
6
      }
7
}

Mag das jemand mal kompilieren? Hab gerade keinen Compiler zur Hand (vom 
nicht vorhandenen Header für den TI ganz abgesehen).

Würde selbst aber auch die Methode von Vlad anwenden.

Grüße,
Edson

von tom (Gast)


Lesenswert?

...ich sach nur: erzeugten asm-code anschauen und abchecken ob man nicht 
evtl. in eine read-modify-write falle tappen kann, wenn das ganze 8-bit 
port gesetzt wird und nicht das einzelne portpin...

von Sam .. (sam1994)


Lesenswert?

Ich hätte noch diese Idee:
1
while(UCA1IFG == 0x02) // mache solange , bis was im rx Puffer ist
2
    P1OUT |= (P6IN << 2) & 0x04;

von Sam .. (sam1994)


Lesenswert?

Meister Eder schrieb im Beitrag #2310292:
> Das ist nur die halbe Lösung, weil das Bit im Ausgangsregister P1OUT nie
> zurückgesetzt wird.

Verdammt du hast recht. Kleiner Denkfehler von mir.
1
while(UCA1IFG == 0x02) // mache solange , bis was im rx Puffer ist
2
    P1OUT = (P1OUT & 0xFB) | (P6IN << 2) & 0x04;
oder (wenn möglich)
1
int x = P1OUT & 0xFB;
2
while(UCA1IFG == 0x02) // mache solange , bis was im rx Puffer ist
3
    P1OUT = x | (P6IN << 2) & 0x04;

von Meister E. (edson)


Lesenswert?

Samuel K. schrieb:
> Meister Eder schrieb im Beitrag #2310292:
>> Das ist nur die halbe Lösung, weil das Bit im Ausgangsregister P1OUT nie
>> zurückgesetzt wird.
>
> Verdammt du hast recht. Kleiner Denkfehler von mir.

Danke fürs zitieren. Hab meinen Beitrag vorhin "aus Versehen" wieder 
gelöscht, wollte ihn eigentlich bearbeiten.

Deine Korrekturen passen, ich rate aber mal dass das Kompilat gegenüber 
der Inline-Deklaration keine Vorteile hat (genau wie mein Beispiel). 
Werds bei Zeiten mal prüfen.

von Sam .. (sam1994)


Lesenswert?

Die Frage ist, ist if schneller als reine Rechnung? Auf einem AVR wäre 
if schneller, da man Bits von Registern direkt abfragen kann.

von newbi (Gast)


Lesenswert?

einen Guten Morgen an alle

und erstmal vielen Dank für eure Hilfe.
Ich bin gestern all eure Vorschläge, Tips und Denkanstöße durchgegangen.

rausgekommen ist dabei, dass eine If Abfrage schneller ist als ein 
ausrechnen
ala:

int x = P1OUT & 0xFB;
while(UCA1IFG == 0x02) // mache solange , bis was im rx Puffer ist
    P1OUT = x | (P6IN << 2) & 0x04;

der Controller braucht zwischen -Signal am Eingang-( Pin 6.0) bis 
-Signal am Ausgang ( Pin 1.2 ) bei If abfrage ca. 1 µs, bei ausrechnen 
ca. 1,6 µs

@ Helmut Lenzen

Die kuerzeste Version der inneren "if" Abfrage:
mit IAR Compiler

//  142   if(P6IN & 1)
        BIT.B   #0x1, &0x34
        JNC     ??main_1
//  143   {
//  144     P1OUT |= 0x04;
        BIS.B   #0x4, &0x21
        JMP     ??main_2
//  145   } else
//  146   {
//  147     P1OUT &= 0x04;
??main_1:
        AND.B   #0x4, &0x21
//  148   }
??main_2:

Ich würde deinen/diesen Code gerne mal probieren, wie kann an ich ihn 
benutzen/einfügen in meinen Code?
Ich benutze die IAR Kickstart.

Trotz all meiner Bemühungen gestern, schaffe ich es nicht das 
Eingangssignal bis auf 1MHz "hoch zu drehen" und es so Fehlerfrei am 
Ausgang zu messen.
z. Zeit ist die Grenze etwa 350 KHz.

Deshalb ist meine letzte Frage: Ist dies überhaupt möglich / 
Softwareseitig möglich ?
(Wie oben schon geschreiben: es ist ein Evalboard von TI mit einem 
f5506)
Ich möchte meine Helfer hier nicht von der wirklichen Arbeit abhalten


Gruß an alle

von Helmut L. (helmi1)


Lesenswert?

newbi schrieb:
> Ich würde deinen/diesen Code gerne mal probieren, wie kann an ich ihn
> benutzen/einfügen in meinen Code?
> Ich benutze die IAR Kickstart.

Das ist das was der IAR Compiler daraus macht. Wenn du deinen C-Code mit 
dem IAR Compiler uebersetzt hast sollte er das daraus gemacht haben. Du 
kann es dir im C-Compiler Listing anschauen. Du must nur unter Options 
das Assemblerlisting einschalten.

von newbi (Gast)


Lesenswert?

Helmut Lenzen schrieb:
> Das ist das was der IAR Compiler daraus macht. Wenn du deinen C-Code mit
> dem IAR Compiler uebersetzt hast sollte er das daraus gemacht haben. Du
> kann es dir im C-Compiler Listing anschauen. Du must nur unter Options
> das Assemblerlisting einschalten.

mein Sie Options --> links category "Assembler" und rechts tab "List"
und dort Haken bei  "output list file" ?

wo befindedet sich das Assembler list file ?

von Helmut L. (helmi1)


Angehängte Dateien:

Lesenswert?

Das kann man hier einstellen. Dann macht er aus jedem C-File ein 
Assembler Programm.

von stru_aus (Gast)


Lesenswert?

eventuell könnte man den ganzen port mappen:

while(1){p1out=p6in;}

sofern das nicht mit anderer periphery in die quere kommt

von Achim M. (minifloat)


Lesenswert?

newbi schrieb:
> ok, vielen Dank, das eval board sollte ich nicht kaputt machen, sonst
> gibts nen "duchgefallen" für die Prüfung und den Zorn des Profs.   ;-)

Kauf dir halt das Launchpad für nen 5er. Da sind 2 kleine Prozessoren 
dabei mit ähnlicher Architektur. Du kannst selber was basteln und wenn 
ein Prozessor kaputt geht, geht ja immer noch der andere. Der Zorn des 
Professors belibt dir erspart :)

Was auch bei MSP430 interessant ist, sind die Videos von Prof. 
Lovisvcach, die aus hochschulinternen Praktika zur 
Mikrocontrollerprogrammierung entstanden sind. Hier das erste: 
http://www.youtube.com/watch?v=NKgXNXY9OSk

mfg mf

von Max (Gast)


Lesenswert?

Es kann (theoretisch) auch billger sein den Pin einzulesen, zu maskieren 
(verunden) zu schieben und dann wieder auszugeben (mit oder). Wenn 
Sprünge auf dem µC teuer (langsam) sind kann dies beschleunigend wirken 
(muss aber nich).
Auf dem AVR lohnt sichs z.B. nicht, da dort ein Sprung sehr schnell 
geht, wie das beim MSP40 is weis ich nicht.

von Achim M. (minifloat)


Lesenswert?

Max schrieb:
> Auf dem AVR lohnt sichs z.B. nicht, da dort ein Sprung sehr schnell
> geht, wie das beim MSP40 is weis ich nicht.

Definiere mal "sehr schnell". Es braucht mindestens 2 Zyklen, da erst 
der Programcounter auf dem Stack gesichert wird und dann der 
Programcounter mit der neuen Adresse geladen wird. Die Adressen sind 
allerdings 16bit lang. Müsste man in der Auflistung der Befehle 
nachsehen, zumal der AVR ja nur eine 8-Bit-Maschine ist(PC laden: atomic 
Operation von 2x 8 Bit laden??).
Dann macht es ja noch einen Unterschied, ob "weit" oder "kurz" 
gesprungen wird.

Beim MSP ist es, wie ich denke, anders. Der ist aber eine 
16-Bit-Maschine. Es könnte u.U. schneller gehen.

mfg mf

von spess53 (Gast)


Lesenswert?

Hi

>Es braucht mindestens 2 Zyklen, da erst
>der Programcounter auf dem Stack gesichert wird und dann der
>Programcounter mit der neuen Adresse geladen wird.

Du beschreibst einen 'call' keinen 'jmp'.

MfG Spess

von Sam .. (sam1994)


Lesenswert?

Mini Float schrieb:
> Definiere mal "sehr schnell". Es braucht mindestens 2 Zyklen, da erst
> der Programcounter auf dem Stack gesichert wird und dann der
> Programcounter mit der neuen Adresse geladen wird. Die Adressen sind
> allerdings 16bit lang. Müsste man in der Auflistung der Befehle
> nachsehen, zumal der AVR ja nur eine 8-Bit-Maschine ist(PC laden: atomic
> Operation von 2x 8 Bit laden??).
> Dann macht es ja noch einen Unterschied, ob "weit" oder "kurz"
> gesprungen wird.

Bei AVRs braucht rjmp immer 2 Zyklen. Eigentlich braucht er nur einen, 
das Problem ist aber, dass der AVR den nächsten Befehl immer vorraus 
liest. Das funktioniert nach einem rjmp nicht und der µC braucht noch 
einen Takt um diesen zu lesen.

Übrigens kann der avr auch 2 Register gleichzeitig kopieren (movw) und 
braucht nur einen Takt, obwohl er ein 8bit µC ist.

von Peter (Gast)


Lesenswert?

Original Version:
1
while(UCA1IFG == 0x02) // mache solange , bis was im rx Puffer ist
2
  {
3
     if (P6IN & (1 << 0)) // ist 6.0 high
4
     {
5
        P1OUT |= 0x04; // dann setze 1.2 auf high
6
     }
7
     else
8
     {
9
        P1OUT &=~ 0x04;  // oder eben auf "low"
10
     }
11
  }


Das selbe kurz und genau so schnell:
1
while(UCA1IFG==0x02) P1OUT=(P6IN&0x01)?(P1OUT|0x04):(P1OUT&~0x04);



Gruss von mir...

von Meister E. (edson)


Lesenswert?

Peter schrieb:
> Das selbe kurz und genau so schnell:...

Ich dachte erst ich hätte dasselbe schon gestern gepostet. Mein 
(Tipp-)Fehler, im True-Rückgabezweig des ternären Operators 0x04 statt 
(P1OUT|0x04) zu schreiben.

Gruß,
Edson

von newbi (Gast)


Lesenswert?

Hallo Zusammen,

ich habe die letzte Zeit genutzt eure Vorschläge durch zuarbeiten und 
habe richtig dazugelernt.
Vielen Dank dafür

Leider schaffe ich es nicht ein Eingangssignal(Pin 6.0) mit 1MHz auf den 
Ausgang (Pin 1.2) zu "übergeben"
Ich habe auch schon ein TI samplescode genutz um die Frequenz auf 25 MHz 
zu erhöhen.

Ich fragte zwar schonmal, aber ist mein Vorhaben überhaupt möglich ?
Den Ausgang mit 2,5 Mhz zu toggeln auf jeden Fall Ja.


Grüße

von newbi (Gast)


Lesenswert?

Hallo Zusammen,

ich arbeite immernoch an den Problem von oben.
Anstatt einer IF abfrage kann ich doch perm. den Zustand vom Eingang 
setzen

so etwa:

 bool r ;
  while(1)
  {
    r = P6IN & BIT0; // 6.0 eingang
    P5OUT = r & BIT1; // 5.1 ausgang
  }

was ist daran falsch ?

von M. K. (sylaina)


Lesenswert?

newbi schrieb:
> was ist daran falsch ?

Die Art wie du versuchst die Ports zu verwenden? Schau doch mal ins 
Tutorial rein ;)

von newbi (Gast)


Lesenswert?

welches tutorial?

von Sam .. (sam1994)


Lesenswert?

newbi schrieb:
> Ich fragte zwar schonmal, aber ist mein Vorhaben überhaupt möglich ?
> Den Ausgang mit 2,5 Mhz zu toggeln auf jeden Fall Ja.

Du musst schauen was der Comüpiler aus deinem C-Code macht. Ich kann 
jedoch nur Avrasm:
1
loop:
2
  sbic PINA, B
3
  rjmp h
4
  cbi PORTD, A
5
  sbic PINA, C
6
  rjmp loop
7
  rjmp end
8
h:
9
  sbi PORTD, A
10
  sbic PINA, C
11
  rjmp loop
12
end:

worst case 8 Takte (optimierbar auf 7 mit out), das sollte dein MSP auch 
schaffen.

von 1kl9867f (Gast)


Lesenswert?

Bin ich jetzt zu böld oder hab ich was verpasst?

/* P1_P2 als Ausgang konfigurieren */
DP1_P2 = 1;



<SCHLEIFE START>

/* aktuellen Zustand von P6_P0 auf P1_P2 setzen */
P1_P2 = P6_P0;

<SCHLEIFE ENDE>

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
Noch kein Account? Hier anmelden.