PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C-Programm mit einfachen Funktionen für AT90S2313



funky78
20.07.2005, 16:02
Hallo Experten...

Bin ein absoluter Anfänger, habe mir auch schon einige Tutorials angeschaut. Leider liegt mir das Programmieren nicht sehr. Und auf die schnelle sich voll einarbeiten geht leider auch nicht. Ich schreibe derzeit meine Studienarbeit, und ein Teil, was im nachhinein dazu gekommen ist :frown: , ist die Programmierung eines Mikrocontrollers.

Ich möchte das ganze auch gerne lernen, doch geht es nicht, mit dem Zeitdruck, den mein Betreuer mir vorgegeben hat. :cry:
Denn er meinte, für einen, der das kann ist das eine Arbeit von nicht mal einem Tag...und ließ mich dann hängen :cry:

Gibt es Experten unter euch, die mich unterstützen können?

3 LED's habe ich schon zum leuchten gebracht, kann somit die Ports ansprechen. Aber wie ich nun die Ideen Umsetzen soll, weiß ich einfach nicht...

Bin in Not...:cry: Hilfe bitte :cry:

MC ist AT90S2313

dark emporer
20.07.2005, 16:34
Wenn Fragen aufkommen einfach hier rein posten!!!

funky78
21.07.2005, 09:25
Nur vor weg...

Bitte entschuldigt, wenn ich dumme Fragen stelle.

MC: AT90S2313
an PB3, PB4 und PB7 sind LED's angeschlossen.

Ein- und Ausschalten kann ich diese, wie folgt:

int main( void )
{
DDRB=0b11111011; //PortB (außer PB2) als Ausgang definieren
PORTB=0b11111111; //Port's auf High setzen, bzw. PB2 PullUp aktivieren

for(;;)
{
PORTB=0b01111111; //LED an PB7 einschalten
}
}

Bis hierhin ist alles ok.
Nun habe ich an PB2 einen Schalter gegen Masse.

Was ich möchte:
-> Schauen ob PB2 gegen Masse geschaltet ist
-> Wenn ja, LED an PB3 leuchten lassen
-> Wenn nicht, LED an PB7 leuchten lassen
-> Sobald umgeschaltet wird, möchte ich, dass die jeweils andere LED leuchtet (Also wenn LED an PB3 leuchtet, und ich schalte um, soll LED an PB7 leuchten)

