Forum: Mikrocontroller und Digitale Elektronik [ATTiny24] Bitte um Blick auf Code


von Stefan H. (stefan_h16)


Lesenswert?

Ich habe zwar schon ein paar größere und kleiner Programme mit dem 
Arduino fertiggestellt, dabei habe ich mir aber stark von der 
Arduino-eigenen Bibliothek helfen lassen. Deswegen bin ich mir noch 
unsicher was die ganz Systemnahen Sachen angeht, und hoffe das mir ein 
paar geschulte Augen noch Tipps geben können.
Das soll das Programm machen:
Es werden zwei einfache DC-Motoren über H-Brücken angeschlossen. Die 
Motoren beinhalten ausserdem jeweils optische Quadropol-Encoder.
Der vorliegende Programmprototyp soll die Encoder auslesen und jeweils 
die absolute Position und die aktuelle Geschwindigkeit über i2c (slave) 
ausgeben.
Um die Encoder auszulesen werden die PCINT 7,5,3,2 genutzt. Die 
gemeinsame ISR findet dann heraus welcher Pin verantwortlich ist für den 
Interrupt und behandelt diesen entsprechend.
Zur Bestimmung der Geschwindigkeit läuft ein Timer im CTC Modus als 
Zeitbasis der die tausendstel Sekunden seit Reset zählt.
Für i2c  nutze ich die Lib von Martin Junghans, da ich schon gute 
Erfahrungen damit gemacht habe.
Also meine Fragen:
- Sind sowohl Hardwareinterrupts als auch der Timer so konfiguriert wie 
ich das will
- Könnte die ISR Routine für die Hardware interrupts noch optimiert 
werden (sie scheint mir zu groß zu sein)
- Allgemeine Verbesserungsvorschläge, wo könnte das Programm haken ?

Zumindest compilieren lässt es sich mit gcc.
1
/*#################################################################################################
2
 Name  : i2c controlled Motordriver for Lego NXT Motors
3
 Version  : 0.1 alpha
4
 autor  : Stefan  page  :
5
 License  : GNU General Public License
6
7
8
 //################################################################################################*/
9
/*Structur of i2c Communication
10
 * txbuffer    (readable by master)
11
 * txbuffer[0] Motor A speed in ticks/sec high byte
12
 * txbuffer[1] Motor A speed in ticks/sec low byte
13
 * txbuffer[2] Motor A position count high byte
14
 * txbuffer[3] Motor A position count low byte
15
 * txbuffer[4] Motor B speed in ticks/sec high byte
16
 * txbuffer[5] Motor B speed in ticks/sec low byte
17
 * txbuffer[6] Motor B position count high byte
18
 * txbuffer[7] Motor B position count low byte
19
 */
20
21
/* Pinning of Attiny 24
22
 * VCC     -> VCC
23
 * PB0    -> Clkin (Quarzoszillator) or n.c.
24
 * PB1    -> PWM_MOTOR_A0
25
 * PB2    -> PWM_MOTOR_A1
26
 * PB3    -> RESET -> PULLUP-Resistor -> VCC
27
 * PA7    -> TACHO_MOTOR_A0
28
 * PA6    -> i2c SDA / ISP MOSI
29
 * PA5    -> TACHO_MOTOR_A1 / ISP MISO
30
 * PA4    -> i2c SCL / ISP SCK
31
 * PA3    -> TACHO_MOTOR_B1
32
 * PA2    -> TACHO_MOTOR_B0
33
 * PA1    -> PWM_MOTOR_B0
34
 * PA0    -> PWM_MOTOR_B1
35
 * GND    -> GND
36
 */
37
//################### Pinning
38
#define DDR_PWM_MOTOR_A DDRB
39
#define DDR_PWM_MOTOR_B DDRA
40
#define DDR_TACHO DDRA
41
42
#define PORT_PWM_MOTOR_A PORTB
43
#define PORT_PWM_MOTOR_B PORTA
44
#define PIN_TACHO PINA
45
46
#define PWM_MOTOR_A0 1
47
#define PWM_MOTOR_A1 2
48
#define PWM_MOTOR_B0 1
49
#define PWM_MOTOR_B1 0
50
#define TACHO_MOTOR_A0 7
51
#define TACHO_MOTOR_A1 5
52
#define TACHO_MOTOR_B0 2
53
#define TACHO_MOTOR_B1 3
54
55
//Additional constants
56
#define TIMEBASE 1000 //1/1000 s or 1 ms is the timebase for all calculations
57
58
#include   <stdlib.h>
59
#include   <avr/io.h>
60
#include   <avr/interrupt.h>
61
#include   <avr/pgmspace.h>
62
#include   <util/delay.h>
63
64
//###################### USI-TWI-I2C
65
#include   "usiTwiSlave.h"         
66
#define   SLAVE_ADR_ATTINY_1       0b00110100    // i2c slave address
67
#ifndef   F_CPU
68
#define   F_CPU 8000000UL
69
#endif
70
//###################### Global variables
71
volatile uint8_t pwm_settings[4]; //stores speeds for pwm
72
volatile uint16_t tacho_A = 0; // stores tacho count for motor a
73
volatile uint16_t tacho_B = 0; // stores tacho count for motor a
74
75
volatile uint32_t timebase = 0; //stores current time since reset
76
77
#define LOW_BYTE(x)          (x & 0xff)          // 16Bit   --> 8Bit
78
#define HIGH_BYTE(x)         ((x >> 8) & 0xff)      // 16Bit   --> 8Bit
79
//Interrupt vector that handles tacho interrups
80
ISR(PCINT1_vect)
81
{
82
  uint8_t current;
83
  uint8_t masked;
84
  static volatile uint8_t prev = 0;
85
  static volatile uint8_t dir_A;
86
  static volatile uint8_t dir_B;
87
88
  current = PIN_TACHO;
89
  masked = current ^ prev; //Calculate xor to find out which pins have  changed
90
91
  if (masked & (1 << TACHO_MOTOR_A0)) //PIN TACHO_A0 triggers interrupt
92
  {
93
    if ((prev & (1 << TACHO_MOTOR_A0)) == 0) //only interested in rising edge (prev = 0; current = 1);
94
    {
95
      if (dir_A)
96
        tacho_A--;
97
      else
98
        tacho_A++;
99
    }
100
  } else if (masked & (1 << TACHO_MOTOR_A1))
101
    dir_A = !dir_A;
102
103
  if (masked & (1 < TACHO_MOTOR_B0)) //PIN TACHO_A0 triggers interrupt
104
  {
105
    if ((prev & (1 << TACHO_MOTOR_B0)) == 0) //only interested in rising edge (prev = 0; current = 1);
106
    {
107
      if (dir_B)
108
        tacho_B--;
109
      else
110
        tacho_B++;
111
    }
112
  } else if (masked & (1 << TACHO_MOTOR_B1))
113
    dir_B = !dir_B;
114
115
  prev = current;
116
}
117
118
//the ISR is called every millisecond
119
ISR(TIM0_COMPA_vect)
120
{
121
  timebase++;
122
}
123
124
int main(void) {
125
  //Init I2C
126
  cli();
127
  //Set Motorports as outputs
128
  DDR_PWM_MOTOR_A |= (1 << PWM_MOTOR_A0) | (1 << PWM_MOTOR_A1);
129
  DDR_PWM_MOTOR_B |= (1 << PWM_MOTOR_B0) | (1 << PWM_MOTOR_B1);
130
  //Set Tachoports as inputs
131
  DDR_TACHO &= ~((1 << TACHO_MOTOR_A0) | (1 << TACHO_MOTOR_A1) | (1
132
      << TACHO_MOTOR_B0) | (1 << TACHO_MOTOR_B1));
133
134
  //Configure Interrupts for Tacho
135
  GIMSK = (1 << PCIE0); //Changes on PCINT 7:0 may cause interrupt
136
  PCMSK0 = (1 << TACHO_MOTOR_A0) | (1 << TACHO_MOTOR_A1) | (1
137
      << TACHO_MOTOR_B0) | (1 << TACHO_MOTOR_B1); //Enable Tachopins for Interrupt source
138
139
140
  //Configure Timer0 as time base for milliseconds
141
  TCCR0A = (1 << WGM01); //CTC Mode
142
  TCCR0B = (1 << CS01); //clock prescaler 8
143
  OCR0A = ((F_CPU / 8) / TIMEBASE) ; 
144
  TIMSK0 = (1 << OCIE0A); //Enable Compare interrupt
145
146
  //Init TWI Slave
147
  usiTwiSlaveInit(SLAVE_ADR_ATTINY_1);
148
  sei();
149
150
  uint32_t prev_time = 0;
151
  uint16_t prev_tachoA = 0;
152
  uint16_t prev_tachoB = 0;
153
154
  uint16_t speed_A = 0;
155
  uint16_t speed_B = 0;
156
157
  uint16_t delta_time;
158
159
  for (;;) {
160
    delta_time = (uint16_t) (timebase - prev_time);
161
    prev_time = timebase;
162
163
    if (delta_time > 0) //to prevent div by zero
164
    {
165
      speed_A = (tacho_A - prev_tachoA) * 1000 / delta_time;
166
      speed_B = (tacho_B - prev_tachoB) * 1000 / delta_time;
167
    }
168
169
    //Write everything into the txbuffer
170
    txbuffer[0] = HIGH_BYTE(speed_A);
171
    txbuffer[1] = LOW_BYTE(speed_A);
172
    txbuffer[2] = HIGH_BYTE(tacho_A);
173
    txbuffer[3] = LOW_BYTE(tacho_A);
174
    txbuffer[4] = HIGH_BYTE(speed_B);
175
    txbuffer[5] = LOW_BYTE(speed_B);
176
    txbuffer[6] = HIGH_BYTE(tacho_B);
177
    txbuffer[7] = LOW_BYTE(tacho_B);
178
179
  }
180
181
}

