Forum: Compiler & IDEs ATmega64 - _delay_ms und Timer/ISR Problem


von Mounty (Gast)


Lesenswert?

Hallo zusammen!

Ich habe in den letzten Tagen eine Platine mit einem ATmega64 gebaut. 
Anstelle des externen Quarz wird der interen 1Mhz Oszillator (4ms) 
verwendet, d.h. die XTAL1/2 Anschlüsse hängen in der Luft. CkOPT ist 
unprogrammiert.

Mein Ziel: Ein LCD Display ansteuern, wobei dabei "_delay_ms()" 
verwendet wird.
Problem: Mein Prozessor scheint sich aufzuhängen, wenn ich die 
delay-Funktion aufrufe.

Ich habe alternativ als eine Art "Debug-Hardware-Ausgabe" folgendes 
versucht:

Wenn ich den PORTD |= 0xF0 (DDRD = 0xF0) nach dem Aufruf von delay setze 
und eine LED dran packe, dann leuchtet die Led umso weniger hell je 
höher ich den Wert für _delay_ms() setze.
Somit: _delay_ms(1ms);
       PORTD |= 0xF0; led leuchtet hell
       _delay_ms(5ms);
       PORTD |= 0xF0; led leuchtet fast nicht mehr, aber sie leuchtet 
noch
-> Die Spannung für "high" nimmt am ganzen Port ab...

Weiterer Versuch:

Anstelle des anscheinend nicht funktionierenden delay-Befehls habe ich 
dann den Timer0 verwendet und eine eigene "wait_ms" Funktion 
geschrieben.
Dabei wird der CTC-Modus verwendet und der Interrupt mit ISR gefangen. 
Jeder Interrupt sorgt für eine Erhöhung der timer_counter Variable.
Da der Timer alle 1ms etwa einen Interrupt erzeugt, warte ich einfach in 
der wait_ms-Funktion mit "while(timer_counter < 1)" und zähle so die 
Anzahl der Milisekunden (Variable i).

Problem: Wie bei _delay_ms() setze ich den PORTD = 0x00, danach wird ein 
wait_ms(x) aufgerufen und PORTD |= 0xF0 (DDRB = 0xF0) gesetzt. Je höher 
ich x (= ms) setze, desto weniger leuchtet meine LED am PORTD ...

Vielleicht findet jemand im Code einen Fehler. Wenn nicht gibts 
vielleicht sonstige Tips!!


Als Programm verwende ich AVR Studio 5.1 und ich habe folgenden Code 
programmiert:
1
#include "lcd.h"
2
#include <inttypes.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <stdio.h>
6
#include <math.h>
7
8
volatile uint8_t timer_counter;
9
10
void init_LCD(void)   //Initializes LCD
11
{
12
13
  timer_counter = 0;
14
15
  PORTB |= 0xF0;   // Ausgabe zum Testen, LEDS leuchten
16
  PORTD |= 0x78;   // ebenfalls ok
17
  
18
  start_timer();
19
  
20
   wait_ms(3);       <<-- PROBLEM VERMUTET!!!
21
   PORTD &= 0x87;    <<- PORT schaltet sofort um, LEDs leuchten noch 
22
                         schwach, nicht "aus"
23
24
25
  //---------FUNCTION SET: ------ 
26
  LCDsendCommand(LCD_8BIT_2LINES_5X7DOTS); 
27
  wait_ms(1);
28
  //---------DISPLAY CLEAR ------ 
29
  LCDsendCommand(LCD_CLEAR);  
30
  ...
31
}  
32
33
void start_timer() 
34
{
35
  TCNT0 = 0x00; // mit 0 initialisieren
36
  OCR0 = 0x1E;  //Vergleichsregister initialisieren, 30 = 0x1E
37
  TIMSK |= (1 << OCIE0);    //Output Compare interrupt enable
38
    
39
  //Timer Start
40
  TCCR0 |= ((1 << WGM01) | (1 << CS01) | (1 << CS00));
41
  //            CTC Mode | Prescaler clk/32  
42
}
43
44
/** Schläft x-Millisekunden. */
45
inline void wait_ms(uint8_t msec)
46
{
47
  uint8_t i = 0;   // zähle vergangene ms (= Anzahl ISR Aufrufe)  
48
  while(i < msec) 
49
  {
50
    timer_counter = 0;         // counter neu starten
51
    while (timer_counter < 1); // timercounter wird alle 1ms erhöht -> warte bis erste erhöhung eintritt = 1ms 
52
    i++;      
53
  }
54
}
55
56
//Interrupt Service Routine
57
ISR(TIMER0_COMP_vect) {
58
  timer_counter++;
59
}
60
61
void LCDsendCommand(uint8_t cmd)  //Sends Command to LCD
62
{
63
  LCD_CONTROL_PORT &= ~(1<<LCD_RW);  // select write option, RW = 0
64
  LCD_CONTROL_PORT &= ~(1<<LCD_RS);  // select the command register, RS = 0
65
  wait_ms(1);
66
  LCD_CONTROL_PORT |= (1<<LCD_ENABLE);     // set enable line
67
  LCD_DATA_PORT = cmd;    
68
  wait_ms(1);
69
  LCD_CONTROL_PORT &= ~(1<<LCD_ENABLE);     // reset enable line
70
  wait_ms(5);
71
72
}

von Karl H. (kbuchegg)


Lesenswert?

Mounty schrieb:

