Software-UART: Problem beim Empfangen

Gast #1721492
Lesenswert?

Hallo,

ich habe die Suche benutzt und leider konnte mir kein gefundener Beitrag 
hier im Forum (oder bei Google) helfen.

Folgendes Problem:
Ich habe für eine Facharbeit einen Software-UART für den ATtiny13 
geschrieben.
Dafür wird der Timer TCNT0 über die beiden Register OCR0A zum Senden und 
OCR0B zum Empfangen benutzt.
Zum Empfangen des Startbits bei dem Standard RS232 wird der Interrupt 
INT0 zum Erkennen von steigenden Flanken benutzt.

Aber das Empfangen klappt vorne und hinten nicht, dafür aber das Senden.
Meine Frage ist jetzt: Warum läuft das nicht? Ich hab jetzt so oft über 
den Quellcode geblinzelt, dass ich den nicht mehr sehen kann incl. 
Fehler.

Könnte jmd.eventuell mal ein Auge draufwerfen?

MfG
BruceCompanys
1
#include "uart.h"
2

3

4

5
static volatile uint16_t outframe;
6

7

8

9
static volatile uint16_t inframe;
10

11
static volatile uint8_t indata, inbits, received;
12

13

14

15
void uart_init()
16

17
{
18

19
  /* Sichern des Status Registers incl. I-Flag */
20

21
  uint8_t sreg = SREG;
22

23
    cli();
24

25

26

27
    SUART_TXD_DDR   |= (1 << SUART_TXD_BIT);  /* Pin als Ausgang */
28

29
  SUART_TXD_PORT   &= ~(1 << SUART_TXD_BIT);  /* Low-Pegel */
30

31

32

33
  SUART_RXD_DDR   &= ~(1 << SUART_RXD_BIT);  /* Pin als Eingang */
34

35
  SUART_RXD_PORT   |= (1 << SUART_RXD_BIT);   /* Pull-up Widerstand */
36

37

38

39
  /* Output Compare Register A 
40

41
    Anzahl der Taktzyklen für eine Bitlänge 
42

43
    
44

45
    F_CPU = 1,2 MHz; Baudrate = 9600 => 125 Taktzyklen pro Bitlänge */
46

47
  OCR0A = 125; /* OCR0A wird zum Senden verwendet */
48

49
  OCR0B = 183; /* OCR0B wird zum Empfangen verwendet. Korrigierter Stand, eig. 188! */
50

51

52

53
  /* Timer/Control Register A: setzte Clear Timer/Counter on Compare Match  */
54

55
  TCCR0A |= (1 << WGM01);
56

57

58

59
  /* Timer/Control Register B: stoppe Timer*/
60

61
  TCCR0B = 0; /* REF NO.: F02/01 */
62

63

64

65
    /* Setze Interrupt und Flags für Timer zurück */
66

67
  TIFR0  = (1 << OCF0B) | (1 << OCF0A);
68

69
  TIMSK0 = 0;
70

71

72

73
    /* Interrupt wird ausgelöst bei steigender Flanke an PB1 */
74

75
    MCUCR   |= (1 << ISC01) | (1 << ISC00);
76

77
    GIFR    = (1 << INTF0);
78

79
    GIMSK   &= ~(1 << INT0);
80

81
  
82

83
  SREG = sreg;
84

85
}
86

87

88

89
void uart_putc(const char c)
90

91
{
92

93
  /* Warte bis alles gesendet ist */
94

95
  do {
96

97
    sei(); nop(); cli();
98

99
    } while (outframe);
100

101

102

103
  /* frame = *.P.7.6.5.4.3.2.1.0.S   S=Start(0), P=Stop(1), *=Endmarke(1) */
104

105
    outframe = (3 << 9) | (((uint8_t) c) << 1);
106

107

108

109
    /* Setze Interrupt für Timer zurück */
110

111
    TIFR0   = (1 << OCF0A);
112

113

114

115
  /* Timer/Counter Interrupt Mask Register 
116

117
    OCIE0A = 1
118

119
    => Timer/Counter0 Output Compare Match A Interrupt Enable 
120

121
  
122

123
    Aktiviere Interrupt für Timer */
124

125
  TIMSK0 |= (1 << OCIE0A);
126

127
    TCCR0B |= (1 << CS00); /* starte Timer mit 1,2 MHz Takt*/
128

129
  
130

131
  sei();
132

133
}
134

135

136

137
char uart_getc()
138

139
{
140

141
    cli();
142

143
    GIFR    = (1 << INTF0);
144

145
    GIMSK   |= (1 << INT0);
146

147
  
148

149
  received = 0;
150

151
    sei();
152

153

154

155
  /* Warte bis alles empfangen ist */
156

157
  while(received == 0) {}
158

159

160

161
    TCCR0B   = 0; /* Stoppe Timer wieder REF NO.: F02/01 */
162

163
    received = 0;
164

165

166

167
  return (char) indata;
168

169
}
170

171

172

173
/* Senden - Interrupt Service Routine */
174

175
ISR(TIM0_COMPA_vect)
176

177
{
178

179
    uint16_t data = outframe;
180

181
   
182

183
    if(data & 1)   SUART_TXD_PORT &= ~(1 << SUART_TXD_BIT);
184

185
  else       SUART_TXD_PORT |=  (1 << SUART_TXD_BIT);
186

187

188

189
     /* Endmarke erreicht, kille Interrupt */
190

191
    if (1 == data) {
192

193
        TIMSK0 &= ~(1 << OCIE0A);
194

195
        TCCR0B  = 0; /* stoppe Timer REF NO.: F02/01 */
196

197
    }   
198

199
   
200

201
    outframe = data >> 1;
202

203
}
204

205

206

207
/* Empfangen - Interrupt Service Routine */
208

209
ISR(INT0_vect)
210

211
{
212

213
    OCR0B    = 181; /* REF NO.: F01/01 */
214

215
  TIFR0    = (1 << OCF0B);
216

217
  TIMSK0   |= (1 << OCIE0B);
218

219
    TCCR0B  |= (1 << CS00); /* Starte Timer mit 1,2 Mhz Takt */
220

221

222

223
    GIMSK   &= ~(1 << INT0);
224

225

226

227
  inframe  = 0;
228

229
  inbits    = 0;
230

231
}
232

233

234

235
ISR(TIM0_COMPB_vect)
236

237
{
238

239
  uint16_t data = inframe >> 1;
240

241
    OCR0B = 123;
242

243

244

245
  if(!(SUART_RXD_PIN & (1 << SUART_RXD_BIT))) {
246

247
        data |= (1 << 9);
248

249
  }
250

251

252

253
  uint8_t bits = inbits+1;
254

255

256

257
  if(bits >= 10) {
258

259
    /* Kontrolle von Start- und Stoppbit */
260

261
        if( !(data & 1) && (data >= (1 << 9)) ) {
262

263
          indata = data >> 1;
264

265
    }
266

267

268

269
        received = 1;
270

271
        TIMSK0 &= ~(1 << OCIE0B);
272

273
    } else {
274

275
        inbits = bits;
276

277
        inframe = data;
278

279
    }
280

281
}
Gast #1721565
Lesenswert?

Vielen Dank erst einmal für deine schnelle Hilfe!

Habe die Fusebits für 9,6 MHz gesetzt, leider funktioniert das Empfangen 
immer noch nicht richtig.

Werde mal versuchen die Werte von OCR0B weiter herunter zu drehen.

Wobei ich den Takt für den Timer bei 1,2 Mhz gelassen habe, da das 
Timer-Register sonst überläuft (und mir nichts bringt.)

MfG
Bruce

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren