Технический форум по робототехнике.
RootAdmin » 17 сен 2015, 19:31
Промежуточный результат.
- Код: Выделить всё • Развернуть
/*
Управление шаговиком (драйвер степ-дир) переменным резистором
теперь с кнопками! :)
А на этот раз - с экраном и резистивными кнопками.
Добавил измерение скорости вращения экструдера. Чуть подправил генерацию импульса на шаговик.
Управление преработано. Кнопка Select переключает режим "выбор" и "редактирование" Частота экструдера - в оборотах в минуту.
v 0.6 */
/*
Вывод Назначение
0 UART
1 UART
2 Внешнее прерывание от оптопары (не менять!)
3
4
5 Dir_pin
6 Step_pin
7 LCD RS
8 LCD RW
9 LCD E
10 LCD DB4
11 LCD DB5
12 LCD DB6
13 LCD DB7
A0 Резистор
A1 Кнопки
A2
A3
A4
A5
A6
A7
*/
//#define Razr 1 //признак разработчика. Если пользователь - комментируем или удаляем.
#include <EEPROM.h> //подключаем библиотеку EEPROM
#include <LiquidCrystal.h> // Подключаем стандартную библиотеку LiquidCrystal
// Инициализируем объект-экран, передаём использованные
// для подключения контакты на Arduino в порядке:
#define lcd_RS_pin 7
#define lcd_RW_pin 8
#define lcd_E_pin 9
#define lcd_DB4_pin 10
#define lcd_DB5_pin 11
#define lcd_DB6_pin 12
#define lcd_DB7_pin 13
// RS, RW, E, DB4, DB5, DB6, DB7
LiquidCrystal lcd(lcd_RS_pin, lcd_RW_pin, lcd_E_pin, lcd_DB4_pin, lcd_DB5_pin, lcd_DB6_pin, lcd_DB7_pin);
#define Step_pin 6 //вывод Arduino для ноги STEP контроллера (выход)
#define Dir_pin 5 //вывод Arduino для ноги DIR контроллера (выход)
#define Resistor_pin A0 //вывод Arduino резистора 0-5вольт (аналоговый вход)
//Оптодатчик:
#define OptoSensor_pin 2 //вывод Arduino для оптодатчика (вход)
#define ToothSumm 4 //сколько усреднять событий
#define ToothAll 140 // Событий на оборот
float ExtruderConst=(float)60/((float)(ToothAll/ToothSumm)*((float)1/250000)); // Коэффициент тиков :) Для оборотов в минуту делим его на измеренные
volatile unsigned long OptoSensorTicks=0;//Переменная для хранения тиков таймера на 1 вызов (время между зубьями)
volatile byte OptoToothCounter =0; //Указатель на текущтй зуб в массиве
volatile unsigned int OptoToothTimeArray [ToothSumm]; //массив с таймингами зубьев
//********** Кнопки:
#define btnRIGHT 1 //Определяем кнопки, это просто внутренние номера, НЕ ноги-выводы
#define btnUP 2
#define btnDOWN 3
#define btnLEFT 4
#define btnSELECT 5
#define btnNONE 0
//**********
#define btnDEFtime 30 //Значение для антидребезга - клавиша удерживаемая столько времени в миллисекундах считается нажатой.
#define btnPAUSEtime 400 //Значение в миллисекундах паузы между повторами
int lcd_key = btnNONE; //Для хранения полученного значеник кнопки
byte keyTemp = btnNONE; //Переменная для хранения временного состояния кнопок
byte keyCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
unsigned long BtnTime; //Хранит время начала нажатия кнопок
byte btnCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
byte btnTemp=btnNONE; //Для хранения номера ранее нажатой кнопки
#if defined(Razr) //Мне для отладки
#define ButtonPin A7 //Сюда подключены кнопки
#else
#define ButtonPin A1 //Сюда подключены кнопки
#endif
//************
/*
//структура под меню
typedef struct
{
char* nam;
byte posX;
byte posY;
} menu;
//typedef struct menu menuEl;
menu menus[3] ={{"Mm1",0,0},
{"Mm2",1,1},
{"Mm3",3,3}};
*/
//Строка1:
byte ControlPos = 0; //Переменная определяет элемент в строке управления. 1 - коэффициент. 0 - частота протяжки
//строка: 0 - резистор, кнопки 1 - кнопки.
byte ControlMode = 0; //Переменная определяет режим управления. 0 - выбор, 1 - редактирование
//Переменная для значения таймера
volatile unsigned char FullTimer0;
//Переменная для количества холостых 256циклов таймера
volatile unsigned int FullTimer256;//Переменная для количества холостых 256циклов таймера
volatile unsigned int FullTimer256Count; //внутренный счетчик таймера
//значение минимальной частоты
#define LowFreq 10
//значение МАКСИмальной частоты
#define HighFreq 10000
//Переменная для шага чаcтоты на едниницу изменения АЦП
float FreqStep;
int OutFreq = LowFreq; //Переменная для хранения установленной частоты
//Переменная для текущего значения резистора
int sensorValue = 0;
//Переменная для Старого значения резистора
int OLDsensorValue = 0;
void setup() {
pinMode(Step_pin,OUTPUT); // Конфигурим вывод Step_pin как выход
pinMode(Dir_pin,OUTPUT); // Конфигурим вывод Dir_pin как выход
pinMode(Resistor_pin,INPUT); // Конфигурим вывод Dir_pin как вход
pinMode(OptoSensor_pin,INPUT); // Конфигурим вывод OptoSensor_pin как вход
attachInterrupt(0, OptoSensor, CHANGE); // привязываем 0-е прерывание к функции OptoSensor(). На изменение состояния. Да, из-за разницы между шириной самого зуба и межзубного расстояния - бкдкт различия, усредним.
lcd.begin(16,2); //Инициализируем экран
//Установим на выходах 0
digitalWrite(Step_pin, LOW);
digitalWrite(Dir_pin, LOW);
// Посчитаем "шаг" изменения частоты на единицу изменения резистора
FreqStep=(float)(HighFreq-LowFreq)/1024;
//Запускает последовательный порт
Serial.begin(9600);
//Сообщение о запуске программы
Serial.println("Program started");
// Serial.print("FreqStep=");
// Serial.println(FreqStep);
//Запускает таймер и получает загружаемое значение таймера.
//Параметр - желаемая частота в герцах.
FullTimer0=SetupTimer2(OutFreq);
//Установки Таймер2: Делитель частоты /64, режим 0
//Частота = 16MHz/64 = 250000 герц или
//Делитель /64 дает нам хороший рабочий диапазон в районе 1 кгц
//так что сейчас мы просто жестко запрограммируем это.
TCCR2A = 0;
TCCR2B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//Подключение прерывания по переполнению Timer2
TIMSK2 = 1<<TOIE2;
//Установки Таймер1: Делитель частоты /64, режим 0
//Частота = 16MHz/64 = 250000 герц или
//Делитель /64 дает нам хороший рабочий диапазон
//так что сейчас мы просто жестко запрограммируем это.
TCCR1A = 0;
TCCR1B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//Подключение прерывания по переполнению Timer0 (для обнуления скорости)
TIMSK1 = 1<<TOIE1;
//Выводит загружаемое значение таймера
Serial.print("Timer2 Load:");
Serial.println(FullTimer0,HEX);
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.print("Stepper control"); //выводим на него строку
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.print(" St Div Ext"); //выводим на него строку
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.cursor(); //Включим курсор
lcd.blink(); //Пусть мигает
delay(10);
}
void loop() {
lcd_key=read_LCD_buttons(); //прочитаем нажатую кнопку
//0 4 8 12 |
// St Div Ext
//000 00000 00000
if (lcd_key) //Нажата какая-то кнопка
{
if (btnSELECT==lcd_key) //Если нажата кнопка Select
{ControlMode=!ControlMode;} //Меняем режим на другой :)
if (ControlMode) //Если режим - "редактирование"
{
if (btnUP==lcd_key) //Если нажата кнопка "Больше"
{
if (ControlPos==0) //Меняем частоту протяжки шагами
{OutFreq+=10;}
if (ControlPos==1) //Меняем коэффициент шагами
{OutFreq+=10;}
}
if (btnDOWN==lcd_key) //Если нажата кнопка "Больше"
{
if (ControlPos==0) //Меняем частоту протяжки шагами
{OutFreq-=10;}
if (ControlPos==1) //Меняем коэффициент шагами
{OutFreq-=10;}
}
if (btnRIGHT==lcd_key) //Если нажата кнопка "ВПРАВО"
{
if (ControlPos==0) //Меняем частоту протяжки единицами
{OutFreq+=1;}
if (ControlPos==1) //Меняем коэффициент единицами
{OutFreq+=1;}
}
if (btnLEFT==lcd_key) //Если нажата кнопка "ВЛЕВО"
{
if (ControlPos==0) //Меняем частоту протяжки единицами
{OutFreq-=1;}
if (ControlPos==1) //Меняем коэффициент единицами
{OutFreq-=1;}
}
SetupTimer2(OutFreq); //устанавливаем таймер
}
else //режим "выбор"
{
if (btnRIGHT==lcd_key) //нажата кнопка ВПРАВО
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print("#");
ControlPos = 1;
}
if (btnLEFT==lcd_key) //нажата кнопка ВЛЕВО
{
lcd.setCursor(4, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("#");
ControlPos = 0;
}
}
}
// Serial.print("Button=");
// Serial.println(lcd_key,DEC);
// if (btnRIGHT==lcd_key) //нажата кнопка ВПРАВО
// {
// lcd.setCursor(6, 1);
// ControlMode = 1;
// }
// if (btnLEFT==lcd_key) //нажата кнопка ВЛЕВО
// {
// lcd.setCursor(0, 1);
// ControlMode = 0;
// }
// }
// if (ControlMode) //Если режим "кнопки"
// {
// if (btnUP==lcd_key) //Если нажата кнопка "Больше"
// #if defined(Razr) //Мне для отладки
// {OutFreq+=1000;}
// #else
// {OutFreq+=1;}
// #endif
// if (btnDOWN==lcd_key) //Если нажата кнопка "Меньше"
// #if defined(Razr) //Мне для отладки
// {OutFreq-=1000;}
// #else
// {OutFreq-=1;}
// #endif
// if (lcd_key) //Если вообще что-то нажато
// {
// SetupTimer2(OutFreq);
// lcd.setCursor(0, 0);
// lcd.print(" ");
// lcd.setCursor(0, 0);
// lcd.print(FullTimer0);
// lcd.setCursor(4, 0);
// lcd.print(FullTimer256);
// lcd.setCursor(7, 1);
// lcd.print(" "); //чистим вывод
// lcd.setCursor(7, 1);
// lcd.print(OutFreq); //выводим Частоту
// lcd.setCursor(6, 1);
// }
// }
// else //Если режим резистор (светодиод выключен)
// {
// //Тут будем читать занчение
// sensorValue=analogRead(Resistor_pin);
// //Сравним значение со старым, если отличается - пересчитаем установку таймера
// if (sensorValue!= OLDsensorValue)
// { //Serial.println("ReCall"); //debug
// OLDsensorValue=sensorValue;
// OutFreq = LowFreq+FreqStep*sensorValue; //Вычислим новое значение частоты
// lcd.setCursor(1, 1);
// lcd.print(" "); //Чистим вывод
// lcd.setCursor(1, 1);
// lcd.print(OutFreq); //выводим Частоту
// lcd.setCursor(0, 1);
// SetupTimer2(OutFreq);
// }
// }
// lcd.setCursor(0, 1);
// lcd.print(ExtruderConst);
//выведем скорость
OptoSensorTicks=0;
//Один тик таймера - это 4 микросекунды (.000004) Зубъев у нас 70, причем реагируем на вход зуба а оптосенсор и на выход. Значит - 140 событий на оборот экструдера.
//Но
//Складывая время
for (int i=0; i<ToothSumm; i++) {OptoSensorTicks+=OptoToothTimeArray[i];}
lcd.setCursor(10, 0);
lcd.print(" ");
lcd.setCursor(10, 0);
lcd.print(ExtruderConst/OptoSensorTicks);
lcd.setCursor(0, 1);
lcd.print(OutFreq); //выведем частоту
Serial.print("ExtruderConst=");
Serial.println(ExtruderConst,DEC);
/*
Serial.print("sensor=");
Serial.println(sensorValue,DEC);
Serial.print("FullTimerCount");
Serial.println(FullTimerCount);
Serial.print("FullTimer");
Serial.println(FullTimer,DEC);
Serial.print("timer=");
Serial.println(FullTimer0,DEC);
Serial.print("ButtPressed=");
Serial.println(ButtPressed,DEC);
Serial.print("OutFreq=");
Serial.println(OutFreq,DEC);
Serial.println("***");
Serial.println("");
Serial.println("***");
Serial.println(OptoSensorTicks);
delay (200);
*/
delay (200);
}
//Timer1 указатель вектора прерывания по переполнению
ISR(TIMER1_OVF_vect)
{
OptoToothTimeArray[OptoToothCounter]=0; //присваиваем элементу массива 0
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
//Timer2 указатель вектора прерывания по переполнению
ISR(TIMER2_OVF_vect)
{
if (FullTimer256Count>1)
{FullTimer256Count--;}
else
{if (FullTimer256Count==1) //предпоследний цикл
{
TCNT2+=FullTimer0;
FullTimer256Count=0;
}
{if (FullTimer256Count==0) // Срабатывание
{
//Переключение IO-вывода в HIGH
digitalWrite(Step_pin,HIGH);
FullTimer256Count=FullTimer256;
//Переключение IO-вывода в другое состояние.
// digitalWrite(Step_pin,!digitalRead(Step_pin));
//Перезагрузка таймера и коррекция по задержке
if (FullTimer256)
{TCNT2=0;} //Если холостые циклы есть - максимальное значение
else
{TCNT2+=FullTimer0;}
//Переключение IO-вывода в LOW
digitalWrite(Step_pin,LOW);
}
}
}
}
#define TIMER_CLOCK_FREQ 250000.0
//15625 for /1024
//2MHz for /8 prescale from 16MHz
//Установка Таймера2.
//Конфигурирует 8-битный Таймер2 ATMega168 для выработки прерывания
//с заданной частотой.
//Возвращает начальное значение таймера, которое должно быть загружено в TCNT2
//внутри вашей процедуры ISR.
//Смотри пример использования ниже.
unsigned char SetupTimer2(float timeoutFrequency){
//Подсчет начального значения таймера
//Слегка усложним, добавив холостые просчеты
long ticks = TIMER_CLOCK_FREQ/timeoutFrequency; // тиков счетчика для получения заданной частоты
// #if defined(Razr)
// lcd.setCursor(9, 0);
// lcd.print(ticks);
// #endif
FullTimer256=ticks/256; //Вычисляем количество ПОЛНЫХ 256 циклов таймера
ticks-=FullTimer256*256;
FullTimer0=(byte)(257.0-(ticks+0.5)); //Вычисляем количество доплнительных тиков таймера
//257 на самом деле должно быть 256, но я получил лучшие результаты с 257.
//загружает таймер для первого цикла
if (FullTimer256)
{TCNT2=0;} //Если холостые циклы есть - максимальное значение
else
{TCNT2=FullTimer0;}
}
// *****************************
//Чтение кнопок с антидребезгом
// read the buttons
int read_LCD_buttons()
{
int adc_key_in = analogRead(ButtonPin); // Получаем напряжение с АЦП
byte btnTempTemp = btnNONE; //Переменная для хранения свежесчитанного внутри функции
//digitalWrite (LED_pin,0); //debug
//lcd.setCursor(5, 0); //debug
//lcd.print(adc_key_in); //debug
//delay (400); //debug
//Тут используем millis() для отслеживания нажатия кнопки
// Запоминиаем в переменной BtnTime ВРЕМЯ НАЧАЛА нажатия
// Запоминаем в переменной btnTemp нажатия
// Дефиним время антидребезга #define
if (adc_key_in > 950) //Ничего не нажато
{
//BtnTime=0; //Скидываем время нажатия
btnCONTpress=0;
return btnNONE; // We make ths the 1st option for speed reasons since it will be the most likely result
}
else //что-то нажато
{
if (adc_key_in < 790) { btnTempTemp=btnSELECT; } //Определяем в переменную ТЕКУЩУЮ нажатую кнопку.
if (adc_key_in < 555) { btnTempTemp=btnLEFT; }
if (adc_key_in < 380) { btnTempTemp=btnDOWN; }
if (adc_key_in < 195) { btnTempTemp=btnUP; }
if (adc_key_in < 50) { btnTempTemp=btnRIGHT; }
//А тут проверим, совпадает ли с btnTemp (была ли нажата ранее)
/* lcd.setCursor(0, 0); //debug
lcd.print(btnTempTemp); //debug
lcd.setCursor(2, 0); //debug
lcd.print(btnTemp); //debug
lcd.setCursor(1, 1); //debug
lcd.print(millis()); //debug
lcd.setCursor(12, 1); //debug
digitalWrite (LED_pin,1); //debug
delay (100);
lcd.print(" "); //debug
lcd.setCursor(12, 1); //debug
lcd.print(adc_key_in); //debug
*/
if (btnTempTemp==btnTemp) //Кнопка уже БЫЛА нажата
{
if (btnCONTpress) //Повторные установки клавиши
{
if ((millis()-BtnTime) > btnPAUSEtime)
{
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
else //Первая установка клавиши
{
if ((millis()-BtnTime) > btnDEFtime)
{
btnCONTpress=1;
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
}
else //Раньше было другое состояние
{
// digitalWrite (LED_pin,1); //debug
// delay (100);
btnCONTpress=0;
BtnTime=millis(); //Устанавливаем ТЕКУЩЕЕ время в переменную BtnTime
btnTemp=btnTempTemp; //устанавливаем кнопку во временную переменную.
}
}
return btnNONE; // Если ничего не сработало, то ничего не возвращаем
}
//***********************************
void OptoSensor() // функция обработки прерывания. Меняет глобальные прееменные
{//Сработал - значит считаем тики. F njxytt - echtlyztv pf
OptoToothTimeArray[OptoToothCounter]=TCNT1; //присваиваем элементу массива текущее значение таймера
TCNT1 = 0; //сбрасываем таймер
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
Добавлено спустя 50 секунд:Недопилено! коэффициент пока не работает.
Revenger » 17 сен 2015, 22:07
Чудесно! Сейчас принесу все проводочки и попробую залить и запустить ))
А как и чем мы управляем экструдером?
Добавлено спустя 2 часа 7 минут 11 секунд:
Всё загрузил. Работает вроде. В смысле включил, поднял частоту мотора (изначально 10 оочень медленно, но пока экструдер выводим на нужную температуру, то пойдёт)выбрав курсором "влево" и селект кажись (частота ШД заметно меняется только до 100 и после 800). На резистор не реагирует как куда не нажимал. Что значит СТ и ДИВ? Инструкцию похоже пора начинать писать ))
На изменения в оптодатчике тут же меняется показание на дисплее (пока нет движения там просто "ИНФ" с какой-то цифрой), но на обороты шаговика нет реакции.
Вот коротко и всё.
п.с. В моём понимании принцип должен быть таким (просто напоминаю хотелку): включаем экструдер, можно одновременно уже крутить ШД протяжки. Через пару минут "колбаса" дотянется до пластика, заводим в ролики и, догоняя скорость/температуру экструдера и скорость ШД протяжки, доведя до нужного диаметра и скорости работы (не обязательно же на максимуме пытаться) как бы "фиксируем" параметры, отдавая контроль за экструдером уже ардуине, и она подгоняет скорость протяжки уже основываясь на работе экструдера.
Надеюсь понятно пояснил.
Конечно, при наличии цифрового штангеля/микрометра это в механических манипуляциях было бы проще, но для программирования скорее всего сложно. Вроде и есть подобные системы, но чтобы их собрать, надо заново всё покупать.. и ардуины другие и контроллеры ((
RootAdmin » 18 сен 2015, 10:39
Сейчас допишу коэффициент - вот этот самый Div.
Для того чтоб штангель подключить - той же ардуины вполне хватит.
Revenger » 18 сен 2015, 11:00
И инструкцию куда что!

RootAdmin » 18 сен 2015, 19:08
Схема не меняется.
Вот код, надо б получить похожие на рабочие значения: Частоту экструдера (в верхнем правом углу, в оборотах в минуту) Частоту шаговика (пока в герцах, в нижней строке под "St")
Идеология такая: После включения символ "#" обозначает выбранную позицию. Кнопки влево и вправо позволяют выбирать другую.
Нажатие кнопки Select переключает выбранную позицию в режим редактирования. При этом кнопками вверх-вниз меняются единицы, а влево-вправо - десятые значения.
Повторное нажатие Select - возвращает к выбору.
- Код: Выделить всё • Развернуть
/*
Управление шаговиком (драйвер степ-дир) переменным резистором
теперь с кнопками! :)
А на этот раз - с экраном и резистивными кнопками.
Добавил измерение скорости вращения экструдера. Чуть подправил генерацию импульса на шаговик.
Управление преработано. Кнопка Select переключает режим "выбор" и "редактирование" Частота экструдера - в оборотах в минуту.
Добавлен коэффициент
v 0.6a */
/*
Вывод Назначение
0 UART
1 UART
2 Внешнее прерывание от оптопары (не менять!)
3
4
5 Dir_pin
6 Step_pin
7 LCD RS
8 LCD RW
9 LCD E
10 LCD DB4
11 LCD DB5
12 LCD DB6
13 LCD DB7
A0 Резистор
A1 Кнопки
A2
A3
A4
A5
A6
A7
*/
//#define Razr 1 //признак разработчика. Если пользователь - комментируем или удаляем.
#include <EEPROM.h> //подключаем библиотеку EEPROM
#include <LiquidCrystal.h> // Подключаем стандартную библиотеку LiquidCrystal
// Инициализируем объект-экран, передаём использованные
// для подключения контакты на Arduino в порядке:
#define lcd_RS_pin 7
#define lcd_RW_pin 8
#define lcd_E_pin 9
#define lcd_DB4_pin 10
#define lcd_DB5_pin 11
#define lcd_DB6_pin 12
#define lcd_DB7_pin 13
// RS, RW, E, DB4, DB5, DB6, DB7
LiquidCrystal lcd(lcd_RS_pin, lcd_RW_pin, lcd_E_pin, lcd_DB4_pin, lcd_DB5_pin, lcd_DB6_pin, lcd_DB7_pin);
#define Step_pin 6 //вывод Arduino для ноги STEP контроллера (выход)
#define Dir_pin 5 //вывод Arduino для ноги DIR контроллера (выход)
#define Resistor_pin A0 //вывод Arduino резистора 0-5вольт (аналоговый вход)
//Оптодатчик:
#define OptoSensor_pin 2 //вывод Arduino для оптодатчика (вход)
#define ToothSumm 4 //сколько усреднять событий
#define ToothAll 140 // Событий на оборот
float ExtruderConst=(float)60/((float)(ToothAll/ToothSumm)*((float)1/250000)); // Коэффициент тиков :) Для оборотов в минуту делим его на измеренные
float DivK =1; //Коэффициент для соотношения скорости шаговика к скорости экструдера
volatile unsigned long OptoSensorTicks=0;//Переменная для хранения тиков таймера на 1 вызов (время между зубьями)
volatile byte OptoToothCounter =0; //Указатель на текущтй зуб в массиве
volatile unsigned int OptoToothTimeArray [ToothSumm]; //массив с таймингами зубьев
//********** Кнопки:
#define btnRIGHT 1 //Определяем кнопки, это просто внутренние номера, НЕ ноги-выводы
#define btnUP 2
#define btnDOWN 3
#define btnLEFT 4
#define btnSELECT 5
#define btnNONE 0
//**********
#define btnDEFtime 30 //Значение для антидребезга - клавиша удерживаемая столько времени в миллисекундах считается нажатой.
#define btnPAUSEtime 400 //Значение в миллисекундах паузы между повторами
int lcd_key = btnNONE; //Для хранения полученного значеник кнопки
byte keyTemp = btnNONE; //Переменная для хранения временного состояния кнопок
byte keyCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
unsigned long BtnTime; //Хранит время начала нажатия кнопок
byte btnCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
byte btnTemp=btnNONE; //Для хранения номера ранее нажатой кнопки
#if defined(Razr) //Мне для отладки
#define ButtonPin A7 //Сюда подключены кнопки
#else
#define ButtonPin A1 //Сюда подключены кнопки
#endif
//************
/*
//структура под меню
typedef struct
{
char* nam;
byte posX;
byte posY;
} menu;
//typedef struct menu menuEl;
menu menus[3] ={{"Mm1",0,0},
{"Mm2",1,1},
{"Mm3",3,3}};
*/
byte ControlPos = 0; //Переменная определяет элемент в строке управления. 1 - коэффициент. 0 - частота протяжки
byte ControlMode = 0; //Переменная определяет режим управления. 0 - выбор, 1 - редактирование
int ScreenPass =100; //Для пропуска циклов, чтоб экран не мерцал.
//Переменная для значения таймера
volatile unsigned char FullTimer0;
//Переменная для количества холостых 256циклов таймера
volatile unsigned int FullTimer256;//Переменная для количества холостых 256циклов таймера
volatile unsigned int FullTimer256Count; //внутренный счетчик таймера
//значение минимальной частоты
#define LowFreq 10
//значение МАКСИмальной частоты
#define HighFreq 1500
//Переменная для шага чаcтоты на едниницу изменения АЦП
// float FreqStep;
float OutFreq = LowFreq; //Переменная для хранения установленной частоты
/*
//Переменная для текущего значения резистора
int sensorValue = 0;
//Переменная для Старого значения резистора
int OLDsensorValue = 0;
*/
void setup() {
pinMode(Step_pin,OUTPUT); // Конфигурим вывод Step_pin как выход
pinMode(Dir_pin,OUTPUT); // Конфигурим вывод Dir_pin как выход
// pinMode(Resistor_pin,INPUT); // Конфигурим вывод Dir_pin как вход
pinMode(OptoSensor_pin,INPUT); // Конфигурим вывод OptoSensor_pin как вход
attachInterrupt(0, OptoSensor, CHANGE); // привязываем 0-е прерывание к функции OptoSensor(). На изменение состояния. Да, из-за разницы между шириной самого зуба и межзубного расстояния - будут различия, усредним.
lcd.begin(16,2); //Инициализируем экран
//Установим на выходах 0
digitalWrite(Step_pin, LOW);
digitalWrite(Dir_pin, LOW);
// // Посчитаем "шаг" изменения частоты на единицу изменения резистора
// FreqStep=(float)(HighFreq-LowFreq)/1024;
//Запускает последовательный порт
Serial.begin(9600);
//Сообщение о запуске программы
Serial.println("Program started");
// Serial.print("FreqStep=");
// Serial.println(FreqStep);
//Запускает таймер и получает загружаемое значение таймера.
//Параметр - желаемая частота в герцах.
FullTimer0=SetupTimer2(OutFreq);
//Установки Таймер2: Делитель частоты /64, режим 0
//Частота = 16MHz/64 = 250000 герц или
//Делитель /64 дает нам хороший рабочий диапазон в районе 1 кгц
//так что сейчас мы просто жестко запрограммируем это.
TCCR2A = 0;
TCCR2B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//Подключение прерывания по переполнению Timer2
TIMSK2 = 1<<TOIE2;
//Установки Таймер1: Делитель частоты /64, режим 0
//Частота = 16MHz/64 = 250000 герц или
//Делитель /64 дает нам хороший рабочий диапазон
//так что сейчас мы просто жестко запрограммируем это.
TCCR1A = 0;
TCCR1B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//Подключение прерывания по переполнению Timer0 (для обнуления скорости)
TIMSK1 = 1<<TOIE1;
//Выводит загружаемое значение таймера
Serial.print("Timer2 Load:");
Serial.println(FullTimer0,HEX);
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.print("Stepper control"); //выводим на него строку
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.print("#St Div Ext"); //выводим на него строку
lcd.setCursor(0, 0); //устанавливаем курсор
// lcd.cursor(); //Включим курсор
// lcd.blink(); //Пусть мигает
delay(10);
}
void loop() {
OptoSensorTicks=0;
//Один тик таймера - это 4 микросекунды (.000004) Зубъев у нас 70, причем реагируем на вход зуба а оптосенсор и на выход. Значит - 140 событий на оборот экструдера.
//Складывая время
for (int i=0; i<ToothSumm; i++) {OptoSensorTicks+=OptoToothTimeArray[i];}
ScreenPass++; //Инкремент счетчика
if (ScreenPass>1000)
{
ScreenPass=0; //Обнуляем счетчик
lcd_key=read_LCD_buttons(); //прочитаем нажатую кнопку
//0 4 8 12 |
// St Div Ext
//000 00000 00000
if (lcd_key) //Нажата какая-то кнопка
{
if (btnSELECT==lcd_key) //Если нажата кнопка Select
{
ControlMode=!ControlMode;
if (ControlMode)
{
if (ControlPos==0)
{
lcd.setCursor(0, 0);
lcd.print("*");
lcd.setCursor(4, 0);
lcd.print(" ");
}
if (ControlPos==1)
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print("*");
}
}
else
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print(" ");
if (ControlPos==1){lcd.setCursor(4, 0); lcd.print("#"); }
if (ControlPos==0){lcd.setCursor(0, 0); lcd.print("#"); }
}
} //Меняем режим на другой :)
if (ControlMode) //Если режим - "редактирование"
{
if (btnUP==lcd_key) //Если нажата кнопка "Больше"
{
if (ControlPos==0) //Меняем частоту протяжки шагами
{
OutFreq+=10;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент шагами
{DivK+=1;}
}
if (btnDOWN==lcd_key) //Если нажата кнопка "Меньше"
{
if (ControlPos==0) //Меняем частоту протяжки шагами
{
OutFreq-=10;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент шагами
{DivK-=1;}
}
if (btnRIGHT==lcd_key) //Если нажата кнопка "ВПРАВО"
{
if (ControlPos==0) //Меняем частоту протяжки единицами
{
OutFreq+=1;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент единицами
{DivK+=.01;}
}
if (btnLEFT==lcd_key) //Если нажата кнопка "ВЛЕВО"
{
if (ControlPos==0) //Меняем частоту протяжки единицами
{
OutFreq-=1;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент единицами
{DivK-=.01;}
}
}
else //режим "выбор"
{
if (btnRIGHT==lcd_key) //нажата кнопка ВПРАВО
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print("#");
ControlPos = 1;
}
if (btnLEFT==lcd_key) //нажата кнопка ВЛЕВО
{
lcd.setCursor(4, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("#");
ControlPos = 0;
}
}
}
//Теперь в зависимости от режима нужно...
//Либо считать частоту шаговика от коэффициента при ControlMode==1 и ControlPos==1
//Либо вычислять коэффициент при ControlMode==1 и ControlPos==0
//Либо вычислять частоту шаговика от коэффициента при ControlMode==0
//Короче, только при ControlMode==1 и ControlPos==0 вычислять коэффициент. В остальных случаях - частоту.
if ((ControlMode==1) && (ControlPos==0)) //Если режим - редактирование, изменение шаговика
{
DivK= (float)OutFreq* ((float)100/OptoSensorTicks); //Вычислим коэффициент
}
else
{
OutFreq=(float)DivK/(float)(100/OptoSensorTicks);
if (OutFreq>HighFreq){OutFreq=HighFreq;}
if (OutFreq<LowFreq){OutFreq=LowFreq;}
SetupTimer2(OutFreq); //устанавливаем таймер
}
//Выведем коэффициент
lcd.setCursor(10, 1);
lcd.print(DivK);
//выведем скорость
lcd.setCursor(10, 0);
lcd.print(" ");
lcd.setCursor(10, 0);
lcd.print(ExtruderConst/OptoSensorTicks);
// lcd.setCursor(9, 1);
// lcd.print(" ");
// lcd.setCursor(9, 1);
// lcd.print(OptoSensorTicks);
lcd.setCursor(0, 1);
lcd.print(OutFreq); //выведем частоту
/*
Serial.print("sensor=");
Serial.println(sensorValue,DEC);
Serial.print("FullTimerCount");
Serial.println(FullTimerCount);
Serial.print("FullTimer");
Serial.println(FullTimer,DEC);
Serial.print("timer=");
Serial.println(FullTimer0,DEC);
Serial.print("ButtPressed=");
Serial.println(ButtPressed,DEC);
Serial.print("OutFreq=");
Serial.println(OutFreq,DEC);
Serial.println("***");
Serial.println("");
Serial.println("***");
Serial.println(OptoSensorTicks);
delay (200);
*/
}
}
//Timer1 указатель вектора прерывания по переполнению
ISR(TIMER1_OVF_vect)
{
OptoToothTimeArray[OptoToothCounter]=0; //присваиваем элементу массива 0
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
//Timer2 указатель вектора прерывания по переполнению
ISR(TIMER2_OVF_vect)
{
if (FullTimer256Count>1)
{FullTimer256Count--;}
else
{if (FullTimer256Count==1) //предпоследний цикл
{
TCNT2+=FullTimer0;
FullTimer256Count=0;
}
{if (FullTimer256Count==0) // Срабатывание
{
//Переключение IO-вывода в HIGH
digitalWrite(Step_pin,HIGH);
FullTimer256Count=FullTimer256;
//Переключение IO-вывода в другое состояние.
// digitalWrite(Step_pin,!digitalRead(Step_pin));
//Перезагрузка таймера и коррекция по задержке
if (FullTimer256)
{TCNT2=0;} //Если холостые циклы есть - максимальное значение
else
{TCNT2+=FullTimer0;}
//Переключение IO-вывода в LOW
digitalWrite(Step_pin,LOW);
}
}
}
}
#define TIMER_CLOCK_FREQ 250000.0
//15625 for /1024
//2MHz for /8 prescale from 16MHz
//Установка Таймера2.
//Конфигурирует 8-битный Таймер2 ATMega168 для выработки прерывания
//с заданной частотой.
//Возвращает начальное значение таймера, которое должно быть загружено в TCNT2
//внутри вашей процедуры ISR.
//Смотри пример использования ниже.
unsigned char SetupTimer2(float timeoutFrequency){
//Подсчет начального значения таймера
//Слегка усложним, добавив холостые просчеты
long ticks = TIMER_CLOCK_FREQ/timeoutFrequency; // тиков счетчика для получения заданной частоты
// #if defined(Razr)
// lcd.setCursor(9, 0);
// lcd.print(ticks);
// #endif
FullTimer256=ticks/256; //Вычисляем количество ПОЛНЫХ 256 циклов таймера
ticks-=FullTimer256*256;
FullTimer0=(byte)(257.0-(ticks+0.5)); //Вычисляем количество доплнительных тиков таймера
//257 на самом деле должно быть 256, но я получил лучшие результаты с 257.
//загружает таймер для первого цикла
if (FullTimer256)
{TCNT2=0;} //Если холостые циклы есть - максимальное значение
else
{TCNT2=FullTimer0;}
}
// *****************************
//Чтение кнопок с антидребезгом
// read the buttons
int read_LCD_buttons()
{
int adc_key_in = analogRead(ButtonPin); // Получаем напряжение с АЦП
byte btnTempTemp = btnNONE; //Переменная для хранения свежесчитанного внутри функции
//digitalWrite (LED_pin,0); //debug
//lcd.setCursor(5, 0); //debug
//lcd.print(adc_key_in); //debug
//delay (400); //debug
//Тут используем millis() для отслеживания нажатия кнопки
// Запоминиаем в переменной BtnTime ВРЕМЯ НАЧАЛА нажатия
// Запоминаем в переменной btnTemp нажатия
// Дефиним время антидребезга #define
if (adc_key_in > 950) //Ничего не нажато
{
//BtnTime=0; //Скидываем время нажатия
btnCONTpress=0;
return btnNONE; // We make ths the 1st option for speed reasons since it will be the most likely result
}
else //что-то нажато
{
if (adc_key_in < 790) { btnTempTemp=btnSELECT; } //Определяем в переменную ТЕКУЩУЮ нажатую кнопку.
if (adc_key_in < 555) { btnTempTemp=btnLEFT; }
if (adc_key_in < 380) { btnTempTemp=btnDOWN; }
if (adc_key_in < 195) { btnTempTemp=btnUP; }
if (adc_key_in < 50) { btnTempTemp=btnRIGHT; }
//А тут проверим, совпадает ли с btnTemp (была ли нажата ранее)
/* lcd.setCursor(0, 0); //debug
lcd.print(btnTempTemp); //debug
lcd.setCursor(2, 0); //debug
lcd.print(btnTemp); //debug
lcd.setCursor(1, 1); //debug
lcd.print(millis()); //debug
lcd.setCursor(12, 1); //debug
digitalWrite (LED_pin,1); //debug
delay (100);
lcd.print(" "); //debug
lcd.setCursor(12, 1); //debug
lcd.print(adc_key_in); //debug
*/
if (btnTempTemp==btnTemp) //Кнопка уже БЫЛА нажата
{
if (btnCONTpress) //Повторные установки клавиши
{
if ((millis()-BtnTime) > btnPAUSEtime)
{
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
else //Первая установка клавиши
{
if ((millis()-BtnTime) > btnDEFtime)
{
btnCONTpress=1;
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
}
else //Раньше было другое состояние
{
// digitalWrite (LED_pin,1); //debug
// delay (100);
btnCONTpress=0;
BtnTime=millis(); //Устанавливаем ТЕКУЩЕЕ время в переменную BtnTime
btnTemp=btnTempTemp; //устанавливаем кнопку во временную переменную.
}
}
return btnNONE; // Если ничего не сработало, то ничего не возвращаем
}
//***********************************
void OptoSensor() // функция обработки прерывания. Меняет глобальные прееменные
{//Сработал - значит считаем тики. F njxytt - echtlyztv pf
OptoToothTimeArray[OptoToothCounter]=TCNT1; //присваиваем элементу массива текущее значение таймера
TCNT1 = 0; //сбрасываем таймер
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
Добавлено спустя 4 минуты 18 секунд:Хотя да, чего-то с частотой... Непропорционально меняется.
Добавлено спустя 25 минут 18 секунд:Ищу причину.
Revenger » 18 сен 2015, 20:23
А такой вопрос... а экструдером мы как управлять будем? У меня сейчас типа шимконтроллера на 12В китайческого.
И еще бы уточнить, что означает какая позиция. Чтобы не бездумно методом тыка нажимать

Мне, как несоздателю, сложно быстро уловить ход мыслей гуру
Добавлено спустя 41 минуту 32 секунды:Блин... только что дошло... а нафига нам управлять двигателем экструдера, если мы собрались управлять двигателем протяжки

Совсем уже крышу сорвало из-за обилия информации.
Добавлено спустя 20 минут 22 секунды:Залил, попробовал. Пока понял только что верх справа - частота оптодатчика, снизу справа пока нечто не понятное (может что на что делим?). Частота слева почему-то стала 1500 и снижая/повышая кнопками, нажав затем селект, она снова возвращается на 1500. Если сигнал на опто не идёт некоторое время, то ШД останавливается полностью. Почти. Еле тюлюпается вроде и слева частота 10, ну а справа inf0.
Прошу прощения за подобные пояснения.. "что вижу то пою" ))
Добавлено спустя 4 минуты 29 секунд:А сейчас не останавливался.. что-то понажимал наверное.. Так и крутит на 1500.
Я к чему - как бы не менялось показание оптодатчика, ШД на это вроде бы не реагирует. И так же пока не реагирует на переменный резистор.
RootAdmin » 19 сен 2015, 13:59
Работа возможна в трёх режимах.
Первый - автомат. Оба символа # скорость шаговика зависит от скорости экструдера.
Второй - изменение частоты шаговика. Левый символ - * при этом коэффициент рассчитывается динамически.
Третий - изменение коэффициента. Правый символ - *.
Проверять надо при работающем оптодатчике.
Revenger » 19 сен 2015, 15:31
Так надо сначала выйти на рабочий режим, доведя скорость ШД до нужной, затем "передать управление" ардуине.
На резистор не реагирует у меня только или пока эта функция отключена?
Проверял не на шестерне экструдера, а быстро прерывая оптодатчик куском пластика вручную.
RootAdmin » 19 сен 2015, 18:22
Да, в режиме установки частоты ШД - коэффициент и вычисляется.
Добавлено спустя 1 минуту 2 секунды:
Резистор отключен. Вообще планировал запоминание настроек.
Revenger » 19 сен 2015, 18:34
Всё понял. Попробую сегодня/завтра на экструдер пойти всё навесить, чтобы реально на шестерне проверить.
А режимы 1,2,3 как должны реагировать и на что? Первый автомат... как функциклировать должен? Ну второй понятно, меняем частоту шаговика увеличивая тем самым скорость вращения, а третий как и на что должен влиять?
RootAdmin » 19 сен 2015, 23:07
Первый и третий режимы - одно и тоже. Просто третий - возможность регулировки коэффициента "на ходу". Идея в том, что во втором режиме подстраиваем скорость шаговика, переключаем в другой режим - шаговик работает от скорости экструдера. И при необходимости-подстраиваем коэффициент. Если прикрутим микрометр - он и будет задавать коэффициент.
Добавлено спустя 1 минуту 20 секунд:
Первый режим - скорость шаговика=скорость экструдера*коэффициент.
Revenger » 20 сен 2015, 00:37
В общем понял. Завтра попробую собрать на экструдере. Всё равно надо пластик попробовать чуть сделать, а то печатать нечем.
Немного непонятно только как мне уменьшить вращение ШД (в смысле не вообще, про нажатия кнопок я понял) а как зафиксировать это значение, т.к. когда я на столе баловался с оптодатчиком и схемой, то по нажатию на селект, я возвращался автоматом на 1500 вращения сколько бы я кнопками не накрутил, а если в режиме 3 убирал до минимуму коэффициент (или как правильно), то ШД останавливался и показывалась частота 10.
ВопЧем надо пробовать в реальных боевых действиях )
Revenger » 20 сен 2015, 16:59
х.з. что случилось, но перенёс всё к экструдеру, установил оптопару, включил и... не меняются показания оптопары, т.е. сигнала нет. Отвёрточкой потыкал на обратной стороне платы (оптопары, где резисторы паял) показания на дисплее зашевелились, но не более того.
Ну и так же, на слух нет никаких изменений во вращении ШД при изменении частоты, выдаваемой с оптопары.
Разве что как-то получалось так, что если перестали меняться показания оптопары на какой-то промежуток времени, то ШД останавливался полностью (на дисплее слева 10), а если импульс появлялся, то частота ШД тут же становилась 1500.
RootAdmin » 21 сен 2015, 15:27
Чуть отладил.
Теперь обороты шаговика и экструдера в оборотах в секунду.
- Код: Выделить всё • Развернуть
/*
Управление шаговиком (драйвер степ-дир) переменным резистором
теперь с кнопками! :)
А на этот раз - с экраном и резистивными кнопками.
Добавил измерение скорости вращения экструдера. Чуть подправил генерацию импульса на шаговик.
Управление преработано. Кнопка Select переключает режим "выбор" и "редактирование" Частота экструдера - в оборотах в минуту.
Добавлен коэффициент
v 0.6a */
/*
Вывод Назначение
0 UART
1 UART
2 Внешнее прерывание от оптопары (не менять!)
3
4
5 Dir_pin
6 Step_pin
7 LCD RS
8 LCD RW
9 LCD E
10 LCD DB4
11 LCD DB5
12 LCD DB6
13 LCD DB7
A0 Резистор
A1 Кнопки
A2
A3
A4
A5
A6
A7
*/
#include <EEPROM.h> //подключаем библиотеку EEPROM
#include <LiquidCrystal.h> // Подключаем стандартную библиотеку LiquidCrystal
// Инициализируем объект-экран, передаём использованные
// для подключения контакты на Arduino в порядке:
#define lcd_RS_pin 7
#define lcd_RW_pin 8
#define lcd_E_pin 9
#define lcd_DB4_pin 10
#define lcd_DB5_pin 11
#define lcd_DB6_pin 12
#define lcd_DB7_pin 13
// RS, RW, E, DB4, DB5, DB6, DB7
LiquidCrystal lcd(lcd_RS_pin, lcd_RW_pin, lcd_E_pin, lcd_DB4_pin, lcd_DB5_pin, lcd_DB6_pin, lcd_DB7_pin);
#define Step_pin 6 //вывод Arduino для ноги STEP контроллера (выход)
#define Dir_pin 5 //вывод Arduino для ноги DIR контроллера (выход)
#define Resistor_pin A0 //вывод Arduino резистора 0-5вольт (аналоговый вход)
//Оптодатчик:
#define OptoSensor_pin 2 //вывод Arduino для оптодатчика (вход)
#define ToothSumm 4 //сколько усреднять событий
#define ToothAll 140 // Событий на оборот
float ExtruderConst=(float)1/((float)(ToothAll/ToothSumm)*((float)1/250000)); // Коэффициент тиков :) Для оборотов в СЕКУНДУ делим его на измеренные
float DivK =35; //Коэффициент для соотношения скорости шаговика к скорости экструдера
volatile unsigned long OptoSensorTicks=0;//Переменная для хранения тиков таймера на 1 вызов (время между зубьями)
volatile byte OptoToothCounter =0; //Указатель на текущтй зуб в массиве
volatile unsigned int OptoToothTimeArray [ToothSumm]; //массив с таймингами зубьев
//********** Кнопки:
#define btnRIGHT 1 //Определяем кнопки, это просто внутренние номера, НЕ ноги-выводы
#define btnUP 2
#define btnDOWN 3
#define btnLEFT 4
#define btnSELECT 5
#define btnNONE 0
//**********
#define btnDEFtime 30 //Значение для антидребезга - клавиша удерживаемая столько времени в миллисекундах считается нажатой.
#define btnPAUSEtime 400 //Значение в миллисекундах паузы между повторами
int lcd_key = btnNONE; //Для хранения полученного значеник кнопки
byte keyTemp = btnNONE; //Переменная для хранения временного состояния кнопок
byte keyCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
unsigned long BtnTime; //Хранит время начала нажатия кнопок
byte btnCONTpress; //Переменная взводится после первого срабатывания клавиши и определяет автоповтор
byte btnTemp=btnNONE; //Для хранения номера ранее нажатой кнопки
#if defined(Razr) //Мне для отладки
#define ButtonPin A7 //Сюда подключены кнопки
#else
#define ButtonPin A1 //Сюда подключены кнопки
#endif
//************
/*
//структура под меню
typedef struct
{
char* nam;
byte posX;
byte posY;
} menu;
//typedef struct menu menuEl;
menu menus[3] ={{"Mm1",0,0},
{"Mm2",1,1},
{"Mm3",3,3}};
*/
byte ControlPos = 0; //Переменная определяет элемент в строке управления. 1 - коэффициент. 0 - частота протяжки
byte ControlMode = 0; //Переменная определяет режим управления. 0 - выбор, 1 - редактирование
int ScreenPass =100; //Для пропуска циклов, чтоб экран не мерцал.
volatile unsigned char FullTimer0; //Переменная для остатка значения таймера
volatile unsigned int FullTimer256;//Переменная для количества холостых 256циклов таймера
volatile unsigned int FullTimer256Count; //внутренный счетчик таймера
//значение минимальной частоты
#define LowFreq 10
//значение МАКСИмальной частоты
#define HighFreq 2000
//Переменная для шага чаcтоты на едниницу изменения АЦП
// float FreqStep;
float OutFreq = LowFreq; //Переменная для хранения установленной частоты
/*
//Переменная для текущего значения резистора
int sensorValue = 0;
//Переменная для Старого значения резистора
int OLDsensorValue = 0;
*/
void setup() {
pinMode(Step_pin,OUTPUT); // Конфигурим вывод Step_pin как выход
pinMode(Dir_pin,OUTPUT); // Конфигурим вывод Dir_pin как выход
// pinMode(Resistor_pin,INPUT); // Конфигурим вывод Dir_pin как вход
pinMode(OptoSensor_pin,INPUT); // Конфигурим вывод OptoSensor_pin как вход
attachInterrupt(0, OptoSensor, CHANGE); // привязываем 0-е прерывание к функции OptoSensor(). На изменение состояния. Да, из-за разницы между шириной самого зуба и межзубного расстояния - будут различия, усредним.
lcd.begin(16,2); //Инициализируем экран
//Установим на выходах 0
digitalWrite(Step_pin, LOW);
digitalWrite(Dir_pin, LOW);
// // Посчитаем "шаг" изменения частоты на единицу изменения резистора
// FreqStep=(float)(HighFreq-LowFreq)/1024;
//Запускает последовательный порт
Serial.begin(9600);
//Сообщение о запуске программы
Serial.println("Program started");
// Serial.print("FreqStep=");
// Serial.println(FreqStep);
//Запускает таймер и получает загружаемое значение таймера.
//Параметр - желаемая частота в герцах.
FullTimer0=SetupTimer2(OutFreq);
//Установки Таймер2: Делитель частоты /64, режим 0
//Частота = 16MHz/32 = 500000 герц или
//Делитель /32 дает нам лучший рабочий диапазон в районе 1 кгц
//так что сейчас мы просто жестко запрограммируем это.
TCCR2A = 0;
TCCR2B = 0<<CS22 | 1<<CS21 | 1<<CS20; //это на 32
//TCCR2B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//TCCR2B = 1<<CS22 | 0<<CS21 | 1<<CS20; //это на 128
//Подключение прерывания по переполнению Timer2
TIMSK2 = 1<<TOIE2;
//Установки Таймер1: Делитель частоты /64, режим 0
//Частота = 16MHz/64 = 250000 герц или
//Делитель /64 дает нам хороший рабочий диапазон
//так что сейчас мы просто жестко запрограммируем это.
TCCR1A = 0;
TCCR1B = 1<<CS22 | 0<<CS21 | 0<<CS20; //это на 64
//Подключение прерывания по переполнению Timer0 (для обнуления скорости)
TIMSK1 = 1<<TOIE1;
//Выводит загружаемое значение таймера
Serial.print("Timer2 Load:");
Serial.println(FullTimer0,HEX);
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.print("Stepper control"); //выводим на него строку
lcd.setCursor(0, 0); //устанавливаем курсор
lcd.print("#St Div Ext"); //выводим на него строку
lcd.setCursor(0, 0); //устанавливаем курсор
// lcd.cursor(); //Включим курсор
// lcd.blink(); //Пусть мигает
delay(10);
}
void loop() {
OptoSensorTicks=0;
//Один тик таймера - это 4 микросекунды (.000004) Зубъев у нас 70, причем реагируем на вход зуба а оптосенсор и на выход. Значит - 140 событий на оборот экструдера.
//Складывая время
for (int i=0; i<ToothSumm; i++) {OptoSensorTicks+=OptoToothTimeArray[i];}
ScreenPass++; //Инкремент счетчика
if (ScreenPass>1000)
{
ScreenPass=0; //Обнуляем счетчик
lcd_key=read_LCD_buttons(); //прочитаем нажатую кнопку
//0 4 8 12 |
// St Div Ext
//000 00000 00000
if (lcd_key) //Нажата какая-то кнопка
{
if (btnSELECT==lcd_key) //Если нажата кнопка Select
{
ControlMode=!ControlMode;
if (ControlMode)
{
if (ControlPos==0)
{
lcd.setCursor(0, 0);
lcd.print("*");
lcd.setCursor(4, 0);
lcd.print(" ");
}
if (ControlPos==1)
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print("*");
}
}
else
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print(" ");
if (ControlPos==1){lcd.setCursor(4, 0); lcd.print("#"); }
if (ControlPos==0){lcd.setCursor(0, 0); lcd.print("#"); }
}
} //Меняем режим на другой :)
if (ControlMode) //Если режим - "редактирование"
{
if (btnUP==lcd_key) //Если нажата кнопка "Больше"
{
if (ControlPos==0) //Меняем частоту протяжки шагами
{
OutFreq+=10;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент шагами
{DivK+=1;}
}
if (btnDOWN==lcd_key) //Если нажата кнопка "Меньше"
{
if (ControlPos==0) //Меняем частоту протяжки шагами
{
OutFreq-=10;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент шагами
{DivK-=1;}
}
if (btnRIGHT==lcd_key) //Если нажата кнопка "ВПРАВО"
{
if (ControlPos==0) //Меняем частоту протяжки единицами
{
OutFreq+=1;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент единицами
{DivK+=.01;}
}
if (btnLEFT==lcd_key) //Если нажата кнопка "ВЛЕВО"
{
if (ControlPos==0) //Меняем частоту протяжки единицами
{
OutFreq-=1;
SetupTimer2(OutFreq); //устанавливаем таймер
}
if (ControlPos==1) //Меняем коэффициент единицами
{DivK-=.01;}
}
}
else //режим "выбор"
{
if (btnRIGHT==lcd_key) //нажата кнопка ВПРАВО
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(4, 0);
lcd.print("#");
ControlPos = 1;
}
if (btnLEFT==lcd_key) //нажата кнопка ВЛЕВО
{
lcd.setCursor(4, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print("#");
ControlPos = 0;
}
}
}
//Теперь в зависимости от режима нужно...
//Либо считать частоту шаговика от коэффициента при ControlMode==1 и ControlPos==1
//Либо вычислять коэффициент при ControlMode==1 и ControlPos==0
//Либо вычислять частоту шаговика от коэффициента при ControlMode==0
//Короче, только при ControlMode==1 и ControlPos==0 вычислять коэффициент. В остальных случаях - частоту.
if ((ControlMode==1) && (ControlPos==0)) //Если режим - редактирование, изменение шаговика
{
DivK= (float)OptoSensorTicks/(float)OutFreq; //Вычислим коэффициент
}
else
{
OutFreq=(float)OptoSensorTicks/(float)DivK;
if (OutFreq>HighFreq){OutFreq=HighFreq;}
if (OutFreq<LowFreq){OutFreq=LowFreq;}
SetupTimer2(OutFreq); //устанавливаем таймер
}
//Выведем коэффициент
lcd.setCursor(10, 1);
lcd.print(DivK);
//выведем скорость
lcd.setCursor(10, 0);
lcd.print(" ");
lcd.setCursor(10, 0);
lcd.print(ExtruderConst/OptoSensorTicks);
// lcd.setCursor(9, 1);
// lcd.print(" ");
// lcd.setCursor(9, 1);
// lcd.print(OptoSensorTicks);
lcd.setCursor(0, 1);
lcd.print(OutFreq/200); //выведем частоту в оборотах в СЕКУНДУ. Коэффициент 1 секунд*200 имп.оборот = 200
/*
Serial.print("sensor=");
Serial.println(sensorValue,DEC);
Serial.print("FullTimerCount");
Serial.println(FullTimerCount);
Serial.print("FullTimer");
Serial.println(FullTimer,DEC);
Serial.print("timer=");
Serial.println(FullTimer0,DEC);
Serial.print("ButtPressed=");
Serial.println(ButtPressed,DEC);
Serial.print("OutFreq=");
Serial.println(OutFreq,DEC);
Serial.println("***");
Serial.println("");
Serial.println("***");
Serial.println(OptoSensorTicks);
delay (200);
*/
Serial.println("***");
Serial.print(FullTimer256);
Serial.print("===");
Serial.println(FullTimer0);
}
}
//Timer1 указатель вектора прерывания по переполнению
ISR(TIMER1_OVF_vect)
{
OptoToothTimeArray[OptoToothCounter]=0; //присваиваем элементу массива 0
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
//Timer2 указатель вектора прерывания по переполнению
ISR(TIMER2_OVF_vect)
{
noInterrupts(); //Запретили прерывания
if (FullTimer256Count==0) // Срабатывание
{
//Переключение IO-вывода в HIGH
digitalWrite(Step_pin,HIGH); //Переключение IO-вывода в HIGH (Старт импульса)
FullTimer256Count=FullTimer256;
// //Переключение IO-вывода в другое состояние.
// digitalWrite(Step_pin,!digitalRead(Step_pin));
//Перезагрузка таймера и коррекция по задержке
if (!FullTimer256)
// {TCNT2=0;} //Если холостые циклы есть - максимальное значение
// else
// {TCNT2+=FullTimer0;}
{TCNT2=FullTimer0;}
digitalWrite(Step_pin,LOW); //Переключение IO-вывода в LOW (Стоп импульса)
}
if (FullTimer256Count==1) //предпоследний цикл
{
TCNT2=FullTimer0;
FullTimer256Count=0;
}
if (FullTimer256Count>1) //Обычный цикл
{FullTimer256Count--;}
interrupts(); //Разрешили прерывания
}
#define TIMER_CLOCK_FREQ 1000000.0
//15625 for /1024
//2MHz for /8 prescale from 16MHz
//Возвращает начальное значение таймера, которое должно быть загружено в TCNT2
//внутри вашей процедуры ISR.
unsigned char SetupTimer2(float timeoutFrequency){
//Подсчет начального значения таймера
//Слегка усложним, добавив холостые просчеты
long ticks = TIMER_CLOCK_FREQ/timeoutFrequency; // тиков счетчика для получения заданной частоты
// #if defined(Razr)
// lcd.setCursor(9, 0);
// lcd.print(ticks);
// #endif
FullTimer256=ticks/256; //Вычисляем количество ПОЛНЫХ 256 циклов таймера
ticks-=FullTimer256*256;
ticks-=8;
FullTimer0=(byte)(255.0-ticks); //Вычисляем количество доплнительных тиков таймера
//загружает таймер для первого цикла
//Сейчас не надо, убираю.
// if (FullTimer256)
// {TCNT2=0;} //Если холостые циклы есть - максимальное значение
// else
// {TCNT2=FullTimer0;}
}
// *****************************
//Чтение кнопок с антидребезгом
// read the buttons
int read_LCD_buttons()
{
int adc_key_in = analogRead(ButtonPin); // Получаем напряжение с АЦП
byte btnTempTemp = btnNONE; //Переменная для хранения свежесчитанного внутри функции
//digitalWrite (LED_pin,0); //debug
//lcd.setCursor(5, 0); //debug
//lcd.print(adc_key_in); //debug
//delay (400); //debug
//Тут используем millis() для отслеживания нажатия кнопки
// Запоминиаем в переменной BtnTime ВРЕМЯ НАЧАЛА нажатия
// Запоминаем в переменной btnTemp нажатия
// Дефиним время антидребезга #define
if (adc_key_in > 950) //Ничего не нажато
{
//BtnTime=0; //Скидываем время нажатия
btnCONTpress=0;
return btnNONE; // We make ths the 1st option for speed reasons since it will be the most likely result
}
else //что-то нажато
{
if (adc_key_in < 790) { btnTempTemp=btnSELECT; } //Определяем в переменную ТЕКУЩУЮ нажатую кнопку.
if (adc_key_in < 555) { btnTempTemp=btnLEFT; }
if (adc_key_in < 380) { btnTempTemp=btnDOWN; }
if (adc_key_in < 195) { btnTempTemp=btnUP; }
if (adc_key_in < 50) { btnTempTemp=btnRIGHT; }
//А тут проверим, совпадает ли с btnTemp (была ли нажата ранее)
/* lcd.setCursor(0, 0); //debug
lcd.print(btnTempTemp); //debug
lcd.setCursor(2, 0); //debug
lcd.print(btnTemp); //debug
lcd.setCursor(1, 1); //debug
lcd.print(millis()); //debug
lcd.setCursor(12, 1); //debug
digitalWrite (LED_pin,1); //debug
delay (100);
lcd.print(" "); //debug
lcd.setCursor(12, 1); //debug
lcd.print(adc_key_in); //debug
*/
if (btnTempTemp==btnTemp) //Кнопка уже БЫЛА нажата
{
if (btnCONTpress) //Повторные установки клавиши
{
if ((millis()-BtnTime) > btnPAUSEtime)
{
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
else //Первая установка клавиши
{
if ((millis()-BtnTime) > btnDEFtime)
{
btnCONTpress=1;
BtnTime=millis(); // Ставим стартово время для автоповтора
return btnTemp;
}
}
}
else //Раньше было другое состояние
{
// digitalWrite (LED_pin,1); //debug
// delay (100);
btnCONTpress=0;
BtnTime=millis(); //Устанавливаем ТЕКУЩЕЕ время в переменную BtnTime
btnTemp=btnTempTemp; //устанавливаем кнопку во временную переменную.
}
}
return btnNONE; // Если ничего не сработало, то ничего не возвращаем
}
//***********************************
void OptoSensor() // функция обработки прерывания. Меняет глобальные прееменные
{//Сработал - значит считаем тики. F njxytt - echtlyztv pf
OptoToothTimeArray[OptoToothCounter]=TCNT1; //присваиваем элементу массива текущее значение таймера
TCNT1 = 0; //сбрасываем таймер
OptoToothCounter++; //инкрементим счетчик
if (ToothSumm==OptoToothCounter) {OptoToothCounter=0;} //если счетчик равен количеству элементов массива (а индекс массива начинается с 0 - то обнуляем.
}
По поводу оптосенсора - а подключено точно правильно?
Revenger » 21 сен 2015, 17:18
Так вроде как всё взял в кучу со стола, так и отнёс и включил. С переменника провод только отвалился, но я его на всякий случай на место прилепил. А опто ((( так себя повёл (((
Сейчас снова всё кучей принесу домой, чтобы перепрошить. Посмотрю на светУ нормальном, может что где и отвалилось (надеюсь).
Добавлено спустя 1 час 32 минуты 56 секунд:
Кстати, уже спрашивал но напомню.. обороты шаговика не менялись это у меня так где-то косяк или пока это просто незаметно?
Просто обороты экструдера когда падают, это заметно и на слух и визуально (когда попадает пластик например между стенкой и шнеком), тут шаговик должен реагировать ооочень заметно на мой взгляд. Хотя могу конечно ошибаться. Пока не испытал ((
Перепроверю оптодатчик сегодня и если что отпишусь уже после испытания на экструдере.