root/trunk/HighVoltageController.c
| Revision 21, 19.2 kB (checked in by charlie, 3 years ago) |
|---|
| Line | |
|---|---|
| 1 | #include <math.h> |
| 2 | #include <stdint.h> |
| 3 | #include <stdlib.h> |
| 4 | #include <inttypes.h> |
| 5 | #include <avr/eeprom.h> |
| 6 | #include <avr/interrupt.h> |
| 7 | #include <avr/io.h> |
| 8 | #include <avr/pgmspace.h> |
| 9 | #include <avr/sleep.h> |
| 10 | #include <avr/wdt.h> |
| 11 | #include "RingBuffAdv/RingBuff.h" |
| 12 | |
| 13 | //#include <avr/signal.h> |
| 14 | //#include <avr/iom16.h> |
| 15 | |
| 16 | //#define MAX_THROTTLE 511 |
| 17 | //#define MIN_THROTTLE 0 |
| 18 | #define F_OSC 16000000 /* oscillator-frequency in Hz */ |
| 19 | //#define F_OSC 3686400 |
| 20 | #define UART_BAUD_RATE 19200 |
| 21 | #define UART_BAUD_CALC (((float)(F_OSC))/(((float)(UART_BAUD_RATE))*16.0)-1.0+0.5) |
| 22 | |
| 23 | |
| 24 | #define PRE_SCALED_ZERO_THROTTLE 989 // Anything bigger than 989 means 0% throttle. |
| 25 | #define PRE_SCALED_MAX_THROTTLE 683 // Anything smaller than 683 means 100% throttle. |
| 26 | #define PRE_SCALED_OPEN_CIRCUIT_THROTTLE 150 // Indicates a bad throttle. Over ?? kOhms. |
| 27 | |
| 28 | #define VREF 512 // VREF is the measurement of the current sensor at 0 volts. |
| 29 | |
| 30 | #define READY 9 |
| 31 | // Throttle Sensor connected to A/D Channel 2 (pin25 on atmega8) |
| 32 | #define THROTTLE 0 |
| 33 | // Current Sensor connected to A/D Channel 2 (pin25 on atmega8) |
| 34 | #define CURRENT 2 |
| 35 | // Temp sensor connected to A/D Channel 1 (pin24 on atmega8) |
| 36 | #define TEMPERATURE 1 |
| 37 | |
| 38 | #define KP 8l // 8 corresponds to P constant of 1/4. |
| 39 | #define KI 4l // 4 corresponds to I constant of 1/8. |
| 40 | |
| 41 | #define K1 (KP << 10) |
| 42 | #define K2 (KI - K1) |
| 43 | |
| 44 | |
| 45 | #define MAX_CURRENT 506 |
| 46 | #define THERMAL_CUTBACK_START 780 // start at 75 degC, end at 85 degC. |
| 47 | |
| 48 | #define CURRENT_ARRAY_SIZE 16 |
| 49 | |
| 50 | #define SCALE_MUL_THROTTLE 53 |
| 51 | #define SCALE_DIV_THROTTLE 5 |
| 52 | |
| 53 | // Define our IO pins and Ports |
| 54 | #define OVERCURRENT_TRIP PB0 |
| 55 | #define FLIPFLOP_RESET PB2 |
| 56 | #define IDLE_LED PD6 |
| 57 | #define MAIN_CONTACTOR PD7 |
| 58 | |
| 59 | |
| 60 | //#define MAX_THROTTLE |
| 61 | |
| 62 | // FOR CURRENT, using the LEM HASS 300, the 10 bit A/D converter outputs: |
| 63 | |
| 64 | // It makes for a range of 213. |
| 65 | // I also want the throttle to have the same range as the current. |
| 66 | // Right now, 0 throttle is 0, and max throttle is 511. |
| 67 | // I need to map the current onto 0, 511. |
| 68 | // 500 amps -----> 725 |
| 69 | // 0 amps -----> 512 |
| 70 | |
| 71 | // READ CURRENT. |
| 72 | // IT'S IN [512, 512+213] |
| 73 | // subtract 512 |
| 74 | // now its in [0, 213] |
| 75 | // times 24 |
| 76 | // divide by 10. |
| 77 | // Now it's in the range [0, 511.2] |
| 78 | |
| 79 | |
| 80 | |
| 81 | // There are 4 Analog to Digital Voltages. The input of each will range from 0 to 5v. |
| 82 | // After the A/D conversion, the value will be between 0 and 1023. |
| 83 | // 0 will mean 0 volts was measured. 1023 will mean that 5v was measured. |
| 84 | int16_t volatile throttlePos=0;// // the desired current. in [0, 255]. |
| 85 | int16_t volatile _throttlePos = 0;//*** |
| 86 | int16_t volatile tmpCurrent = 0;//*** |
| 87 | int16_t volatile tmpThrottle = 0;//*** |
| 88 | int16_t volatile tmpTemp = 0;// |
| 89 | uint8_t volatile ADCMode = READY; |
| 90 | int16_t volatile pwmDuty = 0; |
| 91 | int32_t volatile pwmDutyFine = 0;//*** |
| 92 | int16_t volatile errorNew = 0;//*** |
| 93 | int16_t volatile errorOld = 0;//*** |
| 94 | |
| 95 | |
| 96 | int16_t volatile temperature = 0; // temperature measurement. Monitor the MOSFETs with a thermistor. |
| 97 | int16_t volatile current = 0; // How much current is being used on a moment by moment basis. |
| 98 | int16_t volatile _current = 0; |
| 99 | int16_t volatile currentSum = 0; |
| 100 | |
| 101 | int16_t volatile i = 0; |
| 102 | int16_t volatile dummy = 0; |
| 103 | uint16_t volatile ISRCounter = 0; |
| 104 | |
| 105 | |
| 106 | uint8_t volatile relayLow = 1; |
| 107 | uint8_t volatile cSREG;//*** |
| 108 | |
| 109 | int16_t volatile currentPtr = 0; |
| 110 | |
| 111 | int16_t volatile currBuffer[CURRENT_ARRAY_SIZE+1]; |
| 112 | RingBuff_t txBuffer; |
| 113 | |
| 114 | void InitUSART(uint16_t ubrr) { |
| 115 | // set baud rate |
| 116 | UBRRH = (uint8_t) (ubrr>>8); |
| 117 | UBRRL = (uint8_t) ubrr; |
| 118 | |
| 119 | // Enable transmitter UART; |
| 120 | // UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE); |
| 121 | UCSRB = (1 << TXEN); |
| 122 | |
| 123 | //asynchronous 8N1 |
| 124 | UCSRC = (1 << URSEL) | (3 << UCSZ0); |
| 125 | } |
| 126 | |
| 127 | |
| 128 | |
| 129 | // Initialize the Pulse Width Modulator timer. |
| 130 | // Let's use timer 1, the 16 bit timer. The others are 8 bit. |
| 131 | // 1. Select the bits that you want set in TCCR1A. See pg. 98 for help with this. |
| 132 | // 2. Set the speed of your pwm by setting the bits you want in TCCR1B. See pg. 100. |
| 133 | // 3. Enable Pin B1 as the output for the pwm signal that you made. See pg. 97. |
| 134 | // 4. Initialize the value of the pwm to 0. (may not be necessary) |
| 135 | |
| 136 | // *TESTED PREVIOUSLY* |
| 137 | void InitPWM (void) |
| 138 | { |
| 139 | // We are using Mode 2 which is phase correct PWM |
| 140 | // The TCNT1 starts at BOTTOM (0) and starts counting to TOP. When it reaches TOP, the counter counts back to BOTTOM |
| 141 | // When it reaches BOTTOM, it will trigger the Timer1 Overflow interrupt (see the ISR code further down) |
| 142 | // For the PWM, as TCNT1 is increasing and it matches OCR1A it will set the OC1A I/O pin to 0 |
| 143 | // as TCNT1 is decreasing and it matches OCR1A it will set the OC1A I/O pin to 1 |
| 144 | TCCR1A = _BV(COM1A1) | _BV(WGM11); // set COM1A1 and WGM11 |
| 145 | |
| 146 | // Tclk = Fosc = 16MHz |
| 147 | // Tclk/1024 (from 0 to 511 and then 511 back to 0) = 16KHz freq for the Toverflow ISR |
| 148 | TCCR1B = _BV(CS10); // pg. 100. Pre-scaler = 1. |
| 149 | |
| 150 | // Enable OC1A (the Output Compare Match A Output Pin) as the output pin of the PWM at pin B1. |
| 151 | // DDRB (Port B Data Direction Register) bit 1 must be set to 1 to make Pin B1 act as the |
| 152 | // Output Pin for the PWM. |
| 153 | // On reset all pins are set to 0 or output |
| 154 | PORTB &= ~_BV(PB1); // this sets PB1 (the pwm output) to 0 at startup |
| 155 | DDRB = _BV(PB1); // Enable pin b1 to act as an output. Pg. 52. |
| 156 | |
| 157 | // OCR1A is the throttle value. |
| 158 | // Set Initial PWM duty value to 0, both high and low bytes. |
| 159 | OCR1A = 0; |
| 160 | } |
| 161 | |
| 162 | // This initializes the analog to digital converter. |
| 163 | // 1. Enable the converter by setting the ADEN bit in ADCSRA |
| 164 | // 2. Choose the sample speed, by messing with ADPS0, ADPS1, and ADPS2. |
| 165 | // 3. Choose what voltage you want the converter to view as the highest. The lowest will be 0. |
| 166 | // To do that, you must mess with the REFS bits in the ADMUX register. |
| 167 | // 4. Choose which A/D channel you want to use by messing with the MUX bits in ADMUX register. |
| 168 | // 5. To start a conversion, you must set the ADSC bit in the ADCSRA. Then you have to wait |
| 169 | // for it to finish. The result is in the ADC data register, so save it in some variable. |
| 170 | |
| 171 | // *TESTED PREVIOUSLY* |
| 172 | void InitADC(void) { |
| 173 | ADCSRA = _BV(ADEN); // Enable the analog to digital converter. |
| 174 | ADCSRA |= _BV(ADPS2); // pg. 208. How fast to sample ADC? 16MHz/16 |
| 175 | ADMUX = _BV(REFS0); // Use AVcc as the reference voltage for the ADC, pg. 206 |
| 176 | } |
| 177 | |
| 178 | |
| 179 | // This checks the Analog to Digital Converter Throttle input. |
| 180 | // 1. Choose which ADC channel (which pin on the chip) you want to convert the voltage of. Pg. 206. |
| 181 | // 2. Set the ADSC bit to 1. This starts the conversion. |
| 182 | // 3. Wait for the conversion to finish. (Do nothing until it's done) |
| 183 | // 4. The result is saved in ADC. Move that result to a variable for later. |
| 184 | |
| 185 | void ReadThrottle(void) { |
| 186 | throttlePos = ADC; |
| 187 | |
| 188 | // zero throttle is 989 OR GREATER. That's a 10% dead zone. |
| 189 | // Full throttle is 683 |
| 190 | |
| 191 | // if (throttlePos < PRE_SCALED_OPEN_CIRCUIT_THROTTLE) { // Bad Throttle! More than ??kOhms from a 5k pot! |
| 192 | // throttlePos = 0; |
| 193 | // for (i = 0; i < 16; i++) { |
| 194 | // ADCSRA |= 64; // 64 = 01000000. So, this sets the ADSC Start Conversion Bit. |
| 195 | // while (ADCSRA & 64); // Do nothing until the conversion is done. |
| 196 | // dummy = ADC; |
| 197 | // throttlePos += dummy; |
| 198 | // } |
| 199 | // throttlePos >>= 4; // find the average of the 16 throttle reads, to make sure it wasn't just a bad read. |
| 200 | // if (throttlePos < PRE_SCALED_OPEN_CIRCUIT_THROTTLE) { // if the average of 16 throttle reads was bad... |
| 201 | // OCR1A = 0; // make sure PWM duty is 0. Kill the throttle. |
| 202 | // while (1) { |
| 203 | // wdt_reset(); // get a new dang throttle! hahaha! |
| 204 | // don't let the watchdog reset the program. |
| 205 | // } |
| 206 | // } |
| 207 | // } |
| 208 | |
| 209 | if (throttlePos < PRE_SCALED_MAX_THROTTLE) // 683 is max throttle this time. |
| 210 | throttlePos = PRE_SCALED_MAX_THROTTLE; // 683 |
| 211 | |
| 212 | |
| 213 | if (throttlePos > PRE_SCALED_ZERO_THROTTLE) // 989, allowing for 10% dead zone. |
| 214 | throttlePos = PRE_SCALED_ZERO_THROTTLE; // 989. |
| 215 | |
| 216 | throttlePos -= PRE_SCALED_MAX_THROTTLE; |
| 217 | // Now throttlePos is in [0, 306]. |
| 218 | throttlePos = (PRE_SCALED_ZERO_THROTTLE - PRE_SCALED_MAX_THROTTLE) - throttlePos; |
| 219 | // Now, 0 throttle is 0, and max throttle is 306. |
| 220 | // |
| 221 | //throttlePos *= 1.66; |
| 222 | // do throttlePos*53/32. |
| 223 | throttlePos *= SCALE_MUL_THROTTLE; // multiply by SCALE_MUL_THROTTLE |
| 224 | throttlePos >>= SCALE_DIV_THROTTLE; // divide by SCALE_DIV_THROTTLE |
| 225 | // now throttlePos is in [0, 507], about identical to current range. |
| 226 | // this is important because the PWM range is 0 to 511, where 0 means 0% duty, and 511 means 100% duty. |
| 227 | } |
| 228 | |
| 229 | // *TESTED IN SIMULATOR* |
| 230 | void ReadCurrent(void) { |
| 231 | current = ADC; |
| 232 | |
| 233 | // Current starts in [512, 512 + 213] (if it's in 0 to 500 amps for the LEM 300) |
| 234 | // vRef is defined at the top. It is the calibrated "0" value. |
| 235 | if (current < VREF) // if slightly below 0, just call it 0. |
| 236 | current = VREF; |
| 237 | current -= VREF; |
| 238 | // now, for the LEM 500, it's in the range [0,128]. |
| 239 | currentSum -= currBuffer[currentPtr]; |
| 240 | currBuffer[currentPtr] = current; |
| 241 | currentSum += current; |
| 242 | _current = currentSum >> 2; // "divide by 16, multiply by 4" = divide by 4 |
| 243 | if (currentPtr == CURRENT_ARRAY_SIZE - 1) |
| 244 | currentPtr = 0; |
| 245 | else |
| 246 | currentPtr++; |
| 247 | //_current is average current |
| 248 | } |
| 249 | |
| 250 | // *TESTED PREVIOUSLY* |
| 251 | |
| 252 | //void ReadTemperature(void) { |
| 253 | // ADMUX &= (0b11110000); // This sets MUX to 0000, and leaves the top 4 bits unchanged. |
| 254 | // pg. 206 |
| 255 | // I'd like to suggest defining a TEMPERATURE at the top |
| 256 | // ADMUX |= TEMPERATURE; // TEMPERATURE, the temperature monitor. |
| 257 | |
| 258 | // Read temperature. |
| 259 | // Pg. 198. |
| 260 | //ADCSRA |= 64; // 64 = 01000000. So, this sets the ADSC Start Conversion Bit. |
| 261 | // ADCSRA |= _BV(ADSC); // Start Conversion |
| 262 | // while (ADCSRA & 64); // Do nothing until the conversion is done. |
| 263 | // temperature = ADC; |
| 264 | //} |
| 265 | |
| 266 | // *TESTED PREVIOUSLY* |
| 267 | |
| 268 | void HighPedalLockout(void) { |
| 269 | // pwmDuty = 0; |
| 270 | OCR1A = 0; |
| 271 | do { |
| 272 | // Select channel 0. |
| 273 | ADMUX &= (0b11110000); // = 11110000. So, this sets MUX to 0000, and leaves the top 4 bits unchanged. |
| 274 | // pg. 206 |
| 275 | |
| 276 | // Read throttle position. |
| 277 | // Pg. 198. |
| 278 | |
| 279 | ADCSRA |= _BV(ADSC); // Start Conversion |
| 280 | while (ADCSRA & 64); // Do nothing until the conversion is done. |
| 281 | throttlePos = ADC; |
| 282 | |
| 283 | wdt_reset(); |
| 284 | } while (throttlePos < PRE_SCALED_ZERO_THROTTLE); // I'm not doing all the rescaling and shifting for this part. |
| 285 | throttlePos = 0; |
| 286 | } |
| 287 | |
| 288 | // At 8 MHz, a 'for' loop of 100 iterations takes 280 microseconds according to the debugging simulator. |
| 289 | // To call the function takes 4.6 microseconds. |
| 290 | // So, a delay of 21 is about one PWM period. 2 nand gates in series need 1 microsecond to change |
| 291 | // their state, so at least a delay of 1 is fine for resetting the flip flop. |
| 292 | |
| 293 | // It is important to have Optimization turned off in Configuration Options. |
| 294 | // The optimizations don't let you do a loop for no reason. |
| 295 | // *TESTED IN SIMULATOR* |
| 296 | // watch out for the watchdog timeout if you use too large of a delay. |
| 297 | |
| 298 | // http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html |
| 299 | void Delay(int k) { |
| 300 | // int m; |
| 301 | int volatile m; |
| 302 | for (m = 0; m < k; m++); |
| 303 | return; |
| 304 | } |
| 305 | |
| 306 | void BigDelay(int k) { |
| 307 | int m, n; |
| 308 | |
| 309 | for (m = 0; m < k; m++) { |
| 310 | for (n = 0; n < 1000; n++); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | // This checks for and deals with an overcurrent event. If there is an overcurrent event, |
| 315 | // it clears the overcurrent event by pulsing port b2 low for a moment, which resets the hardware flip-flop. |
| 316 | |
| 317 | // *TESTED IN SIMULATOR* |
| 318 | |
| 319 | void ResetOverCurrentEvent() { |
| 320 | // for things configured as inputs, to read the value of the input, you read pinb, not portb! |
| 321 | // TO SET VALUES, YOU MUST USE PORTB, NOT PINB! |
| 322 | |
| 323 | // if pin b0 is 1, then an overcurrent event has occurred. |
| 324 | // if (PINB & 1) { // clear overcurrent event. |
| 325 | if (PINB & _BV(OVERCURRENT_TRIP)) { // clear overcurrent event. |
| 326 | // At this point, portb2 is high. It was initialized high at the beginning. |
| 327 | // clear the overcurrent event. Bring port b2 low... |
| 328 | PORTB &= ~_BV(FLIPFLOP_RESET); // Clear FLIPFLOP aka &= 11111011b |
| 329 | Delay(2); |
| 330 | // Now bring port b2 high again... This clears the overcurrent event. |
| 331 | PORTB |= _BV(FLIPFLOP_RESET); // Reset FLIPFLOP |
| 332 | pwmDuty--; |
| 333 | if (pwmDuty < 0) |
| 334 | pwmDuty = 0; |
| 335 | // pwmDutyFine -= (1 << 15); |
| 336 | // if (pwmDutyFine < 0) |
| 337 | // pwmDutyFine = 0; |
| 338 | // OCR1A = (pwmDutyFine >> 15); |
| 339 | } |
| 340 | return; |
| 341 | } |
| 342 | |
| 343 | |
| 344 | ISR (ADC_vect) { |
| 345 | if (ADCMode == CURRENT) { |
| 346 | //current=ADC; |
| 347 | ReadCurrent(); |
| 348 | } |
| 349 | |
| 350 | else if (ADCMode==THROTTLE) { |
| 351 | //throttlePos=ADC; |
| 352 | ReadThrottle(); |
| 353 | } |
| 354 | // else { // it's temperature |
| 355 | // temperature=ADC; |
| 356 | // } |
| 357 | ADCMode=READY; //signify that we are ready for another reading |
| 358 | } |
| 359 | |
| 360 | // Based on the setting in the Timer1 InitPWM() function this ISR will be called at ~16KHz |
| 361 | ISR (TIMER1_OVF_vect) { |
| 362 | ResetOverCurrentEvent(); // Maybe turn on after 'n' cycles of being off, |
| 363 | // where n is a function of PWM duty? |
| 364 | |
| 365 | if (ADCMode==READY) { //wait for last adc request to finish |
| 366 | ISRCounter++; |
| 367 | ADCMode = CURRENT; // This is the default |
| 368 | |
| 369 | // if ((ISRCounter & 32767) == 32767) { // 32767 = 0b0111111111111111. This happens every 2 seconds. |
| 370 | // ADCMode=TEMPERATURE; |
| 371 | // ISRCounter = 0; |
| 372 | // } |
| 373 | |
| 374 | if ((ISRCounter & 15) == 15) // 15 = 0b1111. |
| 375 | ADCMode = THROTTLE; |
| 376 | |
| 377 | ADMUX &= 0b11110000; // zero out the MUX |
| 378 | ADMUX |= ADCMode; //select channel |
| 379 | ADCSRA |= 64;//start adc conversion |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | |
| 384 | ISR (TIMER2_OVF_vect) { |
| 385 | //place 8 bit values in the tx FIFO |
| 386 | Buffer_StoreElement(&txBuffer, (uint8_t) (tmpThrottle >>8)); // Store value for throttleH into ringbuff |
| 387 | Buffer_StoreElement(&txBuffer, (uint8_t) tmpThrottle); // Store value for throttleL into ringbuff |
| 388 | Buffer_StoreElement(&txBuffer, (uint8_t) (tmpCurrent >>8)); // Store value for currentH into ringbuff |
| 389 | Buffer_StoreElement(&txBuffer, (uint8_t) tmpCurrent); // Store value for currentL into ringbuff |
| 390 | Buffer_StoreElement(&txBuffer, (uint8_t) (pwmDuty >>8)); // Store value for currentH into ringbuff |
| 391 | Buffer_StoreElement(&txBuffer, (uint8_t) pwmDuty); // Store value for currentL into ringbuff |
| 392 | Buffer_StoreElement(&txBuffer, (uint8_t) 0xF0); // Sync Byte |
| 393 | Buffer_StoreElement(&txBuffer, (uint8_t) 0xFF); // Sync Byte |
| 394 | |
| 395 | |
| 396 | //enable USART "TX buffer empty" interrupt |
| 397 | UCSRB |= _BV(UDRIE); |
| 398 | } |
| 399 | |
| 400 | |
| 401 | // *TESTED IN SIMULATOR* |
| 402 | // Pin b0 is going to be a flag to let the controller know that the hardware shut off the mosfets. |
| 403 | // Pin b0 is 0 if the hardware has not shut off the mosfets. If you read the value of pin b0 is |
| 404 | // 1, then a hardware overcurrent shutdown has occurred. You then have a delay, and clear the |
| 405 | // hardware overcurrent event by changing port b2 from 1 to 0, and then back to 1. |
| 406 | // First pin b0 needs to be initialized as an input and pin b2 initialized as an output. |
| 407 | |
| 408 | // *TESTED IN SIMULATOR* |
| 409 | void InitializeIOPins(void) { |
| 410 | |
| 411 | //DDRB |= 4; // Configure PINB2 as output |
| 412 | DDRB |= _BV(FLIPFLOP_RESET); // Configure PINB2 as output |
| 413 | // The stupid documentation says this next step might be necessary. See pg. 52. |
| 414 | PORTB &= ~_BV(FLIPFLOP_RESET); // Clear only B2 aka &= 11111011b |
| 415 | |
| 416 | // Pulsing pin b2 low for a moment guarantees that the state of the flip flop in the hardware overcurrent |
| 417 | // shutdown circuit is known. |
| 418 | PORTB |= _BV(FLIPFLOP_RESET); // Reset FLIPFLOP_RESET |
| 419 | Delay(5); |
| 420 | PORTB &= ~_BV(FLIPFLOP_RESET); // Clear FLIPFLOP_RESET aka &= 11111011b |
| 421 | Delay(5); |
| 422 | PORTB |= _BV(FLIPFLOP_RESET); // RESET FLIPFLOP_RESET |
| 423 | |
| 424 | DDRD |= _BV(MAIN_CONTACTOR); // configure pin MAIN_CONTACTOR for output. It is a relay that turns on the main contactor. |
| 425 | DDRD |= _BV(IDLE_LED); // configure pin IDLE_LED for output. It is the IDLE LED. Pulse it every second for Chris. |
| 426 | |
| 427 | // Now configure pin b0 as an input pin. It will be the indicator of when a hardware overcurrent |
| 428 | // shutdown has occurred. Reading a 0 from this pin means there has NOT been an |
| 429 | // overcurrent shutdown, so everything is working normally. Reading a 1 from this pin means |
| 430 | // that an overcurrent shutdown has happened. So, output a trip reset at port b2 to turn the mosfet driver back on. |
| 431 | |
| 432 | // setting DDRB bit 'n' to 0 makes that bit configured for input. |
| 433 | DDRB &= ~_BV(PB0); // DDRB = XXXXXXX0 Configure PINB0 as input. |
| 434 | PORTB |= _BV(PB0); // Maybe unnecessary intermediate step. See page 52. |
| 435 | PORTB &= ~_BV(PB0); // PORTB = XXXXXXX0 Turn off the pull-up resistor at pin b0. |
| 436 | return; |
| 437 | } |
| 438 | |
| 439 | |
| 440 | |
| 441 | ISR (USART_UDRE_vect) { |
| 442 | if (txBuffer.Elements > 0) { |
| 443 | UDR = Buffer_GetElement(&txBuffer); //place data for transmission |
| 444 | //UDR = txBuffer.Elements; |
| 445 | } |
| 446 | else |
| 447 | UCSRB &= ~_BV(UDRIE); //disable interrupt |
| 448 | } |
| 449 | |
| 450 | |
| 451 | int main (void) { |
| 452 | InitADC(); // initialize the analog to digital converter |
| 453 | InitializeIOPins(); // pin b0 acts as an input, pin b2 acts as an output. |
| 454 | InitUSART(UART_BAUD_CALC); |
| 455 | Buffer_Initialize(&txBuffer); // Init buffer (also clears/flushes/resets) |
| 456 | |
| 457 | wdt_enable(WDTO_2S); |
| 458 | |
| 459 | for (currentPtr = 0; currentPtr < CURRENT_ARRAY_SIZE; currentPtr++) |
| 460 | currBuffer[currentPtr] = 0; |
| 461 | currentPtr = 0; |
| 462 | |
| 463 | HighPedalLockout(); |
| 464 | InitPWM(); |
| 465 | |
| 466 | // Finally, enable interrupts for the timer and the A/D converter. It causes problems if you |
| 467 | // enable them too early. |
| 468 | ADCSRA |= _BV(ADIE); // Enable an interrupt to happen each time an A/D conversion is finished. |
| 469 | // Enable Timer1 Overflow Interrupt |
| 470 | TIMSK = _BV(TOIE1) | _BV(TOIE2); // make an interrupt happen each time the timer reaches the bottom. |
| 471 | TCCR2 = _BV(CS22) | _BV(CS21) | _BV(CS20); |
| 472 | |
| 473 | sei(); // Enable interrupts |
| 474 | |
| 475 | while (1) { // do this forever |
| 476 | cSREG = SREG; /* store SREG value */ |
| 477 | cli(); // disable interrupts |
| 478 | |
| 479 | tmpTemp = temperature; |
| 480 | tmpCurrent = _current; |
| 481 | tmpThrottle = throttlePos; |
| 482 | SREG = cSREG; |
| 483 | |
| 484 | |
| 485 | |
| 486 | _throttlePos = tmpThrottle; |
| 487 | |
| 488 | // The temperature is an input from the A/D converter. It is in the range of 0 to 1023. |
| 489 | // These numbers are specific to the Thermistor Part# B57862S103F40 from Digikey. |
| 490 | |
| 491 | // 25 degC 327 |
| 492 | // 30 degC 377 |
| 493 | // 35 degC 429 |
| 494 | // 40 degC 480 |
| 495 | // 45 degC 537 |
| 496 | // 50 degC 580 |
| 497 | // 55 degC 626 |
| 498 | // 60 degC 670 |
| 499 | // 65 degC 710 |
| 500 | // 70 degC 746 |
| 501 | // 75 degC 779 |
| 502 | // 80 degC 808 |
| 503 | // 85 degC 834 |
| 504 | // 90 degC 857 |
| 505 | // 95 degC 877 |
| 506 | // 100 degC 895 |
| 507 | |
| 508 | // This shifts the current limit down based on how hot the controller is. |
| 509 | // If the temperature is about 70 degC, the current limit is 437 amps. |
| 510 | // If the temperature is about 75 degC, the current limit is about 250 amps. |
| 511 | // At around 80 degC, the current limit is 0. |
| 512 | /* |
| 513 | if (tmpTemp > THERMAL_CUTBACK_START) { // start of thermal cutback. |
| 514 | if (tmpTemp < THERMAL_CUTBACK_START+8) // _throttlePos = 7/8*tmpThrottle. |
| 515 | _throttlePos = (7*tmpThrottle) >> 3; |
| 516 | |
| 517 | else if (tmpTemp < THERMAL_CUTBACK_START + 16) // _throttlePos = 6/8*tmpThrottle; |
| 518 | _throttlePos = (6*tmpThrottle) >> 3; |
| 519 | |
| 520 | else if (tmpTemp < THERMAL_CUTBACK_START + 24) // = 5/8*tmpThrottle; |
| 521 | _throttlePos = (5*tmpThrottle) >> 3; |
| 522 | |
| 523 | else if (tmpTemp < THERMAL_CUTBACK_START + 32) // = 4/8*tmpThrottle; |
| 524 | _throttlePos = tmpThrottle >> 1; |
| 525 | |
| 526 | else if (tmpTemp < THERMAL_CUTBACK_START + 40) // = 3/8*tmpThrottle; |
| 527 | _throttlePos = 3*(tmpThrottle >> 3); |
| 528 | |
| 529 | else if (tmpTemp < THERMAL_CUTBACK_START + 48) // = 2/8*tmpThrottle; |
| 530 | _throttlePos = tmpThrottle >> 2; |
| 531 | |
| 532 | else if (tmpTemp < THERMAL_CUTBACK_START + 56) // = 1/8*tmpThrottle; |
| 533 | _throttlePos = tmpThrottle >> 3; |
| 534 | |
| 535 | else |
| 536 | _throttlePos = 0; |
| 537 | } |
| 538 | */ |
| 539 | // errorNew = _throttlePos - tmpCurrent; |
| 540 | // pwmDutyFine += (((int32_t)(errorNew - errorOld)) << 13) + (int32_t)(errorOld << 2); |
| 541 | // pwmDutyFine += K1*errorNew + K2*errorOld; |
| 542 | // errorOld = errorNew; |
| 543 | |
| 544 | |
| 545 | if (pwmDuty < _throttlePos) |
| 546 | pwmDuty++; |
| 547 | else if (pwmDuty > _throttlePos) |
| 548 | pwmDuty--; |
| 549 | // if (pwmDutyFine > (511l << 15)) |
| 550 | // pwmDutyFine = (511l << 15); |
| 551 | // else if (pwmDutyFine < 0l) |
| 552 | // pwmDutyFine = 0l; |
| 553 | |
| 554 | //pwmDuty = (int16_t)(pwmDutyFine >> 15); |
| 555 | |
| 556 | OCR1A = pwmDuty; |
| 557 | wdt_reset(); |
| 558 | } |
| 559 | return (0); |
| 560 | } |
Note: See TracBrowser for help on using the browser.
