MSP 430 & Uhrzeit

Gast #124774
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).
Angehängte Dateien:
Gast #124775
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;
}
Gast #124776
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
Gast #124784
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++;
          }
        }
      }
    }
  }
}
Gast #124786
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.
Gast #124787
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.
Gast #124788
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.
Gast #124790
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?
Angehängte Dateien:
Gast #124791
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
[..]
Gast #124792
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?
Gast #124794
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.
Angehängte Dateien:
Gast #124795
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
Gast #124796
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
Angehängte Dateien:
Gast #124797
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?
Gast #124798
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. :-)
Gast #124804
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.
Gast #124805
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren