Forum: Mikrocontroller und Digitale Elektronik ATTiny13 dreht völlig durch!


von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Hallo,
ich habe einen einfachen Timer geschrieben und ihn als mein zweites
Projekt (das erste war PORT-Abschalten) nicht in Sisy-Avr sondern in
AVR-Studio mit C-Unterstützung compiliert.
Jetzt will der Controller nicht mehr!
Wenn ich ihn anschließe (JA, RESET auf Plus und Spannung stabilisiert!)
und an PORTB0 und PORTB1 Leds mit 1kOhm Vorwiederstand hänge, dann gehen 
die
Leds mal einzaln, mal zusammen an.
Habt ihr eine Ahnung?
Hier der Code:
1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
int set;
5
int bla;
6
7
ISR(TIM0_OVF_vect){
8
if(set==0) {
9
PORTB = 0b00000110;set = 1;}
10
else{
11
PORTB = 0b00000000;set = 0;}
12
}
13
14
void init(){
15
  TCCR0B = 0b00000100;   // Teiler 1/256
16
  TIMSK0 |= _BV(0);   // Interrupt bei Überlauf
17
  DDRB = 0b00000111;
18
  set = 0;
19
  sei();      
20
}
21
22
int main(void){
23
init();
24
while(1){
25
PORTB = 0b00000001;
26
bla = 0;
27
}
28
return 0;
29
}

mit freundlichen Grüßen,
Valentin

von doc (Gast)


Lesenswert?

Ähm... wie bitte willst du sehen ob die LEDs ein paar Mikrosekunden an 
sind ?
Du schaltest zwei davon in der main() immer aus.. selbst wenn sie im 
Intrrupt angemacht werden, danach werden sie in main sofort wieder 
ausgeschaltet :-)

Ausserdem sollte "set" volatile sein.

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Achso, hätte ich fast vergessen,
die Fuses sind auf 128khz Oszi-Frequenz eingestellt!
Was meinst du mit dem volatile?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Jetzt will der Controller nicht mehr!
So ein kurzes Programm könntest du im AVR-Studio auch einfach mal 
simulieren...

> dann gehen die Leds mal einzaln, mal zusammen an.
Abhängig von was?

von doc (Gast)


Lesenswert?

>Achso, hätte ich fast vergessen,
>die Fuses sind auf 128khz Oszi-Frequenz eingestellt!

Das ändert nix.
Ich habe Deine Frage beantwortet und dir den Grund, warum das Programm 
nicht das macht du willst, genannt.

von R. F. (rfr)


Lesenswert?

1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
int set;     /* volatile unsigned char set */ 
5
int bla;     /* entfernen, wird nur initialisiert */
6
7
ISR(TIM0_OVF_vect){
8
if(set==0) {PORTB = 0b00000110;set = 1;} /* 1 und 2 an */
9
else{PORTB = 0b00000000;set = 0;}  /* alles aus */
10
           /* an B0 und B1 hängt jeweils eine LED, wozu schaltest du B2? */
11
           /* besser mit ! oder ~ arbeiten. -->   Musterinvertierung */
12
}
13
14
void init(){
15
  TCCR0B = 0b00000100;   // Teiler 1/256
16
  TIMSK0 |= _BV(0);      // Interrupt bei Überlauf also alle 500 ms
17
  DDRB = 0b00000111;     /* zwei LEDs an, drei geschaltet  */
18
  set = 0;
19
  sei();      
20
}
21
22
int main(void){
23
init();
24
while(1){
25
PORTB = 0b00000001;  /*eine an */
26
bla = 0;  /* gefasel. weglassen.  */
27
}
28
return 0;
29
}

von doc (Gast)


Lesenswert?

das funktioniert nach wie vor nicht.

von Ben _. (burning_silicon)


Lesenswert?

schaltung her!

von doc (Gast)


Lesenswert?

Quatsch. Das Programm ist falsch.

von (prx) A. K. (prx)


Lesenswert?

