Forum: Mikrocontroller und Digitale Elektronik MSP 430 & Uhrzeit


von Max (Gast)


Lesenswert?

Moin.

Kennt jemand von euch eine Möglichkeit dem MSP 430 die Uhrzeit
'beizubringen'? Ich möchte diese dann zB. auf einem Display ausgeben.

von Läubi (Gast)


Lesenswert?

Eventuell kannst du ja ne RTC dranbauen... die läuft sogar bis zu 5
Jahre weiter wenn du die stromversorgung entfernst.

von Alexander Höller (Gast)


Lesenswert?

> die läuft sogar bis zu 5 Jahre weiter wenn du die stromversorgung
entfernst.

auch auch nur wenn amn ihr ne backup batterie/goldcap/etc. gitb, oder ?

von Sebastian (Gast)


Angehängte Dateien:

Lesenswert?

> Kennt jemand von euch eine Möglichkeit dem MSP 430 die Uhrzeit
> 'beizubringen'? Ich möchte diese dann zB. auf einem Display
> ausgeben.

Klar. Hab sowas letztens mal mit dem MSP430F140 gemacht. Ich benutze
die 50Hz des Netzes als Sekunden-Geber. Über den Tag gemittelt halten
die Energieversorger die 50Hz so präzise wie 'ne Atomuhr. :-) Ich hab
den Code mal angehangen (simple.c ist die Hauptdatei, der Rest sind
Hilfs-Libraries für den USART, I2C usw.). Das Programm liest noch zwei
I2C-Temperatursensoren aus, aber das kannst du ja auskommentieren. Du
kannst die Uhrzeit per Terminalprogramm vom PC aus einstellen, ab dann
läuft die Uhr natürlich völlig eigenständig weiter. Die Ausgabe erfolgt
auf einem Display mit KS0108-Chipsatz. Codeanpassungen für ein
HD44780-Display findest du auf meiner Homepage www.mathar.com (im
LCD-Kapitel).

von Max (Gast)


Lesenswert?

Wow. Wer kommt auf so eine Idee? Nur nutze ich ein
Gleichspannungsnetzteil für meine Schaltungen.
Wäre das denn der übrigbleibende Quelltext für die Uhrzeitbestimmung:


#include <msp430x14x.h>

char uhr_str[]="00";
char hundertstelsekunden=0, sekunden=0, minuten=8, stunden=21, tage=0;


int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // watchdog aus
  _BIS_SR(GIE);           // allgemeiner interrupt-enable
  P1IE=0x10;              // pin 16 interrupt-faehig machen (wg.
100Hz-erkennung)
  P1IES=0x10;             // interrupt auf pin 16 ausloesen bei
high->low - uebergang



#pragma vector=PORT1_VECTOR
__interrupt void Port1_Interrupt (void)
{
  if (P1IFG&0x10)         // 0x10 ist pin 16
  {
  if (!((++hundertstelsekunden)%50))
    {                     // experimentell: uhrzeit ausgeben ...
      hundertstelsekunden = 0;
      if (!((++sekunden)%60))
      {
        sekunden = 0;
        if (!((++minuten)%60))
        {
          minuten = 0;
          if (!((++stunden)%24))
          {
            stunden = 0;
            tage++;
          }
        }
      }
    }
  }
  P1IFG&=~0x10;
}

von Alexander Höller (Gast)


Lesenswert?

Nein, weil du ja keine 50Hz (oder sind's 100? hab mir die Schaltung,
Code nicht wirklich angeschaut) an den Interrupt Pin anliegen hast. Du
hast also nichts was dir eine Zeitbasis liefern würde.

Möglichkeiten:

.) du verwendest (wie oben erwähnt) einen externen RTC IC
.) du verwendest nen internen Timer, der dir die Zeitbasis liefert -
also z.B. alle 20ms (um bei den 50Hz zu bleiben) auslöst

mfG,
aleX

von Sebastian (Gast)


