PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega8 spinnt



BurningWave
20.01.2008, 19:44
Hallo,

ich möchte mit einem Atmega8 2 Tasten abfragen und dann wenn die eine gedrückt wird eine Variable um 1 erhöhen, bzw. wenn die andere Taste gedrückt wird die Variable um 1 erniedrigen. Wenn die Variable dann den Wert 3 hat soll eine LED angehen. Dazu verwende ich folgenden C Code:



#include <avr/io.h>
#include "wait.h"

int count = 0;

void main()
{
DDRC = 0x07;

while(1)
{
if(PINC & (1 << PC5))
{
if(count < 15)
{
count++;
wait_ms(500);
}
}

if(PINC & (1 << PC4))
{
if(count != 0)
{
count--;
wait_ms(500);
}
}

if(count == 3)
{
sbi(PORTC, 1);
}
else
{
cbi(PORTC, 1);
}
}
}


wait.h


#define F_CPU 3686400ul
#include <util/delay.h>

void wait_ms(int miliSec)
{
_delay_loop_2(1*(F_CPU/(1000/4))*miliSec);
}

void wait_us(int mikroSec)
{
_delay_loop_2(1*(F_CPU/(1000000/4))*mikroSec);
}


Dieses Programm funktioniert auch wenn ich es am Computer simuliere (ich benutze das AVR Studio 4), aber wenn ich es dann auf den Mega8 lade und starte blitzt die LED unkontrolierbar auf und die Tasten bewirken gar nichts mehr (als Experimentierboard benutze ich das myAVR Board). Woran liegt das??? :-k

Hubert.G
20.01.2008, 21:16
Ich traue diesem delay nicht. Mach eine LED in die Schleife mit PORTC^=(1<<PC0); wait_ms(1000). Die sollte dann im Sekundentakt blinken. Wenn du länger auf den Tasten bleibst zählt es weiter.

sechsrad
21.01.2008, 08:02
....Ich traue diesem delay nicht. ....


schau dir delay in der hilfe an von winavr-c und du verstehst sie dann.
wenn man mit diesen delay nicht richtig umgehen kann, sollte man die finger von lassen.

Hubert.G
21.01.2008, 09:31
Ich traue diesem delay im Code von _R2D2 nicht, hätte ich besser schreiben sollen. Das die max. Verzögerung mit steigender Taktfrequenz kleiner wird, kann man oft genug lesen.

Hubert.G
21.01.2008, 11:05
@_R2D2 Hast du ext. PullUp an den Tasten, die internen sind ja nicht aktiv.

BurningWave
22.01.2008, 16:49
Ich habe jetzt eine LED an PC0 angeschlossen und


PORTC^=(1<<PC0);
wait_ms(1000);
in die Schleife eingebaut. Jetzt blinkt die LED, die an PC0 angeschlossen ist ca. 5 mal in der Sekunde. Wie kann ich die Delay-Funktionen jetzt so verändern, dass die LED auch wirklich nur ein mal in der Sekunde blinkt?

Ich habe die Delay-Funktionen aus dem Lehrheft LCD Programmierung von myAVR abgeschrieben, deswegen müssten sie doch eigentlich auch funktionieren?!

tholan
22.01.2008, 23:18
Hi,
500mS, bzw 1000mS sind definitiv zu viel,
Du rufst die Funktion _delay_loop_2() aus der delay_basic.h auf.
Dazu steht als Kommentar oben drüber:
"...,at a CPU speed of 1 MHz, delays of up to about 262.1
milliseconds can be achieved."
Bei 3,6864 MHz sind das entsprechend weniger, also:
262.1 / 3,6864 = 71 mS !
Mehr geht nicht mit diesen Funktionen.
Ich hab mal genauso dagesessen und mich gewundert mit der _delay_ms()
aus delay.h.
Was die da so richtig machen mit dem rumgecaste mit Mikrosekunden und 'ner extra "wait.h"
durchblicke ich auch nicht.
Ich würde die wait.h weglassen, dafür die util/delay.h includen.
Dann mußt Du die F_CPU 3686400ul im makefile angeben und schreibst statt wait_ms(500)
folgendes:


