Forum: Mikrocontroller und Digitale Elektronik [AVR] Probleme mit CTC Mode für BCM (OCR0A = 128 -> LED fast aus)


von Daniel (Gast)


Lesenswert?

Hallo,

ich versuche gerade, LEDs per BCM (Binary Code Modulation) anzusteuern. 
Das klappt soweit auch, allerdings habe ich hier einen komischen Effekt, 
den ich mir nicht erklären kann.

Für die BCM nutze ich den Timer0 im CTC-Modus, als Prescaler habe ich 64 
eingestellt. Das Problem ist, dass bei diesem Prescaler-Wert die LEDs 
für den Wert OCR0A = 128 fast aus sind. Im Prinzip verhält sich der 
Timer so, als wäre er nur 7 Bit breit, d.h. OCR0A = 128 ~ 1. Ändere ich 
den Prescaler nun auf 8, so erhalte ich bei OCR0A = 128 die gewünschte 
Helligkeit, dafür flackern die LEDs aber, da nun die ISR viel zu häufig 
feuert und das Fading nicht hinterherkommt. Im Prinzip kann ich auch mit 
Werten von 0 bis 127 gut leben, ich würde aber gerne wissen, woher 
dieses Verhalten rührt. Kann mir da jemand hilfreich in die Seite 
treten? Mein Programm, wie es aktuell zum testen aussieht ist angehängt. 
Dort ist der Teil zum Faden aktuell auskommentiert und es werden nur 
fixe Helligkeitswerte verwendet, wobei für die Werte 128 die LED nur 
schwach glimmt.

Viele Grüße,
Daniel

1
/*
2
 * BCMTest.c
3
 *
4
 * Created: 18.12.2012 21:16:27
5
 *  Author: Commander
6
 */ 
7
8
9
#define F_CPU 8000000UL
10
#include <avr/io.h>
11
#include <util/delay.h>
12
#include <avr/interrupt.h>
13
14
// Zeitslots
15
volatile uint8_t gTime[8] = {1,2,4,8,16,32,64,128};
16
// BCM-Muster für jeden Zeitslot
17
volatile uint8_t gBcm[8];
18
// Helligkeit der LEDs
19
//volatile uint8_t gBrightness[8] = {0,8,16,24,32,40,48,56};
20
  
21
// LEDs 0 und 1 sind AUS, die übrigen leuchten wie gewünscht!
22
volatile uint8_t gBrightness[8] = {128,128,16,24,32,40,48,56};
23
  