Lesenswert?

Hast du einen Uhrenquarz (32kHz) an deinem MSP hängen? Dann kannst du
ganz einfach einen 16-Bit-Timer (Timer_A) überlaufen lassen und hast so
auch einen Sekundengeber.

von Läubi (Gast)


Lesenswert?

Es gibt RTC's mit eingebauter 'eigener' stromversorgung. das sit eine
twas größerer Klotz (etwa doppeltsohoch wie nen normaler IC).

von MAX (Gast)


Lesenswert?

@Sebastian:

Ja, ich habe einen 32 kHz Uhrenquartz und einen 8 Mhz Quartz am MSP.
Hast du einen Tipp oder Codebeispiel wie das damit funktionieren würde?

von Sebastian (Gast)


Lesenswert?

Nicht auswendig. Grab dich mal durch die Tutorials auf meiner Website.
IIRC benutze ich den Timer in dem Disco-Tutorial iVm mit einer PWM.
Dort siehst du dann den Code, den du brauchst.

von Max (Gast)


Lesenswert?

Was bedeutet iVm und PWM? Ich schaue mir mal das Tutorial an.

von Max (Gast)


Lesenswert?

PWM hat sich schon geklärt....stand etwas auf der Leitung. ;-)

von MAX (Gast)


Lesenswert?

Echt geile Page. Das Tutorial für das Discomopped liest sich ja super,
aber mir ist im Moment schleierhaft, wie man daraus eine Uhr bauen
soll!

von tenner (Gast)


Lesenswert?

aclk läuft mit 32,...khz, alle 125ms wird ein interrupt ausgelöst wobei
die uhr um eben 125ms hochgezählt wird ...
wenn dir ein sekundentakt reicht, kannst du auch einfach den
timerüberlauf-interrupt nutzen und dann einfach eine sekunde hoch
zählen

stGlobalTime ist eine struktur.

void init_Timer(void)
{
  TACTL    = TASSEL_1 + TACLR + TAIE; // upcount until CC0 event (using
ACLK)
  TACCTL0  = CCIE;
  TACCR0   = 4096;                             // let count 4096
cycles: 125ms intervals

  TACTL   |= MC_2;                             // start timer
}

interrupt (TIMERA0_VECTOR) Timer_A0(void)
{
  TACCR0  += 4096;               // Add Offset to CCR0 (125ms)
  uiMsCnt += 125;
  if( uiMsCnt == 1000 ) {
    uiMsCnt = 0;
    stGlobalTime.tm_sec++;
    ulUpTime++;
    if( stGlobalTime.tm_sec >= 60 ) {
      stGlobalTime.tm_sec = 0;
      stGlobalTime.tm_min++;
      if( stGlobalTime.tm_min >= 60 ) {
        stGlobalTime.tm_min = 0;
        stGlobalTime.tm_hour++;
        if( stGlobalTime.tm_hour >= 24 ) {
          stGlobalTime.tm_hour = 0;
          stGlobalTime.tm_yday++;
          if( stGlobalTime.tm_yday >= 365 ) {
            stGlobalTime.tm_yday = 0;
            stGlobalTime.tm_year++;
          }
        }
      }
    }
  }
}

von Max (Gast)


Lesenswert?

@tenner: Vielen Dank. Ich werde das später ausprobieren!

von Max (Gast)


Lesenswert?

Bitte nicht böse sein, aber ich kapiere da gar nix. Soll denn der Code
denn du,tenner, jetzte geschrieben hast, eine Uhr ergeben oder muss das
mit den Sachen von Sebastian kombiniert werden? Der nutzt ja die 50 Hz
der Wechselspannung.

von tenner (Gast)


Lesenswert?

