Forum: Mikrocontroller und Digitale Elektronik [Atmega8] PD4 als Eingang trotz USART


von Hugo (Gast)


Lesenswert?

Hallo zusammen,

ich möchte bei einem Atmega8 den Pin PD4 (XCK/T0) als Eingang benutzen. 
Leider ist PIND4 immer low obwohl ich mit dem Multimeter 5V am Pin 
messen kann.
Kann es sein, dass der Pin PD4 nicht also IO-port genutzt werden kann, 
wenn ich UART benutze? Eigentlich sollte es doch gehen, wenn ich UART im 
asynchronen Modus habe.

Folgende einstellungen mache ich in meinem Programm:
1
  DDRB=0b00111101;
2
  DDRC=0b00111111;
3
  DDRD=0b11000000;
4
  PORTB=0;
5
  PORTC=0;
6
  PORTD=0;
7
  TCCR1A=0;
8
  TCCR1B=0b00000001;
9
  TIMSK =0b00011100;
10
  OCR1A =0x7fff;
11
  OCR1B =0x7fff;
12
  MCUCR|=0b00001010;
13
  GICR|=0b11000000;
Die Einstellungen für UART sind:
1
/* Set baud rate */
2
void USART_Init( unsigned int ubrr)
3
{
4
/* Set baud rate */
5
UBRRH = (unsigned char)(ubrr>>8);
6
UBRRL = (unsigned char)ubrr;
7
/* Enable receiver and transmitter */
8
UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);
9
/* Set frame format: 8data, 2stop bit */
10
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
11
}

Gruß
Hugo

von holger (Gast)


Lesenswert?

>Kann es sein, dass der Pin PD4 nicht also IO-port genutzt werden kann,
>wenn ich UART benutze?

Nein, wenn du auf asynchron einstellst kannst du den Pin nutzen.

Zeig mal das komplette Programm.

>/* Enable receiver and transmitter */
>UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);

Senden möchtest du nicht?

von Hugo (Gast)


Lesenswert?

Ich möchte sowohl Senden als auch Empfangen.
Es soll ein 2-KanalInkrementalgeber ausgelesen werden. Die Abfrage, die 
Probleme bereitet ist in INT0. In zweiter Interrupt hängt am Int1 und 
fuktioniertr tadellos.

