Guten Abend,
ich bin bei meinem Versuch, einen Software UART (zu erstmal TX) auf
einem Attiny85 zu implementieren, erneut an eine Grenze gestoßen. Und
zwar möchte ich das Ganze softwareseitig so aufbauen, dass man es
ähnlich bedient wie einen normalen UART. Dafür hatte ich erst die Idee,
das so zu machen (Pseudocode):
1 | volatile char printChar;
|
2 | volatile enablePrinting = 0;
|
3 | ISR{
|
4 | if(enablePrinting == 1)
|
5 | print "printChar"...
|
6 | enablePrinting = 0; //aufhören nachdem der Char geprintet wurde
|
7 | }
|
8 | void setPrintChar(char c){
|
9 | enablePrinting = 1;
|
10 | printChar = c;
|
11 | }
|
12 | int main(void){
|
13 | while(1)
|
14 | setPrintChar('C');
|
15 | setPrintChar('B');
|
16 | }
|
Das führte aber dazu, dass nicht ein C nach einem B folgte, sondern
mehrere Cs und dann mehrere Bs kamen (ich denke, das liegt daran, dass
die Funktion bereits wieder aufgerufen wird, obwohl der alte Char noch
gar nicht übertragen wurde). Daher hab ich mir überlegt, dass mit einer
Queue zu machen. Das sieht aktuell so aus:
1 | #define F_CPU 1000000UL
|
2 |
|
3 | #include <avr/io.h>
|
4 | #include <avr/interrupt.h>
|
5 | #include <stdlib.h>
|
6 |
|
7 | volatile uint8_t enablePrinting = 0;
|
8 | volatile char* queue;
|
9 | volatile uint8_t queueLength = 0;
|
10 |
|
11 | volatile int8_t position = -1;
|
12 | volatile uint8_t pauseBits = 13;
|
13 | volatile uint8_t needPause = 0;
|
14 |
|
15 | ISR(TIMER1_COMPA_vect){
|
16 | if(enablePrinting == 1){
|
17 | if(needPause == 1 && pauseBits > 0){
|
18 | pauseBits--;
|
19 | if(pauseBits == 0){
|
20 | pauseBits = 13;
|
21 | needPause = 0;
|
22 | }
|
23 | } else {
|
24 | if(position == -1){ //start of transmission
|
25 | PORTB &=~(1<<PINB3); //Start Bit
|
26 | position++;
|
27 | } else {
|
28 | if(position == 8){ //end of transmission
|
29 | queue[queueLength-1] = (char)0;
|
30 | queueLength--;
|
31 | if(queueLength == 0)
|
32 | enablePrinting = 0;
|
33 | position = -1;
|
34 | PORTB |= (1<<PINB3); //Stop Bit HIGH
|
35 | needPause = 1;
|
36 | } else{
|
37 | if((queue[queueLength-1] >> position) & 0x01){
|
38 | PORTB |= (1<<PINB3);
|
39 | } else {
|
40 | PORTB &=~(1<<PINB3);
|
41 | }
|
42 | position++;
|
43 | }
|
44 | }
|
45 | }
|
46 | }
|
47 | }
|
48 |
|
49 | void initTimer(){
|
50 | TCCR1 |= (1<<CTC1); //Enable CTC
|
51 | TCCR1 |= (0b0010<<CS10); //CK/2
|
52 | OCR1A = 1;
|
53 | TIMSK |= (1<<OCIE1A); //enable compare interrupt
|
54 | queue = (char*)malloc(sizeof(char));
|
55 | sei(); //Enable Interrupts
|
56 | }
|
57 |
|
58 | void printChar(char c){
|
59 | queue[queueLength] = c;
|
60 | queueLength++;
|
61 | enablePrinting = 1;
|
62 | }
|
63 |
|
64 | int main(void)
|
65 | {
|
66 | DDRB |= (1<<PINB3); //PINB1 as output
|
67 | PORTB |= (1<<PINB3); //PINB3 HIGH
|
68 | initTimer();
|
69 | while(1){
|
70 | printChar('C');
|
71 | printChar('B');
|
72 | }
|
73 | }
|
Leider funktioniert das immer noch nicht. Jetzt kommt CCBBCCBB.
Außerdem verbraucht mein Program nun statt 300Byte über 1KByte (liegt
wahrscheinlich am malloc) :(
Wie würdet ihr das Problem lösen?