current_control.c 5.72 KB
Newer Older
Pontus Giselsson's avatar
Pontus Giselsson committed
1
2
3
4
5
6
/***************************************************************

 Current regulation - Pontus Giselsson, Per-Ola Larsson 18/02/09
           for LTH - reglerteknik

/***************************************************************
7
8
9
10
11
12
13
14
#include <avr/twi.h>
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <inttypes.h>


// control variables
Pontus Giselsson's avatar
Pontus Giselsson committed
15
16
17
18
19
20
21
22
23
24
25
26
27
volatile int16_t ref=0;        // reference value (from velocity controller)
volatile int16_t y;            // measurement, 9 frac bits
volatile uint16_t low, high;   // when reading AD-conversion
volatile int16_t e = 0;        // control error, 9 frac bits
volatile int16_t v = 0;        // temporary ctrl signal, 9 frac bits
volatile int16_t vSat = 0;     // saturated temporary ctrl signal, 9 frac bits
volatile int16_t I = 0;        // integral part of ctrl, 13 frac bits
volatile int16_t u = 0;        // ctrl signal = pwm high time (8 bits)
volatile int16_t K = 111;      // 7 frac bits
volatile int16_t Ke = 38;      // 7 frac bits, K*h/Ti
volatile int8_t intCond = 0;   // flag for conditional integration

#define V_MAX 508              //max/min for saturation
28
29
#define V_MIN -508

30
31
32
// twi variable
volatile int16_t status;

33
// logging variables
34
/*
35
36
37
38
39
40
41
42
#define log_len 100
volatile int16_t ctrl_log[log_len];
volatile int16_t error_log[log_len];
volatile int32_t I_log[log_len];
volatile int16_t skipSamples = 1000;
volatile int16_t countSamples = 0;
volatile int16_t jj=0;
volatile int8_t stop = 0;
43
44
45
46
47
48
49
50
51
52
53
54
*/

/* Routine used to transmit bytes on the serial port */
/*
static void putchar(unsigned char ch)
{
	while ((inp(UCSRA) & 0x20) == 0) {};
	outp(ch, UDR);
	while ((inp(UCSRA) & 0x20) == 0) {};
}
*/

55
/* Send logged data over Serial connection */
56
/*
57
58
59
static inline void sendData() {
  int16_t ii = 0;
  while (ii < log_len) {
60

61
62
    putchar((unsigned char) ((ctrl_log[ii]&0xff00)>>8));
    putchar((unsigned char) (ctrl_log[ii]&0x00ff));
63

64
65
66
67
68
69
70
71
72
73
74
75
    putchar((unsigned char) ((error_log[ii]&0xff00)>>8));
    putchar((unsigned char) (error_log[ii]&0x00ff));

    putchar((unsigned char) ((I_log[ii]&0xff000000)>>24));
    putchar((unsigned char) ((I_log[ii]&0x00ff0000)>>16));

    putchar((unsigned char) ((I_log[ii]&0x0000ff00)>>8));
    putchar((unsigned char) (I_log[ii]&0x000000ff));

    ii++;
  }
}
76
*/
77
78
79



