Compare commits
22 Commits
2bbafd5569
...
rewrite_fo
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c707929a2 | |||
| bfdd4210e1 | |||
| f85971e49b | |||
| ab8fb924ed | |||
| 0b2e532675 | |||
| b87e2b846d | |||
| 934542fd3d | |||
| 470dd2077c | |||
| d9087580b2 | |||
| 5866c1f6f0 | |||
| 1fc729f8ce | |||
| 76ced85569 | |||
| fce2b8b26b | |||
| f7ec99c944 | |||
| e4b0ff8721 | |||
| c944c12fc1 | |||
| 6f41373992 | |||
| 1e51c8a151 | |||
| 852a2ef8a5 | |||
| 911967c9cc | |||
| 92f31a1849 | |||
| c9d5f33a0b |
93
adc.c
Normal file
93
adc.c
Normal file
@@ -0,0 +1,93 @@
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "adc.h"
|
||||
|
||||
void adc_init()
|
||||
{
|
||||
ADMUX = 1 << REFS0 | 0 << REFS1; //Select external Vref
|
||||
|
||||
//ADC Status Register A
|
||||
ADCSRA = 1 << ADEN //Enable ADC
|
||||
| 1 << ADIE //Enable ISR after conversion complete
|
||||
//| 1<<ADATE //Freerunning-Mode
|
||||
//| 1<<ADLAR //2 results bits are left aligned
|
||||
| 1 << ADPS2 //Set clock-prescaler to 128
|
||||
| 1 << ADPS1 | 1 << ADPS0;
|
||||
ADCSRA |= 1 << ADSC; //Start first Conversion for "warmup"
|
||||
}
|
||||
|
||||
void set_ADC_Channel(uint8_t adr)
|
||||
{
|
||||
if (adr < 11)
|
||||
{
|
||||
ADMUX &= (0b11110000); //Clear MUX-Address
|
||||
ADMUX |= adr; //Set new MUX-Address
|
||||
}
|
||||
}
|
||||
|
||||
ISR(ADC_vect)
|
||||
{
|
||||
//static uint8_t init[4] = {0,0,0,0};
|
||||
static uint8_t current_channel = 0;
|
||||
|
||||
static uint16_t read_buffer[128];
|
||||
static uint8_t buffer_pos = 0;
|
||||
|
||||
|
||||
//Reading 10bit conversion result
|
||||
uint16_t ADC_reading = ADCL; //copy the first LSB bits
|
||||
ADC_reading |= ADCH << 8; //copy remaing byte
|
||||
|
||||
read_buffer[buffer_pos] = ADC_reading;
|
||||
buffer_pos++;
|
||||
|
||||
if(buffer_pos == (sizeof(read_buffer) / sizeof(read_buffer[0]))){
|
||||
uint32_t sum = 0;
|
||||
for(uint8_t i = 0; i < buffer_pos; i++){
|
||||
sum += read_buffer[i];
|
||||
}
|
||||
|
||||
//convert to temperature
|
||||
sum /= 3;
|
||||
|
||||
switch(current_channel){
|
||||
case 0:
|
||||
temp_values[3] = sum/buffer_pos;
|
||||
break;
|
||||
case 1:
|
||||
temp_values[0] = sum/buffer_pos;
|
||||
break;
|
||||
case 2:
|
||||
temp_values[1] = sum/buffer_pos;
|
||||
break;
|
||||
case 3:
|
||||
temp_values[2] = sum/buffer_pos;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer_pos = 0;
|
||||
|
||||
current_channel++;
|
||||
if(current_channel == 4)
|
||||
current_channel = 0;
|
||||
set_ADC_Channel(current_channel);
|
||||
}
|
||||
|
||||
ADCSRA |= (1 << ADSC); //Start next conversion
|
||||
|
||||
|
||||
//TODO write non broken adc code
|
||||
//if(adc_buf[current_channel].position == BUFFER_SIZE-1){
|
||||
// //if(init[current_channel]){
|
||||
// //float tmp = (99*adc_avrg[current_channel]) + get_buffer_mean(&adc_buf[current_channel]);
|
||||
// //tmp /= 100;
|
||||
// adc_avrg[current_channel] = get_buffer_mean(&adc_buf[current_channel]);
|
||||
// //}
|
||||
// //else{
|
||||
// // adc_avrg[current_channel] = get_buffer_mean(&adc_buf[current_channel]);
|
||||
// // init[current_channel]=0;
|
||||
// //}
|
||||
//}
|
||||
|
||||
}
|
||||
11
adc.h
Normal file
11
adc.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef _ADC_H_
|
||||
#define _ADC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern volatile uint16_t temp_values[4];
|
||||
|
||||
void adc_init(void);
|
||||
|
||||
#endif//_ADC_H_
|
||||
|
||||
61
i2c.c
Normal file
61
i2c.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* i2c.c
|
||||
*
|
||||
* Created: 20.01.2018 12:50:54
|
||||
* Author: Ulrich
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
void i2c_init(void){
|
||||
I2C_PORT |= (1 << SDA_PIN | 1 << SCL_PIN); //Port Pullup
|
||||
TWCR = 0;
|
||||
TWSR = 0;
|
||||
TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
|
||||
_delay_ms(50);
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
uint8_t i2c_start (uint8_t addr){
|
||||
uint16_t timeout = 0;
|
||||
|
||||
TWCR = (1 << TWINT | 1 << TWSTA | 1 << TWEN);
|
||||
while(!(TWCR & (1<<TWINT))){
|
||||
if((timeout++) > 1000) return 1;
|
||||
}
|
||||
TWDR = addr;
|
||||
TWCR = (1 << TWINT | 1 << TWEN);
|
||||
timeout = 0;
|
||||
while(!(TWCR & (1<<TWINT))){
|
||||
if((timeout++) > 1000) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
uint8_t i2c_byte (uint8_t byte){
|
||||
uint16_t timeout = 0;
|
||||
TWDR = byte;
|
||||
TWCR = (1 << TWINT | 1 << TWEN);
|
||||
while(!(TWCR & (1<<TWINT))){
|
||||
if((timeout++) > 1000) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
uint8_t i2c_readNak(void)
|
||||
{
|
||||
uint16_t timeout = 0;
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
while(!(TWCR & (1<<TWINT))){
|
||||
if((timeout++) > 1000) return 0;
|
||||
}
|
||||
return TWDR;
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
void i2c_stop (void){
|
||||
TWCR = (1 << TWINT | 1 << TWSTO | 1 << TWEN);
|
||||
TWCR = 0;
|
||||
}
|
||||
26
i2c.h
Normal file
26
i2c.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* i2c.h
|
||||
*
|
||||
* Created: 20.01.2018 12:51:11
|
||||
* Author: Ulrich
|
||||
*/
|
||||
|
||||
#ifndef I2C_H_
|
||||
#define I2C_H_
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
//I2C
|
||||
#define SDA_PIN PC4 //PIN am Atmel
|
||||
#define SCL_PIN PC5 //PIN am Atmel
|
||||
#define I2C_PORT PORTC //PORT am Atmel
|
||||
#define SCL_CLOCK 40000UL
|
||||
|
||||
void i2c_init(void);
|
||||
uint8_t i2c_start (uint8_t);
|
||||
uint8_t i2c_byte (uint8_t);
|
||||
uint8_t i2c_readNak(void);
|
||||
void i2c_stop (void);
|
||||
|
||||
#endif /* I2C_H_ */
|
||||
211
lcd.c
Normal file
211
lcd.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* lcd.c
|
||||
*
|
||||
* Created: 20.01.2018 12:51:11
|
||||
* Author: Ulrich
|
||||
*/
|
||||
|
||||
#include "lcd.h"
|
||||
|
||||
volatile unsigned char char_counter = 0;
|
||||
|
||||
volatile uint8_t lcd_ctrl_reg = 0;
|
||||
|
||||
// output data to lcd
|
||||
void lcd_out (unsigned char c) {
|
||||
i2c_start(LCD_I2C_ADDR);
|
||||
i2c_byte(c | LCD_BACKLIGHT);
|
||||
i2c_stop();
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
// CD = Command or Data
|
||||
void lcd_nibble_out(unsigned char c, unsigned char cd) {
|
||||
unsigned char out = 0;
|
||||
unsigned char rs = 0;
|
||||
|
||||
if(cd) rs=LCD_RS;
|
||||
|
||||
//4 upper bits
|
||||
if(c & (1<<4)) out |= LCD_D4;
|
||||
if(c & (1<<5)) out |= LCD_D5;
|
||||
if(c & (1<<6)) out |= LCD_D6;
|
||||
if(c & (1<<7)) out |= LCD_D7;
|
||||
lcd_out(out | rs | LCD_E);
|
||||
_delay_ms(5);
|
||||
lcd_out(out | rs);
|
||||
|
||||
//4 lower bits
|
||||
out=0;
|
||||
if(c & (1<<0)) out |= LCD_D4;
|
||||
if(c & (1<<1)) out |= LCD_D5;
|
||||
if(c & (1<<2)) out |= LCD_D6;
|
||||
if(c & (1<<3)) out |= LCD_D7;
|
||||
lcd_out(out | rs | LCD_E);
|
||||
_delay_ms(5);
|
||||
lcd_out(out | rs );
|
||||
}
|
||||
|
||||
void lcd_set_position(uint8_t row, uint8_t col){
|
||||
if(col >= LCD_WIDTH)
|
||||
return;
|
||||
|
||||
if(row==0)
|
||||
lcd_nibble_out(0x80|col, 0);
|
||||
if(row==1)
|
||||
lcd_nibble_out(0xC0|col, 0);
|
||||
if(row==2)
|
||||
lcd_nibble_out(0x80|(col+LCD_WIDTH), 0);
|
||||
if(row==3)
|
||||
lcd_nibble_out(0xC0|(col+LCD_WIDTH), 0);
|
||||
|
||||
char_counter = (row * LCD_WIDTH) + col;
|
||||
}
|
||||
|
||||
void lcd_cursor(uint8_t en){
|
||||
if(en)
|
||||
lcd_nibble_out(0x08 | 0x04 | 0x02, 0);
|
||||
else
|
||||
lcd_nibble_out(0x08 | 0x04, 0);
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
// clear LCD
|
||||
void lcd_clear() {
|
||||
lcd_nibble_out(0x01, 0); // clear display
|
||||
lcd_nibble_out(0x80, 0);
|
||||
char_counter = 0;
|
||||
}
|
||||
|
||||
|
||||
//***************************************************************************************
|
||||
// LCD home
|
||||
void lcd_home() {
|
||||
lcd_nibble_out(0x80, 0);
|
||||
char_counter = 0;
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
// Init LCD
|
||||
void lcd_init() {
|
||||
unsigned char loop=3;
|
||||
|
||||
while(loop--){
|
||||
lcd_out(LCD_D4 | LCD_D5 | LCD_E);
|
||||
_delay_ms(10);
|
||||
lcd_out(LCD_D4 | LCD_D5);
|
||||
_delay_ms(100);
|
||||
}
|
||||
|
||||
// 4 bit mode
|
||||
lcd_out(LCD_D5 | LCD_E);
|
||||
_delay_ms(10);
|
||||
lcd_out(LCD_D5);
|
||||
_delay_ms(10);
|
||||
|
||||
lcd_nibble_out(0x28, 0);
|
||||
lcd_nibble_out(0x0C, 0);
|
||||
|
||||
lcd_clear();
|
||||
lcd_cursor(0);
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
void lcd_write_char (char c) {
|
||||
if(char_counter == LCD_WIDTH) lcd_set_position(1,0);
|
||||
if(char_counter == 2*LCD_WIDTH) lcd_set_position(2,0);
|
||||
if(char_counter == 3*LCD_WIDTH) lcd_set_position(3,0);
|
||||
if(char_counter == 4*LCD_WIDTH) lcd_set_position(0,0);
|
||||
char_counter++;
|
||||
lcd_nibble_out(c, 1);
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
void lcd_print_str(char *str) {
|
||||
while (*str != 0){
|
||||
if(char_counter == LCD_WIDTH) lcd_set_position(1,0);
|
||||
if(char_counter == 2*LCD_WIDTH) lcd_set_position(2,0);
|
||||
if(char_counter == 3*LCD_WIDTH) lcd_set_position(3,0);
|
||||
if(char_counter == 4*LCD_WIDTH) lcd_set_position(0,0);
|
||||
char_counter++;
|
||||
lcd_nibble_out(*str++, 1);
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
void lcd_write_P (const char *Buffer,...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, Buffer);
|
||||
|
||||
int format_flag;
|
||||
char str_buffer[10];
|
||||
char str_null_buffer[10];
|
||||
char move = 0;
|
||||
char Base = 0;
|
||||
int tmp = 0;
|
||||
char by;
|
||||
char *ptr;
|
||||
|
||||
//Ausgabe der Zeichen
|
||||
for(;;){
|
||||
by = pgm_read_byte(Buffer++);
|
||||
if(by==0) break; // end of format string
|
||||
|
||||
if (by == '%'){
|
||||
by = pgm_read_byte(Buffer++);
|
||||
if (isdigit(by)>0){
|
||||
str_null_buffer[0] = by;
|
||||
str_null_buffer[1] = '\0';
|
||||
move = atoi(str_null_buffer);
|
||||
by = pgm_read_byte(Buffer++);
|
||||
}
|
||||
|
||||
switch (by){
|
||||
case 's':
|
||||
ptr = va_arg(ap,char *);
|
||||
while(*ptr) { lcd_write_char(*ptr++); }
|
||||
break;
|
||||
case 'b':
|
||||
Base = 2;
|
||||
goto ConversionLoop;
|
||||
case 'c':
|
||||
//Int to char
|
||||
format_flag = va_arg(ap,int);
|
||||
lcd_write_char (format_flag++);
|
||||
break;
|
||||
case 'i':
|
||||
Base = 10;
|
||||
goto ConversionLoop;
|
||||
case 'o':
|
||||
Base = 8;
|
||||
goto ConversionLoop;
|
||||
case 'x':
|
||||
Base = 16;
|
||||
//****************************
|
||||
ConversionLoop:
|
||||
//****************************
|
||||
itoa(va_arg(ap,int),str_buffer,Base);
|
||||
int b=0;
|
||||
while (str_buffer[b++] != 0){};
|
||||
b--;
|
||||
if (b<move){
|
||||
move -=b;
|
||||
for (tmp = 0;tmp<move;tmp++){
|
||||
str_null_buffer[tmp] = '0';
|
||||
}
|
||||
//tmp ++;
|
||||
str_null_buffer[tmp] = '\0';
|
||||
strcat(str_null_buffer,str_buffer);
|
||||
strcpy(str_buffer,str_null_buffer);
|
||||
}
|
||||
lcd_print_str (str_buffer);
|
||||
move =0;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
lcd_write_char (by);
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
49
lcd.h
Normal file
49
lcd.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* lcd.h
|
||||
*
|
||||
* Created: 20.01.2018 12:51:11
|
||||
* Author: Ulrich
|
||||
*/
|
||||
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <util/delay.h>
|
||||
#include "i2c.h"
|
||||
|
||||
#define LCD_I2C_ADDR 0x4E
|
||||
|
||||
//Port Belegung am PCF8574 (1<<PORT)
|
||||
#define LCD_RS (1<<0)
|
||||
#define LCD_RW (1<<1)
|
||||
#define LCD_E (1<<2)
|
||||
#define LCD_BACKLIGHT (1<<3)
|
||||
|
||||
#define LCD_D4 (1<<4)
|
||||
#define LCD_D5 (1<<5)
|
||||
#define LCD_D6 (1<<6)
|
||||
#define LCD_D7 (1<<7)
|
||||
|
||||
#define LCD_WIDTH 20
|
||||
#define LCD_ADDR_LINE1 (0x80)
|
||||
#define LCD_ADDR_LINE2 (0xC0)
|
||||
|
||||
void lcd_init(void);
|
||||
void lcd_clear(void);
|
||||
void lcd_home(void);
|
||||
void lcd_print_str (char *str);
|
||||
void lcd_write_P (const char *Buffer,...);
|
||||
|
||||
void lcd_set_position(uint8_t row, uint8_t col);
|
||||
void lcd_cursor(uint8_t en);
|
||||
|
||||
#define lcd_write(format, args...) lcd_write_P(PSTR(format) , ## args)
|
||||
|
||||
#endif
|
||||
319
main.c
319
main.c
@@ -1,171 +1,216 @@
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include <modbus.h>
|
||||
#include <avr/interrupt.h>
|
||||
/*
|
||||
* LCD_HD44780.c
|
||||
*
|
||||
* Created: 20.01.2018 12:51:11
|
||||
* Author: Ulrich
|
||||
*/
|
||||
|
||||
#include "buffer.h"
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include "lcd.h"
|
||||
#include "i2c.h"
|
||||
#include "modbus.h"
|
||||
#include "menu.h"
|
||||
#include "adc.h"
|
||||
#include "pid.h"
|
||||
|
||||
void modbusGet(void);
|
||||
#define COIL1 1<<1
|
||||
#define COIL2 1<<0
|
||||
#define COIL3 1<<2
|
||||
#define COIL4 1<<3
|
||||
|
||||
volatile buffer_t adc_buf[4];
|
||||
volatile float adc_avrg[4];
|
||||
volatile uint16_t holdingRegisters[10];
|
||||
|
||||
volatile float output;
|
||||
volatile uint16_t temp_values[4];
|
||||
volatile uint16_t temp_setpoints[4];
|
||||
|
||||
volatile uint16_t output;
|
||||
volatile struct pid controller;
|
||||
|
||||
volatile float setpoint_1 = 130;
|
||||
volatile float setpoint_2 = 150;
|
||||
volatile float setpoint_3 = 150;
|
||||
|
||||
void initADC(void)
|
||||
{
|
||||
ADMUX = 1 << REFS0 | 0 << REFS1; //Select external Vref
|
||||
|
||||
//ADC Status Register A
|
||||
ADCSRA = 1 << ADEN //Enable ADC
|
||||
| 1 << ADIE //Enable ISR after conversion complete
|
||||
//| 1<<ADATE //Freerunning-Mode
|
||||
//| 1<<ADLAR //2 results bits are left aligned
|
||||
| 1 << ADPS2 //Set clock-prescaler to 128
|
||||
| 1 << ADPS1 | 1 << ADPS0;
|
||||
ADCSRA |= 1 << ADSC; //Start first Conversion for "warmup"
|
||||
}
|
||||
|
||||
int main(){
|
||||
DDRD |= (1 << 4); // LED
|
||||
DDRD |= (1 << 3); // FU PWM
|
||||
DDRD |= (1 << 2); // 485 DE
|
||||
|
||||
PORTD |= 1 << 4;
|
||||
|
||||
DDRB |= 0x0F; // out channels
|
||||
|
||||
PORTD|=(1<<0); // RX
|
||||
|
||||
// FU PWM on PD3
|
||||
TCCR2A |= (1 << COM2B1) | (1 << COM2B0);
|
||||
TCCR2A |= (1 << WGM21) | (1 << WGM20);
|
||||
TCCR2B |= (1 << CS21);
|
||||
|
||||
modbusSetAddress(1);
|
||||
modbusInit();
|
||||
|
||||
// Modbus Tick Timer
|
||||
TCCR0B|=(1<<CS01); //prescaler 8
|
||||
TIMSK0|=(1<<TOIE0);
|
||||
|
||||
initADC();
|
||||
sei();
|
||||
|
||||
_delay_ms(1000);
|
||||
init_pid(&controller, 5, 0.2, 0);
|
||||
|
||||
|
||||
// timer for regler
|
||||
TCCR1B|=(1<<CS12) | (1<<CS10);
|
||||
TIMSK1|=(1<<TOIE1)|(1<<OCIE1A);
|
||||
|
||||
while(1){
|
||||
modbusGet();
|
||||
}
|
||||
}
|
||||
|
||||
void set_ADC_Channel(uint8_t adr)
|
||||
{
|
||||
if (adr < 11)
|
||||
{
|
||||
ADMUX &= (0b11110000); //Clear MUX-Address
|
||||
ADMUX |= adr; //Set new MUX-Address
|
||||
}
|
||||
}
|
||||
volatile uint32_t duty[3];
|
||||
|
||||
void modbusGet(void) {
|
||||
if (modbusGetBusState() & (1<<ReceiveCompleted))
|
||||
{
|
||||
switch(rxbuffer[1]) {
|
||||
switch(rxbuffer[1]) {
|
||||
case fcReadHoldingRegisters:
|
||||
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((uint16_t *)&OCR2B,0,1);
|
||||
case fcPresetMultipleRegisters:
|
||||
modbusExchangeRegisters(holdingRegisters,0,4);
|
||||
menu_state = holdingRegisters[0];
|
||||
break;
|
||||
|
||||
case fcReadCoilStatus:
|
||||
case fcForceSingleCoil:
|
||||
case fcForceMultipleCoils:
|
||||
modbusExchangeBits(&PORTB,0,4);
|
||||
break;
|
||||
|
||||
case fcReadInputRegisters:
|
||||
if(modbusRequestedAddress()<10)
|
||||
modbusExchangeRegisters((uint16_t *)&adc_avrg,0,8);
|
||||
else
|
||||
modbusExchangeRegisters((uint16_t *)&output,10,4);
|
||||
break;
|
||||
|
||||
default:
|
||||
modbusSendException(ecIllegalFunction);
|
||||
modbusSendException(ecIllegalFunction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read_buttons(){
|
||||
i2c_start(0x71);
|
||||
uint8_t buttons = i2c_readNak();
|
||||
i2c_stop();
|
||||
//TODO error handling
|
||||
|
||||
if(buttons & (1 << 0))
|
||||
set_item(1);
|
||||
else if(buttons & (1 << 1))
|
||||
set_item(2);
|
||||
else if(buttons & (1 << 2))
|
||||
set_item(3);
|
||||
else if(buttons & (1 << 3))
|
||||
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();
|
||||
enc_init();
|
||||
|
||||
init_pid(&controller, 1, 0.05, 0);
|
||||
|
||||
modbusSetAddress(1);
|
||||
modbusInit();
|
||||
|
||||
//modbus timer
|
||||
TCCR0B|=(1<<CS01);
|
||||
TIMSK0|=(1<<TOIE0);
|
||||
|
||||
// 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();
|
||||
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 >= 1024)
|
||||
x=0;
|
||||
}
|
||||
}
|
||||
|
||||
ISR(PCINT2_vect){
|
||||
encoder_isr();
|
||||
}
|
||||
|
||||
ISR(TIMER0_OVF_vect) { //this ISR is called 9765.625 times per second
|
||||
modbusTickTimer();
|
||||
}
|
||||
|
||||
ISR(TIMER1_OVF_vect) {
|
||||
output = pid_step(&controller, 1, setpoint_1 - adc_avrg[1]);
|
||||
|
||||
PORTD &= ~(1 << 4);
|
||||
|
||||
if(output > 128)
|
||||
output = 128;
|
||||
|
||||
if(output >= 1){
|
||||
uint32_t tmp = output * 512;
|
||||
if(tmp >= 0x10000)
|
||||
tmp = 0xFFFE;
|
||||
|
||||
OCR1A = tmp;
|
||||
PORTB |= 0x0E;
|
||||
}
|
||||
else
|
||||
OCR1A = 1000;
|
||||
}
|
||||
|
||||
ISR(TIMER1_COMPA_vect) {
|
||||
/* turn off outputs */
|
||||
PORTB &= ~(0x0E);
|
||||
|
||||
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(ADC_vect)
|
||||
{
|
||||
static uint8_t init[4] = {0,0,0,0};
|
||||
static uint8_t current_channel = 0;
|
||||
ISR(TIMER1_OVF_vect) {
|
||||
int16_t tmp_pid = pid_step(&controller, 1, temp_setpoints[0] - temp_values[0]);
|
||||
|
||||
//Reading 10bit conversion result
|
||||
uint16_t ADC_reading = ADCL; //copy the first LSB bits
|
||||
ADC_reading |= ADCH << 8; //copy remaing byte
|
||||
ADC_reading *= 0.33;
|
||||
insert_to_buffer(ADC_reading, &adc_buf[current_channel]);
|
||||
if(tmp_pid>=0)
|
||||
output = tmp_pid;
|
||||
else
|
||||
output = 0;
|
||||
|
||||
if(adc_buf[current_channel].position == BUFFER_SIZE-1){
|
||||
if(init[current_channel]){
|
||||
float tmp = (99*adc_avrg[current_channel]) + get_buffer_mean(&adc_buf[current_channel]);
|
||||
tmp /= 100;
|
||||
adc_avrg[current_channel] = tmp;
|
||||
}
|
||||
else{
|
||||
adc_avrg[current_channel] = get_buffer_mean(&adc_buf[current_channel]);
|
||||
init[current_channel]=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;
|
||||
}
|
||||
|
||||
current_channel++;
|
||||
if(current_channel == 4)
|
||||
current_channel = 0;
|
||||
set_ADC_Channel(current_channel);
|
||||
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;
|
||||
|
||||
|
||||
ADCSRA |= (1 << ADSC); //Start next conversion
|
||||
}
|
||||
|
||||
|
||||
12
makefile
12
makefile
@@ -1,5 +1,5 @@
|
||||
TARGET = main
|
||||
FILES = main modbus buffer pid
|
||||
FILES = main i2c lcd modbus menu adc pid
|
||||
MCU = atmega328p
|
||||
PROGC = m328p
|
||||
CC = avr-gcc
|
||||
@@ -9,7 +9,7 @@ BUILDDIR = build
|
||||
|
||||
DEFINES = -DF_CPU=18432000UL
|
||||
|
||||
CFLAGS =-mmcu=$(MCU) -O2 -Wall $(DEFINES) -I. -std=c99 -ffunction-sections -fdata-sections
|
||||
CFLAGS =-mmcu=$(MCU) -g -O2 -Wall $(DEFINES) -I. -std=c99 -ffunction-sections -fdata-sections
|
||||
LDFLAGS =-mmcu=$(MCU) -Wl,--gc-sections
|
||||
|
||||
LDFILES = $(foreach FILE,$(FILES),$(BUILDDIR)/$(FILE).o)
|
||||
@@ -25,19 +25,17 @@ $(BUILDDIR)/$(TARGET).elf: $(LDFILES)
|
||||
$(CC) $(LDFLAGS) $(LDFILES) -o $(BUILDDIR)/$(TARGET).elf
|
||||
|
||||
$(BUILDDIR)/$(TARGET).hex : $(BUILDDIR)/$(TARGET).elf
|
||||
avr-objcopy -j .data -j .text -O ihex $< $@
|
||||
avr-objcopy -j .data -j .text -O ihex $< $@
|
||||
|
||||
fuse:
|
||||
avrdude -p $(PROGC) -c $(TOOL) -U lfuse:w:0xE8:m -U hfuse:w:0xD1:m
|
||||
.PHONY=load program size clean
|
||||
|
||||
load: $(BUILDDIR)/$(TARGET).hex
|
||||
avrdude -p $(PROGC) -c $(TOOL) -U flash:w:$(BUILDDIR)/$(TARGET).hex -v -B 2
|
||||
avrdude -p $(PROGC) -c $(TOOL) -U flash:w:$(BUILDDIR)/$(TARGET).hex -v -B 4MHz
|
||||
|
||||
program: clean load
|
||||
|
||||
size: $(BUILDDIR)/$(TARGET).elf
|
||||
avr-size -C --mcu=$(MCU) $(BUILDDIR)/$(TARGET).elf
|
||||
|
||||
.PHONY=clean
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
145
menu.c
Normal file
145
menu.c
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "lcd.h"
|
||||
#include "menu.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// 0 = nothing selected
|
||||
// 1 = change zone 1
|
||||
// 2 = change zone 2
|
||||
// 3 = change zone 3
|
||||
volatile uint8_t menu_state = 0;
|
||||
|
||||
void write_heater_real_temp(uint8_t n, uint16_t temp){
|
||||
|
||||
}
|
||||
|
||||
void write_heater_set_temp(uint8_t n, uint16_t temp){
|
||||
|
||||
}
|
||||
|
||||
void update_cursor(){
|
||||
switch(menu_state){
|
||||
case 1:
|
||||
lcd_set_position(0,5);
|
||||
lcd_cursor(1);
|
||||
break;
|
||||
case 2:
|
||||
lcd_set_position(0,9);
|
||||
lcd_cursor(1);
|
||||
break;
|
||||
case 3:
|
||||
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:
|
||||
lcd_cursor(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_menu(){
|
||||
lcd_clear();
|
||||
lcd_set_position(0, 0);
|
||||
lcd_write("s:");
|
||||
lcd_set_position(1, 0);
|
||||
lcd_write("r:");
|
||||
lcd_set_position(2, 0);
|
||||
lcd_write("motor:");
|
||||
lcd_set_position(3, 0);
|
||||
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[5];
|
||||
str[4] = 0; //null terminated
|
||||
|
||||
lcd_set_position(1, 3);
|
||||
sprintf(str, "%3i", temp_values[0]);
|
||||
str[3] = 0xDF;
|
||||
lcd_print_str(str);
|
||||
|
||||
lcd_set_position(1, 7);
|
||||
sprintf(str, "%3i", temp_values[1]);
|
||||
str[3] = 0xDF;
|
||||
lcd_print_str(str);
|
||||
|
||||
lcd_set_position(1, 12);
|
||||
sprintf(str, "%3d", temp_values[2]);
|
||||
str[3] = 0xDF;
|
||||
lcd_print_str(str);
|
||||
}
|
||||
|
||||
void write_setpoints(){
|
||||
char str[5];
|
||||
str[4] = 0; //null terminated
|
||||
|
||||
lcd_set_position(0, 3);
|
||||
sprintf(str, "%3i", temp_setpoints[0]);
|
||||
str[3] = 0xDF;
|
||||
lcd_print_str(str);
|
||||
|
||||
lcd_set_position(0, 7);
|
||||
sprintf(str, "%3i%%", temp_setpoints[1]);
|
||||
lcd_print_str(str);
|
||||
|
||||
lcd_set_position(0, 12);
|
||||
sprintf(str, "%3i%%", temp_setpoints[2]);
|
||||
lcd_print_str(str);
|
||||
}
|
||||
|
||||
void set_item(uint8_t page_num){
|
||||
//if(menu_state=page_num)
|
||||
// menu_state=0;
|
||||
//else
|
||||
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)
|
||||
// }
|
||||
}
|
||||
18
menu.h
Normal file
18
menu.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef _MENU_H_
|
||||
#include <stdint.h>
|
||||
|
||||
extern volatile uint8_t menu_state;
|
||||
|
||||
extern volatile uint16_t temp_values[4];
|
||||
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
Normal file
36
pid.c
Normal file
@@ -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
Normal file
21
pid.h
Normal file
@@ -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
|
||||
7
scripts/dw.sh
Executable file
7
scripts/dw.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
make program
|
||||
avrdude -c atmelice_isp -p m328p -U hfuse:w:0x99:m
|
||||
echo "Power cycle now!"
|
||||
read
|
||||
avarice -5 -w -P atmega328p :4242 &
|
||||
read
|
||||
avrdude -c atmelice_isp -p m328p -U hfuse:w:0xD9:m
|
||||
3
scripts/exitdw.sh
Executable file
3
scripts/exitdw.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
avarice -5 -w -P atmega328p :4242 &
|
||||
sleep 2
|
||||
avrdude -c atmelice_isp -p m328p -U hfuse:w:0xD9:m
|
||||
43
scripts/plot.py
Normal file
43
scripts/plot.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import time
|
||||
from simple_pid import PID
|
||||
from itertools import count
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.animation import FuncAnimation
|
||||
|
||||
import minimalmodbus
|
||||
|
||||
tempSens = minimalmodbus.Instrument('/dev/ttyUSB0', 1)
|
||||
tempSens.serial.baudrate = 38400
|
||||
|
||||
plt.style.use('fivethirtyeight')
|
||||
|
||||
x_values = []
|
||||
y_values = []
|
||||
|
||||
index = count()
|
||||
|
||||
|
||||
def animate(i):
|
||||
try:
|
||||
#temp1 = tempSens.read_float(1, functioncode=4, byteorder=0) / 100
|
||||
#temp2 = tempSens.read_float(3, functioncode=4, byteorder=0) / 100
|
||||
#temp3 = tempSens.read_float(5, functioncode=4, byteorder=0) / 100
|
||||
|
||||
#temp = tempSens.read_register(1)
|
||||
temp2 = tempSens.read_float(3, functioncode=4)
|
||||
|
||||
y_values.append(temp2)
|
||||
x_values.append(next(index))
|
||||
print(tempSens.read_float(11, functioncode=4), end="\t")
|
||||
print(temp2)
|
||||
|
||||
plt.cla()
|
||||
plt.scatter(x_values, y_values)
|
||||
except Exception as e: print(e)
|
||||
|
||||
|
||||
ani = FuncAnimation(plt.gcf(), animate, 2000)
|
||||
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
Reference in New Issue
Block a user