der code zeigt wie eine uhr mit hilfe des 32kHz quarz und dem timer
interrupt implementiert werden kann. hat nichts mit dem von sebastian
zu tun.
der timerA wird mit dem 32768Hz uhrenquarz getaktet. alle 4096 takte
wird ein interrupt ausgelöst, der den milisekunden-zähler um 125ms
erhöt. nach 8 interrupts, also wenn der ms-zähler auf 1000 steht, wird
der sekundenzähler um 1 erhöt. nach 60 sec der min-zähler 1+ usw.

stGlobalTime ist eine struktur die wie folgt aussieht

struct tm
{
  int tm_sec;     /* 0..59 */
  int tm_min;     /* 0..59 */
  int tm_hour;    /* 0..23 */
  int tm_mday;    /* 1..31 */
  int tm_mon;     /* 0..11 */
  int tm_year;    /* 0(:=1900).. */
  int tm_wday;    /* 0..6 */
  int tm_yday;    /* 0..365 */
  int tm_isdst;   /* 0 */
};

das anzeigen der uhrzeit mußt du schon selbst erledigen.

von Max (Gast)


Lesenswert?

Hallo Tenner,

vielen Dank für deine Programmauschnitte. Ich habe mal versucht etwas
daraus zu basteln:


#include  "msp430x14x.h"

void init_Timer(void);
void main(void);


void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;             // watchdog aus
}


struct tm
{
  int tm_sec;     /* 0..59 */
  int tm_min;     /* 0..59 */
  int tm_hour;    /* 0..23 */
  int tm_mday;    /* 1..31 */
  int tm_mon;     /* 0..11 */
  int tm_year;    /* 0(:=1900).. */
  int tm_wday;    /* 0..6 */
  int tm_yday;    /* 0..365 */
  int tm_isdst;   /* 0 */
};



void init_Timer(void)
{
  TACTL    = TASSEL_1 + TACLR + TAIE; // upcount until CC0 event
(usingACLK)
  TACCTL0  = CCIE;
  TACCR0   = 4096;                             // let count 4096
cycles: 125ms intervals
  TACTL   |= MC_2;                             // start timer
}

interrupt (TIMERA0_VECTOR) Timer_A0(void)
{
  TACCR0  += 4096;               // Add Offset to CCR0 (125ms)
  uiMsCnt += 125;
  if( uiMsCnt == 1000 ) {
    uiMsCnt = 0;
    stGlobalTime.tm_sec++;
    ulUpTime++;
    if( stGlobalTime.tm_sec >= 60 ) {
      stGlobalTime.tm_sec = 0;
      stGlobalTime.tm_min++;
      if( stGlobalTime.tm_min >= 60 ) {
        stGlobalTime.tm_min = 0;
        stGlobalTime.tm_hour++;
        if( stGlobalTime.tm_hour >= 24 ) {
          stGlobalTime.tm_hour = 0;
          stGlobalTime.tm_yday++;
          if( stGlobalTime.tm_yday >= 365 ) {
            stGlobalTime.tm_yday = 0;
            stGlobalTime.tm_year++;
          }
        }
      }
    }
  }
}


Aber so richtig will das noch nicht. Die Displayausgabe habe ich im
Moment weggelassen. Dafür bieten sich die Sachen von Sebastian ja
hervorragend an.

von Sebastian (Gast)


Lesenswert?

Was heisst "so richtig will das noch nicht"? Was will nicht? Klappt
gar nix, oder zählt er nur falsch, oder zu schnell, oder zu langsam
oder wie?

von tenner (Gast)


Angehängte Dateien:

Lesenswert?

moin,

naja, so kanns auch nicht funktionieren. zunaächst mußt die die
variable stGlobalTime anlegen. diese muß global angelegt werden.

struct tm stGlobalTime;

die definition der struktur muß natürlich vor dem anlegen erfolgen. am
besten beides vor der main funktion.
uiMsCnt muß global angelegt und initialisiert werden

unsigned int uiMsCnt = 0;

ulUpTime kann du streichen oder sie muß global angelegt und mit 0
initialisiert werden.