von Thomas E. (thomase)


Lesenswert?

Stefan H. schrieb:

>static volatile uint8_t prev = 0;
>static volatile uint8_t dir_A;
>static volatile uint8_t dir_B;

Das hat in der ISR nichts zu verloren, sondern gehört global deklariert.


> speed_A = (tacho_A - prev_tachoA) * 1000 / delta_time;
> speed_B = (tacho_B - prev_tachoB) * 1000 / delta_time;

Das wird Probleme machen.

Wenn die Differenz (tacho_A - prev_tachoA) größer als 6 ist, ist das 
Ergebnis der folgenden Multiplikation min. 70000, unsigned int geht aber 
nur bis 65536.


mfg.

von Stefan H. (stefan_h16)


Lesenswert?

Thomas Eckmann schrieb:
> Stefan H. schrieb:
>
>>static volatile uint8_t prev = 0;
>>static volatile uint8_t dir_A;
>>static volatile uint8_t dir_B;
>
> Das hat in der ISR nichts zu verloren, sondern gehört global deklariert.

Kannst du mir bitte sagen wieso ? Ich dachte, da ich die Variablen nur 
lokal brauche, sind sie als Static in der ISR am besten aufgehoben 
(gekapselt). Wo liegt der Unterschied ?


>> speed_A = (tacho_A - prev_tachoA) * 1000 / delta_time;
>> speed_B = (tacho_B - prev_tachoB) * 1000 / delta_time;
>
> Das wird Probleme machen.
>
> Wenn die Differenz (tacho_A - prev_tachoA) größer als 6 ist, ist das
> Ergebnis der folgenden Multiplikation min. 70000, unsigned int geht aber
> nur bis 65536.
>
An dem Teil arbeite ich zugegebener Maßen noch. Aber ich habe 
ausgerechnet das es nicht mehr als zwei Tachoticks pro Millisekunde 
geben kann (Motor ist nicht schneller), so dass die Variablen zumindest 
nicht überlaufen sollte.

Und der Rest, ist der richtig eingestellt ?

mfg
Stefan

von Helfer (Gast)


Lesenswert?

>>>static volatile uint8_t prev = 0;
>>>static volatile uint8_t dir_A;
>>>static volatile uint8_t dir_B;
>>
>> Das hat in der ISR nichts zu verloren, sondern gehört global deklariert.
>
> Kannst du mir bitte sagen wieso ? Ich dachte, da ich die Variablen nur
> lokal brauche, sind sie als Static in der ISR am besten aufgehoben
> (gekapselt). Wo liegt der Unterschied ?

Du kannst die schon lokal in der ISR definieren (inkl. 
Initialisierung!), brauchst dann aber das volatile nicht.