Das ist es mal für den Anfang...(hatte ich recht mit "dummen Fragen"? 8-[

Radian
21.07.2005, 09:31
Hast du schon mal ins AVR-GCC Tutorial geschaut?
Da werden zumindest mal die grundlegensten Sachen in Bezug auf AVR und C Programmierung geklärt.
gibts auf mikrocontroller dot net und ich glaub auch hier im Downloadbereich in einer erweiterten Version.
Vielleicht hilft das ja?!

funky78
26.07.2005, 16:59
Hallo nochmals...

Ich habe Fortschritte gemacht.\:D/
Das Ein- und Ausschalten von den einzelnen Ports habe ich nun drauf. Eine kleine Umlötaktion, und der Schalter hängt nun an Port PD3 (INT1) Eingang. Das ganze wird nun per Interrup-Routine abgearbeitet.

Doch jetzt kommt der nächste Schritt.
Die Ausgänge sollen über UART angesteuert werden.
Und damit habe ich mein nächstes Problem: UART.

Gibt es irgendwo Beispielprogramme (im Tutorial leider nicht ganz fündig geworden)...

Vielleicht einige Worte zu dem, was ich machen möchte:
Empfange ich "CH1"
->Interrupt auslösen
-PB3 auf LOW
-PB4 auf HIGH
-PD5 auf LOW
-Rückmeldung an PC: "CH1_OK"

Empfange ich "CH2"
->Interrupt auslösen
-PB3 auf HIGH
-PB4 auf LOW
-PD5 auf HIGH
-Rückmeldung an PC: "CH2_OK"

Kann mir jemand weiter helfen?
Vielleicht ein Beispielprogramm?

izaseba
26.07.2005, 17:56
Hallo,
Folgende Überlegung:
Ein char Array, als Puffer.
Permanent UDR auslesen, bzw, per interrupt nach ankommenden Zeichen überprüfen,
wenn was angekommen ist erst nach RETURN prüfen, wenn ja dann Puffer mit den Konstanten nacheinander vergleichen und entsprechende Funktion anspringen, wenn kein RETURN, Zeichen in Puffer schieben, gleichzeitig in UDR zurückschreiben (damit man im Terminal auch was sieht), Routine verlassen.
Gruß Sebastian

Kjion
26.07.2005, 18:05
Ich hatte mal ein Beispiel für den UART geschrieben, vielleicht hilft dir das ja schonmal weiter:
http://www.kreatives-chaos.com/index.php?seite=c_uart

MfG Kjion

funky78
26.07.2005, 18:10
Hallo,
Folgende Überlegung:
Ein char Array, als Puffer.
Permanent UDR auslesen, bzw, per interrupt nach ankommenden Zeichen überprüfen,
wenn was angekommen ist erst nach RETURN prüfen, wenn ja dann Puffer mit den Konstanten nacheinander vergleichen und entsprechende Funktion anspringen, wenn kein RETURN, Zeichen in Puffer schieben, gleichzeitig in UDR zurückschreiben (damit man im Terminal auch was sieht), Routine verlassen.
Gruß Sebastian

Hört sich Interessant an...das Problem ist nur, bin wirklich ein Anfänger, was Programmieren allg. angeht...

funky78
26.07.2005, 18:12
Ich hatte mal ein Beispiel für den UART geschrieben, vielleicht hilft dir das ja schonmal weiter:
http://www.kreatives-chaos.com/index.php?seite=c_uart

MfG Kjion

Da bin ich vorhin hingekommen...

Habe es auch abgeändert (für den AT90S2313), compiliiert und übertragen, kann natürlich auch Fehler eingebaut haben...
Die Frage ist...was macht es nun...(in meinem Fall tut sich leider nichts :cry: )
Sollte ich etwas im Hyperterminal sehen?

izaseba
26.07.2005, 18:16
das Problem ist nur, bin wirklich ein Anfänger, was Programmieren allg. angeht...

Ich will Dich nicht gerade, hmmm angreifen, aber Du kannst mir nicht erzählen, daß man von Euch Sachen verlangt, die Ihr nicht durchgearbeitet habt ?

Wie kann ich Dir sonst noch helfen? was verstehst Du nicht?

Gruß Sebastian

EDIT: Mit dem Beispiel von Kjion hast Du schon das halbe Programm fertig.

funky78
26.07.2005, 18:25
das Problem ist nur, bin wirklich ein Anfänger, was Programmieren allg. angeht...

Ich will Dich nicht gerade, hmmm angreifen, aber Du kannst mir nicht erzählen, daß man von Euch Sachen verlangt, die Ihr nicht durchgearbeitet habt ?

Wie kann ich Dir sonst noch helfen? was verstehst Du nicht?

Gruß Sebastian

EDIT: Mit dem Beispiel von Kjion hast Du schon das halbe Programm fertig.

Fühle mich auch nicht angegriffen...
Wie kann man von uns Sachen verlangen, die wir nicht durchgearbeitet haben.
Diese Arbeit war eine reine Hardwarearbeit...
Mein Betreuer meinte, ich solle die Hardwaretechnischen Probleme lösen, und er wird dann die Software, sprich den Mikrocontroller programmieren.
Na ja, nun meinte er eben, dass er keine Zeit hat, und ich mich mal etwas damit beschäftigen soll.
Zuvor habe ich nie etwas mit Mikrocontroller zu tun gehabt (bin doch eher der Hardwaremensch). Programmieren musste ich im zweiten Semester, wo es hieß, wir müssen die Sprach der Zukunft lernen, nämlich Oberon...
Das Institut hat damals darauf geschwört...und kein Jahr später sind sie selbst zu JAVA umgestiegen...

izaseba
26.07.2005, 18:49
Na ja, wie gesagt, das Beispiel von Kjion ist die halbe Miete, wobei der µC damit Beschäftigt ist auf die ankommenden Zeichen zu warten.
Eleganter ist es einen Interrupt auszulösen, wenn ein Zeichen gekommen ist.
erstelle Dir ein Puffer volatile unsigned char puffer[10], eine hilfsvariable volatile unsigned char zaehler, lass das Zeichen das sich in UDR befindet nach zeilenvorschub prüfen ASCII Code 13 bzw. 0x0D, wenn TRUE dann hängst Du noch ein '\0' an dein Puffer hintendran setzt Dein zaehler auf 0 und vergleichst den Puffer mit Konstanten wie CH1 oder wie auch immer.

Wenn kein Zeilenvorschub im UDR drin ist schreib Dir das zeichen in das Array an der zaehler Stelle, erhöhe den zaehler um 1, und verlasse den Interrupt.

Worauf man aber achten sollte ist daß der Puffer nicht überläuft, das dürfte aber kein großes Problem werden.

Versuch einfach irgendwas zu schreiben, und wenn es nicht klappt poste Dein Programm hier rein, es wird Dir sicher jemand helfen können.

Gruß Sebastian

P.S. Solte ich irgendwas falsches von mir gegeben haben, möge man mich darauf hinweisen.

SprinterSB
26.07.2005, 22:12
Günstiger ist es, nen Ringpuffer zu verwenden und nicht den ganzen Puffer volatile zu machen.
Der obige ansatz fürt zu sporadischen Fehlern wenn der Interrupt zu ungünstiger Zeit auftritt.

Wenn ein Teil schreibt (Zb die Interrupt Service Routine) und im Hauptprogram gelesen wird, dann funktioniert folgendes. Ist eher ein Vorschlag als ne copy-and-paste-Lösung. Fehlerbahandlunf bei vollem Puffer fehlt noch.

Im Header:


extern byte rbuf_get();
extern void rbuf_put(byte data);
extern volatile byte rbuf_count;


Im C-File:


#define RBUF_SIZE 70

static byte rbuf[RBUF_SIZE] __attribute__ ((section (".noinit")));

volatile byte rbuf_count = 0;
byte *rbuf_read = rbuf;
byte *rbuf_write = rbuf;

byte rbuf_get()
{
while (0 == rbuf_count)
;

byte *rd = rbuf_read;
byte data = *(rd++);

if (rd == rbuf+RBUF_SIZE)
rd = rbuf;

rbuf_read = rd;

rbuf_count--;

return data;
}

void rbuf_put(byte data)
{
byte *wrt = rbuf_write;

*(wrt++) = data;

if (wrt == rbuf+RBUF_SIZE)
wrt = rbuf;

rbuf_write = wrt;

rbuf_count++;
}


byte ist bei mit ein unsigned char

izaseba
26.07.2005, 22:46
Der obige ansatz fürt zu sporadischen Fehlern wenn der Interrupt zu ungünstiger Zeit auftritt.

Das stimmt, um das zu vermeiden mache ich es so:
Wenn 0x0D empfangen wurde, schalte ich RXCIE ab, und setze noch in der SIG_UART_RECV irgendein Bit auf 1 (ich definiere mir immer eine uint8_t Variable als Volatile, dann habe ich 8 Flags zu Verfügung.)
in der main funktion wird der Flag dauernd abgefragt, und falls 1, wird verglichen.
Danach, wenn Vergleich abgearbeitet ist wird der Flag gelöscht und RXCIE wieder eingeschaltet.
Es ist vielleicht nicht super optimal, es fiel mir aber dazu nichts besseres ein, als ich mich damit seinerzeit beschäftigt habe.
Deine Beispiele werde ich mir mal in RUHE mal angucken, danke.
Ich hätte da auch ein Beispiel gepostet, aber funky will ja auch was lernen.

Gruß Sebastian

Kjion
26.07.2005, 22:53
Mit dem Beispiel von Kjion hast Du schon das halbe Programm fertig.

Ich mal kurz den Rest dazu geschrieben, ganz ohne Ringpuffer oder sonstiges :-)

http://www.kreatives-chaos.com/code/2313_uart.c
und das Makefile dazu:
http://www.kreatives-chaos.com/code/Makefile

Habs auch gerade mit einem ATMega8 geteset und sollte soweit funktionieren.

@SprinterSB
Ringpuffer sind ja ganz cool, aber in dem Beispiel doch ein wenig übertrieben, oder ??

MfG Kjion

SprinterSB
27.07.2005, 08:35
Ringpuffer sind ja ganz cool, aber in dem Beispiel doch ein wenig übertrieben, oder ??
Wieso übertrieben?
Was nutzt mir schlanker oder schneller Code wenn er nicht korrekt ist... ;-) Zudem frisst der Code nicht wirklich Platz.
Ich hatte meine UART Routinen eben mit FiFo konzipiert, ist ja nicht so ungewöhnlich. AUsserdem trennt das meine Applikation von den UART-Routinen. Die UART-Routinen müssen nicht wissen, was da denn ankommt.


