Сейчас проверю...
Добавлено спустя 2 минуты 50 секунд:Такс, кажется напутал. Сейчас.
Добавлено спустя 20 минут 8 секунд:Код:
/*
Управление шаговиком (драйвер степ-дир) переменным резистором 
теперь с кнопками! :)
А на этот раз - с экраном и резистивными кнопками.
Добавил измерение скорости вращения экструдера. Чуть подправил генерацию импульса на шаговик.
Управление преработано. Кнопка 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 =500; //Коэффициент для соотношения скорости шаговика к скорости экструдера 
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)OutFreq*(float)OptoSensorTicks)/1000;  //Вычислим коэффициент 
         }
      else
        {
          OutFreq=((float)DivK*1000)/(float)OptoSensorTicks;
          if (OutFreq>HighFreq){OutFreq=HighFreq;}
          if (OutFreq<LowFreq){OutFreq=LowFreq;}
          SetupTimer2(OutFreq); //устанавливаем таймер
        }
  
      //Выведем коэффициент
         lcd.setCursor(8, 1);
         lcd.print(DivK, DEC);
      
      //выведем скорость
          lcd.setCursor(10, 0);
          lcd.print("     ");
          lcd.setCursor(10, 0);
          lcd.print(ExtruderConst/OptoSensorTicks, DEC);
          
      //    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.print("OutFreq=");
            Serial.println(OutFreq,DEC);
          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 - то обнуляем.
}