Du kannst den DCO auch vom Timer A automatisch auf ein ganzzahliges
vielfaches der 32,768kHz einstellen.
Hier der Code: DELTA ist der Vervierfachungsfaktor:
1 | //------------------------------------------------------------------------------
|
2 | void Set_DCO (void) // Set DCO to selected frequency
|
3 | //------------------------------------------------------------------------------
|
4 | {
|
5 |
|
6 | #define DELTA 125 // target DCO = DELTA*(32768) = 4096000
|
7 | unsigned int Compare, Oldcapture = 0;
|
8 |
|
9 | CCTL2 = CM_1 + CCIS_1 + CAP; // CAP, ACLK
|
10 | TACTL = TASSEL_2 + MC_2 + TACLR; // SMCLK, cont-mode, clear
|
11 |
|
12 | while (1)
|
13 | {
|
14 | while (!(CCIFG & CCTL2)); // Wait until capture occured
|
15 | CCTL2 &= ~CCIFG; // Capture occured, clear flag
|
16 | Compare = CCR2; // Get current captured SMCLK
|
17 | Compare = Compare - Oldcapture; // SMCLK difference
|
18 | Oldcapture = CCR2; // Save current captured SMCLK
|
19 |
|
20 | if (DELTA == Compare) break; // If equal, leave "while(1)"
|
21 | else if (DELTA < Compare) // DCO is too fast, slow it down
|
22 | {
|
23 | DCOCTL--;
|
24 | if (DCOCTL == 0xFF)
|
25 | {
|
26 | if (!(BCSCTL1 == (XT2OFF)))
|
27 | BCSCTL1--; // Did DCO roll under?, Sel lower RSEL
|
28 | }
|
29 | }
|
30 | else
|
31 | {
|
32 | DCOCTL++;
|
33 | if (DCOCTL == 0x00)
|
34 | {
|
35 | if (!(BCSCTL1 == (XT2OFF + 0x07)))
|
36 | BCSCTL1++; // Did DCO roll over? Sel higher RSEL
|
37 | }
|
38 | }
|
39 | }
|
40 | CCTL2 = 0; // Stop CCR2
|
41 | TACTL = 0; // Stop Timer_A
|
42 | }
|
Zu Beachten ist aber, dass der DCO einen schrecklichen Temperatur- und
Betriebsspannungsdrift hat. Für so schnelle Kommunikation ist das dann
ein ganz schönes Glücksspiel, vor allem, wenn sich mal die Temperatur
ändert.
Am besten die o.g. Funktion zyklisch ausführen, z.B. alle 1 Min oder so.
Oder einen Quarz an XT2 anschließen.