Compare commits

...

3 Commits

Author SHA1 Message Date
Eggert Jung 2c707929a2 pid files 4 years ago
Eggert Jung bfdd4210e1 menu layout 4 years ago
Eggert Jung f85971e49b integrate pid
2nd and 3rd channel can be coupled via percentage
4 years ago

@ -15,7 +15,7 @@
#define SDA_PIN PC4 //PIN am Atmel
#define SCL_PIN PC5 //PIN am Atmel
#define I2C_PORT PORTC //PORT am Atmel
#define SCL_CLOCK 100000UL
#define SCL_CLOCK 40000UL
void i2c_init(void);
uint8_t i2c_start (uint8_t);
@ -23,4 +23,4 @@
uint8_t i2c_readNak(void);
void i2c_stop (void);
#endif /* I2C_H_ */
#endif /* I2C_H_ */

@ -107,6 +107,7 @@ void lcd_init() {
lcd_nibble_out(0x0C, 0);
lcd_clear();
lcd_cursor(0);
}
//***************************************************************************************

151
main.c

@ -14,18 +14,38 @@
#include "modbus.h"
#include "menu.h"
#include "adc.h"
#include "pid.h"
#define COIL1 1<<1
#define COIL2 1<<0
#define COIL3 1<<2
#define COIL4 1<<3
volatile uint16_t holdingRegisters[10];
volatile uint16_t temp_values[4];
volatile uint16_t temp_setpoints[4];
volatile uint16_t output;
volatile struct pid controller;
volatile uint32_t duty[3];
void modbusGet(void) {
if (modbusGetBusState() & (1<<ReceiveCompleted))
{
switch(rxbuffer[1]) {
case fcReadHoldingRegisters:
holdingRegisters[0] = menu_state;
holdingRegisters[0] = duty[0];
holdingRegisters[1] = duty[1];
holdingRegisters[2] = duty[2];
holdingRegisters[3] = temp_values[0];
holdingRegisters[4] = temp_values[1];
holdingRegisters[5] = temp_values[2];
modbusExchangeRegisters(holdingRegisters,0,10);
break;
case fcPresetSingleRegister:
case fcPresetMultipleRegisters:
modbusExchangeRegisters(holdingRegisters,0,4);
@ -38,7 +58,7 @@ void modbusGet(void) {
}
}
void do_buttons(){
void read_buttons(){
i2c_start(0x71);
uint8_t buttons = i2c_readNak();
i2c_stop();
@ -54,62 +74,143 @@ void do_buttons(){
set_item(4);
else if(buttons & (1 << 4))
set_item(5);
else if((buttons & (1 << 5)) == 0) // inverted logic on this one
set_item(0);
}
int main(void)
{
DDRB |= 0x0F; // output coils
DDRD |= (1 << 4); // board LED
i2c_init();
lcd_init();
adc_init();
lcd_clear();
enc_init();
init_pid(&controller, 1, 0.05, 0);
sei();
modbusSetAddress(1);
modbusInit();
TCCR0B|=(1<<CS01); //prescaler 8
//modbus timer
TCCR0B|=(1<<CS01);
TIMSK0|=(1<<TOIE0);
PORTD |= (1<<6) | (1 << 7);
PCICR |= (1<<PCIE2);
PCMSK2 |= (1<<PCINT23);
// timer for regulator
TCCR1B|=(1<<CS12) | (1<<CS10);
TIMSK1|=(1<<TOIE1)|(1<<OCIE1A);
sei();
lcd_clear();
draw_menu();
uint16_t x = 0;
while(1){
modbusGet();
do_buttons();
read_buttons();
//blink cursor
if(x==0){
//}
////write values
//if(x % 2048 == 0){
lcd_cursor(0);
write_temps();
write_setpoints();
write_motor();
update_cursor();
}
x++;
if(x>=2024)
if(x >= 1024)
x=0;
}
}
ISR(PCINT2_vect){
encoder_isr();
}
ISR(TIMER0_OVF_vect) { //this ISR is called 9765.625 times per second
modbusTickTimer();
}
ISR(PCINT2_vect){
//TODO good quadrature reading code
if((PIND & (1<<7)) && (menu_state >= 1) && (menu_state <= 3)){
if(PIND & (1<<6))
temp_setpoints[menu_state-1]--;
else
temp_setpoints[menu_state-1]++;
ISR(TIMER1_COMPA_vect) {
/* turn off outputs */
if(OCR1A >= duty[0]){
PORTB &= ~(COIL1);
PORTD &= ~(1 << 4);
}
if(OCR1A >= duty[1])
PORTB &= ~(COIL2);
if(OCR1A >= duty[2])
PORTB &= ~(COIL3);
uint16_t new_ocr = 0xFFFE;
for(uint8_t i = 0; i < 3; i++){
if((duty[i] > OCR1A) && (duty[i] < new_ocr))
new_ocr = duty[i];
}
OCR1A = new_ocr;
//uint16_t tmp1 = duty[0];
//uint16_t tmp2;
//for(uint8_t i = 0; i < 3; i++){
// if(duty[i] < tmp1 && duty[i] > OCR1A)
// tmp2 = duty[i];
//}
//OCR1A = tmp2;
}
ISR(TIMER1_OVF_vect) {
int16_t tmp_pid = pid_step(&controller, 1, temp_setpoints[0] - temp_values[0]);
if(tmp_pid>=0)
output = tmp_pid;
else
output = 0;
if(output >= 128){
output = 128;
duty[0]=0xFFFE;
}
else if(output >= 1){
uint32_t tmp = output * 512;
duty[0] = tmp;
}
else
duty[0]=0;
duty[1] = duty[0] / 100 * temp_setpoints[1];
duty[2] = duty[0] / 100 * temp_setpoints[2];
for(uint8_t i = 0; i < 3; i++){
if(duty[i] >= 0xFFFE)
duty[i] = 0xFFFE;
}
OCR1A = 0xFFFE;
for(uint8_t i = 0; i < 3; i++){
if(duty[i] < OCR1A && duty[i] >= (uint16_t)1000)
OCR1A = duty[i];
}
if(duty[0] >= 1000){
PORTB |= COIL1;
PORTD |= 1<<4;
}
if(duty[1] >= 1000)
PORTB |= COIL2;
if(duty[2] >= 1000)
PORTB |= COIL3;
//if(PIND & (1<<7))
// if(PIND & (1<<6)){
// if(temp_setpoints[menu_state] > 0)
// }
// else{
// if(temp_setpoints[menu_state] < 300)
// }
}

@ -1,5 +1,5 @@
TARGET = main
FILES = main i2c lcd modbus menu adc
FILES = main i2c lcd modbus menu adc pid
MCU = atmega328p
PROGC = m328p
CC = avr-gcc

@ -19,15 +19,23 @@ void write_heater_set_temp(uint8_t n, uint16_t temp){
void update_cursor(){
switch(menu_state){
case 1:
lcd_set_position(2,6);
lcd_set_position(0,5);
lcd_cursor(1);
break;
case 2:
lcd_set_position(2,11);
lcd_set_position(0,9);
lcd_cursor(1);
break;
case 3:
lcd_set_position(2,16);
lcd_set_position(0,14);
lcd_cursor(1);
break;
case 4:
lcd_set_position(2,9);
lcd_cursor(1);
break;
case 5:
lcd_set_position(3,9);
lcd_cursor(1);
break;
default:
@ -38,45 +46,60 @@ void update_cursor(){
void draw_menu(){
lcd_clear();
lcd_write(" Heat Zone Control");
lcd_set_position(0, 0);
lcd_write("s:");
lcd_set_position(1, 0);
lcd_write("r:");
lcd_set_position(2, 0);
lcd_write(" set:");
lcd_write("motor:");
lcd_set_position(3, 0);
lcd_write("real:");
//char str[16];
//sprintf(str, "test %d", 1);
//lcd_print_str(str);
lcd_write("fan :");
}
void write_motor(){
char str[5];
str[4] = 0; //null terminated
lcd_set_position(2, 7);
sprintf(str, "%3i", OCR2B);
lcd_print_str(str);
}
void write_temps(){
char str[4];
char str[5];
str[4] = 0; //null terminated
lcd_set_position(3, 6);
lcd_set_position(1, 3);
sprintf(str, "%3i", temp_values[0]);
str[3] = 0xDF;
lcd_print_str(str);
lcd_set_position(3, 11);
lcd_set_position(1, 7);
sprintf(str, "%3i", temp_values[1]);
str[3] = 0xDF;
lcd_print_str(str);
lcd_set_position(3, 16);
lcd_set_position(1, 12);
sprintf(str, "%3d", temp_values[2]);
str[3] = 0xDF;
lcd_print_str(str);
}
void write_setpoints(){
char str[4];
char str[5];
str[4] = 0; //null terminated
lcd_set_position(2, 6);
lcd_set_position(0, 3);
sprintf(str, "%3i", temp_setpoints[0]);
str[3] = 0xDF;
lcd_print_str(str);
lcd_set_position(2, 11);
sprintf(str, "%3i", temp_setpoints[1]);
lcd_set_position(0, 7);
sprintf(str, "%3i%%", temp_setpoints[1]);
lcd_print_str(str);
lcd_set_position(2, 16);
sprintf(str, "%3i", temp_setpoints[2]);
lcd_set_position(0, 12);
sprintf(str, "%3i%%", temp_setpoints[2]);
lcd_print_str(str);
}
@ -84,6 +107,39 @@ void set_item(uint8_t page_num){
//if(menu_state=page_num)
// menu_state=0;
//else
menu_state = page_num;
menu_state = page_num;
}
void enc_init(){
PORTD |= (1<<6) | (1 << 7);
PCICR |= (1<<PCIE2);
PCMSK2 |= (1<<PCINT23);
}
void encoder_isr(){
//TODO good quadrature reading code
if((PIND & (1<<7))){
if((menu_state >= 1) && (menu_state <= 3)){
if(PIND & (1<<6))
temp_setpoints[menu_state-1]--;
else
temp_setpoints[menu_state-1]++;
}
if(menu_state == 4){
if(PIND & (1<<6) && (OCR2B > 0))
OCR2B--;
else if(!(PIND & (1<<6)) && (OCR2B < 255))
OCR2B++;
}
}
//if(PIND & (1<<7))
// if(PIND & (1<<6)){
// if(temp_setpoints[menu_state] > 0)
// }
// else{
// if(temp_setpoints[menu_state] < 300)
// }
}

@ -8,8 +8,11 @@ extern volatile uint16_t temp_setpoints[4];
void write_temps(void);
void write_setpoints(void);
void write_motor(void);
void update_cursor(void);
void set_item(uint8_t page_num);
void draw_menu(void);
void enc_init(void);
void encoder_isr(void);
#endif

36
pid.c

@ -0,0 +1,36 @@
#include <util/atomic.h>
#include "pid.h"
extern volatile uint16_t holdingRegisters[10];
int16_t pid_step(volatile struct pid* controller, float dt, int16_t error) {
// Calculate p term
uint16_t p = error * controller->kP;
// Calculate i term
ATOMIC_BLOCK(ATOMIC_FORCEON){
controller->integral += error * dt * controller->kI;
if(controller->integral > 80)
controller->integral = 80;
if(controller->integral < -80)
controller->integral = -80;
}
//holdingRegisters[3]=((float)(error) * controller->kI);
//holdingRegisters[4] = error;
// Calculate d term, taking care to not divide by zero
float d = dt == 0 ? 0 : ((error - controller->lastError) / dt) * controller->kD;
controller->lastError = error;
return p + controller->integral + d;
}
void init_pid(volatile struct pid* controller, float p, float i, float d){
*controller = (struct pid){
.kP = p,
.kI = i,
.kD = d,
.lastError = 0,
.integral = 0
};
}

21
pid.h

@ -0,0 +1,21 @@
#ifndef _PID_H_
#define _PID_H_
#include <stdint.h>
struct pid{
// Controller gains
float kP;
float kI;
float kD;
// State variables
float lastError;
float integral;
};
//float pid_step(volatile struct pid* controller, float dt, float error);
int16_t pid_step(volatile struct pid* controller, float dt, int16_t error);
void init_pid(volatile struct pid* controller, float p, float i, float d);
#endif
Loading…
Cancel
Save