/*
* ADC.cpp
*
* Created: 11.03.2020 13:36:41
* Author: павел
*/
#define F_CPU 10000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "pins.h"
uint16_t read_ADC(uint8_t pin);
uint8_t calc_temp_value(uint16_t temp_v);
float calc_fan_speed(uint16_t fan_s);
void set_cur_temp(uint8_t t);
void set_fan_speed(float fs);
void adc_init(void)
{
// левое смещение, 8 битный АЦП
// устанавливаем источник АЦП пин с номером PIN
ADMUX |= (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (0<<MUX0);
ADCSRA |= (1<<ADEN) | // разрешение работы АЦП
(1<<ADSC) | // запуск АЦП
(1<<ADFR) | // автоматический режим АЦП
(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
// предделитель АЦП 128
}
//чтение значения с ацп
uint16_t read_ADC(uint8_t channel)
{
//select pin
ADMUX = (ADMUX & 0xE0) | (channel & 0x1F);
_delay_us (500);
// wait until ADC conversion is complete
return (uint16_t)ADC;
}
void read_sensors(void)
{
uint16_t temp_v = read_ADC(0);
uint8_t cur_temp = calc_temp_value(temp_v);
set_cur_temp(cur_temp);
//uint16_t fan_s = read_ADC(1);
//float cur_rpm = calc_fan_speed(fan_s);
//set_fan_speed(cur_rpm);
}
uint8_t calc_temp_value(uint16_t temp_v)
{
uint16_t adc_table[] = {716,693,671,633,611,583,522,455};
uint8_t temp_table[] = {29,55,70,90,100,110,130,150};
//до таблицы
|
|
if(temp_v>adc_table[0]) return 0;
//после
if(temp_v<adc_table[7]) return 255;
//в таблице
uint8_t temp = 255;
for(int i=0; i<7; i++)
{
//между соседними значениями
if(temp_v<=adc_table[i] & temp_v>=adc_table[i+1])
{
float dADC = adc_table[i] - adc_table[i+1];
float dT = temp_table[i+1] - temp_table[i];
float ADC_value_offset = adc_table[i] - temp_v;
float temp_offset = ADC_value_offset * dT/dADC;
temp = temp_table[i] + (uint8_t)temp_offset;
break;
}
}
return temp;
}
float calc_fan_speed(uint16_t fan_s)
{
return (float) fan_s;
}
/*
* btninput.cpp
*
* Created: 11.03.2020 14:24:16
* Author: Павел
*/
#include <avr/io.h>
#include "pins.h"
const uint8_t btn_count = 6;
uint8_t btn_prev_state[btn_count] = {0xFF,0xFF,0xFF,0xFF,0xFF};
uint8_t read_btn_value(uint8_t index);
//опрос кнопок, возвращает индексы спадающих фронтов 1->0 (нажатие)
uint8_t poll_btns(void)
{
uint8_t falling_edges = 0x00;
for(int i=0; i<btn_count; i++)
{
uint8_t btn_cur_state = read_btn_value(i);
// ~0 && 1
if((btn_cur_state==0x00) & (btn_prev_state[i]==0xFF))
falling_edges |= (1<<i);
btn_prev_state[i] = btn_cur_state;
};
return falling_edges;
}
//дребезг
uint8_t read_btn(uint8_t index)
{
uint8_t prev = read_btn_value(index);
uint8_t counter = 50;
while(counter>0)
{
uint8_t cur = read_btn_value(index);
if(cur == prev)
counter--;
else
counter = 50;
prev = cur;
}
return prev;
}
//текущее состояние
uint8_t read_btn_value(uint8_t index)
{
if(BTN_INPUT_PORT & (1<<index)) return 0xFF;
else return 0x00;
}
/*
* init.cpp
*
* Created: 09.03.2020 16:42:31
* Author: pavel
*/
#include <avr/interrupt.h>
#include "pins.h"
void data_init(void);
void lcd_init(void);
void uart_init(void);
void adc_init(void);
void btninput_init(void);
void led_init(void);
void timer_init(void);
void interrupt_init(void);
void port_init(void)
{
//lcd1602
LCD_PORT_DDR |= (1<<D7) | (1<<D6) | (1<<D5) | (1<<D4) | (1<<E) | (1<<RS);
|
|
LCD_PORT &= ~(1<<D7) & ~(1<<D6) & ~(1<<D5) & ~(1<<D4) & ~(1<<E) & ~(1<<RS);
//ADC
ADC_PORT_DDR &= ~(1<<THERMISTOR_SENSOR_PIN);
ADC_PORT &= ~(1<<THERMISTOR_SENSOR_PIN);
//btns
BTN_PORT_DDR &= ~(1<<ENABLE_SWITCH_BTN_PIN) & ~(1<<MENU_BTN_PIN) & ~(1<<UP_BTN_PIN) &
~(1<<DOWN_BTN_PIN) & ~(1<<SELECT_BTN_PIN) & ~(1<<BACK_BTN_PIN);
BTN_PORT |= (1<<ENABLE_SWITCH_BTN_PIN) | (1<<MENU_BTN_PIN) | (1<<UP_BTN_PIN) |
(1<<DOWN_BTN_PIN) | (1<<SELECT_BTN_PIN) | (1<<BACK_BTN_PIN);
//PWM
PWM_PORT_DDR |= (1<<HEATER_PWM_PIN) | (1<<FAN_PWM_PIN);
PWM_PORT &= ~(1<<HEATER_PWM_PIN) & ~(1<<FAN_PWM_PIN);
//led
LED_PORT_DDR |= (1<<MODE0_LED_PIN) | (1<<MODE1_LED_PIN) | (1<<MODE2_LED_PIN) | (1<<POWER_LED_PIN);
LED_PORT &= ~(1<<MODE0_LED_PIN) & ~(1<<MODE1_LED_PIN) & ~(1<<MODE2_LED_PIN) & ~(1<<POWER_LED_PIN);
//interrupt
FAN_PORT_DDR &= ~(1<<FAN_SPEED_SENSOR_PIN);
FAN_PORT &= ~(1<<FAN_SPEED_SENSOR_PIN);
}
void init()
{
cli();
port_init();
interrupt_init();
uart_init();
adc_init();
data_init();
led_init();
lcd_init();
timer_init();
sei();
}
/*
* interrupt.cpp
*
* Created: 03.05.2020 20:44:12
* Author: pavel
*/
#include "pins.h"
#include <avr/interrupt.h>
#include <avr/io.h>
int pulse_counter;
ISR (INT7_vect) {
pulse_counter++;
}
void interrupt_init(void){
// Прерывание INT0 по спадающему фронту
EICRA = (1<<ISC71) | (1<<ISC70);
EIMSK = (1<<INT7);
EIFR = (1<<INTF7);
pulse_counter = 0;
}
int get_impulse_counter(void){
int value = pulse_counter;
pulse_counter = 0;
return value;
}
/*
* LCD1602.cpp
*
* Created: 09.03.2020 16:38:42
* Author: pavel
*/
#define F_CPU 10000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "pins.h"
#define ENABLE_INPUT() PORTC|= (1<<E)
#define DISABLE_INPUT() PORTC &= ~(1<<E)
#define SET_COMMAND_OUTPUT() PORTC &= ~(1<<RS)
#define SET_DATA_OUTPUT() PORTC |= (1<<RS)
#define CLEAR_SCR() write_command(0x01)
#define NEXT_ROW() write_command(0xC0) //!1
void write_char(unsigned char data);
void write_command(unsigned char command);
void write_first_half(unsigned char c);
void write_second_half(unsigned char c);
void LCD_print(uint8_t arr[32]);
//
void menu_init(void);
uint8_t * get_cur_screen(void);
unsigned char arr_prev[32];
//init
void lcd_init()
{
menu_init();
_delay_ms (50);
//write_command(0x30); //8 bit
write_first_half(0x28); //4 bit, new cycle
write_command(0x08); //off
write_command(0x28);
write_command(0x01); //clear, zero pos
write_command(0x06); //cursor -> on write
write_command(0x0C); //on, no cursor
for (int i=0; i<32; i++)
arr_prev[i] = 0x00;
}
//вывод на 1602
void screen_output()
{
//input image
uint8_t * arr = get_cur_screen();
//same as before
bool eq = true;
for (int i=0; i<32; i++)
if(arr[i]!=arr_prev[i])
{
//different
eq = false;
break;
}
//different
if(!eq)
{
CLEAR_SCR();
LCD_print(arr);
}
//save to prev
for (int i=0; i<32; i++) arr_prev[i] = arr[i];
}
//отправить команду
void write_command(unsigned char command) //функция управления
{
SET_COMMAND_OUTPUT();
_delay_ms (1);
write_first_half(command);
write_second_half(command);
_delay_ms (1);
}
//отправить символ
void write_char(unsigned char data)
{
SET_DATA_OUTPUT();
_delay_ms (1);
write_first_half(data);
write_second_half(data);
}
//старшая половина
void write_first_half(unsigned char c) //функция вывода символов
{
ENABLE_INPUT();
LCD_PORT = (LCD_PORT & 0x0F) | (c & 0xF0);
_delay_ms (1);
DISABLE_INPUT();
_delay_ms (1);
}
//младшая половина
void write_second_half(unsigned char c) //функция вывода символов
{
ENABLE_INPUT();
LCD_PORT = (LCD_PORT & 0x0F) | (c << 4);
_delay_ms (1);
DISABLE_INPUT();
_delay_ms (1);
}
//вывод страницы
void LCD_print(uint8_t arr[32])
{
for (int i=0; i<32; i++)
{
if(i==16) NEXT_ROW();
write_char(arr[i]);
}
}
//видимый курсор
void enable_cursor(void)
{
write_command(0x0F);
}
//невидимый курсор
void disable_cursor(void)
{
write_command(0x0C);
}
//перемещение курсора
void set_cursor_pos(uint8_t cur_pos)
{
write_command(0x80+cur_pos);
}
/*
* leds.cpp
*
* Created: 15.03.2020 12:43:54
* Author: pavel
*/
#include <avr/io.h>
#include "pins.h"
uint8_t get_active_relay(void);
uint8_t get_power_enabled(void);
uint8_t prev;
void led_init(void)
{
prev = 0x00;
}
void led_output(void)
{
uint8_t cur = (1 << (get_active_relay()-1));
if(get_power_enabled()==0xFF)
cur |= 0b00001000;
if(prev!= cur)
{
//off
LED_PORT &= ~(1<<MODE0_LED_PIN) & ~(1<<MODE1_LED_PIN) & ~(1<<MODE2_LED_PIN) & ~(1<<POWER_LED_PIN);
//new
LED_PORT |= cur;
}
prev = cur;
}
/*
* ISU.cpp
*
* Created: 09.03.2020 15:55:28
* Author: pavel
*/
#define F_CPU 10000000UL
#include <util/delay.h>
#include <avr/io.h>
|
|
//прототипы функций
//init
void init(void);
//LCD
void screen_output(void);
//
void uart_send_char(void);
uint16_t poll_adc();
uint8_t poll_btns(void);
void process_button(uint8_t falling_edges);
void led_output(void);
void read_sensors(void);
void pwm_output(void);
void message_exchange(void);
void temp_regulation(void);
int main(void)
{
uint16_t count = 500;
init();
while (1)
{
//sensors
read_sensors();
//PID
temp_regulation();
//PWM
//pwm_output();
//buttons input
uint8_t falling_edges = poll_btns();
//buttons processing
process_button(falling_edges);
//UART
count--;
if(count==0)
{
message_exchange();
count = 500;
}
//LEDs
led_output();
//LCD
screen_output();
//_delay_ms(10);
}
}
/*
* menu.cpp
*
* Created: 12.03.2020 9:40:17
* Author: pavel
*/
#include <avr/io.h>
#include <math.h>
#include "pins.h"
const uint8_t TEST_SCREEN[32] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
uint8_t MAIN_SCREEN[32] = {'t','=','*','*','*','/','*','*','*',' ','@','=','*','*','*','*',
'P','=','*','*','*','I','=','*','*','*','D','=','*','*','*',' '};
uint8_t MENU_SCREEN[32] = {'-','*','*','*','*','*','*','*','*','*','*','*','*','*','*','S',
'B','A','C','K',' ',' ',' ',' ',' ',' ','S','E','L','E','C','T',};
uint8_t INPUT_SCREEN[32] = {'*','*','*','*','*','*','*','*','*','*','*','*','*','*','*','S',
'M','E','N','U','>',' ','+','-',' ','S','E','L',' ','B','A','K'};
const uint8_t menu[6][16] = {
{'K','p',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ','1','/','6'},
{'K','i',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ','2','/','6'},
{'K','d',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ','3','/','6'},
{'t','(','t','a','r','g','e','t', ')',' ',' ',' ',' ','4','/','6'},
{'t','(','s','h','u','t','d','o','w', 'n',')',' ',' ','5','/','6'},
{'s','w','i','t','c','h',' ','r','e', 'l','a','y',' ','6','/','6'},
};
void insert_data(void);
void set_template_screen(uint8_t template_screen[32]);
void set_button_actions(uint8_t page_type);
void perform_action(uint8_t action);
void enable_value_edit(uint8_t start_pos, uint8_t end_pos, float value);
void enable_value_edit(uint8_t start_pos_val, uint8_t end_pos_val, uint8_t value);
void enable_value_edit(uint8_t start_pos_val, uint8_t end_pos_val);
void disable_value_edit(void);
void enable_cursor(void);
void disable_cursor(void);
void set_cursor_pos(uint8_t cur_pos);
uint8_t get_target_temp(void);
uint8_t get_cur_temp(void);
float get_fan_speed(void);
float get_Kp(void);
float get_Ki(void);
float get_Kd(void);
uint8_t get_shutdown_temp(void);
uint8_t get_active_relay(void);
uint8_t get_power_enabled(void);
void enable_power(void);
|
|
void disable_power(void);
void set_Kp(float kp);
void set_Ki(float ki);
void set_Kd(float kd);
void set_target_temp(uint8_t t);
void set_shutdown_temp(uint8_t t);
void set_active_relay(uint8_t r);
//текущая страница
//содержимое
uint8_t cur_screen[32];
//тип
uint8_t page_type;
//назначения кнопок
uint8_t menu_btn_action;
uint8_t back_btn_action;
uint8_t select_btn_action;
uint8_t up_btn_action;
uint8_t down_btn_action;
//const action
uint8_t power_btn_action;
//позиция в меню
uint8_t menu_pos;
//редактирование параметров через меню
bool is_edit_enabled;
bool float_value; //float/uint8_t
uint8_t start_pos; //индекс старшего разряда
uint8_t end_pos; //индекс младшего разряда
uint8_t cur_pos; //текущий разряд
uint8_t i_source_value; //исходное
float f_source_value; //значение
//действия кнопок в зависимоти от текущего экрана
// -
#define BTN_ACTION_MENU_DOWN 0
#define BTN_ACTION_VALUE_DEC 1
//+
#define BTN_ACTION_MENU_UP 2
#define BTN_ACTION_VALUE_INC 3
//menu
#define BTN_ACTION_OPEN_MENU 4
#define BTN_ACTION_NEXT_DIGIT 5
//+ close menu
//back
#define BTN_ACTION_CLOSE_MENU 7
//select
//+ open menu
#define BTN_ACTION_OPEN_INPUT 8
#define BTN_ACTION_ACCEPT_VALUE 9
//еще
#define BTN_ACTION_NO_ACTION 10
#define BTN_ACTION_POWER_SWITCH 11
//типы страницы
#define MAIN_PAGE 0
#define MENU_PAGE 1
#define INPUT_PAGE 2
void menu_init(void)
{
//курсор
is_edit_enabled = false;
set_template_screen(MAIN_SCREEN);
page_type = MAIN_PAGE;
set_button_actions(page_type);
power_btn_action = BTN_ACTION_POWER_SWITCH;
insert_data();
}
//вставка значений на страницу
void insert_data(void)
{
switch(page_type)
{
case MAIN_PAGE:
{
//uint8_t MAIN_SCREEN[32] = {'t','=','*','*','*','/','*','*','*',' ','@','=','*','*','*','*',
// 'P','=','*','*','*','I','=','*','*','*','D','=','*','*','*',' '};
uint8_t t = get_cur_temp();
cur_screen[2] = ((int)t%1000)/100 + '0';
cur_screen[3] = ((int)t%100)/10 + '0';
cur_screen[4] = ((int)t%10) + '0';
t = get_target_temp();
cur_screen[6] = (t/100) + '0';
cur_screen[7] = ((t%100)/10) + '0';
cur_screen[8] = (t%10) + '0';
float f = get_fan_speed();
cur_screen[12] = ((int)f/1000) + '0';
cur_screen[13] = ((int)f%1000)/100 + '0';
cur_screen[14] = ((int)f%100)/10 + '0';
cur_screen[15] = ((int)f%10) + '0';
f = get_Kp();
cur_screen[18] = ((int)f) + '0';
cur_screen[19] = '.';
cur_screen[20] = ((int)(10 * f) %10) + '0';
f = get_Ki();
cur_screen[23] = ((int)f) + '0';
cur_screen[24] = '.';
cur_screen[25] = ((int)(10 * f) %10) + '0';
f = get_Kd();
cur_screen[28] = ((int)f) + '0';
cur_screen[29] = '.';
cur_screen[30] = ((int)(10 * f) %10) + '0';
break;
}
case MENU_PAGE:
for (int i=0; i<16; i++)
{
cur_screen[i] = menu[menu_pos][i];
}
break;
case INPUT_PAGE:
switch(menu_pos)
{
//P
case 0:
{
if(!is_edit_enabled)
enable_value_edit(3,5,get_Kp());
cur_screen[0] ='K';
cur_screen[1] ='p';
cur_screen[2] ='=';
cur_screen[3] = ((int)f_source_value) + '0';
cur_screen[4] = ((int)(10 * f_source_value) %10) + '0';
cur_screen[5] = ((int)(100 * f_source_value) %10) + '0';
for(int i =6; i<16; i++)
cur_screen[i] = ' ';
break;
}
//I
case 1:
{
if(!is_edit_enabled)
enable_value_edit(3,5,get_Ki());
cur_screen[0] ='K';
cur_screen[1] ='i';
cur_screen[2] ='=';
cur_screen[3] = ((int)f_source_value) + '0';
cur_screen[4] = ((int)(10 * f_source_value) %10) + '0';
cur_screen[5] = ((int)(100 * f_source_value) %10) + '0';
for(int i =6; i<16; i++)
cur_screen[i] = ' ';
break;
}
//D
case 2:
{
if(!is_edit_enabled)
enable_value_edit(3,5,get_Kd());
cur_screen[0] ='K';
cur_screen[1] ='d';
cur_screen[2] ='=';
cur_screen[3] = ((int)f_source_value) + '0';
cur_screen[4] = ((int)(10 * f_source_value) %10) + '0';
cur_screen[5] = ((int)(100 * f_source_value) %10) + '0';
for(int i =6; i<16; i++)
cur_screen[i] = ' ';
break;
}
//t targ
case 3:
{
if(!is_edit_enabled)
enable_value_edit(10,12,get_target_temp());
cur_screen[0] ='t';
cur_screen[1] ='(';
cur_screen[2] ='t';
cur_screen[3] ='a';
cur_screen[4] ='r';
cur_screen[5] ='g';
cur_screen[6] ='e';
cur_screen[7] ='t';
cur_screen[8] =')';
cur_screen[9] ='=';
cur_screen[10] = (i_source_value/100) + '0';
cur_screen[11] = ((i_source_value%100)/10) + '0';
cur_screen[12] = (i_source_value%10) + '0';
for(int i =13; i<16; i++)
cur_screen[i] = ' ';
break;
}
//t shutdown
case 4:
{
if(!is_edit_enabled)
enable_value_edit(12,14,get_shutdown_temp());
cur_screen[0] ='t';
cur_screen[1] ='(';
cur_screen[2] ='s';
cur_screen[3] ='h';
cur_screen[4] ='u';
cur_screen[5] ='t';
cur_screen[6] ='d';
cur_screen[7] ='o';
cur_screen[8] ='w';
cur_screen[9] ='n';
cur_screen[10] =')';
cur_screen[11] ='=';
cur_screen[12] = (i_source_value/100) + '0';
cur_screen[13] = ((i_source_value%100)/10) + '0';
cur_screen[14] = (i_source_value%10) + '0';
cur_screen[15] = ' ';
break;
}
//relay 1..3
case 5:
if(!is_edit_enabled)
enable_value_edit(15,15,get_active_relay());
cur_screen[0] ='a';
cur_screen[1] ='c';
cur_screen[2] ='t';
cur_screen[3] ='i';
cur_screen[4] ='v';
cur_screen[5] ='e';
cur_screen[6] =' ';
cur_screen[7] ='r';
cur_screen[8] ='e';
cur_screen[9] ='l';
cur_screen[10] ='a';
cur_screen[11] ='y';
cur_screen[12] =' ';
cur_screen[13] ='=';
cur_screen[14] =' ';
cur_screen[15] = '0' + i_source_value;
break;
}
break;
}
}
//шаблон страницы
void set_template_screen(uint8_t template_screen[32])
{
for(int i=0; i<32; i++)
cur_screen[i] = template_screen[i];
}
//назначения кнопок в зависимости от типа страницы
void set_button_actions(uint8_t page_type)
{
switch(page_type)
{
case MAIN_PAGE:
menu_btn_action = BTN_ACTION_OPEN_MENU;
back_btn_action = BTN_ACTION_OPEN_MENU;
select_btn_action = BTN_ACTION_OPEN_MENU;
up_btn_action = BTN_ACTION_OPEN_MENU;
down_btn_action = BTN_ACTION_OPEN_MENU;
break;
case MENU_PAGE:
menu_btn_action = BTN_ACTION_CLOSE_MENU;
back_btn_action = BTN_ACTION_CLOSE_MENU;
select_btn_action = BTN_ACTION_OPEN_INPUT;
up_btn_action = BTN_ACTION_MENU_UP;
down_btn_action = BTN_ACTION_MENU_DOWN;
break;
case INPUT_PAGE:
menu_btn_action = BTN_ACTION_NEXT_DIGIT;
back_btn_action = BTN_ACTION_OPEN_MENU;
select_btn_action = BTN_ACTION_ACCEPT_VALUE;
up_btn_action = BTN_ACTION_VALUE_INC;
down_btn_action = BTN_ACTION_VALUE_DEC;
break;
}
}
//обработка нажатия на кнопку
void process_button(uint8_t falling_edges)
{
for(int i=0; i<8; i++)
{
if(0x01 & (falling_edges>>i))
switch(i)
{
case ENABLE_SWITCH_BTN_PIN:
perform_action(power_btn_action);
break;
case MENU_BTN_PIN:
perform_action(menu_btn_action);
break;
case UP_BTN_PIN:
perform_action(up_btn_action);
break;
case DOWN_BTN_PIN:
perform_action(down_btn_action);
break;
case SELECT_BTN_PIN:
perform_action(select_btn_action);
break;
case BACK_BTN_PIN:
perform_action(back_btn_action);
break;
}
}
}
//выполнение привязанного действия
void perform_action(uint8_t action)
{
switch(action)
{
//открыть страницу меню
case BTN_ACTION_OPEN_MENU:
if(is_edit_enabled) disable_value_edit();
set_template_screen(MENU_SCREEN);
page_type = MENU_PAGE;
menu_pos = 0;
set_button_actions(page_type);
insert_data();
break;
//закрыть страницу меню (открыть главную)
case BTN_ACTION_CLOSE_MENU:
set_template_screen(MAIN_SCREEN);
page_type = MAIN_PAGE;
set_button_actions(page_type);
insert_data();
break;
//запомнить измененное значение
case BTN_ACTION_ACCEPT_VALUE:
{
disable_value_edit();
switch(menu_pos)
{
//P
case 0:
{
set_Kp(f_source_value);
break;
}
//I
case 1:
{
set_Ki(f_source_value);
break;
}
//D
case 2:
{
set_Kd(f_source_value);
break;
}
//t targ
case 3:
{
set_target_temp(i_source_value);
break;
}
//t shutdown
case 4:
{
set_shutdown_temp(i_source_value);
break;
}
//relay 1..3
case 5:
set_active_relay(i_source_value);
break;
}
set_template_screen(MENU_SCREEN);
page_type = MENU_PAGE;
set_button_actions(page_type);
insert_data();
break;
}
//движение по меню вниз
case BTN_ACTION_MENU_DOWN:
menu_pos++;
if(menu_pos==6)
menu_pos=0;
insert_data();
break;
//движение по меню вверх
case BTN_ACTION_MENU_UP:
if(menu_pos==0)
menu_pos=5;
else
menu_pos--;
insert_data();
break;
//циклический выбор разряда справа
case BTN_ACTION_NEXT_DIGIT:
cur_pos++;
if(cur_pos>end_pos)
cur_pos=start_pos;
set_cursor_pos(cur_pos);
break;
//ничего не делать
//case BTN_ACTION_NO_ACTION:
//
//break;
//уменьшить значение в выбранном разряде на 1
case BTN_ACTION_VALUE_DEC:
if(float_value)
{
float dec_value = pow (10,(-2 - (cur_pos - end_pos)));
if(f_source_value - dec_value > 0)
f_source_value -= dec_value;
else
f_source_value = 0.0;
}
else
{
if(menu_pos!=5)
{
uint8_t dec_value = pow (10,(end_pos - cur_pos));
if(i_source_value - dec_value > 0)
i_source_value -= dec_value;
else
i_source_value = 0;
}
//select relay
else
{
if(i_source_value==1)
i_source_value = 3;
else
i_source_value--;
}
}
insert_data();
break;
//увеличить значение в выбранном разряде на 1
case BTN_ACTION_VALUE_INC:
if(float_value)
{
float add_value = pow (10,(-2 - (cur_pos - end_pos)));
if(f_source_value + add_value < 10)
f_source_value += add_value;
else
f_source_value = 9.99;
}
else
{
//others
if(menu_pos!=5)
{
uint8_t add_value = pow (10,(end_pos - cur_pos));
if(i_source_value + add_value < 256)
i_source_value += add_value;
else
i_source_value = 255;
}
//select relay
else
{
i_source_value++;
if(i_source_value>3)
i_source_value = 1;
}
}
insert_data();
break;
//открыть страницу ввода выбранного параметра
case BTN_ACTION_OPEN_INPUT:
set_template_screen(INPUT_SCREEN);
page_type = INPUT_PAGE;
set_button_actions(page_type);
insert_data();
break;
case BTN_ACTION_POWER_SWITCH:
if(get_power_enabled()==0xFF)
disable_power();
else
enable_power();
break;
}
}
uint8_t * get_cur_screen(void)
{
insert_data();
if(is_edit_enabled)
set_cursor_pos(cur_pos);
return cur_screen;
}
//вкючить редактирование выбранного значения
void enable_value_edit(uint8_t start_pos_val, uint8_t end_pos_val, float value)
{
float_value = true;
f_source_value = value;
enable_value_edit(start_pos_val,end_pos_val);
}
void enable_value_edit(uint8_t start_pos_val, uint8_t end_pos_val, uint8_t value)
{
float_value = false;
i_source_value = value;
enable_value_edit(start_pos_val,end_pos_val);
}
void enable_value_edit(uint8_t start_pos_val, uint8_t end_pos_val)
{
is_edit_enabled = true;
start_pos = start_pos_val;
end_pos = end_pos_val;
cur_pos = start_pos;
enable_cursor();
set_cursor_pos(cur_pos);
}
void disable_value_edit(void)
{
is_edit_enabled = false;
disable_cursor();
}
/*
* parameters.cpp
*
* Created: 12.03.2020 12:11:55
* Author: pavel
*/
#include <avr/io.h>
#include <avr/eeprom.h>
#define HEATER_ON 0xFF;
#define HEATER_OFF 0x00;
//сохраненные параметры
float EEMEM EEPROM_Kp;
float EEMEM EEPROM_Ki;
float EEMEM EEPROM_Kd;
uint8_t EEMEM EEPROM_target_temp;
uint8_t EEMEM EEPROM_shutdown_temp;
uint8_t EEMEM EEPROM_active_relay;
//параметры
float Kp;
float Ki;
float Kd;
uint8_t target_temp;
uint8_t shutdown_temp;
uint8_t active_relay;
//
uint8_t cur_temp;
float fan_speed;
//вкл/выкл нагрев
uint8_t power;
float read_from_eeprom(float* addr);
uint8_t read_from_eeprom(uint8_t * addr);
void write_to_eeprom(uint8_t val, uint8_t * addr);
void write_to_eeprom(float val, float* addr);
void disable_power(void);
void data_init(void)
{
Kp = read_from_eeprom(&EEPROM_Kp);
Ki = read_from_eeprom(&EEPROM_Ki);
Kd = read_from_eeprom(&EEPROM_Kd);
target_temp = read_from_eeprom(&EEPROM_target_temp);
shutdown_temp = read_from_eeprom(&EEPROM_shutdown_temp);
active_relay = read_from_eeprom(&EEPROM_active_relay);
fan_speed = 0;
cur_temp = 0;
disable_power();
}
float get_Kp(void)
{
return Kp;
}
void set_Kp(float kp)
{
Kp = kp;
write_to_eeprom(kp,&EEPROM_Kp);
}
float get_Ki(void)
{
return Ki;
}
void set_Ki(float ki)
{
Ki = ki;
write_to_eeprom(ki,&EEPROM_Ki);
}
float get_Kd(void)
{
return Kd;
}
void set_Kd(float kd)
{
Kd = kd;
write_to_eeprom(kd,&EEPROM_Kd);
}
uint8_t get_target_temp(void)
{
return target_temp;
}
void set_target_temp(uint8_t t)
{
target_temp = t;
write_to_eeprom(t,&EEPROM_target_temp);
}
uint8_t get_shutdown_temp(void)
{
return shutdown_temp;
}
void set_shutdown_temp(uint8_t t)
{
shutdown_temp = t;
write_to_eeprom(t,&EEPROM_shutdown_temp);
}
uint8_t get_active_relay(void)
{
return active_relay;
}
void set_active_relay(uint8_t r)
{
active_relay = r;
write_to_eeprom(r,&EEPROM_active_relay);
}
uint8_t get_cur_temp(void)
{
return cur_temp;
}
void set_cur_temp(uint8_t t)
{
cur_temp = t;
}
float get_fan_speed(void)
{
return fan_speed;
}
void set_fan_speed(float fs)
{
fan_speed = fs;
}
//switch power
void disable_power(void)
{
power = HEATER_OFF;
}
void enable_power(void)
{
power = HEATER_ON;
}
uint8_t get_power_enabled(void)
{
return power;
}
//чтение/запись параметров
void write_to_eeprom(uint8_t val, uint8_t * addr)
{
eeprom_write_byte(addr, val);
}
void write_to_eeprom(float val, float* addr)
{
eeprom_write_float(addr, val);
}
uint8_t read_from_eeprom(uint8_t * addr)
{
return eeprom_read_byte(addr);
}
float read_from_eeprom(float* addr)
{
return eeprom_read_float(addr);
}
/*
* pins.h
*
* Created: 12.03.2020 5:11:59
* Author: pavel
*/
#ifndef PINS_H_
#define PINS_H_
//pins
//индикаторы активного реле
#define MODE0_LED_PIN PA0
#define MODE1_LED_PIN PA1
#define MODE2_LED_PIN PA2
#define POWER_LED_PIN PA3
//input buttons
#define ENABLE_SWITCH_BTN_PIN PD0
#define MENU_BTN_PIN PD1
#define UP_BTN_PIN PD2
#define DOWN_BTN_PIN PD3
#define SELECT_BTN_PIN PD4
#define BACK_BTN_PIN PD5
#define BTN_INPUT_PORT PIND
//PWM
#define HEATER_PWM_PIN PB5
#define FAN_PWM_PIN PB6
//LCD1602
#define D7 PC7
#define D6 PC6
#define D5 PC5
#define D4 PC4
#define E PC3
#define RS PC2
//sensors
#define THERMISTOR_SENSOR_PIN PF0
#define FAN_SPEED_SENSOR_PIN PE1
//ports
#define LCD_PORT PORTC
#define BTN_PORT PORTD
#define ADC_PORT PORTF
#define FAN_PORT PORTE
#define PWM_PORT PORTC
#define LED_PORT PORTA
//ports direction
#define LCD_PORT_DDR DDRC
#define BTN_PORT_DDR DDRD
#define ADC_PORT_DDR DDRF
#define FAN_PORT_DDR DDRE
#define PWM_PORT_DDR DDRB
#define LED_PORT_DDR DDRA
#endif /* PINS_H_ */
/*
* temp.cpp
*
* Created: 21.05.2020 10:30:03
* Author: pavel
*/
#include <avr/io.h>
uint8_t get_shutdown_temp(void);
uint8_t get_cur_temp(void);
void disable_power(void);
uint8_t get_target_temp(void);
float get_Ki(void);
float get_Kd(void);
float get_Kp(void);
void set_pwm_values(uint8_t heater, uint8_t fan);
void shutdown_control(void);
uint8_t PID(void);
void temp_regulation(void)
{
shutdown_control();
uint8_t pid = PID();
set_pwm_values(pid,255-pid);
}
void shutdown_control(void)
{
uint8_t shutdown_temp = get_shutdown_temp();
uint8_t cur_temp = get_cur_temp();
if(cur_temp>=shutdown_temp) disable_power();
}
int e = 0;
int e1 = 0;
int e2 = 0;
uint8_t PID(void)
{
e2=e1;
e1=e;
uint8_t target_temp = get_target_temp();
uint8_t cur_temp = get_cur_temp();
e = target_temp - cur_temp;
// i*=0.9;
int I = e+e1+e2;
int D = e - e1;
int P = e;
float Ki = get_Ki();
float Kd = get_Kd();
float Kp = get_Kp();
float Y = (Ki*I + Kd*D + Kp*P);
if (Y >= 255) Y = 255;
if(Y<0) Y=0;
return (uint8_t)Y;
}
/*
* timers.cpp
*
* Created: 12.03.2020 6:52:18
* Author: pavel
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "pins.h"
#define F_CPU 10000000UL
#define FAN_TIMER_FREQ 1000
void set_pwm_values(uint8_t heater, uint8_t fan);
void pwm_output(void);
void init_pwm_timer(void);
void init_fan_timer(void);
int get_impulse_counter(void);
void set_fan_speed(float fs);
float fan_pwm;
float heater_pwm;
int ms_counter;
void timer_init(void)
{
//init_pwm_timer();
init_fan_timer();
}
ISR(TIMER0_COMP_vect) {
ms_counter++;
if(ms_counter>=999){
ms_counter = 0;
//имп / опр время (1 сек)
float impulse_counter = get_impulse_counter();
set_fan_speed((float)(impulse_counter));
}
}
void init_pwm_timer(void){
//PWM
set_pwm_values(128, 128);
// Режим Fast PWM, top = 0x03FF
// OCR1A - Неинвертированный ШИМ
// OCR1B - Инвертированный ШИМ
// OCR1C - Вывод отключён
// Предделитель 1
TCCR1A = (1<<COM1A1) | (0<<COM1A0) |
(1<<COM1B1) | (1<<COM1B0) |
(0<<COM1C1) | (0<<COM1C0) |
(1<<WGM11) | (1<<WGM10);
TCCR1B = (0<<ICNC1) | (0<<ICES1) |
(0<<WGM13) | (1<<WGM12) |
(0<<CS12) | (0<<CS11) | (1<<CS10);
TCNT1 = 0;
ICR1 = 0;
OCR1A = 0; // заполнение канала A
OCR1B = 0; // заполнение канала B
OCR1C = 0;
}
void init_fan_timer(void){
//time
// режим сброс при совпадении
// предделитель 64
ASSR= 0<<AS0;
TCCR0 = (0<<WGM00) | (0<<COM01) | (0<<COM00) | (1<<WGM01)
| (1<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0 = 0x00;
OCR0 = ((F_CPU / 64) / FAN_TIMER_FREQ) - 1;
TIMSK |= (1<<OCIE0);
ms_counter=0;
}
void set_pwm_values(uint8_t heater, uint8_t fan)
{
fan_pwm = (float)fan/255.0;
heater_pwm = (float)heater/255.0;
}
void pwm_output(void)
{
OCR1A = (uint16_t)(heater_pwm * 0x03FF);
OCR1B = (uint16_t)(fan_pwm * 0x03FF);
}
/*
* uart.cpp
*
* Created: 11.03.2020 12:23:20
* Author: Павел
*/
#define F_CPU 10000000UL
//границы сообщений
#define PACKET_START_BYTE 0xBB
#define PACKET_END_BYTE 0x81
#define FRAME_START_BYTE 0xFF
#define FRAME_END_BYTE 0x00
//команды от ПК
#define COMMAND_ONOFF_BYTE 0x66
#define COMMAND_SETPARAM_BYTE 0x99
#define COMMAND_EMPTY_BYTE 0x00 //когда нет команды в буфере
//
#define Kp_ID 0x33
#define Ki_ID 0x55
#define Kd_ID 0x99
#define TT_ID 0xAA
#define ST_ID 0x66
#define AR_ID 0xCC
#define TEMP_SENSOR_ID 0xFA
#define FAN_SENSOR_ID 0xAF
//ответы для ПК
#define ANSWER_COMDECLINE_BYTE 0x33
#define ANSWER_COMACCEPT_BYTE 0xCC
#define ANSWER_PARAMINPUT_BYTE 0x66
#define ANSWER_SENSORDATA_BYTE 0x99
#define BUFFER_MAX_LENGTH 0xFF
#define COMMAND_MAX_LENGTH 10 //start id (com), counter, id (param), val:float, checksum end = 1+1+1+1+4+1+1=10
#define DATA_RECEIVED UCSR0A & (1 << RXC)
#define HEATER_ON 0xFF
#define HEATER_OFF 0x00
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
uint8_t get_power_enabled(void);
void disable_power(void);
void enable_power(void);
uint8_t get_com_len(void);
bool command_add_byte(uint8_t data);
void set_Kp(float kp);
void set_Ki(float ki);
void set_Kd(float kd);
void set_target_temp(uint8_t t);
void set_shutdown_temp(uint8_t t);
void set_active_relay(uint8_t r);
uint8_t get_cur_temp(void);
//буфер принятых данных
struct buffer_cell
{
uint8_t data;
buffer_cell* ptr;
bool in_use;
};
buffer_cell* first_element;
buffer_cell* last_element;
buffer_cell* cur_element;
buffer_cell uart_buffer[BUFFER_MAX_LENGTH];
uint8_t buffer_cur_length;
uint8_t received_command[COMMAND_MAX_LENGTH];
bool frame_started;
bool buffer_lock;
bool lock_buffer(void){
cli();
if(buffer_lock)
return false;
else
{
buffer_lock=true;
return true;
}
sei();
}
void unlock_buffer(void){
cli();
buffer_lock=false;
sei();
}
//буфер под команды от пк
void buffer_init(void)
{
first_element = 0;
last_element = 0;
buffer_cur_length = 0;
buffer_lock = false;
for(int i=0;i<BUFFER_MAX_LENGTH; i++)
uart_buffer[i].in_use = false;
}
//найти превый пустой элемент в буфере
uint8_t buffer_find_free_element_index(void)
{
if(lock_buffer())
{
for(int i=0;i<BUFFER_MAX_LENGTH;i++)
if(!uart_buffer[i].in_use)
{
unlock_buffer();
return i;
}
unlock_buffer();
}
return 0;
}
//добавить элемент в буфер
void buffer_add_element(uint8_t data)
{
if(lock_buffer())
{
if(buffer_cur_length<BUFFER_MAX_LENGTH)
{
if(buffer_cur_length==0)
{
first_element = &uart_buffer[0];
first_element->data = data;
first_element->in_use = true;
last_element = first_element;
buffer_cur_length++;
}
else
{
uint8_t index = buffer_find_free_element_index();
if(index!=0)
{
cur_element = &uart_buffer[index];
cur_element->data = data;
cur_element->in_use = true;
last_element->ptr=cur_element;
last_element=cur_element;
buffer_cur_length++;
}
}
}
unlock_buffer();
}
}
//взять элемент из буфера
uint8_t buffer_get_element(void)
{
if(lock_buffer())
{
if(buffer_cur_length>0)
{
last_element->in_use = false;
uint8_t data = last_element->data;
buffer_cur_length--;
if(buffer_cur_length>0)
{
last_element = first_element;
while(last_element->ptr->in_use==true)
last_element = last_element->ptr;
}
unlock_buffer();
return data;
}
unlock_buffer();
}
return 0;
}
uint8_t cur_command_length = 0;
ISR(USART0_RX_vect)
{
received_command[cur_command_length]=UDR0;
cur_command_length++;
}
void uart_init(void)
{
// Инициализация USART0
UCSR0A = 0x00; //flags
UCSR0B = 0x98; //TXEN RXEN rxint
UCSR0C = 0x86; //формат посылки
uint16_t speed = (F_CPU / 16) / 9600 - 1;
UBRR0H = (speed >> 8) & 0xFF;
UBRR0L = speed & 0xFF;
frame_started = false;
buffer_init();
}
void uart_send_char(uint8_t data) {
while (!(UCSR0A & (1<<UDRE0)));
UDR0 = data; // записываем данные в регистр
}
void clear_command(void)
{
cur_command_length = 0;
for(int i=0;i<COMMAND_MAX_LENGTH;i++)
received_command[i] = FRAME_END_BYTE;
}
uint8_t read_uart_command(void)
{
uint8_t result = 0;
//есть принятые данные
if(cur_command_length>0)
{
for(int i=0; i<cur_command_length; i++)
{
bool last_char = false;
uint8_t length = 255;
//принят байт id команды
if(received_command[1]!=FRAME_END_BYTE)
{
//для передачи параметра - тип
switch(received_command[1])
{
//вкл/выкл 5 байт
case COMMAND_ONOFF_BYTE:
length = 5; //start id count check stop
break;
case COMMAND_SETPARAM_BYTE:
if(received_command[3]!=FRAME_END_BYTE)
{
switch(received_command[3])
{
case Kp_ID:
length = 10; // start id count id value1 value2 value3 value4 check stop
break;
case Ki_ID:
length = 10;
break;
case Kd_ID:
length = 10;
break;
case TT_ID:
length = 7; // start id count id value check stop
break;
case ST_ID:
length = 7;
break;
case AR_ID:
length = 7;
break;
}
}
break;
}
}
last_char = i==length-1;
if(last_char)
result = received_command[1];
}
}
return result;
}
bool control(void)
{
bool result = false;
uint8_t sum = 0;
for(int i=1; i<cur_command_length-2; i++)
sum = (sum + received_command[i]) % 256;
if(sum == received_command[cur_command_length-2])
result = true;
return result;
}
uint8_t process_uart_command(uint8_t command)
{
switch(command)
{
//no
case 0:
break;
case COMMAND_ONOFF_BYTE:
if(get_power_enabled()==HEATER_ON)
disable_power();
else
enable_power();
return 0xFF;
break;
case COMMAND_SETPARAM_BYTE:
switch(received_command[3])
{
case Kp_ID:
{
uint8_t buffer[4];
buffer[0] = received_command[7];
buffer[1] = received_command[6];
buffer[2] = received_command[5];
buffer[3] = received_command[4];
float value = *(float*)(&buffer);
set_Kp(value);
break;
}
case Ki_ID:
{
uint8_t buffer[4];
buffer[0] = received_command[7];
buffer[1] = received_command[6];
buffer[2] = received_command[5];
buffer[3] = received_command[4];
float value = *(float*)(&buffer);
set_Ki(value);
break;
}