24
// Aktueller Zeitslot
25
volatile uint8_t gPos = 0;
26
27
// Anzahl ISR-Aufrufe (für langsames Fading)
28
volatile uint8_t gTick = 0;
29
30
// Umwandeln der Helligkeiten in BCM-Muster
31
void encodeBrightness(uint8_t brightness[]) {
32
  uint8_t portbits = 0;
33
  
34
  // Iteriere über alle Bits
35
  for(uint8_t bitPos = 0; bitPos < 8; bitPos++) {
36
    portbits = 0;
37
    
38
    // Iteriere über alle die Helligkeiten aller LEDs
39
    for(uint8_t ledPos = 0; ledPos < 8; ledPos++) {
40
      // Falls Bit gesetzt
41
      if(gBrightness[ledPos] & (1 << bitPos)) {
42
        // Setze entsprechendes Bit im BCM-Muster
43
        portbits |= (1 << ledPos);
44
      }
45
    }
46
    
47
    // Weise BCM-Muster dem Zeitslot zu
48
    gBcm[bitPos] = portbits;
49
  }
50
}
51
52
// Initialisiere SPI
53
void initSPI() {
54
  // Ansteuerung erfolgt über PA3 bis PA5
55
  DDRA |= ((1 << DDA5) | (1 << DDA4) | (1 << DDA3));
56
  
57
  USICR = (1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC);
58
}
59
60
// Initialisiere Timer0, CTC Modus, Prescaler 64, Compare Match Interrupt enable
61
void initTimer() {
62
  TCCR0A = (1 << WGM01);
63
  TCCR0B |= (1 << CS01)|(1 << CS00);
64
  OCR0A = 1;
65
  TIMSK0 |= (1 << OCIE0A);
66
}
67
68
// Sende Wert per SPI an HC595
69
void sendSPI(uint8_t value) {
70
  PORTA |= (1 << PA3);
71
  USIDR = value;
72
  USISR |= (1 << USIOIF);
73
  
74
  while(!(USISR & (1 << USIOIF))) {
75
    USICR |= (1 << USITC);
76
    USICR |= (1 << USITC);
77
  }
78
  PORTA &= ~(1 << PA3);
79
}
80
81
int main(void)
82
{
83
  // Starte mit Zeitslot 2^0
84
  gPos = 0;
85
  
86
  // Initialisiere SPI
87
  initSPI();
88
  // Initialisiere Timer
89
  initTimer();
90
  // Interrupt enables
91
  sei();
92
  
93
  encodeBrightness(gBrightness);
94
    while(1)
95
    {  
96
    // Fade langsam hoch
97
    /*while(gTick < 16) {}
98
    gTick = 0;
99
    
100
    for(uint8_t i = 0; i < 8; i++) {
101
      gBrightness[i]++;
102
    }
103
    
104
    encodeBrightness(gBrightness);  */
105
    }
106
}
107
108
ISR(TIM0_COMPA_vect) {
109
  // Übertrage aktuelles BCM-Muster an HC595
110
  sendSPI(gBcm[gPos]);
111
  // Setze Länge des nächsten Zeitslots
112
  OCR0A = gTime[gPos];
113
  // Reset TCNT0
114
  TCNT0 = 0;
115
  
116
  // Gehe zum nächsten Zeitslot
117
  gPos++;
118
  gPos &= 7;
119
  
120
  // Erhöhe Ticks wenn ein Durchlauf beendet wurde
121
  /*if(gPos == 0) {
122
    gTick += 1;
123
  }*/
124
}

von Markus M. (adrock)


Lesenswert?

Hi,

also auf die Schnelle finde ich keinen Fehler.

Hast Du das Programm mal im Debugger/Simulator laufen lassen? Wie ist 
das Verhalten nach dem Setzen der Ausgabedaten für Bit 7 (128)? 
Eigentlich sollte da ja gaaanz lange nichts passieren außer dem 
while(1).

Ciao...
Markus

von Daniel (Gast)


Lesenswert?

Hallo,

sorry für die späte Antwort, aber Weihnachten und so ;) Ich habe das 
Ganze mal im Simulator laufen lassen, das verhalten ist dort eigentlich 
wie gewünscht. Beim letzten Zeitslot (128) wird der Wert 3 an den HC595 
übertragen und anschließend OCR0A auf 128 gesetzt. Demnach müssten also 
für 8192 Takte (128 * 64 Prescaler) die ersten beiden LEDs leuchten. Bei 
den übrigen Zeitslots sind die ersten beiden Bits immer 0, d.h. sie 
müssten für 8192 Takte aus sein. Macht für mich ein Tastverhältnis von 
1/2, so dass im Mittel 3mA durch die LEDs (low power) fließen müssten. 
Das entspricht aber nicht dem minimalen Glimmen, dass ich in der realen 
Schaltung sehe :-/

Gruß,
Daniel

von Daniel (Gast)


Lesenswert?

Ok... ich habe jetzt gerade noch etwas Trial and Error gemacht. 
Auskommentieren von
1
TCNT0 = 0;

Führt zum gewünschten Ergebnis. Kann mir jemand erklären, woran das 
liegt? In dem moment, in dem ich TCNT0 auf 0 setze habe ich ja den neuen 
Wert für OCR0A schon geschrieben, d.h. es kann doch eigentlich kein 
zweiter, unerwarteter Interrupt auftreten, oder?

Viele Grüße,
Daniel

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.