ich definiere mir immer eine uint8_t Variable als Volatile, dann habe ich 8 Flags zu Verfügung.
Mach ich ähnlich, allerdings mit einem globalen Register. Hat den Vorteil, daß Schreib-und Leseoperationen darauf atomar sind, also ein Interrupt zwischen Lesen und Schreiben beim Verändern nicht zwischenfunken kann :-)
Register haben die AVRs ja genug.

funky78
27.07.2005, 09:53
Mit dem Beispiel von Kjion hast Du schon das halbe Programm fertig.

Ich mal kurz den Rest dazu geschrieben, ganz ohne Ringpuffer oder sonstiges :-)

http://www.kreatives-chaos.com/code/2313_uart.c
und das Makefile dazu:
http://www.kreatives-chaos.com/code/Makefile

Habs auch gerade mit einem ATMega8 geteset und sollte soweit funktionieren.

@SprinterSB
Ringpuffer sind ja ganz cool, aber in dem Beispiel doch ein wenig übertrieben, oder ??

MfG Kjion


Guten Morgen...

Also das sieht ja echt sehr gut aus...Vielen Dank.

Ich habe gestern Nacht die Nachricht von izaseba mir ans Herz gelegt und angefangen irgendwie irgendwelche Buffer zu erstellen.

Ich schaue mir mal eben dieses Beispiel an...vielleicht stelle ich mich ja diesmal nicht so dumm an, und es funktioniert...

funky78
27.07.2005, 11:20
Ich weiß nicht, wie ich euch danken soll...

Vielen vielen Dank... :cry: mir kommen gleich die Tränen...

Es funktioniert...

Habe es so umgesetze, wie Kjion beschrieben...

Danke...

Später hätte ich vielleicht noch einige Verständnisfragen...

funky78
27.07.2005, 15:20
Da bin ich wieder...

Wie gesagt, hat fast alles (Empfangen) bestens geklappt, nun stehe ich aber wieder vor einem Problem:

die Umschaltbefehle sollen in Klammer geschrieben werden.

statt CH1 soll <CH1> stehen...
bzw. statt CH2...<CH2>...

Das "Kleiner Zeichen" kann ich analog einlesen. Probleme habe ich beim "Größer Zeichen", weil ja davor die 1 oder je nach dem die 2 empfangen wird.

Ich habe versucht es in zwei switch-Anweisungen zu machen...
D.h. eine Empfängt <CH1> die andere <CH2>. Das Problem war dann, dass es nicht wiederholt werden konnte. Also einmal umschalten, und es war alles vorbei...

Was mache ich nun?

Kjion
27.07.2005, 15:35
Was mache ich nun?

Poste dein Programm damit man sehen kann was nicht stimmt :-)

MfG Kjion

Kjion
27.07.2005, 15:44
Die Anpassung ist aber ganz einfach:
http://www.kreatives-chaos.com/code/2313_uart.c

Habs aber nicht geteset ...

MfG Kjion

funky78
27.07.2005, 15:48
static uint8_t state = 0;

// empfangenes Zeichen auslesen
uint8_t buffer = UDR;

switch (state)
{
case 0:
if (buffer == '<')
{
state = 1;
}
else state = 0;
break;

case 1:
if (buffer == 'C')
{
state = 2;
}
else state = 0;
break;

case 2:
if (buffer == 'H')
{
state = 3;
}
else state = 0;
break;


case 3:
if (buffer == '1')
{
state = 4;
}
else state = 0;
break;

case 4:
if (buffer == '>')
{
PORTD = 0b11011111;
PORTB = 0b11110111;
// PORTB &= ~(1<<PB3);
// PORTB |= (1<<PB4);
// PORTD &= ~(1<<PD5);

p_string = ch1;
USR |= (1<<UDRE);
}
else state = 0;
break;

case 5:
if (buffer == '2')
{
state = 5;
}
else state = 0;
break;
case 6:
if (buffer == '>')
{
PORTD = 0b11111111;
PORTB = 0b11101111;
// PORTB |= (1<<PB3);
// PORTB &= ~(1<<PB4);
// PORTD |= (1<<PD5);

p_string = ch2;
USR |= (1<<UDRE);
}
else state = 0;
break;
default:
state = 0;
}


In case 3 prüft er ja, ob 1 kommt, und wenn nicht, geht er auf 0 zurück. D.h. ich komme nie in case 4 rein.
in case 3 das else state=0 entfernen hat mich leider auch nicht weiter gebracht.

Wie kann ich ihm bei bringe, dass er sowohl nach einer 1 als auch nach einer 2 ausschau halten soll, und dem entsprechend weiter vorgehen soll?

:-k

funky78
27.07.2005, 15:56
Die Anpassung ist aber ganz einfach:
http://www.kreatives-chaos.com/code/2313_uart.c

Habs aber nicht geteset ...

MfG Kjion

Probiere ich eben mal aus...

