Приложение А. Код программы для микроконтроллера

/*

 * 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;

                      }


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: