This code is from project: "The" PCB Laminator
Files: pid.h and pid.c was downloaded from: AVR221 - PID controller Documentation
pid.h
/*This file has been prepared for Doxygen automatic documentation generation.*/ #ifndef PID_H #define PID_H // #include "stdint.h" #include <stdint.h> #define SCALING_FACTOR 128 typedef struct PID_DATA{ int16_t lastProcessValue; int32_t sumError; int16_t P_Factor; int16_t I_Factor; int16_t D_Factor; int16_t maxError; int32_t maxSumError; } pidData_t; // Maximum value of variables #define MAX_INT INT16_MAX #define MAX_LONG INT32_MAX #define MAX_I_TERM (MAX_LONG / 2) // Boolean values #define FALSE 0 #define TRUE 1 void pid_Init(int16_t p_factor, int16_t i_factor, int16_t d_factor, struct PID_DATA *pid); int16_t pid_Controller(int16_t setPoint, int16_t processValue, struct PID_DATA *pid_st); void pid_Reset_Integrator(pidData_t *pid_st); #endif
pid.c
/*This file has been prepared for Doxygen automatic documentation generation.*/ #include "pid.h" // #include "stdint.h" void pid_Init(int16_t p_factor, int16_t i_factor, int16_t d_factor, struct PID_DATA *pid) // Set up PID controller parameters { // Start values for PID controller pid->sumError = 0; pid->lastProcessValue = 0; // Tuning constants for PID loop pid->P_Factor = p_factor; pid->I_Factor = i_factor; pid->D_Factor = d_factor; // Limits to avoid overflow pid->maxError = MAX_INT / (pid->P_Factor + 1); pid->maxSumError = MAX_I_TERM / (pid->I_Factor + 1); } int16_t pid_Controller(int16_t setPoint, int16_t processValue, struct PID_DATA *pid_st) { int16_t error, p_term, d_term; int32_t i_term, ret, temp; error = setPoint - processValue; // Calculate Pterm and limit error overflow if (error > pid_st->maxError){ p_term = MAX_INT; } else if (error < -pid_st->maxError){ p_term = -MAX_INT; } else{ p_term = pid_st->P_Factor * error; } // Calculate Iterm and limit integral runaway temp = pid_st->sumError + error; if(temp > pid_st->maxSumError){ i_term = MAX_I_TERM; pid_st->sumError = pid_st->maxSumError; } else if(temp < -pid_st->maxSumError){ i_term = -MAX_I_TERM; pid_st->sumError = -pid_st->maxSumError; } else{ pid_st->sumError = temp; i_term = pid_st->I_Factor * pid_st->sumError; } // Calculate Dterm d_term = pid_st->D_Factor * (pid_st->lastProcessValue - processValue); pid_st->lastProcessValue = processValue; ret = (p_term + i_term + d_term) / SCALING_FACTOR; if(ret > MAX_INT){ ret = MAX_INT; } else if(ret < -MAX_INT){ ret = -MAX_INT; } return((int16_t)ret); } void pid_Reset_Integrator(pidData_t *pid_st) { pid_st->sumError = 0; }
main.h
#ifndef _H_MAIN_ #define _H_MAIN_ #define F_CPU 1000000L #define H(a,b) a |=(1<<(b)) #define L(a,b) a &=~(1<<(b)) #define IS(a,b) bit_is_set(a,b) #define BS(a,b) (a & (1<<(b))) #endif #ifndef F_CPU #error CPU speed unknown #endif
main.c
#include "main.h" #include "delay.h" #include "pid.h" #include <avr/interrupt.h> #define Dec2Bcd(dec) (((dec / 10) << 4) + (dec % 10)) uint8_t heat_off_flag = 0; uint8_t desired_temp = 90; uint8_t show_desired_temp = 0; uint8_t reset = 1; uint8_t digits[3]; void led_set(uint8_t n) { digits[0] = (n / 100); n-= (digits[0] * 100); digits[1] = (n / 10); n-= (digits[1] * 10); digits[2] = n; digits[0] = Dec2Bcd(digits[0]); digits[1] = Dec2Bcd(digits[1]); digits[2] = Dec2Bcd(digits[2]); } void led_off() { L(PORTB, PB7); L(PORTB, PB6); L(PORTD, PD4); } // led driver SIGNAL(TIMER0_OVF_vect) { static uint8_t i; switch(i) { case 0: H(PORTD, PD4); L(PORTB, PB6); L(PORTB, PB7); break; case 1: L(PORTD, PD4); H(PORTB, PB6); L(PORTB, PB7); break; case 2: L(PORTD, PD4); L(PORTB, PB6); H(PORTB, PB7); break; case 3: L(PORTD, PD4); L(PORTB, PB6); L(PORTB, PB7); i = 0; return; default: break; }; if IS(digits[i], 0) H(PORTC, PC2); else L(PORTC, PC2); if IS(digits[i], 1) H(PORTC, PC5); else L(PORTC, PC5); if IS(digits[i], 2) H(PORTC, PC4); else L(PORTC, PC4); if IS(digits[i], 3) H(PORTC, PC3); else L(PORTC, PC3); i++; } void spi_enable() { L(PORTB, PB2); } void spi_disable() { H(PORTB, PB2); } void spi_init() { spi_disable(); SPSR = (1<<SPI2X); SPCR = (1<<SPE) | (1<<MSTR); } uint8_t spi_write(uint8_t data) { SPDR = data; while(!(SPSR & (1 << SPIF))); return SPDR; } uint16_t get_temp() { uint16_t t = 0; uint8_t data[4]; data[3] = 0; data[2] = 0; data[1] = 0; data[0] = 0; spi_enable(); data[3] = spi_write(0); data[2] = spi_write(0); data[1] = spi_write(0); data[0] = spi_write(0); // 31 23 15 // xxxxxxxx xxxxxxxx xxxxxxxx t = ((data[3] << 8) | data[2]) ; if (!(IS(data[2], 0))) { t = t >> 4; } else { t = 255; } spi_disable(); return t; } // heater int16_t cycles = 0; SIGNAL(TIMER2_OVF_vect) { static uint16_t f; if(f == 0 && cycles != 0) { L(PORTD, PD0); } if(f >= cycles * 10) { H(PORTD, PD0); } if(++f == (38 * 10)) f = 0; } SIGNAL(INT0_vect) { L(GICR, INT0); led_off(); heat_off_flag = 1; } SIGNAL(INT1_vect) { H(GICR, INT0); L(GICR, INT1); led_off(); show_desired_temp = 1; reset = 1; if (heat_off_flag) { H(TIMSK, TOIE0); heat_off_flag = 0; } else switch(desired_temp) { case 90: desired_temp = 125; break; case 125: desired_temp = 150; break; case 150: desired_temp = 160; break; case 160: desired_temp = 170; break; case 170: desired_temp = 175; break; case 175: desired_temp = 180; break; case 180: desired_temp = 90; break; }; led_set(desired_temp); } /****************************************************************************/ /* */ /****************************************************************************/ int main() { // BCD driver H(DDRC, PC2); H(DDRC, PC3); H(DDRC, PC4); H(DDRC, PC5); H(PORTC, PC2); H(PORTC, PC3); H(PORTC, PC4); H(PORTC, PC5); // Miultiplexer H(DDRB, PB6); H(DDRB, PB7); H(DDRD, PD4); L(PORTB, PB6); L(PORTB, PB7); L(PORTD, PD4); H(TCCR0, CS01); H(TIMSK, TOIE0); // Buttons L(DDRD, PD2); L(DDRD, PD3); H(PORTD, PD2); H(PORTD, PD3); L(MCUCR, ISC01); L(MCUCR, ISC00); L(MCUCR, ISC11); L(MCUCR, ISC10); H(GICR, INT0); H(GICR, INT1); // Heater H(DDRD, PD0); H(PORTD, PD0); H(TCCR2, CS21); H(TIMSK, TOIE2); sei(); // SPI H(DDRB, PB5); // sck H(DDRB, PB2); // ss L(DDRB, PB4); // so spi_init(); led_set(0); uint16_t pid_ret = 0; uint8_t current_temp = 0; struct PID_DATA pd; pid_Init(150, 1, 0, &pd); while(1) { current_temp = get_temp(); if (show_desired_temp) { show_desired_temp = 0; delay_ms(400); H(GICR, INT1); continue; } else led_set(current_temp); if (heat_off_flag) { cycles = 0; L(TIMSK, TOIE0); led_off(); delay_ms(500); H(TIMSK, TOIE0); delay_ms(500); continue; } else H(TIMSK, TOIE0); if ((current_temp > desired_temp - 20) && reset) { reset = 0; pid_Reset_Integrator(&pd); } pid_ret = pid_Controller(desired_temp, current_temp, &pd); if (pid_ret >= 0) { if (pid_ret > 38) pid_ret = 38; cycles = pid_ret; } else { cycles = 0; while(pid_ret++) delay_ms(100); } delay_ms(500); } }
delay.h
#ifndef _H_DELAY_H #define _H_DELAY_H #include "main.h" #include <util/delay.h> #define nop() __asm__ __volatile__("nop") void delay_ms(unsigned short ms); void delay_us(unsigned short us); #endif
delay.c
#include "delay.h" void delay_ms(unsigned short ms) { while ( ms ) { ms--; _delay_ms(1); } } void delay_us(unsigned short us) { while ( us ) { us--; _delay_us(1); } }
Makefile
CPU=atmega8 GCC=avr-gcc CFLAGS= -Os -mmcu=$(CPU) -Wall -fpack-struct -fshort-enums -funsigned-bitfields -Wl,--relax -fno-move-loop-invariants -funsigned-char -fno-inline-small-functions -fdata-sections -fno-tree-loop-optimize -lprintf_min INCLUDES= LIBS= OBJCPY=avr-objcopy OBJECTS=main.o delay.o pid.o PROJECT_NAME=mega8 HEX_FILE=$(PROJECT_NAME).hex HEX_FILE_DUMP=$(PROJECT_NAME)_dump.hex PROG=avrdude PROG_FLAGS=-V -c usbasp -p $(CPU) all: $(MAKE) cls $(MAKE) $(PROJECT_NAME) $(MAKE) obj $(MAKE) size #upload $(PROJECT_NAME): $(OBJECTS) $(GCC) -o $(PROJECT_NAME) $(OBJECTS) $(CFLAGS) $(LIBS) $(INCLUDES) main.o: main.c main.h $(GCC) $(CFLAGS) $(INCLUDES) -c main.c delay.o: delay.c delay.h $(GCC) $(CFLAGS) $(INCLUDES) -c delay.c pid.o: pid.c pid.h $(GCC) $(CFLAGS) $(INCLUDES) -c pid.c obj: $(OBJECTS) $(OBJCPY) -O ihex $(PROJECT_NAME) $(HEX_FILE) clean: rm -f $(PROJECT_NAME) $(OBJECTS) $(HEX_FILE) cls: clear size: du -b $(HEX_FILE) upload: $(MAKE) all $(MAKE) $(HEX_FILE) $(PROG) $(PROG_FLAGS) -e -U flash:w:$(HEX_FILE) download: $(PROG) $(PROG_FLAGS) -U flash:r:$(HEX_FILE_DUMP)
No comments:
Post a Comment