80
/* Timer 2 compare match interupt, 28.8 kHz, syncronized with pwm-period */
81
SIGNAL(SIG_OUTPUT_COMPARE2) {
82

83
84
85
  // Start AD conversion
  ADCSRA |= BV(ADSC);
  
86
  // Read previous AD-conversion result
87
88
  low = inp(ADCL);
  high = inp(ADCH);
89
90
91
92
  y = ((int16_t)((high<<8) | low)) - 512; // y 9 frac bits

  // control error
  e = ref-y; // e 9 frac bits
93
  
94
  // temporary ctrl-signal
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  v = (((K*e+64)>>7)+((I+8)>>4));

  // variable that decides if I-part should be updated
  intCond = 1;

  // saturation and update integral part of ctrl with antiwindup
  if (v > V_MAX) {
    vSat = V_MAX;
    if (e > 0)
      intCond = 0;
  } else if (v < V_MIN) {
    vSat = V_MIN;
    if (e < 0)
      intCond = 0; 
109
  } else {
110
    vSat = v;
111
  }
112
113
114
115

  if (intCond)
    I = I + (((Ke*e)+(1<<2))>>3);

116
  // ctrl signal, 7 bits + direction
117
  u = ((vSat+2)>>2); //7 frac bits to pwm 
118

119
120
  // set pwm switching time
  if (u < 0) {
121
    PORTC |= 0x80;  // set direction of motion
122
    OCR1BL = ((unsigned char) (-u)); // set length of pwm-high
123
  } else {
124
125
    PORTC &= 0x7f; // set direction of motion
    OCR1BL = ((unsigned char) (u)); // set length of pwm-high
126
127
  }

128
  
129
  // TWI-communication, recieve reference from velocity controller
130
131
  if ((BV(TWINT)&inp(TWCR))) {
    status = (inp(TWSR)&0xf8);
132
    // status 0x80 means data recieved
133
    if (status == 0x80) {
134
      ref = (int16_t)((int8_t)inp(TWDR)); // read 8 bit reference
Pontus Giselsson's avatar
Pontus Giselsson committed
135
      ref = (ref<<2);  // shift up 2 steps for 10 bits reference in loop
136
137
138
139
140
141
    } 
    else {
    }
    outp(BV(TWINT)|BV(TWEN)|BV(TWEA),TWCR);
  }

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  // For logging purposes
  /*
  countSamples++;
  if (countSamples == skipSamples) {
    ctrl_log[jj] = u;
    I_log[jj] = I;
    error_log[jj] = e;
    jj++;
    countSamples = 0;
    
    // Stop after a while
    if ((jj == (log_len-1)) & !stop) {
	outp(0x7f,OCR1BL);
	stop = 1;
	sendData();
    }
  }
  */
160
  
161
162
163
164
165
}


int main()
{
166
  // clear interrupts (might not be needed)
167
168
169
  cli();
  
  //Port directions
170
171
172
  outp(0x08,PORTC); // pull up on overtemperature signals
  outp(0xa0,DDRC);  // output on direction and brake
  outp(0x10,DDRD);  // output on pwm-signal
173
174
  outp(0x40,DDRB);  // temp pwm output

175
  /* Timer section */
Pontus Giselsson's avatar
Pontus Giselsson committed
176
  // Timer 1, fast PWM no prescaling (non-inverting mode (start high, switch to low))
177
  outp(BV(COM1B1)|BV(WGM11)|BV(WGM10),TCCR1A);
178
179
  outp(BV(CS10)|BV(WGM13)|BV(WGM12),TCCR1B);
  
180
  // Reset Timer1 and set TOP-value to 128 (means 7-bit pwm-signal-> 115.2 kHz)
181
182
183
184
185
186
187
  outp(0x00,OCR1AH);
  outp(0x7f,OCR1AL);
  outp(0x00,TCNT1H);
  outp(0x00,TCNT1L);
  outp(0x00,OCR1BH);
  outp(0x7f,OCR1BL); // to not start motor-rotation before control

188

189
  
190
  /* Timer 2, 4 times pwm-period, for control sampling, prescaler 8, 28.8 kHz */
191
192
193
194
  outp(BV(WGM21)|BV(CS21),TCCR2);
  outp(0x3f,OCR2);
  /* Reset timer 2 */
  outp(0,TCNT2);
195
196
197
198

  // Enable timer2 compare match interrupts
  outp(BV(OCIE2),TIMSK);

199
200
  //Serial communication
  outp(0x00, UCSRA);	// USART:
201
  outp(0x18, UCSRB);	// USART: RxEnable|TxEnable
202
203
204
205
  outp(0x86, UCSRC);	// USART: 8bit, no parity
  outp(0x00, UBRRH);	// USART: 115200 @ 14.7456MHz
  outp(7,UBRRL);	// USART: 115200 @ 14.7456MHz
  
206
  /* AREF (AREF is 5V) pin external capacitor, MUX0 for current measurement */
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  outp(BV(REFS0)|BV(MUX0),ADMUX); 	
  
  // Enable ADC, start first conversion, prescaler 32, not free running mode
  outp(BV(ADEN)|BV(ADSC)|BV(ADPS2)|BV(ADPS0),ADCSRA);


  // Initialize TWI
  outp(0x02,TWBR);  // set SCL-frequency CPU-freq/(16+2*2)
  outp(0x02,TWAR);  // slave address
  outp(BV(TWEA)|BV(TWEN),TWCR); // enable TWI, enable ACK

  //Enable interrupts
  sei();

  // loop
  while (1) {}
}