Compare commits
	
		
			20 Commits 
		
	
	
		
			master
			...
			rewrite_fo
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 2c707929a2 | 4 years ago | 
|  | bfdd4210e1 | 4 years ago | 
|  | f85971e49b | 4 years ago | 
|  | ab8fb924ed | 4 years ago | 
|  | 0b2e532675 | 4 years ago | 
|  | b87e2b846d | 5 years ago | 
|  | 934542fd3d | 5 years ago | 
|  | 470dd2077c | 5 years ago | 
|  | d9087580b2 | 5 years ago | 
|  | 5866c1f6f0 | 5 years ago | 
|  | 1fc729f8ce | 5 years ago | 
|  | 76ced85569 | 5 years ago | 
|  | fce2b8b26b | 5 years ago | 
|  | f7ec99c944 | 5 years ago | 
|  | e4b0ff8721 | 5 years ago | 
|  | c944c12fc1 | 5 years ago | 
|  | 6f41373992 | 5 years ago | 
|  | 1e51c8a151 | 5 years ago | 
|  | 852a2ef8a5 | 5 years ago | 
|  | 911967c9cc | 5 years ago | 
| @ -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;
 | ||||
|     //    //}
 | ||||
|     //}
 | ||||
| 
 | ||||
| } | ||||
| @ -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_
 | ||||
| 
 | ||||
| @ -1,42 +0,0 @@ | ||||
| #include <util/atomic.h> | ||||
| 
 | ||||
| #include "buffer.h" | ||||
| 
 | ||||
| void insert_to_buffer(uint16_t val, volatile buffer_t* buf){ | ||||
|     ATOMIC_BLOCK(ATOMIC_FORCEON){ | ||||
|         buf->position++; | ||||
|         if(buf->position == BUFFER_SIZE) | ||||
|             buf->position = 0; | ||||
|         buf->values[buf->position] = val; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| float get_buffer_mean(volatile buffer_t* buf){ | ||||
| 
 | ||||
|     ///* discard lowest and highest value */
 | ||||
|     //uint16_t low=0xFFFF;
 | ||||
|     //uint16_t high=0;
 | ||||
|     //uint16_t index_l = 0;
 | ||||
|     //uint16_t index_h = 0;
 | ||||
|     //for(uint16_t i=0; i<BUFFER_SIZE; i++){
 | ||||
|     //    if(buf->values[i] < low){
 | ||||
|     //        low=buf->values[i];
 | ||||
|     //        index_l = i;
 | ||||
|     //    }
 | ||||
|     //    if(buf->values[i] > high){
 | ||||
|     //        high=buf->values[i];
 | ||||
|     //        index_h = i;
 | ||||
|     //    }
 | ||||
|     //}
 | ||||
|          | ||||
| 
 | ||||
|     uint32_t sum = 0; | ||||
|     for(uint16_t i=0; i<BUFFER_SIZE; i++){ | ||||
|         //if(i == index_h || i == index_l)
 | ||||
|         //    continue;
 | ||||
|         sum += buf->values[i]; | ||||
|     } | ||||
| 
 | ||||
|     uint16_t res = sum/(BUFFER_SIZE/*-2*/); | ||||
|     return res; | ||||
| } | ||||
| @ -1,11 +0,0 @@ | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #define BUFFER_SIZE 200 | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint16_t values[BUFFER_SIZE]; | ||||
|     uint16_t position; | ||||
| } buffer_t; | ||||
| 
 | ||||
| void insert_to_buffer(uint16_t val, volatile buffer_t* buf); | ||||
| float get_buffer_mean(volatile buffer_t* buf); | ||||
| @ -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; | ||||
| } | ||||
| @ -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_ */ | ||||
| @ -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); | ||||
| } | ||||
| @ -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 | ||||
| @ -1,171 +1,216 @@ | ||||
| /*
 | ||||
|  * LCD_HD44780.c | ||||
|  * | ||||
|  * Created: 20.01.2018 12:51:11 | ||||
|  *  Author: Ulrich | ||||
|  */  | ||||
| 
 | ||||
| #include <avr/io.h> | ||||
| #include <util/delay.h> | ||||
| #include <modbus.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <util/delay.h> | ||||
| 
 | ||||
| #include "buffer.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; | ||||
| volatile uint32_t duty[3]; | ||||
| 
 | ||||