Hier das komplette Programm bis jetzt.
1
#include <avr/io.h>
2
#include <avr/delay.h>
3
#include <avr/interrupt.h>
4
#include "USART.h"
5
6
#define F_CPU 8000000L
7
#define FOSC 8000000L// Clock Speed
8
#define BAUD 9600
9
#define MYUBRR FOSC/16/BAUD-1
10
11
int uart_state;
12
int16_t M1,M2;
13
int16_t pos1,pos2;
14
15
void USART_Init( unsigned int ubrr);
16
void USART_Transmit( unsigned char data )
17
{
18
  
19
 //Wait for empty transmit buffer 
20
while ( !( UCSRA & (1<<UDRE)) )
21
;
22
// Put data into buffer, sends the data 
23
UDR = data;
24
}
25
unsigned char USART_Receive( void )
26
{
27
/* Wait for data to be received */
28
while ( !(UCSRA & (1<<RXC)) )
29
;
30
/* Get and return received data from buffer */
31
return UDR; 
32
}
33
void USART_Init( unsigned int ubrr)
34
{
35
/* Set baud rate */
36
UBRRH = (unsigned char)(ubrr>>8);
37
UBRRL = (unsigned char)ubrr;
38
/* Enable receiver and transmitter */
39
UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);
40
/* Set frame format: 8data, 2stop bit */
41
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
42
}
43
44
45
46
void init(){
47
  USART_Init ( MYUBRR );
48
  DDRB=0b00111101;
49
  DDRC=0b00111111;
50
  DDRD=0b11000000;
51
  PORTB=0;
52
  PORTC=0;
53
  PORTD=0;
54
  TCCR1A=0;
55
  TCCR1B=0b00000001;
56
  TIMSK =0b00011100;
57
  OCR1A =0x7fff;
58
  OCR1B =0x7fff;
59
  MCUCR|=0b00001010;
60
  GICR|=0b11000000;
61
  
62
  uart_state=0;
63
  pos1=0;
64
  pos2=0;
65
}
66
67
ISR(INT0_vect){
68
  if((PIND&0b10000)>>4){
69
    pos2++;
70
    USART_Transmit('+');
71
  }else{
72
    pos2--;
73
    USART_Transmit('-');
74
  }
75
}
76
ISR(INT1_vect){
77
  if((PIND&0b100000)>>5){
78
    pos1++;
79
  }else{
80
    pos1--;
81
  }
82
}
83
84
85
ISR(TIMER1_OVF_vect){
86
  PORTB|=0b00000110;
87
}
88
ISR(TIMER1_COMPA_vect){
89
  PORTB&=0b11111101;
90
}
91
ISR(TIMER1_COMPB_vect){
92
  PORTB&=0b11111011;
93
}
94
ISR(USART_RXC_vect)
95
{
96
  char tmp;
97
  tmp=USART_Receive();
98
  switch (uart_state)
99
  {
100
  case 0:
101
    if(tmp=='s')uart_state=1;
102
    break;
103
  case 1:
104
    if(tmp=='e') {
105
      uart_state=2;
106
    }else{
107
      uart_state=0;
108
    }  
109
    break;
110
  case 2:
111
  if(tmp=='t') {
112
      uart_state=3;
113
    }else{
114
      uart_state=0;
115
    }
116
    break;
117
  case 3:
118
  
119
    if(tmp=='r'){
120
      M1=10;
121
      USART_Transmit('r');  
122
    }
123
    if(tmp=='l'){
124
      M1=-10;
125
      USART_Transmit('l');
126
    }
127
    if(tmp=='u'){
128
      M2=10;
129
      USART_Transmit('u');  
130
    }
131
    if(tmp=='d'){
132
      M2=-10;
133
      USART_Transmit('d');
134
    }
135
    uart_state=0;
136
  }
137
  USART_Transmit(uart_state);
138
  
139
}  
140
141
142
int main(void)
143
{
144
  init();
145
  sei();
146
    while(1)
147
    {
148
    
149
    }
150
}

von Hugo (Gast)


Lesenswert?

holger schrieb:
>>/* Enable receiver and transmitter */
>>UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);
>
> Senden möchtest du nicht?

Das Senden war nur als versuch ausgeschaltet. Es muss natürlich
1
UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);
heißen.
Das ist aber nicht das problem, sondern der Pin PD4 als eingang.

von Karl H. (kbuchegg)


Lesenswert?

Du hast, soweit ich das sehen kann, keine Pullups am PortD aktiviert.

Ansonsten, auch wenn deine Schreibweisen furchtbar unübersichtlich sind, 
sehe ich nichts was die Funktion verhindern würde.

Hast du schon mal versucht ein einfaches Testprogramm zu schreiben, mit 
dem du nur den Pin PD4 testest?

von H.Joachim S. (crazyhorse)


Lesenswert?

Und das hier ist Absicht?
UCSRC = (1<<URSEL)|(1<<USBS)|(->3<- <<UCSZ0);
Hab jetzt aber nicht nachgeschaut, was daraus wird. Unüblich find ich es 
auf jeden Fall.

von holger (Gast)


Lesenswert?

>holger schrieb:
>>>/* Enable receiver and transmitter */
>>>UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);
>>
>> Senden möchtest du nicht?
>
>Das Senden war nur als versuch ausgeschaltet. Es muss natürlich
>
>UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);
>
>heißen.

Senden ist damit immer noch nicht möglich.
Wozu dann die ganzen USART_Transmit('u'); ?

>Das ist aber nicht das problem, sondern der Pin PD4 als eingang.

Woher weisst du ob das da ein Problem ist? Wie kommst
du in den Int0?

Schreib dir mal ein Miniprogramm wo du PIND4 abfragst.

von Karl H. (kbuchegg)


