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