| void initADC(void) | ||||
| void modbusGet(void) { | ||||
| 	if (modbusGetBusState() & (1<<ReceiveCompleted)) | ||||
| 	{ | ||||
|     ADMUX = 1 << REFS0 | 0 << REFS1; //Select external Vref
 | ||||
|         switch(rxbuffer[1]) { | ||||
|             case fcReadHoldingRegisters: | ||||
|                 holdingRegisters[0] = duty[0]; | ||||
|                 holdingRegisters[1] = duty[1]; | ||||
|                 holdingRegisters[2] = duty[2]; | ||||
| 
 | ||||
|     //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"
 | ||||
|                 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); | ||||
|                 menu_state = holdingRegisters[0]; | ||||
|                 break; | ||||
|             default: | ||||
|                 modbusSendException(ecIllegalFunction); | ||||
|                 break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int main(){ | ||||
|     DDRD |= (1 << 4); // LED
 | ||||
|     DDRD |= (1 << 3); // FU PWM
 | ||||
|     DDRD |= (1 << 2); // 485 DE
 | ||||
| void read_buttons(){ | ||||
|     i2c_start(0x71); | ||||
|     uint8_t buttons = i2c_readNak(); | ||||
|     i2c_stop(); | ||||
|     //TODO error handling
 | ||||
| 
 | ||||
|     PORTD |= 1 << 4; | ||||
|     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); | ||||
| 
 | ||||
|     DDRB |= 0x0F; // out channels
 | ||||
| } | ||||
| 
 | ||||
| int main(void) | ||||
| { | ||||
|     DDRB |= 0x0F;       // output coils
 | ||||
|     DDRD |= (1 << 4);   // board LED
 | ||||
| 
 | ||||
| 	PORTD|=(1<<0); // RX
 | ||||
| 	i2c_init(); | ||||
| 	lcd_init(); | ||||
|     adc_init(); | ||||
|     enc_init(); | ||||
| 
 | ||||
|     // FU PWM on PD3
 | ||||
|     TCCR2A |= (1 << COM2B1) | (1 << COM2B0); | ||||
|     TCCR2A |= (1 << WGM21) | (1 << WGM20); | ||||
|     TCCR2B |= (1 << CS21); | ||||
|     init_pid(&controller, 1, 0.05, 0); | ||||
| 
 | ||||
|     modbusSetAddress(1); | ||||
|     modbusInit(); | ||||
| 
 | ||||
|     // Modbus Tick Timer
 | ||||
|     TCCR0B|=(1<<CS01); //prescaler 8
 | ||||
|     //modbus timer
 | ||||
|     TCCR0B|=(1<<CS01); | ||||
| 	TIMSK0|=(1<<TOIE0); | ||||
| 
 | ||||
|     initADC(); | ||||
|     sei(); | ||||
|     // timer for regulator
 | ||||
|     TCCR1B|=(1<<CS12) | (1<<CS10); | ||||
| 	TIMSK1|=(1<<TOIE1)|(1<<OCIE1A); | ||||
| 
 | ||||
|     _delay_ms(1000); | ||||
|     init_pid(&controller, 5, 0.2, 0); | ||||
|     sei(); | ||||
| 
 | ||||
| 	lcd_clear(); | ||||
|     draw_menu(); | ||||
| 
 | ||||
|     // timer for regler
 | ||||
|     TCCR1B|=(1<<CS12) | (1<<CS10); | ||||
| 	TIMSK1|=(1<<TOIE1)|(1<<OCIE1A); | ||||
| 
 | ||||
|     uint16_t x = 0; | ||||
| 	while(1){ | ||||
|         modbusGet(); | ||||
|     } | ||||
| } | ||||
|         read_buttons(); | ||||
| 
 | ||||
| void set_ADC_Channel(uint8_t adr) | ||||
| { | ||||
|     if (adr < 11) | ||||
|     { | ||||
|         ADMUX &= (0b11110000); //Clear MUX-Address
 | ||||
|         ADMUX |= adr;          //Set new MUX-Address
 | ||||
|         //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; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void modbusGet(void) { | ||||
| 	if (modbusGetBusState() & (1<<ReceiveCompleted)) | ||||
| 	{ | ||||
| 		switch(rxbuffer[1]) { | ||||
|             case fcReadHoldingRegisters: | ||||
|             case fcPresetSingleRegister: | ||||
| 			case fcPresetMultipleRegisters:  | ||||
| 				modbusExchangeRegisters((uint16_t *)&OCR2B,0,1); | ||||
|                 break; | ||||
| ISR(PCINT2_vect){ | ||||
|     encoder_isr(); | ||||
| } | ||||
| 
 | ||||
|             case fcReadCoilStatus: | ||||
|             case fcForceSingleCoil: | ||||
|             case fcForceMultipleCoils: | ||||
| 				modbusExchangeBits(&PORTB,0,4); | ||||
|                 break; | ||||
| ISR(TIMER0_OVF_vect) { //this ISR is called 9765.625 times per second
 | ||||
| 	modbusTickTimer(); | ||||
| } | ||||
| 
 | ||||
|             case fcReadInputRegisters: | ||||
|                 if(modbusRequestedAddress()<10) | ||||
|                     modbusExchangeRegisters((uint16_t *)&adc_avrg,0,8); | ||||
|                 else | ||||
|                     modbusExchangeRegisters((uint16_t *)&output,10,4); | ||||
|                 break; | ||||
| ISR(TIMER1_COMPA_vect) { | ||||
|     /* turn off outputs */ | ||||
| 
 | ||||
|             default: | ||||
| 				modbusSendException(ecIllegalFunction); | ||||
|                 break; | ||||
| 		} | ||||
|     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; | ||||
| 
 | ||||
| ISR(TIMER0_OVF_vect) { //this ISR is called 9765.625 times per second
 | ||||
| 	modbusTickTimer(); | ||||
|     //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) { | ||||
|     output = pid_step(&controller, 1, setpoint_1 - adc_avrg[1]); | ||||
|     int16_t tmp_pid = pid_step(&controller, 1, temp_setpoints[0] - temp_values[0]); | ||||
|      | ||||
|     PORTD &= ~(1 << 4); | ||||
|     if(tmp_pid>=0) | ||||
|         output = tmp_pid; | ||||
|     else | ||||
|         output = 0; | ||||
| 
 | ||||
|     if(output > 128) | ||||
|         output = 128; | ||||
| 
 | ||||
|     if(output >= 1){ | ||||
|     if(output >= 128){ | ||||
|         output = 128; | ||||
|         duty[0]=0xFFFE; | ||||
|     } | ||||
|     else if(output >= 1){ | ||||
|         uint32_t tmp = output * 512; | ||||
|         if(tmp >= 0x10000) | ||||
|             tmp = 0xFFFE; | ||||
| 
 | ||||
|         OCR1A = tmp; | ||||
|         PORTB |= 0x0E; | ||||
|         duty[0] = tmp; | ||||
|     } | ||||
|     else | ||||
|         OCR1A = 1000; | ||||
| } | ||||
| 
 | ||||
| ISR(TIMER1_COMPA_vect) { | ||||
|     /* turn off outputs */ | ||||
|     PORTB &= ~(0x0E); | ||||
| } | ||||
|         duty[0]=0; | ||||
| 
 | ||||
| ISR(ADC_vect) | ||||
| { | ||||
|     static uint8_t init[4] = {0,0,0,0}; | ||||
|     static uint8_t current_channel = 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]); | ||||
|     duty[1] = duty[0] / 100 * temp_setpoints[1]; | ||||
|     duty[2] = duty[0] / 100 * temp_setpoints[2]; | ||||
| 
 | ||||
|     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; | ||||
|     for(uint8_t i = 0; i < 3; i++){ | ||||
|         if(duty[i] >= 0xFFFE) | ||||
|             duty[i] = 0xFFFE; | ||||
|     } | ||||
|         else{ | ||||
|             adc_avrg[current_channel] = get_buffer_mean(&adc_buf[current_channel]); | ||||
|             init[current_channel]=0; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     current_channel++; | ||||
|     if(current_channel == 4) | ||||
|         current_channel = 0; | ||||
|     set_ADC_Channel(current_channel); | ||||
| 
 | ||||
|     ADCSRA |= (1 << ADSC); //Start next conversion
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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)
 | ||||
|     //    }
 | ||||
| } | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -0,0 +1,3 @@ | ||||
| avarice -5 -w -P atmega328p :4242 & | ||||
| sleep 2 | ||||
| avrdude -c atmelice_isp -p m328p  -U hfuse:w:0xD9:m | ||||
					Loading…
					
					
				
		Reference in New Issue