du mußt die ACLK auf den externen 32768kHz quarz konfigurieren.
der timer muß initialisiert werden, aufruf der funk. init_Timer() in
der main().

ich hab mal ne datei angehängt, mit der es funktionieren sollte. kann
es aber hier selber nicht testen, da keine compiler und keine hardware
zur verfügung.

welchen compiler benutzt du?

von OldBug (Gast)


Lesenswert?

[..]
        if( stGlobalTime.tm_hour >= 24 ) {    // 24hour -> 1day
          stGlobalTime.tm_hour = 0;           // reset hour counter
          stGlobalTime.tm_yday++;             // increment day
[..]

Hier fehlt noch der tm_wday:

[..]
        if( stGlobalTime.tm_hour >= 24 ) {    // 24hour -> 1day
          stGlobalTime.tm_hour = 0;           // reset hour counter
          stGlobalTime.tm_yday++;             // increment day
          stGlobalTime.tm_wday++;             // increment day of week
[..]

von tenner (Gast)


Lesenswert?

moin oldbug,

die eigentliche datumsberechnung wird außerhalb der isr gemacht.

außerdem würde dann nochetwas fehlen

[..]
        if( stGlobalTime.tm_hour >= 24 ) {    // 24hour -> 1day
          stGlobalTime.tm_hour = 0;           // reset hour counter
          stGlobalTime.tm_yday++;             // increment day
          stGlobalTime.tm_wday++;             // increment day of week
          if( stGlobalTime.tm_wday >= 6 ) {    // 24hour -> 1day
            stGlobalTime.tm_wday = 0;
          }
[..]

und was ist dann stGlobalTime.tm_mday und stGlobalTime.tm_mon?
nee, nee, die isr dient nur um die fortlaufende zeit "messen"
datumsberechnungen sollten dann auf abruf geschehen.

wenn man die isr möglichst kurz halten will benutzt man eine 32bit
integer und incrementiert dies jede sekunde. so zu sagen ein
uptimecounter, dann setzt man setzt dann die Uhr und speichert den
aktuelen uptimecount. aus diesem läst sich dann jederzeit die uhrzeit
und das datum berechnen.
bsp-code?

von OldBug (Gast)


Lesenswert?

Hm, stimmt schon...
Bin da auch erst durch "tm_mday" drauf gekommen.

von Max (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

>welchen compiler benutzt du?

Bis gestern habe ich noch den MSPGCC benutzt. Habe mir aber vor ein
paar Tagen den ICC Compiler von Imagecraft bestellt, welcher heute
angekommen ist.
Das sind die Fehlermeldungen:


!E d:\uhr\uhr.c(42): invalid octal constant `08'
!E d:uc\uhr\uhr.c(67): type error in argument 1 to `LCDOuts'; found
`struct tm' expected `pointer to char'
!E d:\uhr\uhr.c(109): syntax error; found `12' expecting `)'
!E d:\uhr\uhr.c(109): skipping `12'
!W d:\uhr\uhr.c(109):[warning] declaring a function without prototype
may cause errors
!E d:\uhr\uhr.c(109): syntax error; found `Timer_A0' expecting `;'
!W d:\uhr\uhr.c(133):[warning] missing return value
F:\tools\icc\bin\imakew.exe: Error code 1
Done: there are error(s). Exit code: 1


Ich hänge mal das um die erweiterten Funktionen von Sebastian (Danke
dafür) c-file an.

von StephanW (Gast)


Lesenswert?

Nochmal zu der Netzteil-Sache:
Das man ein Gleichspannungsnetzteil benutzt ist ja wohl klar,
jedenfalls habe ich noch kein uC mit eingebauter Spannungsaufbereitung
gesehen :)

@Sebastian:
Das mit den 50Hz finde ich interessant. Im Physik-Unterricht hatten wir
mal einen Versuch, in dem die 50Hz als Referenz benutzt wurden; mein
Lehrer meinte dann auf meine Frage der Ungenauigkeit hin, das diese
50Hz absolut präzise gehalten werden...
Wie holst du dir denn die 50Hz aus dem NT? Ich stelle mir gerade so ne
Kombination aus ner Silizium- und Zenerdiode vor...

Gruß Stephan

von tenner (Gast)


Angehängte Dateien:

Lesenswert?

auspacken,
#define __ICC430
in uhr.c am anfang hinzufügen
die ports an deine hw anpassen
mit icc430 compilieren

sollte aber auch ohne das #define mit dem gcc gehen

code anschauen und versuchen zu verstehen.

gruß tenner

von Max (Gast)


Lesenswert?

Mensch tenner, du bist ja eine Wucht. Ich könnte dich knutschen. ;-)
Nee, ist nur Spaß. Vielen Dank für das Programm, es funktioniert
ausgezeichnet. Nur eine Frage: Gibt es eine Möglichkeit, die Uhrzeit zu
stellen, ohne den MSP jedes Mal neu programmieren zu müssen?

von Sebastian (Gast)


Lesenswert?

AAARGH! Jetzt habe ich gerade eine halbe Stunde lang getippt und das
blöde Forum hat meinen Beitrag gefressen. :-( Hab keine Lust, alles
noch mal zu tippen.

@Stephan: Nulldurchgangserkennung, hab ich auf
http://mathar.com/msp_dimmer1.html erklärt. Die 50Hz sind AFAIK sehr
genau, genauer jedenfalls als jede Taiwan-Armbanduhr.

@Max: Nein, gibt es nicht. Aber dem MSP430 verbraucht ja superwenig
Strom im LPM, daher: Einfach immer anlassen. :-)

von Max (Gast)


Lesenswert?

Schade. Naja, egal. Dann lasse ich den MSP 430 einfach an.

von tenner (Gast)


Lesenswert?

sicher gibt das ne möglichkeit die uhr zu stellen, ich zeigs euch
morgen, hab jetzt nicht die muße dazu.

von Max (Gast)


Lesenswert?

Jau, mach mal. Das würde mich sehr interessieren...
_____
Fällt dir vielleicht etwas zu meinem Usart-Problem ein?!

von Sebastian (Gast)


Lesenswert?

@tenner: Dann bin ich ja mal gespannt, wie du einem ausgeschalteten
MSP430 beibringen willst, ohne externe Bauteile (RTC o.ä.) die Uhrzeit
zu behalten. :-p

von Max (Gast)


Lesenswert?

Von behalten hat tenner hat nix geschrieben. ;-)