uint8_t n; //das kommt vor dem while (1) {
for (n=0; n<10; n++)
_delay_ms(50); //Unterstrich bei _delay nicht vergessen.


Wenn Du's eifach haben willst, setze nur wait_ms(50) und
laß das 10x durch 'ne Schleife laufen.
p.s.
die Fuses sind doch hoffentlich richtig gesetzt?

BurningWave
23.01.2008, 17:35
Ich habe wait_ms durch _delay_ms ersetzt so wie tholan geraten het. Das funktioniert jetzt echt gut. :)

Aber die LED, die an PC1 angeschlossen ist leuchtet weiterhin unkontolliert auf. Liegt das vielleicht daran, dass die Tasten PINC5, bzw. PINC4 mit dem Minuspol der Stromversorgung verbinden? Müsste das nicht der Pluspol sein?!

tholan
23.01.2008, 23:45
Ich bin eigentlich auch eher Einsteiger in C.
Ports werden allerdings allgemein "invertiert" abgefragt.
Dazu legt man, wie es hier auch gemacht wird zunächst die Ports im Datenrichtungsregister
auf 0, sprich Eingang. Damit werden die Eingänge hochohmig!
D.h. die reagieren evtl schon, wenn Du dich dem Eingangspin nur mit der Hand näherst.
Die kleinen Kapazitäten am Eingang sorgen dann dafür, daß der Eingang nach einer undefinierten
Zeit vielleicht wieder ausgeht.
Aus diesem Grund aktiviert man die Pullups und schaltet nach Null, also invertiert.
In Deinem Code sind die Pullups nicht aktiviert. Das macht man auch mit "PORTC ="
Also oben noch einfügen:
PORTC |= (1<< PC4) |(1<<PC5); //Aktivieren der Pullups
Dann mußt du natürlich die Pinabfrage auch invertieren:
Statt: if(PINC & (1 << PC5)) steht dann da: if (! (PINC & (1 << PC5)))
Dasgleiche in der anderen Bedingung. Dann werden Selbstverständlich noch die
Pins über den Taster nach Minus verbunden.
Ich hab auch noch nie mit sbi() und cbi() gearbeitet.
Normalerweise bemühe ich hier die üblichen Bitschiebereien.
Und wenn dann alles funktioniert, solltest Du Dir schnell abgewöhnen mit aktivem Warten zu arbeiten.
Blinken macht man eigentlich mit "Timer Overflow Interrupt"- ISRs.
Ich würde Dir das AVR- Tutorial von mikrocontroller.net empfehlen.
Das hat mir auch sehr geholfen.

sechsrad
24.01.2008, 10:04
.....Ich hab auch noch nie mit sbi() und cbi() gearbeitet. ......

ist eine schreiberleichterung und übesichtlich.

tholan
24.01.2008, 11:36
Ich komm vom Basic und find das auch leserlicher, als diese akademischen
Hieroglyphenschiebereien, wobei ich sowas wie inp() und outp() bevorzuge.
Man sollte nur nicht davon ausgehen, daß die Compilerautoren etwas
so lassen, wie es ist, weil es einfach ist.
C-Code darf halt nur für Eingeweihte lesbar sein :) .
Soweit ich weiß. gibts da ein Gerangel um die weitere Unterstützung
von sbi(), cbi(), outp() und inp().
Guckt mal hier:
http://www.mikrocontroller.net/topic/24517

BurningWave
24.01.2008, 14:30
Ich habe noch die Anweisung
PORTC |= (1<< PC4) |(1<<PC5);
in den Code eingesetzt und jetz funktioniert alles perfekt! :D

Ich arbeite auch lieber mit cbi() und sbi(), weil der Code dann übersichtlicher wird und man dann leichter arbeiten kann. Wenn die Funktionen nicht definiert sind, kann man sie einfach mit
#define cbi(sfr, bit) sfr &= ~(1 << bit)
#define sbi(sfr, bit) sfr |= (1 << bit)
definieren.

tholan
24.01.2008, 19:51
Na bitte,
noch viel Spaß und Erfolg,
tholan

BurningWave
25.01.2008, 13:41
Ja, danke für eure freundliche Hilfe