Als "Nachteil" fällt mir nur ein, dass du eventuell schwieriger Debuggen 
kannst, weil die lokalen Variablen halt nur lokal sichtbar sind, d.h. 
wenn die ISR läuft. Mal eben einen Statusdump zu machen ist schwierig.

von Helfer (Gast)


Lesenswert?

>    delta_time = (uint16_t) (timebase - prev_time);
>    prev_time = timebase;

Den Zugriff auf die gemeinsam benutzte Variable timebase musst du 
atomar machen. Siehe Artikel Interrupt

von Helfer (Gast)


Lesenswert?

>      speed_A = (tacho_A - prev_tachoA) * 1000 / delta_time;
>      speed_B = (tacho_B - prev_tachoB) * 1000 / delta_time;

Ebenso den Zugriff auf die Variablen tacho_A und tacho_B

von Helfer (Gast)


Lesenswert?

Es bietet sich an dafür einen eigenen Block zu Beginn des 
for-Anweisungsblocks zu machen, in dem die von der ISR gesetzten 
Variablen als "Schnappschuss" atomar in eine lokale Kopie kopiert werden
1
#include <util/atomic.h>
2
...
3
4
  for(;;) {
5
    uint32_t akt_timebase;
6
    uint16_t akt_tacho_A;
7
    uint16_t akt_tacho_B; 
8
9
    ATOMIC_BLOCK(ATOMIC_FORCEON)
10
    {
11
      akt_timebase = timebase;
12
      akt_tacho_A = tacho_A;
13
      akt_tacho_B = tacho_B; 
14
    }
15
16
    delta_time = (uint16_t) (akt_timebase - prev_time);
17
    prev_time = akt_timebase;
18
19
    if (delta_time > 0) //to prevent div by zero
20
    {
21
      speed_A = ((akt_tacho_A - prev_tachoA) * 1000) / delta_time;
22
      speed_B = ((akt_tacho_B - prev_tachoB) * 1000) / delta_time;
23
    }
24
25
    //Write everything into the txbuffer
26
    txbuffer[0] = HIGH_BYTE(speed_A);
27
    txbuffer[1] = LOW_BYTE(speed_A);
28
    txbuffer[2] = HIGH_BYTE(akt_tacho_A);
29
    txbuffer[3] = LOW_BYTE(akt_tacho_A);
30
    txbuffer[4] = HIGH_BYTE(speed_B);
31
    txbuffer[5] = LOW_BYTE(speed_B);
32
    txbuffer[6] = HIGH_BYTE(akt_tacho_B);
33
    txbuffer[7] = LOW_BYTE(akt_tacho_B);
34
  }

von Helfer (Gast)


Lesenswert?

In deinem Code (und meinem Vorschlag) fehlt IMHO noch, das regelmäßige 
Update von prev_tachoA und prev_tachoB ähnlich wie bei prev_time.

Anschliessend stellt sich die Frage, wann die so stetig weitergezählten 
Variablen irgendwann überlaufen...

von Stefan H. (stefan_h16)


Lesenswert?

Helfer schrieb:
> In deinem Code (und meinem Vorschlag) fehlt IMHO noch, das regelmäßige
> Update von prev_tachoA und prev_tachoB ähnlich wie bei prev_time.
>
> Anschliessend stellt sich die Frage, wann die so stetig weitergezählten
> Variablen irgendwann überlaufen...

Vielen Dank für deine umfangreiche Hilfe. Insbesondere die Sache mit dem 
atomaren Kopien hatte ich völlig übersehen. Der Vollständigkeit halber 
muss ich aber anmerken das ich die drei akt_ Variablen wohl Global 
deklarieren muss damit innerhalb des Atomblocks sichtbar sind.

Ich habe jetzt eine neue korrigierte Version meines Codes angehängt. 
Ausserdem habe ich jetzt das Software-PWM ergänzt. Es ist eine 
hoffentlich richtig angepasste Version des C-Software-PWM das hier 
http://www.mikrocontroller.net/articles/Soft-PWM erklärt wird.