von Sebastian (Gast)


Lesenswert?

Ja Momeeeeent. Das EINSTELLEN der Uhrzeit ist trivial. Hast du dir den
Code durchgelesen, von dem ich geredet habe? Offenbar nein. Also
guckstu http://www.mathar.com und da den Link auf der Startseite zu der
clock.zip. Da drin ist eine Routine, die die Uhr per serieller
Schnittstelle von einem PC aus einstellt. Einmal eingestellt läuft die
Uhr dann lustig vor sich hin, bis der Strom weg ist. Und wenn er weg
ist, ist es definitiv unmöglich, die aktuelle Uhrzeit weiter laufen zu
lassen.

von tenner (Gast)


Lesenswert?

na kann ich mir die mühe ja sparen.

aber um die uhr weiter laufen zu lassen könnte ma zb. eine
batteriepufferung einbauen und bei stromausfall den µc in den lpm3
schicken und beim timerinterrupt aufwecken um die uhr weiter zu
stellen.

von Sebastian (Gast)


Lesenswert?

Ja, das wäre z.B. eine sehr elegante Lösung.

von Max (Gast)


Lesenswert?

Hat gut geklappt mit der Uhreinstellung durch die serielle
Schnittstelle. Danke euch Beiden nochmal.
Nur die ollen Usart-Schnitstellen bereiten mir nach wie vor
Kopfschmerzen...

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.