funky78
27.07.2005, 16:04
{
static uint8_t state = 0;
static uint8_t channel = 0;

// empfangenes Zeichen auslesen
uint8_t buffer = UDR;

switch (state)
{
case 0:
if (buffer == '<')
{
state = 1;
}
else state = 0;
break;

case 1:
if (buffer == 'C')
{
state = 2;
}
else state = 0;
break;

case 2:
if (buffer == 'H')
{
state = 3;
}
else state = 0;
break;


case 3:
channel = buffer;
state = 4;

break;

case 4:
if (buffer == '>')
if (channel == '1')
{
PORTD = 0b11011111;
PORTB = 0b11110111;

p_string = ch1;
USR |= (1<<UDRE);
}

if (channel == '2')
{
PORTD = 0b11111111;
PORTB = 0b11101111;

p_string = ch2;
USR |= (1<<UDRE);
}
else state = 0;
break;
default:
state = 0;
}

Funktioniert leider auch nur einmal...bleibt in CH2 hängen.
Wenn ich uC resete, dann <CH1> eingebe, wechselt er...
Wenn ich jetzt <CH2> eingebe, wechselt er auch...
Und von hier an hängt er...

Wenn ich nach dem Reset mit <CH2> anfange hängt er sich gleich auf...

Kjion
27.07.2005, 16:30
{
static uint8_t state = 0;
static uint8_t channel = 0;

// empfangenes Zeichen auslesen
uint8_t buffer = UDR;

switch (state)
{
case 0:
if (buffer == '<')
{
state = 1;
}
else state = 0;
break;

case 1:
if (buffer == 'C')
{
state = 2;
}
else state = 0;
break;

case 2:
if (buffer == 'H')
{
state = 3;
}
else state = 0;
break;


case 3:
channel = buffer;
state = 4;

break;

case 4:
if (buffer == '>') {
if (channel == '1')
{
PORTD = 0b11011111;
PORTB = 0b11110111;

p_string = ch1;
USR |= (1<<UDRE);
}

if (channel == '2')
{
PORTD = 0b11111111;
PORTB = 0b11101111;

p_string = ch2;
USR |= (1<<UDRE);
}
}
state = 0;
break;
default:
state = 0;
}
Du solltest dem Code noch eine Klammer mehr spendieren, dann sollte das auch gehen...

funky78
27.07.2005, 16:32
Tschuldigung, alles wieder zurück...

Habe den Fehler entdeckt...

Ich muss nach Case 4 wieder zurück auf state=0, sonst hängt er ja eben an diesem Punkt.

Ach ja, nochmals vielen Dank für die Unterstützung...

funky78
27.07.2005, 16:33
Du solltest dem Code noch ein Klammer mehr spendieren, dann sollte das auch gehen...

Danke...habe ich ergänzt...

funky78
27.07.2005, 17:53
Hallo nochmals,

darf ich eigentlich weiter nerven, oder habe ich mein Kontingent erreicht? [-o<

Kjion
27.07.2005, 19:29
Solange dir noch jemand antwortet scheint's noch nicht so weit zu sein :-)

funky78
27.07.2005, 23:10
Solange dir noch jemand antwortet scheint's noch nicht so weit zu sein :-)

Ich interpretiere das mal eben als ein ja :-b

Derzeit habe ich noch probleme mit der Rückmeldung.
Der Controller sollte mir ja zurück geben, in welchem Zustand er jetzt ist.

So wie es in dem Code war hat es ja irgendwie nicht geklappt.

Ok, eine allgemeine Frage.

Ist es nicht möglich, einen string in Form eines Arrays zu definieren und das dann mit UDR auszugeben?

char ch1[7] = "CH1_OK\n"

und dann an der nötigen Stelle es auf zu rufen...

UDR = ch1;

Wo habe ich meinen Denkfehler?

Du hattest ja in deinem Code (wenn ich die avr-lib nicht falsch verstanden habe) Pointer drin.

Vielleicht noch zu erwähnen, in dem jetztigen Zustand gibt er mir ein Dreickchen oder einen dichen Strich zurück...

SprinterSB
28.07.2005, 08:08
Ist es nicht möglich, einen string in Form eines Arrays zu definieren und das dann mit UDR auszugeben?

char ch1[7] = "CH1_OK\n"

und dann an der nötigen Stelle es auf zu rufen...

UDR = ch1;

Zum einen gibt dir ch1 nur die Anfangsadresse des Strings (ist ein char*).
Die einzelnen Zeichen bekommst du mit
ch1[0], ch1[1], etc

Zudem ist dein String nicht 7, sondern 8 Zeichen lang!!! Da wird immer noch ne abschliessende '\0' als Stringende mit abgelegt.

funky78
28.07.2005, 09:40
Ist es nicht möglich, einen string in Form eines Arrays zu definieren und das dann mit UDR auszugeben?

char ch1[7] = "CH1_OK\n"

und dann an der nötigen Stelle es auf zu rufen...

UDR = ch1;

Zum einen gibt dir ch1 nur die Anfangsadresse des Strings (ist ein char*).
Die einzelnen Zeichen bekommst du mit
ch1[0], ch1[1], etc

Zudem ist dein String nicht 7, sondern 8 Zeichen lang!!! Da wird immer noch ne abschliessende '\0' als Stringende mit abgelegt.

:-k Ok, danke...

Einzelne Buchstaben lassen sich nun ausgeben (z.B. mit ch1[2])...
Aber leider schaffe ich es noch nicht, dass er mir den gesamten String ausgibt...werde mal bisschen rum experementieren.

SprinterSB
28.07.2005, 09:56
Für mehrere gehts in ner Schleife

...
const char * pc;

for (pc = ch1; *pc != '\0'; pc++)
{
char zeichen = *pc;
// zeichen ausgeben
}
...

funky78
28.07.2005, 11:21
:Haue

Ich glaube, ich bin wirklich zu doof...

Ich setze mal den Codeteil rein...


char ch1[9] = "CH1_OK\n";
char ch2[9] = "CH2_OK\n";
const char *pc;
char zeichen;

...

for (pc = ch1; *pc!= '\0';pc++)
zeichen = *pc;
UDR = zeichen;

...

Was er mir ausgibt ist...
neue Zeile...

Was mache ich falsch?

:oops: Entschuldigt bitte, wenn ich nerve...

SprinterSB
28.07.2005, 11:32
Wie wär's mit {} um den Block in der for-Schleife?
Die sind nicht nur Deko ;-)
Und jedes Zeichen *übertragen*, nicht einfach alles in UDR reinrußen...warte bis der Puffer wieder leer ist.
Wie der UART arbeitet, steht auch vorzüglich im Manual beschrieben.

Kjion
28.07.2005, 11:35
const prog_char *pc;

for (pc = ch1; *pc!= '\0';pc++) {
zeichen = *pc;
// Warten bis der Sendepuffer frei ist
while ( !( USR & (1<<UDRE)) )
;
UDR = zeichen;
}

funky78
28.07.2005, 12:21
#-o #-o #-o

Kjion...SprinterSB...

Tausend dank...mir fehlen wirklich die Worte...vielen vielen Dank...

Wenn der Code mal da steht, ist es einleuchtend...aber ganz ohne Code leuchtet bei mir leider nicht viel
](*,)

funky78
31.07.2005, 10:59
Hallo...

habe ein Problem mit meiner Interruptroutine.

An PD3 hatte ich zuvor einen Schalter gegen Masse. Diesen habe ich nun durch einen Taster ersetzt, was mir dann Probleme bereitete.

Vielleicht sollte ich schreiben, was ich machen wollte.

Drücke ich den Taster soll der Zustand 1 aktiviert werden. Drücke ich ihn nochmal, soll der Zustand 2 aktiviert werden.
Das läuft auch soweit recht gut.
Das Problem ist, dass der Taster prellt...die Zustände ändern sich. Habe bereits einen Kondensator und einen Wiederstand zur Entprellung eingelötet. Ist besser geworden, aber das Problem gibt es zwischen durch immer wieder.

Als der Schalter drin war, konnte ich den Zustand abfragen, entweder war er High oder Low, und dann eine simple Warteschleife (zur Entprellung) einbauen. Aber beim Taster geht das doch nicht so einfach (bzw. kriege ich es nicht hin), weil ja jedes mal mit dem Zustand Low geschaltet wird, und der Taster leider auch beim loslassen prellt.

Wie kann ich dieses Problem lösen? Bin über jeden Hinweis dankbar...

Ich füge eben auch mal den Code ein...


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


unsigned int status_taster=1; // Status beim Eintritt in Interruptroutine

void Inter(); // Interrupt funktion

int main()
{
DDRB = 0b11111111; // PORTB als Ausgang definieren
PORTB = 0b00011000; // PORTB setzen

DDRD = 0b11110110; // PD0 und PD3 als Eingang definieren
PORTD = 0b11111111;

Inter();

for (;;)
{}

}

void Inter()
{
MCUCR = 0b00001000; // Flanke definieren
GIMSK = 0b10000000; // Enable interrupt

sei(); // Interrupt freigeben
}


SIGNAL(SIG_INTERRUPT1) // Taster an PD3 löst Interrupt aus
{

if(status_taster==1)
{

PORTB |= (1<<PB3); /*Setzt PB3 HIGH...LED aus \ */
PORTB &= ~(1<<PB4); //Setzt PB4 LOW...LED an } Zustand 1
PORTD |= (1<<PD5); //Setzt PD5 HIGH /

status_taster=2;
}

else
{
PORTB &= ~(1<<PB3); /*Setzt PB3 LOW...LED an \ */
PORTB |= (1<<PB4); //Setzt PB4 HIGH...LED aus } Zustand 2
PORTD &= ~(1<<PD5); //Setzt PD5 LOW /

status_taster=1;
}

GIFR=0;
}


[-o<

Kjion
31.07.2005, 11:13
Hi,

http://www.mikrocontroller.net/forum/read-4-20549.html
http://www.mikrocontroller.net/forum/read-4-16594.html

Das sollte dir weiterhelfen :-)

MfG Kjion

funky78
31.07.2005, 22:13
Hi,


http://www.mikrocontroller.net/forum/read-4-20549.html

Das sollte dir weiterhelfen :-)

