/*
* mig-mod.cpp
*
* Created: 19.05.2023 17:50:08
* Author : sem
* Mig-mag kaynak makinesi için tel hızı kontrolü ve postflow ve preflow ayar fonksiyonlarını ekler
* Kaynak makinesi kontrol katı ve inverter katından oluşuyor.
* Bu kod kullanıcı inputları ile kontrol kartı inputları ve outputları arasında çalışıyor.
*
* Kullanıcının tetik inputunu okumak,
* Kullanıcının tetik inputunu kontrol kartına iletmek.
* Gaz selenoidini kontrol etmek
* Tel sürme motorunu kontrol etmek
* Ayar potlarını okumak.
*
*State machine olarak çalıştırmak daha kolay olacak
* 1. durum bekleme durumu
* -tüm outputlar kapalı.
* -sürekli inputları okuma
* -Bu durumdan tek çıkış preflow durumuna (tetiğe basılmasıyla)
* -Bu modda hızlı tel besleme tuşu çalışır, kaynak tli değişiminde kolaylık için
* 2. preflow durumu
* -Gaz selenoidi açılır.
* -preflow süresi boyunca;
* -tetik inputu okunur, tetik kapanırsa bekleme durumuna dönülür
* -preflow süresi dolunca kaynak yapma durumuna geçilir
* 3. kaynak yapma durumu
* -Buraya geçildiğinde gaz selenoidi zaten açıktır.
* -tetik-out çıkışı açılır. orjinal kontrol katının inverteri etkinleştirmesi sağlanır
* -motor sürülür.
* -tetik sürekli okunur.
* -tetik bırakıldığında postflow durumuna geçilir.
* 4. postflow durumu
* -motor durdurulur
* -tetik-out çıkışı kapatılır.
* -postflow süresi boyunca;
* -tetik inputu okunur.
* -tetik tekrar basılırsa kaynak yapma durumuna geçilir
* -postflow süresi dolunca bekleme durumuna geçilir.
*
*/
#define F_CPU 8000000 // dahili osilatörle
#include <avr/io.h>
#include <avr/interrupt.h>
#include <ctype.h>
#include <util/delay.h>
// Debugging için uart ayarları
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1
// durumlar
#define BEKLEME 0
#define PREFLOW 1
#define KAYNAK 2
#define POSTFLOW 3
#define motor_on
#define motor_off
#define gaz_on PORTD|=1<<PIND6
#define gaz_off PORTD&=~(1<<PIND6)
#define tetik_on PORTD|=1<<PIND7
#define tetik_off PORTD&=~(1<<PIND7)
#define tetik_oku !((PIND>>2)&1)
#define post_oku ADMUX&=~0b1111; ADMUX|=0b1; ADCSRA|= (1<<ADSC); //ADC1
#define pre_oku ADMUX&=~0b1111; ADCSRA|= (1<<ADSC); //ADC0
#define spd_oku ADMUX&=~0b1111; ADMUX|=0b10; ADCSRA|= (1<<ADSC); //ADC2
#define devir_oku ((PIND>>PIND5)&1)
uint8_t durum,gaz,devir_durum;
uint16_t post,pre; // spd;
uint8_t spd;
uint8_t u8buffer;
int8_t i8buffer;
uint16_t devir_per[8];
uint32_t per_top;
void timer1_init(uint8_t on_off);
void USART_Init( unsigned int ubrr); //datasheet'ten olduğu gibi alındı
void USART_Transmit( unsigned char data ); //datasheet'ten olduğu gibi alındı
int main(void)
{
DDRB|=0b111111;
//while(1);
// I/O ayarla
DDRD |= 0b11001000;
PORTD |= 1<<PIND2 ; // tetik inputunun pullup direncini açar
DDRC =0; // sadece ADC inputları var
//ADC ayarla 8 bit okunacak frekans yüksek olabilir
ADMUX|= 1<<REFS0 | 1<<ADLAR; // 8 bit ADC için left adjust, referans voltajı AVCC
ADCSRA |= 1<<ADEN | 1<<ADPS2 ; //
DIDR0 |= 0b111111; //
ADCSRA|= (1<<ADSC); // İlk adc çevrimini başlat
//Timer2 motor pwm için OC2B'ye bağlı
TCCR2A|= 1<< COM2B1 | 1<<WGM21 | 1<<WGM20 ; // fazst PWM OC2B non-inverting
TCCR2B |= 0b10; // 0b10: prscl FCPU/8 yaklaşık 4KHz pwm frekansı
OCR2B=0;
USART_Init(MYUBRR);
while (1)
{
spd_oku;
/*
timer1_init(1);
while(1) // pid geliştirme
{
if((ADCSRA & (1<<ADIF)))// Eğer adc çevrimi tamamlanmışsa çalışır
{
spd=ADCH; // Pot oku
OCR2B=ADCH;
ADCSRA|= (1<<ADSC); // Yeni çevrim başlat
}
if((devir_oku>0)&&(devir_durum<1))
{
devir_durum=devir_oku;
u8buffer=TCNT1;
TCNT1=0;
//timer1_init(1);
}
USART_Transmit(u8buffer);
//USART_Transmit(255);
devir_durum=devir_oku;
//_delay_us(100);
}
*/
while(durum==BEKLEME)
{
PORTB=0b111; // debugging için portb'ye bağlı led dizisini yakar önemsiz
// adc 8 bit okunacak, left adjust yapılandırılacak
// ADC sinyallerinin birbirine etkisini azaltmak için ardışık üç ölçümden sonuncusunu örnekliyorum.
spd_oku;
ADCSRA|= 1<<ADSC; //ADC okuma başlat
while(!(ADCSRA & (1<<ADIF))); //okuma tamamlanana kadar bekle
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
spd=ADCH;
post_oku;
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
// postlow değeri 0-5 saniye olması için bir sabitle çarpılmalı
// TCNT1 sayacı 65535 tikte 8,39 saniye oluyor 5 saniye için 39.055 tik
// postlow potunun 255 olan max değerini 39.055/255=153 ile çarpmak gerek
post=ADCH*153;
pre_oku;
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
ADCSRA|= 1<<ADSC;
while(!(ADCSRA & (1<<ADIF)));
// preflow değeri 0-5 saniye olması için bir sabitle çarpılmalı
// TCNT1 sayacı 65535 tikte 8,39 saniye oluyor 5 saniye için 39.055 tik
// preflow potunun 255 olan max değerini 39.055/255=153 ile çarpmak gerek
pre=ADCH*153;
gaz_off;
if(tetik_oku>0)
{
_delay_ms(25);
if(tetik_oku>0)
{
durum=PREFLOW;
gaz_on;
timer1_init(1); // timeri burada etkinleştiriyorum çünkü preflow durumu eksta while döngüsü eklemek istemiyorum
}
}
}
while(durum==PREFLOW)
{
PORTB=0b100;
if(TCNT1>=pre)
{
durum=KAYNAK;
tetik_on;
_delay_ms(25);
}
if(!tetik_oku) //tetik oku 0 dönerse beklemeye geç
{
_delay_ms(25);
if(!tetik_oku)
{
durum=BEKLEME;
gaz_off; //gaz kapat
timer1_init(0); //timer1 kapat
}
}
}
while(durum==KAYNAK)
{
PORTB=0b10000;
tetik_on;
while(tetik_oku)
{
// motor devir okuma ve pwm pid kontrolü
// devir sinyali frekansı düşük ve yapılacak çok iş yok
// bu nedenle sinyal periyodunu sürekli okuma ile ölçmek hataya sebep olmayacak
// yazılımla pin change test edip zaman damgasıyla kontrol edilebilir.
// burada da timer1'i kullanmak mümkün. precale daha uygun seçerek.
// timer1_init
/*
devir_durum=devir_oku;
if(devir_durum!=deviroku)
{
devir_per[i]=TCNT1;
timer1_init(2); //
}
*/
}
// döngüden çıkıldığında postflowa geçilir
tetik_off;
motor_off;
timer1_init(1);
durum=POSTFLOW;
}
while(durum==POSTFLOW)
{
PORTB=0b111000;
if(TCNT1>=post)
{
timer1_init(0);
durum=BEKLEME;
gaz_off;
}
if(tetik_oku)
{
_delay_ms(25);
if(tetik_oku)
{
timer1_init(0);
durum=KAYNAK;
}
}
}
}
}
void timer1_init(uint8_t on_off)
{
// onoff=0 timer kapalı
// on_off=1 timer pre-post flow sürelerine göre yapılandırılır.
// on_off=2 timer kaynak durumunda motor devir periyodunu ölçecek şekilde yapılandırılmış.
if(on_off==0)//timer kapat
{
TCCR1B &= ~(0b111); // prescale kapat
TCNT1=0; // sayacı resetle
}
else if(on_off==1)// süre ölçümü için
{
// 65.535*1.024/8.000.000=8,39 saniye taşım süresi preflow ve postflow sınırları için yeterli
// 7.812,5 tik/saniye
TCCR1B&=~0b111; // timer prscl önce resetlenir
TCNT1=0;
TCCR1B|= 0b101; //prescaler 0b1101 için 1024
}
else if(on_off==2)// hız ölçümü için
{
// motor devir ölçümü için 100hz ila 10hz arasında sinyal sürelerini ölçeceğim.
// en az 0,1 saniyede taşım oluşmalı
// 0,1*8.000.000/65.535=12,2 prescaler bundan büyük olmalı 64 olabiliyor en yakın
// 65535*64/80000000=0,525 yaklaşık yarım saniyede sayaç taşar.
// 8000000/64/1000=125 tik/ms
// 256 prscl için 31,25 tik/ms
TCCR1B&=~0b111; // timer prscl önce resetlenir
TCNT1=0;
TCCR1B |= 0b100; // prscl 0b11 için 64 -prscl 0b100 için 256
}
}
void USART_Init( unsigned int ubrr)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
//Enable receiver and transmitter
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01);
}
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
if( ( UCSR0A & (1<<UDRE0)) )
{
UDR0 = data;
}
/* Put data into buffer, sends the data */
}
/*
ADCSRA|= 1<<ADSC; //ADC okuma başlat
while(!(ADCSRA & (1<<ADIF))); //okuma tamamlanana kadar bekle
spd=ADCH;
OCR2B=ADCH;
*/