Вроде та версия. Но боюсь Вы там ничего не поймете т к программисто из меня не оч. Я как всегда сделаю кривой код потом костыль и костыль костыля.
Код: Выделить всё
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 03.04.2020
Author :
Company :
Comments:
Chip type : ATmega8
Program type : Application
AVR Core Clock frequency: 1,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/
#define ADCMULT 0.0048828125 // разр¤дность ацп
#define mode 2 // кол-во режимов
#include <mega8.h>
#include <stdio.h>
#include <delay.h>
// Alphanumeric LCD Module functions
#include <alcd.h>
volatile unsigned short button_count=0,button_flag=2,press_count=0,counter=0,flag_rotate_encoder=0;
eeprom float kP=12.0,kI=0.4,kD=60.0,dt=500.0; //записть в энергонезависимую память
int ms=0,flag=0,set_temp=40;
float out=0.0;
unsigned char lcd_buff[16];
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int get_temp();
float constrain(float , float, float);
int calculateDID(float,float,float,float,float,float,int,int);
void setting();
void show(float,float,int);
void buzzer(unsigned int delay_buzz,unsigned int count);
// out рез рассчета( выход с регул¤тора (управл¤ющий сигнал))
//button_count // считает до 5 дл¤ определени¤ короткого нажати¤ и пропуска дребезга
// button_flag=0// засчитывает нажатие
//press_count // счетчик нажатий
// float prevErr=0.0; //прошлые ошибки регулировани¤
//float dt=0.0; // период вычислени¤ и регулировани¤ в секундах
//float P=0.0; //ѕропорциональна¤ составл¤юща¤
// float D=0.0; //Диференциальна¤
// float I=0.0; // интегральна¤
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
if(((PIND) & (1<<PIND.3))==1) //проверка вращения в одну сторону
{
flag_rotate_encoder=1;
switch(press_count)
{
case 0:set_temp+=1;break; //Устаноака температуры
case 1:kP+=0.1;break; //Установка коэффициентов
case 2:kI+=0.01;break;
case 3:kD+=0.1;break;
case 4:dt+=100;break;
case 5:set_temp+=1;break;
}
if(set_temp>350)
set_temp=40;
}
else //»наче в другую
{
flag_rotate_encoder=1;
switch(press_count)
{
case 0:set_temp-=1;break;
case 1:kP-=0.1;break;
case 2:kI-=0.01;break;
case 3:kD-=0.1;break;
case 4:dt-=100;break;
case 5:set_temp-=1;break;
}
if(set_temp<40)
set_temp=350;
}
}
// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here
}
// Timer2 output compare interrupt service routine
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
// Place your code here
// срабатывает каждую миллисекунду
ms++;
if(ms>dt)
{
flag=1;// если дотикало до уст значения
ms=0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// обработка нажатий кнопок
if(PIND.1==1) //отпущеная кнопка
{
if(button_count>=50&&button_count<1000) // если нажатие было длительностью от 50до 1000 мс это короткое нажатие
{ // провер¤ется при отжатой кнопке что бы не реарировало короткое нажатие
button_flag=1; // фиксируем короткое нажатие
}
button_count=0; // сбрасываем счетчик КОРОТКИХ нажатий пока не пройдет дребезг
}
else
{
if(button_count<1001)
{
button_count++; // считаем пока пройдет дребезг
}
if(button_count==1000) // если досчитали до 1000 это длинное нажатие
{
button_flag=2; // фиксируем длинное нажатие
press_count++; // счетчик ДЛИННЫХ нажатий
}
}
}
#define ADC_VREF_TYPE 0x40
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0xFF;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State6=P State5=T State4=1 State3=1 State2=0 State1=1 State0=1
PORTC=0x5B;
DDRC=0x1F;
// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=In Func2=In Func1=In Func0=Out
// State7=1 State6=1 State5=1 State4=1 State3=P State2=P State1=P State0=1
PORTD=0xFF;
DDRD=0xF1;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 3,906 kHz
// Mode: Fast PWM top=0x00FF
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x81;
TCCR1B=0x0C;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: CTC top=OCR2A
// OC2 output: Disconnected
// Timer Period: 1 ms
ASSR=0<<AS2;
TCCR2=(0<<PWM2) | (0<<COM21) | (0<<COM20) | (1<<CTC2) | (0<<CS22) | (1<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2=0x7C;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(1<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<TOIE0);
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: On
// INT1 Mode: Falling Edge
GICR|=0xC0;
MCUCR=0x0A;
GIFR=0xC0;
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Any change
// INT1: On
// INT1 Mode: Any change
//GICR|=(1<<INT1) | (1<<INT0);
//MCUCR=(0<<ISC11) | (1<<ISC10) | (0<<ISC01) | (1<<ISC00);
//GIFR=(1<<INTF1) | (1<<INTF0);
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x80;
// USART initialization
// USART disabled
UCSRB=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AVCC pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x83;
// SPI initialization
// SPI disabled
SPCR=0x00;
// TWI initialization
// TWI disabled
TWCR=0x00;
// Alphanumeric LCD initialization
// Connections specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTB Bit 0
// RD - PORTB Bit 2
// EN - PORTB Bit 3
// D4 - PORTB Bit 4
// D5 - PORTB Bit 5
// D6 - PORTB Bit 6
// D7 - PORTB Bit 7
// Characters/line: 16
lcd_init(16);
// Global enable interrupts
#asm("sei")
lcd_clear();
PORTB.2=1; //вкл подсветку
buzzer(10,3); // пикнуть
while (1)
{
if(flag==1) // рассчет значений в заданный промежутки времени
{
out=calculateDID(get_temp(),set_temp,kP,kI,kD,dt,0,255); // вычсление PID
flag=0;
}
OCR1AL=out; // отправляем управляющий сигнал на ШИМ
if(button_flag==1) // если первое короткое нажатие
{
counter++; //Счетчик коротких нажатий
button_flag=0; // что бы реагировало только на одно нажатие и на сл после отпускани¤ и снова нажати¤
}
/////////////////////////////////////////////////////////////////
if(button_flag==2&&press_count==1&&counter==1) // Если длинное нажатие не реагировать, только на короткое
{
lcd_gotoxy(7,0); // верхняя строка
lcd_putchar(0x3c); // показать знак <
lcd_gotoxy(7,1);
lcd_puts(" ");
}
if(button_flag==2&&press_count==2)
{
lcd_gotoxy(7,1); // нижняя строка
lcd_putchar(0x3c); // показать знак <
lcd_gotoxy(7,0);
lcd_puts(" ");
}
if(button_flag==2&&press_count==3)
{
lcd_gotoxy(7,0);
lcd_putchar(0x3e); // показать знак >
lcd_gotoxy(7,1);
lcd_puts(" ");
}
if(button_flag==2&&press_count==4)
{
lcd_gotoxy(7,1);
lcd_putchar(0x3e);
lcd_gotoxy(7,0);
lcd_puts(" ");
}
if(press_count==5)
{
lcd_gotoxy(7,0);
lcd_putchar(0x3c);
lcd_gotoxy(7,1);
lcd_puts(" ");
}
if( press_count==5&&counter==1) //если в режиме натроек прошли все пункты перейти на первый
press_count=1;
if(press_count==0&&counter==1) // костыль стрелочки указывающей изменяемый режим
{
lcd_gotoxy(7,0);
lcd_puts(" ");
lcd_gotoxy(7,1);
lcd_puts(" ");
}
if(counter==1&&flag_rotate_encoder==1&&button_flag!=2)
{
counter=0;
press_count=0;
flag_rotate_encoder=0;
lcd_gotoxy(13,1);
lcd_puts(" ");
}
switch(counter)// в зависимости от кол-ва нажатий разные режимы.
{
case 1:setting();break; // вызвать настойку коэффициентов
default:show(get_temp(),set_temp,out),press_count=0;break; // по умолчанию отображать текущий режим
}
if(counter==mode) // Если дошли до последнего режима
{
counter=0; // Сбросить счетчик коротких нажатий
lcd_clear(); // очистить диспрей
}
//пределы настроек
if(dt>9999.0)
dt=0.0;
else
if(dt<=0.0)
dt=9999.0;
if(kP<=0.0)
kP=0.0;
if(kI<=0.0)
kI=0.0;
if(kD<=0.0)
kD=0.0;
///////////////////////////////////////
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int get_temp() // получить температуру
{
unsigned int i; // сетчик цикла
int m_temp[20]; //массив значений
int g_temp=0; // временная переменная
// int *p=m_temp;
for(i=0;i<20;i++) //усреднить температуру
{
m_temp[i]=read_adc(5)*ADCMULT/0.0041;
//перевсчитываем в температуру(1градус Цельсия=41мв)
}
for(i=0;i<20;i++)
{
g_temp+=m_temp[i]; // читаем из массива и записываем в временную переменную
}
return g_temp/=20; // усредняем и возвращаем
}
int calculateDID(float c_input,float c_setpoint,float c_kP,float c_kI,float c_kD,float c_dt,int minOut, int maxOut)
{
// input температура из датчика
// set point установленна температура
//dt период измерени¤ в секундах
static float integral=0.0, prevErr=0.0;
float err=0.0,D=0.0;
c_dt/=1000; //переводим в секунды
err=c_setpoint-c_input; // ошибка регулировани¤
integral=constrain(integral+(float)err * c_dt * c_kI, minOut, maxOut);
D=(err-prevErr)/c_dt;
prevErr=err;
return constrain(err*c_kP+integral*c_kI+D*c_kD,minOut, maxOut);
}
float constrain(float in_val, float min, float max) // ограничение диапазона шим и интегральной составляющей
{
if(in_val< min) {
return min;
}
else if(in_val>max) {
return max;
}
else
return in_val;
}
void show(float t,float set_t,int out)
{
lcd_gotoxy(0,0);
sprintf(lcd_buff,"Temp=%dC",(int)t);
lcd_puts(lcd_buff);
if(t<100)
{
lcd_gotoxy(8,0);
lcd_puts(" ");
}
lcd_gotoxy(9,0);
if(out>0)
{
out=out/255.0*100.0; // перевести выходной сигнал в 0-100% в диапазоне от 0 до 255
}
sprintf(lcd_buff,"PWM%d%%",(int)out);
lcd_puts(lcd_buff);
if(out<100)
{
lcd_gotoxy(15,0);
lcd_puts(" ");
}
if(out<10)
{
lcd_gotoxy(14,0);
lcd_puts(" ");
}
lcd_gotoxy(0,1);
sprintf(lcd_buff,"Set temp=%dC",(int)set_t);
lcd_puts(lcd_buff);
if(set_t<100)
{
lcd_gotoxy(12,1);
lcd_puts(" ");
}
}
void setting()
{
float tmp=0.0;
tmp=dt/1000.0;
lcd_gotoxy(0,0);
sprintf(lcd_buff,"kP%d.%02d",(int)kP,(int)(kP*100)%100);
lcd_puts(lcd_buff);
lcd_gotoxy(6,0);
lcd_puts(" ");
lcd_gotoxy(0,1);
sprintf(lcd_buff,"kI%d.%02d",(int)kI,(int)(kI*100)%100);
lcd_puts(lcd_buff);
if(kI<1||kI>=1)
{
lcd_gotoxy(6,1);
lcd_puts(" ");
lcd_gotoxy(8,1);
lcd_puts(" ");
}
lcd_gotoxy(9,0);
sprintf(lcd_buff,"kD%d.%02d",(int)kD,(int)(kD*100)%100);
lcd_puts(lcd_buff);
lcd_gotoxy(9,1);
sprintf(lcd_buff,"dt%d.%01ds",(int)tmp,(int)(tmp*10)%10);
lcd_puts(lcd_buff);
if(tmp<10.0)
{
lcd_gotoxy(15,1);
lcd_puts(" ");
}
}
void buzzer(unsigned int delay_buzz,unsigned int count) // пищалка
{
unsigned int i;
for(i=0;i<count;i++)
{
PORTC.2=1;
delay_ms(delay_buzz);
PORTC.2=0;
delay_ms(delay_buzz);
}
}