MfG Kjion

Hallo nochmals...

Habe mir mal alles ausgedruckt und in Ruhe angeschaut...
Den kürzesten Code wollte ich dann auch verstehen...was mir wohl nicht besonders gelungen ist.

Wo muss ich diesen Code unterbringen?
In die Interruptroutine oder als eigene Funktion hinstellen?
Wenn nicht Interruptroutine, woher weiß dann der uC das dieser zum Interrupt mit dem Taster gehört?
Der Taster wird doch nicht abgefragt, oder?

#pragma cd pl (9999) ....hmmm, was das wohl zu bedeuten hat...
#include <reg51.h> .... da müsste wohl bei mir was anders stehen...
void to_int(void) interrupt INT_T0...ich denke, mit der Zeile wird irgendwie der Bezug zur Interruptroutine gemacht.

In den ganzen Artikeln zur Entprellung war stets eine Rede von Timer...dieser ist doch nicht in diesem Code, oder?

Vielleicht sollte ich das ganze doch wirklich aufgeben...oder ich sitze nun wirklich zu lange vor meinem PC und sehe den Wald vor Bäumen nicht mehr...

:-k

SprinterSB
01.08.2005, 08:57
#pragma cd pl (9999)
#include <reg51.h>
void to_int(void) interrupt INT_T0...


Das Zeug ist compilerspezifisch. Jeder Compiler hat seinen eingenen Weg, Interrupts und Signale zu definieren und implementiert unterschiedliche Pragmas -- wenn überhaupt.
avr-gcc zB implementiert überhaupt keine Pragmas und externen Interrupt0 definiert man via

#include <avr/interrupt.h>
#include <avr/signal.h>

// keine rekursiven Interrupts
SIGNAL (SIG_INTERRUPT0)
{
// ...
}

// rekursive Interrupts
INTERRUPT (SIG_INTERRUPT0)
{
// ...
}

Eine Möglichkeit, auf Tastendruck/Loslassen zu reagieren, ist über externe Interrupts. Zum Entprellen wartet man danach eine kurze Zeit, bis man wieder auf nen Tastendruck reagiert.
Oder man schaut in regelmässigen Abständen in einem Timer-Interrupt, ob sich an den Tastern was getan hat.

Der erste Weg hat den Nachteil, daß man so nur einen Taster checken kann und auch eine Zeitbasis braucht. Zudem landet man bei prellendem Taster oft im Interrupt. Tastendrucke sind keine zeitkritischen Ereignisse, da rechts es wenn man alle 10ms drauf schaut und sich externe Interrupts für wichtige Sachen aufspart.

funky78
01.08.2005, 11:06
#pragma cd pl (9999)
#include <reg51.h>
void to_int(void) interrupt INT_T0...


Das Zeug ist compilerspezifisch. Jeder Compiler hat seinen eingenen Weg, Interrupts und Signale zu definieren und implementiert unterschiedliche Pragmas -- wenn überhaupt.
avr-gcc zB implementiert überhaupt keine Pragmas und externen Interrupt0 definiert man via

#include <avr/interrupt.h>
#include <avr/signal.h>

// keine rekursiven Interrupts
SIGNAL (SIG_INTERRUPT0)
{
// ...
}

// rekursive Interrupts
INTERRUPT (SIG_INTERRUPT0)
{
// ...
}

Eine Möglichkeit, auf Tastendruck/Loslassen zu reagieren, ist über externe Interrupts. Zum Entprellen wartet man danach eine kurze Zeit, bis man wieder auf nen Tastendruck reagiert.
Oder man schaut in regelmässigen Abständen in einem Timer-Interrupt, ob sich an den Tastern was getan hat.