> Wenn ich den PORTD |= 0xF0 (DDRD = 0xF0) nach dem Aufruf von delay setze
> und eine LED dran packe, dann leuchtet die Led umso weniger hell je
> höher ich den Wert für _delay_ms() setze.
> Somit: _delay_ms(1ms);
>        PORTD |= 0xF0; led leuchtet hell
>        _delay_ms(5ms);
>        PORTD |= 0xF0; led leuchtet fast nicht mehr, aber sie leuchtet
> noch
> -> Die Spannung für "high" nimmt am ganzen Port ab...
>
> Weiterer Versuch:
>
> Anstelle des anscheinend nicht funktionierenden delay-Befehls habe ich
> dann den Timer0 verwendet und eine eigene "wait_ms" Funktion

> wait_ms(x) aufgerufen und PORTD |= 0xF0 (DDRB = 0xF0) gesetzt. Je höher
> ich x (= ms) setze, desto weniger leuchtet meine LED am PORTD ...


Du hast also auf 2 unterschiedlichen Wegen dieselben Symptome. Wie 
kommst du dann zum Schluss, dass _delay_ms nicht funktioniert?

Wenn du das abklären willst, dann wirf alles raus, was nicht mit den 
Ports bzw LED zu tun hat und überzeug dich davon, dass _delay_ms 
tadellos funktioniert

int main()
{
  Led Port auf Ausgang

  while( 1 )
  {
    Led einschalten

    _delay_ms( 1000 );

    Led aussschalten

    _delay_ms( 1000 );
  }
}


Erst wenn das nicht funktioniert, bist du in der gesicherten Lage eine 
Aussage über ein Nicht-funktionieren von _delay_ms zu geben.

von Peter D. (peda)


Lesenswert?

M103 Fuse

Warum nimmst Du nicht den moderneren ATmega1281?


Peter

von Mounty (Gast)


Lesenswert?

Folgender Code liefert weder en Blinken noch sonstwas...


#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 1000000UL

int main(void)
{
    while(1)
    {
    _delay_ms( 1000 );
    PORTD |= 0x78;
    _delay_ms( 1000 );
    PORTD &= 0x87;
    }
    return 0;
}

Stelle ich allerdings beide Delay-Zeiten auf 100ms: LEDs leuchten 
durchgehend ganz schwach
10ms: mittel, 1ms: Leds leuchten stärker... da soll sich wer auskennen?

von Karl H. (kbuchegg)


Lesenswert?

Peter Dannegger schrieb:
> M103 Fuse

Der M64 hat eine M103 Fuse?
Ich dachte, die hätte nur der M128.
Wieder was gelernt.

(Den Typen, der sich den Quatsch ausgedacht hat, das diese Fuse per 
Default eingeschaltet ist, dem würde ich auch gerne mal in die .... 
treten)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mounty schrieb:
> Folgender Code liefert weder en Blinken noch sonstwas...

Kein Wunder, wenn du keinen Ausgang aktivierst, sondern nur die
Pullups.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Peter Dannegger schrieb:
>> M103 Fuse
>
> Der M64 hat eine M103 Fuse?

Ja, das ist gewissermaßen nur ein runterskalierter ATmega128.

> (Den Typen, der sich den Quatsch ausgedacht hat, das diese Fuse per
> Default eingeschaltet ist, dem würde ich auch gerne mal in die ....
> treten)

Vermutlich gab's da einen volume-Kunden, der bis dato ATmega103
verbaut hatte, und dem man daher den ATmega128 als Upgrade-Typ so
schmackhaft wie nur möglich verkaufen wollte, um den '103 aus dem
Programm streichen zu können.

von Mounty (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Kein Wunder, wenn du keinen Ausgang aktivierst, sondern nur die
> Pullups.


Sorry, etwas beim Kopieren vergessen... folgende Zeile fehlt nicht im
Code von oben:
DDRD = 0x78;   // vor dem while(1)

von Mounty (Gast)


Lesenswert?

Hab das Problem näher eingeschränkt:

Das Problem muss irgendwie mit dem Interrupt / ISR zusammenhängen.

Wenn ich wait_ms(1) aufrufe kann ich danach meine Ausgänge auf "low" 
setzen (= 0.3V) ... wenn ich allerdings wait_ms(2) aufrufe, dann wird 
die "low" spannung etwa 1V.
Die Ausgänge werden jeweils nach dem wait_ms() mit DDRx = 0xF0, PORTx = 
0x00; gesetzt.

Weiß einer warum die Spannung raufgeht?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mounty schrieb:
> Das Problem muss irgendwie mit dem Interrupt / ISR zusammenhängen.

Mit welchem?  In deinem Minimalbeispiel hast du doch gar keinen drin.
Oder hast du auch nur wieder vergessen, uns den mit zu kopieren?

Bitte poste uns exakt den Code, den du auch benutzt, und am besten
noch die Compiler-Kommandozeile dazu.

von Stefan E. (sternst)


Lesenswert?

Und äußere dich bitte mal zur M103C-Fuse. Ich kann in keinem deiner 
Beiträge eine Bestätigung dazu sehen, dass du diesen Hinweis von Peter 
überhaupt zur Kenntnis genommen, geschweige denn überprüft hast.

von Karl H. (kbuchegg)


Lesenswert?

Mounty schrieb:

> Weiß einer warum die Spannung raufgeht?


Klare Aussage:
Dein Problem ist erst mal die M103 Fuse!
Die scheint immer noch gesetzt zu sein, wodurch es beim ersten 
Funktionsaufruf zu einem Prozessorreset kommt!
Solange du die nicht ausgeschaltet hast, brauchst du nicht weitermachen.

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.