Stützkondensator vergessen mit häufigem Reset als Folge?

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Vielen Dank für die Antworten!
Also jetzt sieht mein Code so aus:
1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
volatile unsigned char set;
5
6
7
ISR(TIM0_OVF_vect){
8
if(set==0) {
9
PORTB = 0b00000011;set = 1;}
10
else{
11
PORTB = 0b00000000;set = 0;}
12
}
13
14
void init(){
15
  TCCR0B = 0b00000100;   // Teiler 1/256
16
  TIMSK0 |= _BV(0);   // Interrupt bei Überlauf
17
  DDRB = 0b00000011;
18
  set = 0;
19
  sei();      
20
}
21
22
int main(void){
23
init();
24
while(1){
25
PORTB = 0b00000001;
26
}
27
return 0;
28
}
Allerdings geht die LED an PORTB2 immer noch nicht an.
Und wie geht das mit dem Simulieren?
Valentin

von R. F. (rfr)


Lesenswert?

ich habe nichts repariert, sondern nur kommentiert, was ich ändern 
würde. Insbesonders das volatile. Leider weiss ich nicht, ob der Timer 
sich selbst nach Ablauf startet bzw. durchläuft, oder ob man das zu Fuss 
machen muss, in diesem Falle hat der Programmierer noch was vor sich.

Den Rest bitte den Kommentaren entnehmen.

Robert

von R. F. (rfr)


Lesenswert?

lass das setzen der LED in main mal weg. Setze dafür die LED in der ISR. 
Verwende dort Toggelbefehle.

Gruss

Robert

von doc (Gast)


Lesenswert?

Bohh.. leute..

in main ist ein schleife die portb auf 1 setzt.
immer wieder.

mag zwar sein, daß man bei nur 128 khz ein gaaanz kurzes blitzen der 
anderen led sehen könnte, aber so ist das vermutlich nicht gedacht

blind ??

von Möhre X. (keks0r)


Lesenswert?

du musst den timer auch schon neu laden!
sonst bringt das nichts!
lade den timer am besten schon im init um, und besser ist es
wenn du im timer noch nen zähler drin hast,
sprich der timer muss x mal aufgerufen werden,
rechne mal hoch bei wie viel hz du da schaltest!
irgend wann ist der impuls zu kurz und die led bleibt dunkel
aber lade mal den timer vor!

hier von nem 2313er der code:

// achtung etwas viel overhead. is mir uart und co... und tasten von 
meiner schreibtisch lampe abervielleicht findest du ja stücke die du 
gebrauchen kannst,...


#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

  // Ceramic Resonator
  #ifndef F_CPU
  #define F_CPU 20000000 // 4MHz
  #endif

  // UART
  #define UART_BAUD_RATE 9600
  #define 
UART_BAUD_CALC(UART_BAUD_RATE,F_OSC)((F_CPU)/((UART_BAUD_RATE)*16L)-1)



volatile uint8_t     Run = 0;
volatile uint8_t on_kk1  = 50;
volatile uint8_t on_kk2  = 30;

volatile uint8_t kk1  = 0;
volatile uint8_t kk2  = 0;

volatile uint16_t fadeout  = 2000;


ISR(TIMER0_OVF_vect){
cli();
  if(Run==0){
    kk1 = on_kk1;
    kk2 = on_kk2;
    Run = 50;
    if(kk1 == 0 && kk2 == 0){
      PORTB|=4;
    } else {
      PORTB&=~4;
    }
  } else {

    if(kk1 > 0){
      kk1 --;
      PORTB|=1;
    } else {
      PORTB&=~1;
    }
    if(kk2 > 0){
      kk2 --;
      PORTB|=2;
    } else {
      PORTB&=~2;
    }
  }
 Run --;


 if(fadeout != 0)fadeout --;

 if(fadeout == 1){
  if(on_kk1 > 0){ on_kk1 --; }
  if(on_kk2 > 0){  on_kk2 --; }
  fadeout = 100;
 }

TCNT0 = 50;
 sei();
}

int main(void)
{



 DDRB=0xFF;
 PORTB=0x00;

 DDRD=0xFF;
 PORTD=0x00;

  // USART
  UBRRH =(uint8_t) (UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);
  UBRRL =(uint8_t) UART_BAUD_CALC(UART_BAUD_RATE,F_CPU);

  UCSRB = (1<<RXEN) | (1<<TXEN);  // enable receiver and transmitter
  UCSRC = (3<<UCSZ0);        // 8 bit (default: asynchronous, no 
parity,1stop-bit)

  // Set values for Timer 0: No Prescaler, Timer start, Preload
  TCCR0B |= (1 << CS01); // TINY
  TIMSK  |= (1 << TOIE0);

DDRD  &= ~(1<<DDD3);  /* Pin PC7 als Eingang */
DDRD  &= ~(1<<DDD5);  /* Pin PC7 als Eingang */
DDRD  &= ~(1<<DDD4);  /* Pin PC7 als Eingang */
DDRD  &= ~(1<<DDD3);  /* Pin PC7 als Eingang */
DDRD  &= ~(1<<DDD6);  /* Pin PC7 als Eingang */
DDRD  &= ~(1<<DDD2);  /* Pin PC7 als Eingang */
//PORTB |= (1<<PB5);

  // VARIABLES
  uint8_t get;


  // PROGRAM

  // wait for empty transmit buffer
  while (!(UCSRA & (1<<UDRE)));
  /* put data into buffer, sends the data*/
  UDR = 'x';

 TCNT0 = 80;
 sei();

  while(1) // forever
  {
  if ( PIND & (1<<PIND4) ) {  // Knopf 1
    fadeout =0;
    on_kk1 = 55;
    on_kk2 = 55;

  }
  if ( PIND & (1<<PIND5) ) {  // Knopf 2
    fadeout = 5;
  }
  }

}

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Ohhh, das habe ich garnicht gesehen!!!!
Gut.
Also muss ich da den Port mit einer Oder-Verknüpfung beschreiben!
Was für Togglebefehle? Die gibts in Sisy-C nicht!
Und wie geht das Simulieren?
Valentin

PS: Danke für die Antworten!

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Hier nochmal der Code:
1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
volatile unsigned char set;
5
6
7
ISR(TIM0_OVF_vect){
8
if(set==0) {
9
PORTB = 0b00000011;set = 1;}
10
else{
11
PORTB = 0b00000000;set = 0;}
12
}
13
14
void init(){
15
  TCCR0B = 0b00000100;   // Teiler 1/256
16
  TIMSK0 |= _BV(0);   // Interrupt bei Überlauf
17
  DDRB = 0b00000011;
18
  set = 0;
19
  sei();      
20
}
21
22
int main(void){
23
init();
24
while(1){
25
PORTB = PORTB | 0b00000001;
26
}
27
return 0;
28
}

Kann man das Set auch vielleicht mit einem bool machen?
Valentin

von R. F. (rfr)


Lesenswert?

Schag nach in deinem C-handbuch  unter '!' und '~'.

Gruss

Robert

von doc (Gast)


Lesenswert?

nicht "!"
sondern ^

besser ist das.

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Ohhh, also per NOT oder XOR! Das heißt in GCC also "!"!
Danke
Kann ich die Schleife einfach leer lassen? Oder kürzt der die dann weg?
Und wie geht das mit dem Simulator?
Valentin

PS: Hier der Code:
1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
volatile unsigned char set;
5
6
7
ISR(TIM0_OVF_vect){
8
PORTB = PORTB ^ 0b00000011;set = 1;}
9
}
10
11
void init(){
12
  TCCR0B = 0b00000100;   // Teiler 1/256
13
  TIMSK0 |= _BV(0);   // Interrupt bei Überlauf
14
  DDRB = 0b00000011;
15
  set = 0;
16
  sei();      
17
}
18
19
int main(void){
20
init();
21
while(1){}
22
return 0;
23
}

von doc (Gast)


Lesenswert?

huch, vergiss meinen letzten beitrag, lol.
&

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

DA war noch eine } zuviel. Hab ich inzwischen weggemacht!
Valentin

PS: Soll ich jetzt doch mit NOT arbeiten? x xor x = 0 , oder?

von Walter (Gast)


Lesenswert?

>Allerdings geht die LED an PORTB2 immer noch nicht an.
warum sollte sie auch wenn PORTB2 ein Eingang ist ...

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Wie "ein Eingang"?
Ich habe ihn doch auf Ausgang geschaltet!
Valentin

von Karl H. (kbuchegg)


Lesenswert?

Wo?

von Karl H. (kbuchegg)


Lesenswert?

Dein Programm ist mitlerweile ein heftiges Sammelsurium an 
Sschreibweisen. Nur die eine, die du eigentlich benutzen solltest, die 
ist nicht dabei :-)