Der erste Weg hat den Nachteil, daß man so nur einen Taster checken kann und auch eine Zeitbasis braucht. Zudem landet man bei prellendem Taster oft im Interrupt. Tastendrucke sind keine zeitkritischen Ereignisse, da rechts es wenn man alle 10ms drauf schaut und sich externe Interrupts für wichtige Sachen aufspart.

OK...danke...hört sich logisch an...
Jetzt muss ich schauen, wie ich das realisiere... :-k

funky78
01.08.2005, 12:09
:-k

Angenommen ich bekomme das mit dem Timer hin (was ich auch bezweifle ](*,) ), muss ich dann in meinem Tasterinterrupt den Timer Interrupt einfügen.
Des weiteren muss ich doch den Taster abfragen, oder?
Ich mein ok, abfragen mit...

a=PIND;
a=a&0b00001000;

kann man ja irgendwie...

aber wie dann der Verweis auf den TasterInterrupt...

Ich schreibe mal eben, wie ich es "versucht" :-b habe...mit einer quick&dirty Zählschleife...


{
int a, b, c;
a=PIND;
a=a&0b00001000;
b=a/8;

for (i=0; i<255; i++) //Warteschleife
for(j=0; j<255;j++)
k++;

if (~b)
{
//Wenn b = 0 gehe in Interruptschleife...bitte nicht lachen...

SIGNAL(SIG_INTERRUPT1) // Taster an PD3 löst Interrupt aus
{

//...Interruptbefehle...
}

funky78
01.08.2005, 12:23
Ok, neuer versuch...


SIGNAL(SIG_INTERRUPT1) // Taster an PD3 löst Interrupt aus
{
for (i=0; i<4000; i++) // Warteschleife...
for(j=0; j<20;j++)
k++;


if(status_taster==1)
{

PORTB |= (1<<PB3); /*Setzt PB3 HIGH...LED aus \ */
PORTB &= ~(1<<PB4); //Setzt PB4 LOW...LED an } Zustand 1
PORTD |= (1<<PD5); //Setzt PD5 HIGH /

status_taster=2;
}

else
{

for (i=0; i<4000; i++) // Warteschleife...
for(j=0; j<20;j++)
k++;

PORTB &= ~(1<<PB3); /*Setzt PB3 LOW...LED an \ */
PORTB |= (1<<PB4); //Setzt PB4 HIGH...LED aus } Zustand 2
PORTD &= ~(1<<PD5); //Setzt PD5 LOW /

status_taster=1;
}

GIFR=0;
}

Kann man das so lassen?
Es wird zwar ziemlich langsam umgeschaltet, aber zu mindestens tritt das "Überschwingen" nicht so oft auf...erst dann wenn ich den Taster mit dem Finger leicht und schnell antippe...

Weiterhin sind auch ein 100nF Kondensator und ein 11kOhm Wiederstand an den Taster angelötet...

Reicht das alles aus?

SprinterSB
01.08.2005, 13:04
Haupsache es geht mal.
Den C und den R solltest du eigentlich nicht brauchen...

Zu deinem Code:

Falls du gcc optimieren lässt, wird er die Warteschleife komplett in die Tonne kloppen, weil sie nix macht. Also zB ein k = PORTB oder ein _NOP(); (gibts mit #include <avr/ina90.h>)
Die 2.Warteschleife ist zu viel, so wartest du 2x.
Die Warteschleife besser ans Ende der Interrupt-Routine, vor das GIFR=...
Falls während der Routine der Taster flackert, wird ja wieder das INTF1 Flag gesetzt, das du versuchst zurück zu setzen. Das geht, indem man eine 1 hin schreibt (keine 0):
GIFR = _BV(INTF1); // reset INT1 Flag
INT1 so initialisieren, daß er flankengetriggert ist, also nur bei Änderung anspricht; nicht levelgetriggert, sonst landest du auch dauernd im Interrupt solange der Taster noch gedrückt ist.


Falls dein Prog sonst nix maches soll, ist's ok. Aber wenn sonst noch Zeug zu erledigen ist, muss dir klar sein, daß zu ziemlich lange im Interrupt rumschnarchst...

funky78
01.08.2005, 23:45
Haupsache es geht mal.
Den C und den R solltest du eigentlich nicht brauchen...

Zu deinem Code:

Falls du gcc optimieren lässt, wird er die Warteschleife komplett in die Tonne kloppen, weil sie nix macht. Also zB ein k = PORTB oder ein _NOP(); (gibts mit #include <avr/ina90.h>)
Die 2.Warteschleife ist zu viel, so wartest du 2x.
Die Warteschleife besser ans Ende der Interrupt-Routine, vor das GIFR=...
Falls während der Routine der Taster flackert, wird ja wieder das INTF1 Flag gesetzt, das du versuchst zurück zu setzen. Das geht, indem man eine 1 hin schreibt (keine 0):
GIFR = _BV(INTF1); // reset INT1 Flag
INT1 so initialisieren, daß er flankengetriggert ist, also nur bei Änderung anspricht; nicht levelgetriggert, sonst landest du auch dauernd im Interrupt solange der Taster noch gedrückt ist.


Falls dein Prog sonst nix maches soll, ist's ok. Aber wenn sonst noch Zeug zu erledigen ist, muss dir klar sein, daß zu ziemlich lange im Interrupt rumschnarchst...

Hallo und schönen guten Abend...
Vielen Dank für diese Tipps...
Die Sache mit der prellenden Taste habe ich dann doch hardwaremäßig gelöst.
Ich habe den 100nF gegen einen 1uF Tantal Kondensator ausgetauscht. Der Widerstand ist bei 10kOhm geblieben. Erreiche hiermit eine Zeit von ca. 11ms wodurch das Problem mit dem prellenden Taster aus der Welt geschaffen ist.
Sicherlich ist es angenehmer die Sache softwaremäßig zu lösen, doch für einen Neuling wird es schwierig, auch noch den Timer zu implementieren.

Ach ja, INT1 ist auf fallende Flanke initialisiert.

So langsam habe ich den gesamten Code, dank eurer Hilfe zusammen...

Heute Abend bin ich noch an den Kommentaren usw. dran...

Im großen Ganzen verstehe ich auch das, was ich geschrieben habe. Doch es gibt bestimmte Stellen, wo ich nicht ganz schlüssig werde.

Würde mich freuen, wenn ich noch einige Verständnisfragen stellen dürfte (falls notwendig 8-[ )

Hier schon die erste...

GIFR = _BV(INTF1);
was bedeutet hier das _BV?

Nochmals aber vielen Dank für die tolle Unterstützung... =D>

Dino Dieter
02.08.2005, 00:19
Hallo

_BV steht für Bit Value. Es wird das Bit INF1 gesetzt.

Ist das gleiche wie GIFR = ( 1<< INF1)

Schaui mal in der Doku de AVR LIBC unter Related Pages / FAQ

Gruß
Dieter

funky78
02.08.2005, 09:28
Guten Morgen...
_BV...BitValue...wusste ich doch, dass ich das mal irgendwo gelesen hatte...vielen Dank Dieter...


Ok, ein neuer Tag, und ich denke ich stehe heute total auf dem Schlauch.

Irgendwie schaffe ich es nicht mehr, meinem Compiler beizubringen, dass er PD7 bzw. PIND7 erkennt. Er meckert, dass es "undeclared" ist



#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <avr/signal.h>


DDRD = 0b11110110; //Alles außer PD0 und PD3 als Ausgang
PORTD = 0b01111111;

/*Nun möchte ich PD7 abfragen, schauen ob er beim Einschalten HIGH oder LOW gesetzt wurde und dementsprechen was auf dem Bildschirm ausgeben (was ich ja mitlerweile mit eurer Hilfe kann :-)...*/
...
if (PD7) //akzeptiert er so nicht...
PORTB = 0b11110111;

else
PORTB = 0b11101111;
...


statt dem PD7 habe ich auch

PORTD&0b10000000
bzw.
PIND7

probiert...hilft alles nichts...

SprinterSB
02.08.2005, 10:00
AT90S2313 hat keinen PortD.7
Oder verwendest du inzwischen nen anderen Controller?
In dem Falle must du avr-gcc mit der korrekten -mmcu=... aufrufen, sonst generierst du falschen Code.

funky78
02.08.2005, 10:29
AT90S2313 hat keinen PortD.7
Oder verwendest du inzwischen nen anderen Controller?
In dem Falle must du avr-gcc mit der korrekten -mmcu=... aufrufen, sonst generierst du falschen Code.

#-o #-o #-o Mensch bin ich doof...

Ok, dann probier ich das ganze mal mit PD5.


int main( void )
{
DDRB = 0b11111111;
PORTB = 0b11111111;

DDRD = 0b00100000;
PORTD = 0b11011111;

for(;;)
{

if (PD5)
PORTB = 0b11110111;

else
PORTB = 0b11101111;
}

}


wenn ich
PORTD = 0b11111111;
sollte er in die if-Schleife rein und LED an PB3 müsste brennen. Tut sie auch.

wenn ich dann
PORTD = 0b11011111;
schreibe, müsste er doch in die else-Schleife und LED ab PB4 müsste brennen...tut sie aber nicht...PB3 brennt immer.

mit dem Oszi an PD5 gemessen kommt das Signal so, wie es kommen soll. Also mal High, mal Low...

Was mache ich falsch?
[-o<

funky78
02.08.2005, 10:51
:oops: :oops: :oops:

Nehme alles zurück 8-[

überprüfe das ganze jetzt mit "bit_is_set"...

Und es passt dann alles... \:D/

SprinterSB
02.08.2005, 10:53
Was du wahrscheinlich haben willst ist

DDRD &= ~_BV (PD5); // PortD.5 auf Eingang
oder
DDRD = 0b00000000; // PortD auf Eingang

Nach RESET sind zwar alle Ports aud Eingang, aber schaden tuts nicht.

!!! PD5 ist ein Konstante (nähmlich 5)!

Die Abfrage geht mit
if (PIND & _BV(PD5)) // oder PIND & 0b00100000
{
...
}

oder

if (bit_is_set (PIND, PD5)) // oder bit_is_set (PIND, 5)
{
...
}
Überleg dir auch warum hier nicht PORTD steht, sondern PIND.

funky78
02.08.2005, 11:29
if (bit_is_set (PIND, PD5)) // oder bit_is_set (PIND, 5)
{
...
}


Genau so habe ich es gemacht...

Hmmm, aber habe, wie du wahrscheinlich vermutest
if(bit_is_set(PORTD, PD5))
geschrieben...
Na ja, habe es eben umgeändert...aber an der Funktion hat sich nichts geändert. Es tat auch mit dem PORTD...



Überleg dir auch warum hier nicht PORTD steht, sondern PIND.
Ok...scheint mir, ich werde so eben geprüft O:)

Also, laut Tutorial, welches ich ja mittlerweile fast auswendig kenne O:) fragt man mit PORTD den gesamten Register ab...und somit den Zustand des internen PullUp-Widerstandes...und nicht etwa den Zustand am Pin.

Ok, jetzt kommts O:) Das gilt doch, wenn es als Eingangsport definiert ist. Und da ich ja PD5 als Ausgang definiert habe...(mal ganz vorsichtig) dürfte es wohl nichts ausmachen...

Wobei ich eins auf jeden Fall hinzufügen muss:
Erare humanum est :cheesy:

SprinterSB
02.08.2005, 11:40
Aber warum aus Ausgang? bzw warum dann die if-Abfrage auf diesen Port? Du weisst ja, welchen Wert du liest, nähmlich den, den du in PORT reingeschrieben hast.
Wenn du auf Taster bzw Zustandsänderung testen willst, dann musst du das Ding 1) als Eingang definieren und 2) PIN abfragen und nicht PORT. PIN steht hier nicht für 'pin' (von Nadel) sondern für Port INput.

funky78
02.08.2005, 11:54
Es ist was wahres drann, wenn man sagt, dass Menschen keine helseherischen Fähigkeiten haben.

Vielleicht hätte ich auch dazu schreiben sollen, was ich überhaupt machen möchte ](*,)

Also, ich habe zwei Zustände...sagen wir CH1 und CH2.
Mit einem Taster, der gegen Masse geschaltet ist, wird zwischen den Zuständen umgeschaltet, und je nach dem, welcher Zustand aktiv ist, wird seriell am Rechner CH1_OK oder CH2_OK ausgegeben.

Weiterhin kann ich seriell mit dem Rechner Befehle an den uC schicken.
wenn ich schreibe <CH1> ist Zustand CH1 aktiv und ich bekomme die Rückmeldung CH1_OK. Analog für CH2...

Jetzt wollte ich auch noch am PC sehen, welcher Zustand anliegt, wenn man die Spannungsversorgung einschaltet. Bzw. wollte ich mit einem Befehl vom PC aus sehen, welcher Zustand derzeit aktiv ist...ohne den Zustand ändern zu wollen.
Also kommt ein Befehl mit <CH?> und je nach dem welcher aktiv ist, CH1_OK oder CH2_OK zurück.

Warum die Überprüfung vom Ausgangsport PD5?
PD5 ist im Zustand CH1 auf high gesetzt und im Zustand CH2 auf low.

Das war es dann eigentlich auch schon...

Ähm, jetzt nochmal um sicher zu gehen...
Muss ich jetzt in der if-Anweisung PIND oder PORTD verwenden?

funky78
02.08.2005, 12:21
:-k Eine Frage zum reseten...

im Datenblatt steht ja...
An External Reset is generated by a low level on the RESET pin. Reset pulses longer
than 50 ns will generate a reset, even if the clock is not running. Shorter pulses are not
guaranteed to generate a reset. When the applied signal reaches the Reset Threshold
Voltage (VRST) on its positive edge, the delay timer starts the MCU after the Time-out
period tTOUT has expired.

War ich falsch informiert? Ich dachte der Reset wird durch schalten des PIN1 (Reset) an Vcc (über einen 1k Wiederstand) hervorgerufen.
Im Datenblatt heißt es ja gegen Masse...oder wie habe ich "low level" zu verstehen

SprinterSB
02.08.2005, 12:39
Wenn der Port auf Ausgang steht, kannst du aus PORT den Wert wieder zurücklesen. Diese wiederum entspriche dem Potental am Pad, falls du nicht irgend ne Sonderfunktion aktiviert hast.
Bei Input nimmst du PIN. PIN sollte auch funktionieren bei Output, um den Wert wieder zurück zu lesen.
Jedenfalls sollte dein Programm jetzt im else-Zweig landen mit PORTD = 0b11011111;
Für Charakteristika der Ports und deren interne Verdrahtung ist das Handbuch erste und sehr gute Anlaufstelle, und zu den Port-Macros steht was in der avr-libc-Doku (im AVR-Verzeichnis unter ./doc/avr-libc, Abschnitt 5.18).
Manchmal ist auch ein Blick in die Header erhellend, unter
./avr/include/avr/ioxxxx.h

funky78
02.08.2005, 13:47
...falls du nicht irgend ne Sonderfunktion aktiviert hast.


Iccccccccccccccchhhhhhhhhhhh und Sonderfunktionen... [-( weiß nicht mal wie man das schreibt O:)

ja, die *.h Dateien habe ich auch schon betrachtet...

Ähm, darf ich eigentlich etwas zum UART fragen. Habe ja den Code von Kjion übernommen...

const unsigned char *tx_buffer; //das ist die Variablendeklaration bzw. Pointer

for (tx_buffer = ch1; *tx_buffer!= '\0'; tx_buffer++)
{
sending = *tx_buffer;
while ( !( USR & (1<<UDRE)))
;
UDR = sending; //Return "CH1_OK" to PC
}

tx_buffer wurde ja nur als Pointer deklariert, wie kann man dann in der for-Schleife es als Variable verwenden? Macht das dann der Compiler automatisch? Oder wird hier die Initialisierung des Zeigers vorgenommen?

Nach dem while kommt ja eine Leeranweisung, ist diese unbedingt nötig?

SprinterSB
02.08.2005, 15:30
...falls du nicht irgend ne Sonderfunktion aktiviert hast.

Iccccccccccccccchhhhhhhhhhhh und Sonderfunktionen... [-( weiß nicht mal wie man das schreibt O:)

Scherzkeks, du verwendest zu Beispiel den UART ;-)

--------------------------------------------------

In C gibt es Pointer Arithmetik. Auf Pointer kann man ganzzahlige Werte draufaddieren und abziehen. Dabei wird der Pointer um so viel weiter gezählt, wie die Größe des Typs, auf den er deklariert wurde:

Beispiel:
short wert;
short *p;
p = &wert; // & = Adressoperator, wenn als Prefix verwendet.
// kurz: short *p = &wert;

Mit p += 1 wird p um 2 (ein short ist 2 Byte lang) weitergezählt.
In diesem Fall zeigt p allerdings auf einen undefinierten Speicherbereich.

Man benutzt das gerne, um Arrays zu durchlaufen. Zum Dereferenzieren schreibt man ein * davor.
p ist also ein Zeiger
*p ist der Wert dessen, worauf er zeigt
&p ist die Adresse von p, vom Typ short**, also Zeiger auf Zeiger auf short.
Mit *p = 3 weist man wert den Wert 3 zu.

Eigentlich sind Pointer in C fast normale Variablen, und man kann auch int und einen Pointer umwandeln:
p = (short*) 100; ist ein Zeiger auf die Speicherzellen 100/101
und mit *p=0 kann man diese beiden Speicherstellen löschen.

Da stehts etwas besser erklärt:
http://www.cl.uni-heidelberg.de/kurs/ws02/prog2/html/page023.html

Edit:

Nach dem while kommt ja eine Leeranweisung, ist diese unbedingt nötig?
Ja, eine Leeranweisung ist notwendig. Zu while gehört genau ein Block, also
while (bedingung)
;
oder
while (bedingung)
{}

Sonst wird dein C-Compiler das UDR = ..., das darauf folgt, als while-Block ausführen.

SprinterSB
02.08.2005, 15:43
:-k Eine Frage zum reseten...

im Datenblatt steht ja...
An External Reset is generated by a low level on the RESET pin. Reset pulses longer
than 50 ns will generate a reset, even if the clock is not running. Shorter pulses are not
guaranteed to generate a reset. When the applied signal reaches the Reset Threshold
Voltage (VRST) on its positive edge, the delay timer starts the MCU after the Time-out
period tTOUT has expired.

War ich falsch informiert? Ich dachte der Reset wird durch schalten des PIN1 (Reset) an Vcc (über einen 1k Wiederstand) hervorgerufen.
Im Datenblatt heißt es ja gegen Masse...oder wie habe ich "low level" zu verstehen
Der Reset bei den AVRs ist LOW-aktiv, an Reset hängt man üblicherweise nen Pullup nach Vcc, um ein unbeabsichtigtes resetten durch ein Spike auf der Resetleitung zu unterbinden.
RESET hat auch einen internen Pullup, dessen Wert jedoch größer ist als die üblicherweise verwendeten 10k. Schwankt glaub so um die 50k. Das Handbuch ist schon korrekt.