Ich erwarte, grob überschlagen 3900 Interruptereignisse von meinen 
Encodern pro Sekunde bei maximaler Geschwindigkeit der Motoren. Reichen 
da für das Programm 8 MHZ Takt oder sollte ich eine schnellere 
Taktquelle anschließen.
1
/*#################################################################################################
2
 Name  : i2c controlled Motordriver for Lego NXT Motors
3
 Version  : 0.1 alpha
4
 autor  : Stefan Huber
5
 page  :
6
 License  : GNU General Public License
7
8
9
 //################################################################################################*/
10
/*Structur of i2c Communication
11
 * txbuffer    (readable by master)
12
 * txbuffer[0] Motor A speed in ticks/sec high byte
13
 * txbuffer[1] Motor A speed in ticks/sec low byte
14
 * txbuffer[2] Motor A position count high byte
15
 * txbuffer[3] Motor A position count low byte
16
 * txbuffer[4] Motor B speed in ticks/sec high byte
17
 * txbuffer[5] Motor B speed in ticks/sec low byte
18
 * txbuffer[6] Motor B position count high byte
19
 * txbuffer[7] Motor B position count low byte
20
 */
21
22
/* Pinning of Attiny 24
23
 * VCC     -> VCC
24
 * PB0    -> Clkin (Quarzoszillator) or n.c.
25
 * PB1    -> PWM_MOTOR_A0
26
 * PB2    -> PWM_MOTOR_A1
27
 * PB3    -> RESET -> PULLUP-Resistor -> VCC
28
 * PA7    -> TACHO_MOTOR_A0
29
 * PA6    -> i2c SDA / ISP MOSI
30
 * PA5    -> TACHO_MOTOR_A1 / ISP MISO
31
 * PA4    -> i2c SCL / ISP SCK
32
 * PA3    -> TACHO_MOTOR_B1
33
 * PA2    -> TACHO_MOTOR_B0
34
 * PA1    -> PWM_MOTOR_B0
35
 * PA0    -> PWM_MOTOR_B1
36
 * GND    -> GND
37
 */