Das ändert aber immer noch nichts daran, dass dein Timer zu schnell 
läuft. So kannst du die Overflows noch weiter runterteilen.
1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
unsigned char counter;
5
6
ISR(TIM0_OVF_vect)
7
{
8
  counter++;
9
10
  if( counter == 7 )    // ergbit bei 1Mhz ca. 0.5 Sekunden bei Presc. 256
11
  {
12
     PORTB = PORTB ^ ( (1<<PB0) | (1<<PB1) );
13
     counter = 0;
14
  }
15
}
16
17
void init()
18
{
19
  TCCR0B = ( 1 << CS02 );    // Teiler 1/256
20
  TIMSK0 = ( 1 << TOIE0 );   // Interrupt bei Überlauf
21
22
  DDRB = (1<<PB0) | (1<<PB1);
23
24
  sei();      
25
}
26
27
int main(void)
28
{
29
  init();
30
31
  while(1)
32
  {
33
  }
34
35
  return 0;
36
}

von doc (Gast)


Lesenswert?


von Hc Z. (mizch)


Lesenswert?

Mal abgesehen von all dem Gesagten: das ist sehr schlechter Stil:
1
>   TIMSK0 |= _BV(0);   // Interrupt bei Überlauf
und überdies falsch.  Bit 0 in TIMSK0 gips beim Tiny13 nicht.  Das wäre 
nicht passiert, wenn Du gleich
1
TIMSK0 |= (1<<TOIE0);
geschrieben hättest, wie es sauberer Programmierstil erfordert hätte. 
Der ist nämlich nicht dazu da, fremde Schönheitsideale zu befriedigen, 
sondern sehr nützlich, um sich selbst vor diesem und vielen anderen 
solchen Fehlern zu bewahren.

Aus langer Erfahrung:  So wie ein Programm aussieht, ist es meistens 
auch.  In Deinem Fall sieht schon der kurze Schnipsel so aus, als wäre 
es nicht der Tiny13, der am völligen Durchdrehen ist.

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

So, ich habe eure Tipps mal umgesetzt. Ich benutze aber den internen 
Takt auf 128Khz mit Vorteiler 256 und dann wird das Ganze noch durch 255 
geteilt, bis es zum Overflow kommt. Das gibt meiner Rechnung nach gerade 
mal 1,9 Hz.
Deshalb habe ich den Teiler weggelassen. Hier mein endgültiges Programm:
1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
ISR(TIM0_OVF_vect)
5
{
6
     PORTB = PORTB ^ ( (1<<PB0) | (1<<PB1) );
7
}
8
9
void init()
10
{
11
  TCCR0B = ( 1 << CS02 );    // Teiler 1/256
12
  TIMSK0 = ( 1 << TOIE0 );   // Interrupt bei Überlauf
13
  DDRB = (1<<PB0) | (1<<PB1);
14
  sei();      
15
}
16
17
int main(void)
18
{
19
  init();
20
21
  while(1)
22
  {
23
  }
24
25
  return 0;
26
}
Vielen Dank an alle!!!
Valentin

von Hc Z. (mizch)


Lesenswert?

Ein schneller Lerneffekt.  Glückwunsch zum nun laufenden Programm!

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Jetzt wollte ich mein Programm mal auf einen ATMEGA32 transferieren, und 
dabei nur bis 250 zählen. Ich verwende aber wieder Timer0.
Allerdings meint AVR Studio nun, dass TCCR0 kein COM0-Bit hat.
Hier der Code:
1
...
2
ISR (TIMER0_COMPA_vect){
3
PORTB = PORTB ^ ( (1<<PB0) | (1<<PB1) );
4
}
5
...
6
TCCR0 =  (1<<CS02)|(1<<COM0);// Teiler 1/256, Modus: Zählen bis //Vergleichswert
7
   OCR0 = 250;   // Vergleichswert speichern
8
  TIMSK = (1<<TOIE0);//interrupt einschalten
9
  TIFR = (1<<OCF0); //Interrupt bei CompareMatch
10
  sei();//Interrupts einschalten
11
...
Danke für die Antworten,
Valentin

von doc (Gast)


Lesenswert?

Dafür gibts Datenblätter.
REINGUCKEN :-)

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Da steht GAR-NIX von einem Compare Register. Vergleicht der das dauernd?
Valentin

von Michael P. (mipo)


Lesenswert?

tja, dann musst Du wohl in Datenblatt schauen...

von Justus S. (jussa)


Lesenswert?

Valentin Buck schrieb:
> Da steht GAR-NIX von einem Compare Register.

doch

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

"The double buffered Output Compare Register (OCR0) is compared with the
Timer/Counter value at all times."
OK, der vergleicht es also dauernd.
Valentin

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.