Re: Ламинатор FGK-230
Добавлено: Пт июл 17, 2026 19:09:45
Во всяком случае, во всех 3D-принтерах сделано именно так.
Код: Выделить всё
//------------------------
//
// Регулировка температуры ламинатора (или подобного прибора) в диапазоне 25-220°С
// Massaraksh7 17.07.2026
//
//------------------------
#include <EEPROM.h>
#include <math.h>
#include <avr/pgmspace.h>
//---таблица кодов температуры от 0 до 220°С для термистора NTC 100k B3950
const int ntc[221] ={1009,1008,1007,1007,1006,1005,1004,1003,1002,1001,1000,999,997,996,995,994,992,991,989,988,986,984,983,981,
979,977,975,973,971,969,966,964,962,959,957,954,951,949,946,943,940,937,933,930,927,923,920,916,912,908,905,901,896,892,888,884,
879,875,870,865,860,855,850,845,840,835,830,824,819,813,807,802,796,790,784,778,772,766,759,753,747,740,734,727,721,714,707,701,
694,687,680,674,667,660,653,646,639,632,625,618,611,604,597,590,583,576,569,562,556,549,542,535,528,521,515,508,501,495,488,481,
475,468,462,456,449,443,437,430,424,418,412,406,400,395,389,383,377,372,366,361,355,350,345,340,335,329,324,319,315,310,305,300,
296,291,287,282,278,274,269,265,261,257,253,249,245,241,238,234,230,227,223,220,216,213,209,206,203,200,197,194,191,188,185,182,
179,176,174,171,168,166,163,161,158,156,153,151,149,146,144,142,140,138,136,134,132,130,128,126,124,122,120,119,117,115,113,112,
110,108,107,105,104};
int ttemp; //---Целевое значение температуры
int seg7; //---Счётчик сегментов
int rate; //---Режим =0-работа, =1-программирование
int val_to_show; //---Значение, которое показываетя на индикатореЮ в зависимости от режима
float lastval; //---Последнее сглаженное значение температуры
int countr; //---Счётчик
int btn1; //---Счётчик кнопки prog
int btn2; //---Счётчик кнопки -
int btn3; //---Счётчик кнопки +
int load; //---Управление нагрузкой
float kf_exp=0.9; //---Коэффициент экспоненциального фильтра
double integral = 0.0; //---Накопление интегральных данных
double prevError = 0.0; //---Предыдущая разница
double prevTemp = 0.0; //---Предыдущая температура
const int outMin = 0; //---Ограничения
const int outMax = 255; //---по выходу
//---Коэффициенты для ПИД-регулятора
float kf_p=10.0;
float kf_i=0.028; // 0.023 циклилось на 146-147-148, 0,033 - 151-152
float kf_d=305.0;
//---Индикация одной цифры
void drawDigit(int dig) {
PORTD &= 3;
PORTB &= 0xFC;
switch (dig)
{
case 0: PORTD |= 0x7C; PORTB |= 2; break;
case 1: PORTD |= 4; PORTB |= 2; break;
case 2: PORTD |= 0x74; PORTB |= 1; break;
case 3: PORTD |= 0x54; PORTB |= 3; break;
case 4: PORTD |= 0x0C; PORTB |= 3; break;
case 5: PORTD |= 0x58; PORTB |= 3; break;
case 6: PORTD |= 0x78; PORTB |= 3; break;
case 7: PORTD |= 0x14; PORTB |= 2; break;
case 8: PORTD |= 0x7C; PORTB |= 3; break;
case 9: PORTD |= 0x5C; PORTB |= 3; break;
case 10: break;
}
if (rate |= 0) PORTD |= (1 << 7);
}
//---Выбор номера разряда
void setNumber(int n) {
PORTB |= 0x1C;
switch (n)
{
case 0: PORTB &= ~4;break;
case 1: PORTB &= ~8;break;
case 2: PORTB &= ~16;break;
}
}
//---Показать температуру на индикаторе
void showValue(int seg){
int n;
switch (seg)
{
case 0: n=val_to_show / 100; if (n==0) n=10; break;
case 1: n=(val_to_show / 10) % 10; break;
case 2: n=val_to_show % 10; break;
}
drawDigit(n); setNumber(seg);
}
//--Основной цикл 256 Гц
void setTimer0() {
cli();
TCCR0A = (1 << WGM01);
TCCR0B = 0;
TCCR0B |= (1 << CS02) | (1 << CS00); // 16000000/1024=15625
OCR0A = 61; // 15625/61 ~ 256
TIMSK0 |= (1 << OCIE0A);
sei();
}
//---Читать целевую температуру из EEPROM
void readTTemp() {
int eeaddr=0;
ttemp = EEPROM.read(eeaddr);
if (ttemp==255)
{
ttemp=100;
writeTTemp();
}
}
//---Записать целевую температуру в EEPROM
void writeTTemp() {
int eeaddr=0;
EEPROM.write(eeaddr,ttemp);
}
//
//---Бинарный поиск значения температуры в массиве кодов
//
float BinarySearch(int code) {
int amin,amax,amid,i;
float t;
amax = 220; amin = 0;
//---Бинарный поиск
while (amax>amin)
{
amid = (amin+amax)/2;
if (code==ntc[amid]) return(amid);
if (code>ntc[amid]) amax=amid; else amin = amid+1;
}
//---Точного значения не нашли, интерполяция
if (code>ntc[amid]) amid--;
if (amid<0) return(0);
if (ntc[amid]==ntc[amid+1]) return(amid);
t = amid+(code-ntc[amid])/(ntc[amid+1]-ntc[amid]);
return(t);
}
//---Читать код с NTC100k и применить экспоненциальное сглаживание
void ReadAndSmooth() {
int code;
float tval;
code = analogRead(A5); //
tval = BinarySearch(code);
prevTemp=lastval;
lastval = tval*kf_exp+lastval*(1-kf_exp);
}
//---ПИД-регулятор
int PID (void){
double error = ttemp - lastval;
//---Интегральная часть
integral += error;
const double integralMax = 5000.0;
if (integral > integralMax) integral = integralMax;
if (integral < -integralMax) integral = -integralMax;
//---Дифференциальная часть
double derivative = (error - prevError);
prevError = error;
double output = kf_p * error + kf_i * integral + kf_d * derivative;
//---Ограничение выхода
if (output > outMax) output = outMax;
else if (output < outMin) output = outMin;
return (int)output;
}
//---Установки
void setup() {
//-Порты
DDRB=0x3F;PORTB=0x00;
DDRD=0xFC;PORTD=0x00;
DDRC=0x01;PORTC=0x1A;
//--Нач. значения
integral=0;
prevError=0;
prevTemp=0;
val_to_show = 0;
seg7=0;rate=0;countr=0;lastval=0;
btn1=0;btn2=0;btn3=0;load=0;
readTTemp();
val_to_show=777;
//---Запуск таймера
setTimer0();
}
//--256 Гц - основной цмкл
ISR(TIMER0_COMPA_vect) {
byte inp;
//---показать одну из цифр
showValue(seg7);
seg7++;if (seg7>=3)seg7=0;
//---Программирование целевой температуры
if (rate == 1)
{
val_to_show = ttemp;
inp = PINC; if (!(inp & (1 << PC3))) btn2++; else btn2=0;
inp = PINC; if (!(inp & (1 << PC4))) btn3++; else btn3=0;
inp = PINC; if (!(inp & (1 << PC1))) btn1++; else btn1=0;
if (btn1>=256) {btn1=0;writeTTemp();rate=0;return;}
if (btn2>=25) {btn2=0;if (ttemp>=25)ttemp--;val_to_show = ttemp;}
if (btn3>=25) {btn3=0;if (ttemp<=220)ttemp++;val_to_show = ttemp;}
return;
}
//---считывание кода 1 раз в секунду
countr++;
if (countr==256)
{
countr=0;
ReadAndSmooth();
val_to_show=lastval;
if (rate==0) val_to_show = lastval;
//---ПИД-регулятор
load = PID();
}
//---Вход в режим программирования целевой температуры
inp = PINC; if (!(inp & (1 << PC1))) btn1++; else btn1=0;
if (btn1>=256) {btn1=0;rate=1;}
//--- Реализация расчёта ПИД
if (countr==0){PORTB |= (1<<PB5);PORTC |= (1 << PC0);}
if (countr>=load){PORTB &= ~(1<<PB5); PORTC &= ~(1 << PC0);}
}
void loop() {
while(1){};
}Massaraksh7 писал(а): Сб июл 18, 2026 22:53:20 Два прохода, один раз медью вверх, другой раз медью вниз.
210°С
https://cloud.mail.ru/public/Q1r7/b5MBaK7YH
Так, может, 4 прохода много?Massaraksh7 писал(а): Вс июл 19, 2026 01:14:35 215°С, 4 прохода. По-моему, уже перебор местами.
https://cloud.mail.ru/public/qpSg/wfyvVTD2R
Или 215°С много. Проверю.
Проверил, интереса ради, релейный вариант, как без гистерезиса, так и с ним.BOB51 писал(а): Пт июл 17, 2026 19:35:00 Так в данном случае релейный вариант не особо от обычного регулятора на паре операционных усилителей по результатам отличаться будет...
Есть. Температура плавает на ±3-5-7 °С (и чем больше инерционность объекта, тем выше), а это может повлиять на качество перевода рисунка.
Угу. У меня ещё с юношеского возраста с регулярностью примерно раз в 5-7 лет возникает обострение интереса к электронным поделкам, длится короткий период, а потом снова затухает... до следующего цикла.BOB51 писал(а): Пн июл 20, 2026 14:12:25 Вот так из лени (да ЖАБЫ) и деградируем помаленьку, теряя интерес к самоделкам.