38
//################### Pinning
39
#define DDR_PWM_MOTOR_A DDRB
40
#define DDR_PWM_MOTOR_B DDRA
41
#define DDR_TACHO DDRA
42
43
#define PORT_PWM_MOTOR_A PORTB
44
#define PORT_PWM_MOTOR_B PORTA
45
#define PIN_TACHO PINA
46
47
#define PWM_MOTOR_A0 1
48
#define PWM_MOTOR_A1 2
49
#define PWM_MOTOR_B0 1
50
#define PWM_MOTOR_B1 0
51
#define TACHO_MOTOR_A0 7
52
#define TACHO_MOTOR_A1 5
53
#define TACHO_MOTOR_B0 2
54
#define TACHO_MOTOR_B1 3
55
56
//Additional constants
57
#define TIMEBASE 1000 //1/1000 s or 1 ms is the timebase for all calculations
58
#include   <stdlib.h>
59
#include   <avr/io.h>
60
#include   <avr/interrupt.h>
61
#include   <avr/pgmspace.h>
62
#include   <util/delay.h>
63
#include <util/atomic.h>
64
65
//###################### USI-TWI-I2C
66
#include   "usiTwiSlave.h"         
67
#define   SLAVE_ADR_ATTINY_1       0b00110100    // i2c slave address
68
#ifndef   F_CPU
69
#define   F_CPU 8000000UL
70
#endif
71
//###################### Global Macros
72
73
#define LOW_BYTE(x)          (x & 0xff)          // 16Bit   --> 8Bit
74
#define HIGH_BYTE(x)         ((x >> 8) & 0xff)      // 16Bit   --> 8Bit
75
//###################### PWM configuration
76
#define F_PWM 50                       // PWM-Frequenz in Hz
77
#define PWM_STEPS 256                   // PWM-Schritte pro Zyklus(1..256)
78
// ab hier nichts ändern, wird alles berechnet
79
80
#define T_PWM (F_CPU/(F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
81
#if (T_PWM<(93+5))
82
#error T_PWM zu klein, F_CPU muss vergrösst werden oder F_PWM oder PWM_STEPS verkleinert werden
83
#endif
84
//###################### Global variables
85
volatile uint8_t pwm_settings[4]; //stores speeds for pwm
86
volatile uint16_t tacho_A = 0; // stores tacho count for motor a
87
volatile uint16_t tacho_B = 0; // stores tacho count for motor a
88
volatile uint32_t akt_timebase = 0;
89
volatile uint16_t akt_tachoA = 0;
90
volatile uint16_t akt_tachoB = 0;
91
volatile uint32_t timebase = 0; //stores current time since reset
92
93
94
//Interrupt vector that handles tacho interrups
95
ISR(PCINT1_vect)
96
{
97
  uint8_t current;
98
  uint8_t masked;
99
  static  uint8_t prev = 0;
100
  static  uint8_t dir_A = 0;
101
  static  uint8_t dir_B = 0;
102
103
  current = PIN_TACHO;
104
  masked = current ^ prev; //Calculate xor to find out which pins have  changed
105
106
  if (masked & (1 << TACHO_MOTOR_A0)) //PIN TACHO_A0 triggers interrupt
107
  {
108
    if ((prev & (1 << TACHO_MOTOR_A0)) == 0) //only interested in rising edge (prev = 0; current = 1);
109
    {
110
      if (dir_A)
111
        tacho_A--;
112
      else
113
        tacho_A++;
114
    }
115
  } else if (masked & (1 << TACHO_MOTOR_A1))
116
    dir_A = !dir_A;
117
118
  if (masked & (1 < TACHO_MOTOR_B0)) //PIN TACHO_B0 triggers interrupt
119
  {
120
    if ((prev & (1 << TACHO_MOTOR_B0)) == 0) //only interested in rising edge (prev = 0; current = 1);
121
    {
122
      if (dir_B)
123
        tacho_B--;
124
      else
125
        tacho_B++;
126
    }
127
  } else if (masked & (1 << TACHO_MOTOR_B1))
128
    dir_B = !dir_B;
129
130
  prev = current;
131
}
132
133
//the ISR is called every millisecond
134
ISR(TIM0_COMPA_vect)
135
{
136
  timebase++;
137
}
138
139
ISR(TIM1_COMPA_vect)
140
{
141
  static uint8_t pwm_cnt = 0;
142
143
  OCR1A += (uint16_t) T_PWM;
144
145
  if(pwm_settings[0] > pwm_cnt)
146
    PORT_PWM_MOTOR_A |= (1<<PWM_MOTOR_A0);
147
  else
148
    PORT_PWM_MOTOR_A &= ~(1<<PWM_MOTOR_A0);
149
150
  if(pwm_settings[1] > pwm_cnt)
151
    PORT_PWM_MOTOR_A |= (1<<PWM_MOTOR_A1);
152
  else
153
    PORT_PWM_MOTOR_A &= ~(1<<PWM_MOTOR_A1);
154
155
  if(pwm_settings[2] > pwm_cnt)
156
    PORT_PWM_MOTOR_B |= (1<<PWM_MOTOR_B0);
157
  else
158
    PORT_PWM_MOTOR_B &= ~(1<<PWM_MOTOR_B0);
159
160
  if(pwm_settings[3] > pwm_cnt)
161
    PORT_PWM_MOTOR_B |= (1<<PWM_MOTOR_B1);
162
  else
163
    PORT_PWM_MOTOR_B &= ~(1<<PWM_MOTOR_B1);
164
165
  if (pwm_cnt == (uint8_t) (PWM_STEPS - 1))
166
    pwm_cnt = 0;
167
  else
168
    pwm_cnt++;
169
}
170
171
int main(void) {
172
  //Init I2C
173
  cli();
174
  //Set Motorports as outputs
175
  DDR_PWM_MOTOR_A |= (1 << PWM_MOTOR_A0) | (1 << PWM_MOTOR_A1);
176
  DDR_PWM_MOTOR_B |= (1 << PWM_MOTOR_B0) | (1 << PWM_MOTOR_B1);
177
  //Set Tachoports as inputs
178
  DDR_TACHO &= ~((1 << TACHO_MOTOR_A0) | (1 << TACHO_MOTOR_A1) | (1
179
      << TACHO_MOTOR_B0) | (1 << TACHO_MOTOR_B1));
180
181
  //Configure Interrupts for Tacho
182
  GIMSK = (1 << PCIE0); //Changes on PCINT 7:0 may cause interrupt
183
  PCMSK0 = (1 << TACHO_MOTOR_A0) | (1 << TACHO_MOTOR_A1) | (1
184
      << TACHO_MOTOR_B0) | (1 << TACHO_MOTOR_B1); //Enable Tachopins for Interrupt source
185
186
187
  //Configure Timer0 as time base for milliseconds
188
  TCCR0A = (1 << WGM01); //CTC Mode
189
  TCCR0B = (1 << CS01); //clock prescaler 8
190
  OCR0A = ((F_CPU / 8) / TIMEBASE) - 1; //-1 because interrupt is performed in the next cycle
191
  TIMSK0 |= (1 << OCIE0A); //Enable Compare interrupt
192
193
  //Configure Timer 1 for Software PWM
194
  TCCR1B |= (1 << WGM12); //CTC Mode
195
  TCCR1B |= (1 << CS10); //no prescaling
196
  TIMSK1 |= (1 << OCIE1A); //Activate Interrupt
197
198
199
  //Init TWI Slave
200
  usiTwiSlaveInit(SLAVE_ADR_ATTINY_1);
201
  sei();
202
203
  uint32_t prev_time = 0;
204
  uint16_t prev_tachoA = 0;
205
  uint16_t prev_tachoB = 0;
206
207
208
  uint16_t speed_A = 0;
209
  uint16_t speed_B = 0;
210
211
  uint16_t delta_time;
212
213
  for (;;) {
214
      ATOMIC_BLOCK(ATOMIC_FORCEON)
215
      {
216
        akt_timebase = timebase;
217
        akt_tachoA = tacho_A;
218
        akt_tachoB = tacho_B;
219
      }
220
    delta_time = (uint16_t) (akt_timebase - prev_time);
221
    prev_time = akt_timebase;
222
223
    if (delta_time > 0) //to prevent div by zero
224
    {
225
      speed_A = (akt_tachoA - prev_tachoA) * 1000 / delta_time;
226
      speed_B = (akt_tachoB - prev_tachoB) * 1000 / delta_time;
227
    }
228
    prev_tachoA = akt_tachoA;
229
    prev_tachoB = akt_tachoB;
230
231
    //Write everything into the txbuffer
232
    txbuffer[0] = HIGH_BYTE(speed_A);
233
    txbuffer[1] = LOW_BYTE(speed_A);
234
    txbuffer[2] = HIGH_BYTE(tacho_A);
235
    txbuffer[3] = LOW_BYTE(tacho_A);
236
    txbuffer[4] = HIGH_BYTE(speed_B);
237
    txbuffer[5] = LOW_BYTE(speed_B);
238
    txbuffer[6] = HIGH_BYTE(tacho_B);
239
    txbuffer[7] = LOW_BYTE(tacho_B);
240
241
    //Read speed settings rxbuffer -
242
    //TODO: change to access PID controller
243
    pwm_settings[0] = rxbuffer[0];
244
    pwm_settings[1] = rxbuffer[1];
245
    pwm_settings[2] = rxbuffer[2];
246
    pwm_settings[3] = rxbuffer[3];
247
248
  }
249
250
}

von Helfer (Gast)


Lesenswert?

> Der Vollständigkeit halber muss ich aber anmerken das ich die drei
> akt_ Variablen wohl Global deklarieren muss damit innerhalb des
> Atomblocks sichtbar sind.

Musst du nicht.

von Helfer (Gast)


Lesenswert?

> Ich erwarte, grob überschlagen 3900 Interruptereignisse von meinen
> Encodern pro Sekunde bei maximaler Geschwindigkeit der Motoren. Reichen
> da für das Programm 8 MHZ Takt oder sollte ich eine schnellere
> Taktquelle anschließen.

8000000/3900 = 2051 Takte zwischen den IRQs. Deine drei ISRs zusammen 
sehen nicht so mächtig aus. Kannst du aber im Simulator ausmessen.

von Stefan H. (stefan_h16)


Lesenswert?

Helfer schrieb:
>> Der Vollständigkeit halber muss ich aber anmerken das ich die drei
>> akt_ Variablen wohl Global deklarieren muss damit innerhalb des
>> Atomblocks sichtbar sind.
>
> Musst du nicht.

Ja war mein Fehler, da haben sich andere Fehler im Quelltext zu einer 
missverstandenen Compilermeldung vermischt :)

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.