Lesenswert?

Einschub, weil ich jetzt schon 3 Minuten 0-en zähle

1
 if((PIND&0b10000)>>4){

das schreibt man nicht so. Programmierer sind faule Hunde. Das hier zu 
lesen und zu analysieren erfordert viel zu viel Aufwand und ist auch 
viel zu fehleranfällig zu schreiben.

Erstens:
In C ist ALLES logisch wahr, was ungleich 0 ist. Ob in deinem Ausdruck 
daher das Bitmuster 0b00010000 oder 0b00000001 rauskommt, spielt 
überhaupt keine Rolle. Ungleich 0 ist ungleich 0.
Daher: Du brauchst dir das eine ausmaskierte Bit nicht zurechtschieben.

Daher
1
 if( PIND & 0b10000 ){

macht exakt und genau das gleiche wie deine Version. Der einzige 
Unterschied: Du laufst in deiner Version Gefahr, dass die Anzahl der 
Verschiebungen nicht stimmt und dann kommt nicht 1 raus, sonder 0. Und 
das ist dann tatsächlich ein logisches FALSE.

Also: in C gilt
        ein Wert von 0          gilt als logisch FALSE
        ein Wert ungleich 0     gilt als logisch TRUE

und bei ungleich 0 spielt es keine Rolle, was der Wert genau ist. Er 
darf nur nicht 0 sein.

Zweitens:
Diese ewige 0-en Zählerei in den Binärkonstanten ist genauso 
fehleranfällig. Überhaupt dann, wenn du nicht alle 8 Bits eines Bytes 
anschreibst.
1
  if( PIND % (1 << PD4) )

jetzt braucht kein Mensch mehr 0-en zählen. Auch ein Blinder kann hier 
greifen, dass du den Pin PD4 abfrägst. Die Abfrage lautet in normalem 
Deutsch: Wenn Bit 4 am Port PIND auf 1 ist, dann mach was.
Und in dieser Schreibweise gibt es dann auch kaum mehr blödsinnige 
Fehler, die nur deshalb entstehen, weil man sich irgendwo mit den 0-en 
und 1-en verzählt hat.


Aber: Das ist nicht das Problem. So wie du das geschrieben hast, läuft 
es aufs gleiche raus. Es ist nur schwerer zu lesen und es gibt mehr 
Möglichkeiten für Schreibfehler.
Und es dauert 5 mal so lange, sich davon zu überzeugen, dass die Abfrage 
in Ordnung ist.

von holger (Gast)


Lesenswert?

>  if( PIND % (1 << PD4) )
>
>jetzt braucht kein Mensch mehr 0-en zählen. Auch ein Blinder kann hier

Eine Taste daneben;)
  if( PIND & (1 << PD4) )

von Karl H. (kbuchegg)


Lesenswert?

:-)
Danke holger.

von holger (Gast)


Lesenswert?

Ich frag mich immer noch wie er darauf kommt das PIND4
nicht funktioniert.

Den UART Transmit hat er sich ja selber abgeknipst:

>UCSRB = (1<<RXEN)|(0<<TXEN)|(1<<RXCIE);

Da wird also kein
    USART_Transmit('+');
oder
    USART_Transmit('-');
aus dem Int0 kommen.

Kommt da überhaupt ein '+' oder '-' am Terminal?

Das könnte helfen:

UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);

Transmitter einschalten.

Wie er in den Int0 kommt ist seine Sache.
Der Rest ist mir jetzt echt zu blöd.

von Hugo (Gast)


Lesenswert?

Danke für eure Hilfe.
Es war jedoch ein komplett anderer Fehler. Die Gabellichtschranke war um 
ein paar Grad verdreht. Dadurch war der Phasenversatz von den beiden 
Signalen des Inkrementalgebers so gut wie Null und immer wenn INT0 
ausgelöst hast war PD4 auf 0V egal in welche richtung man den 
Inkrementalgeber gedreht hat. Der Code funtioniert einwandfrei (auch 
wenn man ihn schöner schreiben könnte).

Gruß Hugo

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.