Kód: Vybrat vše
// Версия для Arduino UNO
#include <avr/pgmspace.h>
// ***** LCD *****
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
char LCD_Row_1[17];
char LCD_Row_2[17];
// ***** Stepper Motor *****
#define Motor_X_SetPulse() PORTB &= ~(1<<2) // Pin10 1
#define Motor_X_RemovePulse() PORTB |= (1<<2) // Pin10 0
#define Motor_X_Forward() PORTB |= (1<<3) // Pin11 0
#define Motor_X_Reverse() PORTB &= ~(1<<3) // Pin11 1
#define Motor_X_Enable() PORTB |= (1<<4) // Pin12 0
#define Motor_X_Disable() PORTB &= ~(1<<4) // Pin12 1
boolean Step_On_flag=false; // Флаг разрешаем/запрещаем счет до "шагать"
boolean Mode_On_flag=false; // Флаг On/Off режим
// ***** Taho *****
#define TahoSetPulse() PORTB |= (1<<5) // Pin13 1
#define TahoRemovePulse() PORTB &= ~(1<<5) // Pin13 0
// ***** Encoder *****
#define Enc_Line_per_Revolution 1800 // Кол-во линий энкодера
#define Enc_Line Enc_Line_per_Revolution*2 // Рабочее кол-во тиков
#define Enc_Read() (PIND & B00001000)
volatile int Enc_Pos = 0; // Счетчик положения энкодера
volatile byte Ks_Count = 0; // Счетчик для "Подача", "Резьба" целая часть
volatile int Km_Count = 0; // Счетчик для "Подача", "Резьба" дробная часть
byte Ks_Divisor = 0; // Делитель для "Подача", "Резьба" целая часть
int Km_Divisor = 0; // Делитель для "Подача", "Резьба" дробная часть
int Enc_Pos_tmp = 0;
long Spindle_Angle = 0;
#define Spindle_Direction_CW 0 // прямое вращение
#define Spindle_Direction_CCW 1 // обратное вращение
boolean Spindle_Direction = Spindle_Direction_CW;
//***** Ускорение *****
#define Accel 64 // Коэф.деления с которого будем ускоряться,
byte tmp_Accel = Accel; // должен быть больше максимального коэф-та на резьбах
byte tmp_Ks_Divisor = Accel; //
#define Repeat 8 // Кол-во повторов для постоянной скорости в пределах полного шага,
byte tmp_Repeat = 0; // выставить кратно дроблению шага
//***** Sensor *****
#define Sensor PINC
#define Sensor_Left B00010000 // AD4
#define Sensor_Right B00100000 // AD5
char Sensor_Mask = B00000000;
//***** Key & Joy *****
enum Pressed_Key
{
Key_None,
Key_Right,
Key_Up,
Key_Down,
Key_Left,
Key_Select
};
byte Pressed_Key=Key_None;
boolean key_flag=false; // флаг нажатой/отжатой кнопки
#define Joy_Left_Read() (PINC & B00000100) // AD2
#define Joy_Right_Read() (PINC & B00001000) // AD3
// ***** Mode *****
enum Mode
{
Mode_Thread = 1,
Mode_Feed
};
byte Mode = Mode_Feed;
// ***** Feeds *****
#define Total_Feeds 7 // Кол-во подач
typedef struct
{
byte s_Divisor; // Делитель для "Подача" целая часть
char Text[7];
}
FEED_INFO;
FEED_INFO Feed_Info[Total_Feeds] =
{
{ 225, "0.03mm" }, // Считаем по формуле:
{ 113, "0.06mm" }, // Enc_Line/(Step_Per_Revolution/Feed_Screw*Feed_mm)
{ 75, "0.09mm" },
{ 56, "0.12mm" },
{ 45, "0.15mm" },
{ 38, "0.18mm" },
{ 32, "0.21mm" },
};
byte Feed_Step = 2; // выборка из массива по умолчанию (0.09mm)
// ***** Threads *****
#define Total_Threads 38 // Кол-во резьб
typedef struct
{
byte s_Divisor; // Делитель для "Резьба" целая часть
int m_Divisor; // Делитель для "Резьба" дробная часть
char Text[7];
}
THREAD_INFO;
THREAD_INFO Thread_Info[Total_Threads] =
{
{ 33, 7500, "0.20mm" }, // Считаем по формуле:
{ 27, 0, "0.25mm" }, // Enc_Line/(Step_Per_Revolution/Feed_Screw*Thread_mm)
{ 22, 5000, "0.30mm" }, // Просчитан под 800 шаг/оборот (1/4 дробление, 1.5мм шаг винта)
{ 19, 2857, "0.35mm" },
{ 16, 8750, "0.40mm" },
{ 13, 5000, "0.50mm" },
{ 11, 2500, "0.60mm" },
{ 9, 6429, "0.70mm" },
{ 9, 0, "0.75mm" },
{ 8, 4375, "0.80mm" },
{ 6, 7500, "1.00mm" },
{ 5, 4000, "1.25mm" },
{ 4, 5000, "1.50mm" },
{ 3, 8571, "1.75mm" },
{ 3, 3750, "2.00mm" },
{ 2, 7000, "2.50mm" },
{ 2, 2500, "3.00mm" },
{ 7, 866, "80tpi " },
{ 6, 3780, "72tpi " },
{ 5, 6693, "64tpi " },
{ 5, 3150, "60tpi " },
{ 4, 9606, "56tpi " },
{ 4, 2520, "48tpi " },
{ 3, 8976, "44tpi " },
{ 3, 5433, "40tpi " },
{ 3, 1890, "36tpi " },
{ 2, 8347, "32tpi " },
{ 2, 4803, "28tpi " },
{ 2, 3917, "27tpi " },
{ 2, 3032, "26tpi " },
{ 2, 1260, "24tpi " },
{ 1, 9488, "22tpi " },
{ 1, 7717, "20tpi " },
{ 1, 6831, "19tpi " },
{ 1, 5945, "18tpi " },
{ 1, 4173, "16tpi " },
{ 1, 2402, "14tpi " },
{ 1, 0630, "12tpi " },
};
byte Thread_Step = 10; // выборка из массива по умолчанию (1.0mm)
//*********************************************************
void setup()
{
TIMSK0 = 0; // !Отключаем таймер! (он в фоновом режиме обрабатывает не нужные нам функции)
DDRB=B00111111;
PORTB = B00100011; // подтяжка PIN_
DDRD=B11110011;
PORTD = B11111100; // подтяжка PIN_
DDRC=B00000000;
PORTC = B00111100; // подтяжка PIN_
EICRA = B00000001; // INT_0 по фронту + по спаду
EIMSK |= (1 << INT0); // Enable INT_0
lcd.begin(16, 2);
}
//**********************************************************
void loop()
{
Enc_Pos_tmp = Enc_Pos; // ниже будем читать повторно и сравнивать
menu();
Joystick();
if (Enc_Pos == Enc_Pos_tmp) // Читаем повторно и сравниваем
{
Spindle_Angle = (Enc_Pos*360000/(Enc_Line)); // Считаем угол
snprintf(LCD_Row_2, 17, "Angle: %3ld.%03ld ", Spindle_Angle/1000, Spindle_Angle%1000); // Вторая строка для печати
}
Print();
}
// ********** Функция обработки событий в главном меню **********
void menu()
{
int ADC_value = analogRead(A0);
if (ADC_value < 50) Pressed_Key=Key_Right;
else if (ADC_value < 180) Pressed_Key=Key_Up;
else if (ADC_value < 330) Pressed_Key=Key_Down;
else if (ADC_value < 520) Pressed_Key=Key_Left;
else if (ADC_value < 830) Pressed_Key=Key_Select;
else Pressed_Key = Key_None;
if (!key_flag)
{
switch (Pressed_Key)
{
case Key_Left:
MenuKeyLeftPressed();
break;
case Key_Right:
MenuKeyRightPressed();
break;
case Key_Up:
MenuKeyUpPressed();
break;
case Key_Down:
MenuKeyDownPressed();
break;
case Key_Select:
MenuKeySelectPressed();
break;
}
}
if (Pressed_Key == Key_None) key_flag = false;
SelectWorkMode(); // вызов выбранного рабочего режима
}
// ********** Обработчик нажатия кнопки Select **********
void MenuKeySelectPressed()
{
switch (Mode)
{
case Mode_Thread:
if (!Mode_On_flag)
{
Ks_Count = 0;
Km_Count = 0;
tmp_Repeat = 0;
Step_On_flag = false;
Mode++;
}
break;
case Mode_Feed:
if (!Mode_On_flag)
{
Ks_Count = 0;
Km_Count = 0;
tmp_Accel = Accel;
tmp_Repeat = 0;
tmp_Ks_Divisor = Accel;
Step_On_flag = false;
Mode--;
}
break;
}
key_flag = true;
}
// ********** Обработчик нажатия кнопки Up **********
void MenuKeyUpPressed()
{
switch (Mode)
{
case Mode_Thread:
if (Thread_Step < Total_Threads-1)
{
if (Mode_On_flag == false)
{
Ks_Count = 0;
Km_Count = 0;
tmp_Accel = Accel;
tmp_Repeat = 0;
tmp_Ks_Divisor = Accel;
Step_On_flag = false;
Thread_Step++;
}
}
break;
case Mode_Feed:
if (Feed_Step < Total_Feeds-1)
{
Ks_Count = 0;
Km_Count = 0;
tmp_Repeat = 0;
Feed_Step++;
}
break;
}
key_flag = true;
}
// ********** Обработчик нажатия кнопки Down **********
void MenuKeyDownPressed()
{
switch (Mode)
{
case Mode_Thread:
if (Thread_Step > 0)
{
if (Mode_On_flag == false)
{
Ks_Count = 0;
Km_Count = 0;
tmp_Accel = Accel;
tmp_Repeat = 0;
tmp_Ks_Divisor = Accel;
Step_On_flag = false;
Thread_Step--;
}
}
break;
case Mode_Feed:
if (Feed_Step > 0)
{
Ks_Count = 0;
Km_Count = 0;
tmp_Repeat = 0;
Feed_Step--;
}
break;
}
key_flag = true;
}
// ********** Обработчик нажатия кнопки Left **********
void MenuKeyLeftPressed()
{
switch (Mode)
{
break;
}
key_flag = true;
}
// ********** Обработчик нажатия кнопки Right **********
void MenuKeyRightPressed()
{
switch (Mode)
{
break;
}
key_flag = true;
}
// ********** Выбор режима работы **********
void SelectWorkMode()
{
switch (Mode)
{
case Mode_Thread:
Thread();
break;
case Mode_Feed:
Feed();
break;
}
}
// ********** Обработка джойстика **********
void Joystick()
{
if (!Joy_Left_Read())
{
Motor_X_Enable();
Mode_On_flag = true;
if (Spindle_Direction == Spindle_Direction_CW)
{
Motor_X_Forward();
Sensor_Mask = Sensor_Left;
}
if (Spindle_Direction == Spindle_Direction_CCW)
{
Motor_X_Reverse();
Sensor_Mask = Sensor_Right;
}
}
else if (!Joy_Right_Read())
{
Motor_X_Enable();
Mode_On_flag = true;
if (Spindle_Direction == Spindle_Direction_CW)
{
Motor_X_Reverse();
Sensor_Mask = Sensor_Right;
}
if (Spindle_Direction == Spindle_Direction_CCW)
{
Motor_X_Forward();
Sensor_Mask = Sensor_Left;
}
}
else
{
Mode_On_flag = false;
if (Step_On_flag == false)
{
Motor_X_Disable();
}
}
}
//***************************************
void Thread()
{
Ks_Divisor=Thread_Info[Thread_Step].s_Divisor;
Km_Divisor=Thread_Info[Thread_Step].m_Divisor;
snprintf(LCD_Row_1, 17, "Thread: %s", Thread_Info[Thread_Step].Text); // Первая строка для печати
}
void Feed()
{
Ks_Divisor=Feed_Info[Feed_Step].s_Divisor;
tmp_Accel = Ks_Divisor;
tmp_Ks_Divisor = Ks_Divisor;
Km_Divisor=0;
Km_Count=0;
snprintf(LCD_Row_1, 17, "Feed: %s", Feed_Info[Feed_Step].Text); // Первая строка для печати
}
//******************************************************************
void Print()
{
lcd.setCursor(0, 0);
lcd.print(LCD_Row_1);
lcd.setCursor(0, 1);
lcd.print(LCD_Row_2);
}
//******************************************************************
ISR(INT0_vect)
{
TahoRemovePulse();
Motor_X_RemovePulse();
if (!Enc_Read()) // Вращение шпинделя вправо
{
Spindle_Direction = Spindle_Direction_CW;
Enc_Pos++;
if (Enc_Pos == Enc_Line) // полный оборот
{
Enc_Pos = 0;
TahoSetPulse(); // при проходе 0 генерим сигнал Taho
if (Mode_On_flag == true) // проверка режима на ON/OFF, только! после прохода 0 разрешаем счет до к.деления
{
Step_On_flag = true;
}
}
}
else // Вращение шпинделя влево
{
Spindle_Direction = Spindle_Direction_CCW;
Enc_Pos--;
if (Enc_Pos < 0) // полный оборот
{
Enc_Pos = Enc_Line - 1;
TahoSetPulse(); // при проходе 0 генерим сигнал Taho
if (Mode_On_flag == true) // проверка режима на ON/OFF, только! после прохода 0 разрешаем счет до к.деления
{
Step_On_flag = true;
}
}
}
if (!(Sensor & Sensor_Mask) || (!Mode_On_flag)) // Торможение
{
if (tmp_Ks_Divisor < tmp_Accel)
{
Ks_Count++;
if (Ks_Count > tmp_Ks_Divisor)
{
Motor_X_SetPulse();
Ks_Count = 0;
tmp_Repeat ++;
if (tmp_Repeat == Repeat)
{
tmp_Repeat = 0;
tmp_Ks_Divisor ++;
}
}
}
else
{
Step_On_flag = false;
}
}
if (Step_On_flag == true && Mode_On_flag == true)
{
Ks_Count++;
if (Ks_Count > tmp_Ks_Divisor) // Разгон
{
Motor_X_SetPulse();
if (tmp_Ks_Divisor > Ks_Divisor)
{
Ks_Count = 0;
tmp_Repeat ++;
if (tmp_Repeat == Repeat)
{
tmp_Repeat = 0;
tmp_Ks_Divisor --;
}
}
else
{
Km_Count = Km_Count + Km_Divisor;
if (Km_Count > Km_Divisor)
{
Km_Count = Km_Count - 10000;
Ks_Count = 0;
}
else
{
Ks_Count = 1;
}
}
}
}
}
//*******************************************************************
Obvykle je lepší začínat s vyzkoušeným, když už máš vše potřebné (HW i SW) k dispozici a pak teprve experimentovat ...
leda že by cesta měla být cílem, tak to pak jo.