Этюды для начинающих: blink и без delay, и без millis

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Феерично. Заинтриговался, чего тут так наобсуждали .. неужто ишо новый метод "моргать глазом" уже и без милиса, таймер и вовсе контроллера .. ан нет, всё те же и все об том же ..

Звиняюсь, что вклинился..

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Arhat109-2 пишет:

Феерично. Заинтриговался, чего тут так наобсуждали .. неужто ишо новый метод "моргать глазом" уже и без милиса, таймер и вовсе контроллера .. ан нет, всё те же и все об том же ..

Звиняюсь, что вклинился..

да - усё на конденсаторах и реле. только харкор - в жопу миллис!

Похожее изображение

Smith2007
Offline
Зарегистрирован: 30.10.2017

Новое исследование:

На вход 3 повешена кнопка.

По прерыванию int.0 (pin 3) вызываю процедуру, где происходит инкрементирование переменной. 

Для проверки вывожу значение в терминал.  Работает.

Теперь хочу запрограммировать Timer2 на генерацию прерывания в 1 сек.

d3,11 отключаю

При компиляции выходит ошибка, что переменная TCCR2A не определена

int _count = 0;
int freq = 0;

ISR(TIMER2_COMPA_vect) {
  freq = _count;
  _count = 0;
  Serial.print("freq= "); Serial.println(freq);
}

void signalCount(void) {
  _count++;
  Serial.println(_count);
}
 
void setup() {
    Serial.begin(115200);
    attachInterrupt(0, signalCount, FALLING);
    //TCCR1A = 0;          // Инвертирование пина 9 по сравнению
    //TCCR1A=1<<COM1A0;  // Переключение пина 9 по сравнению
    //TCCR1A=0x50;
    TCCR2A = 0; // Пины 3 и 11 отключаем 

    OCR2A = 15625u; // при делителе 1024, это 1 сек., если я нигде не лажанулся
    TIMSK2 = bit(OCIE2A);   // Разрешаем прерывание по сравнению с OCR2A
    TCCR2B = bit(CS22) | bit(CS21) | bit(CS20);  // Установить СТС режим и делитель частоты
 }
 
void loop() {}

Как в таком случае добраться до регистров второго таймера?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Smith2007 пишет:

Теперь хочу запрограммировать Timer2 

А он у Вас есть?

Какой у Вас контроллер? Я уже как-то спрашивал, но Вы не ответили.

Smith2007
Offline
Зарегистрирован: 30.10.2017

Arduino Leonardo

BN: Arduino Leonardo
VID: 2341
PID: 8036
SN: (null)
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Это не котроллер - это плата.

Обычно леонардо делают на базе ATmega32u4 (хотя, если клон, то там может стоять что угодно). 

Так вот, если у Вас действительно ATmega32u4 (убедитесь!), так и смотрите её даташит, а не ATmega328, который я Вам давал.

Открываем и смотрим. Таймеры №№ 0, 1, 3 и 4 есть, а таймера 2 - нету :(

так что никак Вы до него не доберётесь :(

P.S. Справедливости ради, он там есть, только недокументирован, но это не для игроков из Вашей лиги. Пока считайте, что его нет.

Smith2007
Offline
Зарегистрирован: 30.10.2017

Спасибо за информацию.

Да, действительно в описании есть таймеры 0,1,3,4. Таймера 2 - нет.

Стандартные функции ардуино какие таймеры используют? Тотже millis?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Smith2007, даже если бы вы запустили этот таймер недокументированными командами у вас всё равно бы ничего не получилось, т.к. он 8-битный. А вы хотели записать в его регистр 15625

Smith2007
Offline
Зарегистрирован: 30.10.2017

dimax пишет:

Smith2007, даже если бы вы запустили этот таймер недокументированными командами у вас всё равно бы ничего не получилось, т.к. он 8-битный. А вы хотели записать в его регистр 15625

Предпочту все же документированные возможности.

Переделал на timer3. Все сразу заработало. Собрал новую схему с новой программой. Пока не приехали  генератор с осцилографом - сложно чего-то отлаживать. Но я упрямый и буду дальше изучать.

Не до конца понимаю режимы WGMnx. Таймер правильно отрабатывает прерывание при WGM = 0100  (WGM32 в 1)

sim31
sim31 аватар
Offline
Зарегистрирован: 26.07.2017

Smith2007 пишет:

Переделал на timer3. Все сразу заработало. Собрал новую схему с новой программой. Пока не приехали  генератор с осцилографом - сложно чего-то отлаживать. Но я упрямый и буду дальше изучать.

Не до конца понимаю режимы WGMnx. Таймер правильно отрабатывает прерывание при WGM = 0100  (WGM32 в 1)

Поможет Proteus для эмуляции МК и Codevision AVR для конфигурирования микроконтроллера. Мне связка очень помогла в настройке таймеров, в Codevision можно режимы работы таймеров мышкой выбрать, а в Proteus проверить нет ли ошибок, даже к даташиту обращаться не нужно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sim31 пишет:

 даже к даташиту обращаться не нужно.

Красота!

batu
Offline
Зарегистрирован: 27.08.2013

Привет! Хорошие материалы делаешь. Хотел бы пообщаться. Не нашел как здесь в личку написать.. Можно в скайпе пообщаться. Есть предложение. skype batu1955

leks
Offline
Зарегистрирован: 22.10.2017
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Arduino UNO
//
////////////////////////
//
// Программа мигания светодиода /
//

unsigned int n = 0;

void setup()
{
        pinMode(13, OUTPUT);
        digitalWrite(13, LOW);
 }

void loop()
{
    for (n = 0; n <= 50000; n++)
      {
        digitalWrite(13, HIGH);
      }
    for (n = 0; n <= 50000; n++)
      {
         digitalWrite(13, LOW);
      }
}

//
// Конец /
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Вот так начинал знакомство с Ардуино несколько месяцев назад.

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Всем здравствуйте.

Возникла задача выполнять определенный фрагмент кода(конкретно выложу) в течение 10 секунд, затем переходить к остальной программе. Плата Uno на atmega 328p. Сразу отказался от millis() поскольку она уже задействована в выводе температуры и в обработке кнопок, она тормозит этот код. Понял что здесь нужно  timer1.   ЕвгенийП прочитал ваши этюды, спасибо вам за труд, кое что для себя почерпнул. Но для своей задачи боллее подходящее нашел в #78. Немного поковырялся, и в сериал мониторе увидел то что нужно (секунды пошли). 

Вставив все это и откомпилировав обнаружил что не работает. Можете указать в чем ошибся

// это код из поста 78
word prevTCNT1;
word timeBlink = 1000;//в мсек  (максимум 4194ms)
word totalTic;//15625 ==> 1000ms;  65535; ==> 4194ms максимум

void setup() { 
  Serial.begin(9600); 
  TCCR1A = 0;
  TCCR1B |= (1<<CS10)|(1<<CS12); //предделитель 1024; 1 тик = 64 мкс 
  //TCCR1B = B101;
  totalTic = 1000UL * timeBlink / 64;//сколько тиков в 1000 мсек
  TCNT1 = 0; 
}

void loop() {
  static byte state = 0;
  if(TCNT1 - prevTCNT1 >= totalTic){
    prevTCNT1 = TCNT1;
    state++;
    Serial.println(state); 
  }
}
// тут идет обработка кнопок 
// вывод меню
// вывод температуры каждую секунду 
                 if (tc2 >= setTemp2) {
                       tone(buzzerPin, 800, 2000); 
                       
                      static byte state = 0;                
                       do { // начало цикла do while
                           if(TCNT1 - prevTCNT1 >= totalTic){
                              prevTCNT1 = TCNT1;
                              state++;
                              lcd.setCursor(8, 0);	// Печатаем на ЖК;
                              lcd.print("    ");   // Режим редактирования температуры
                              lcd.write(4);
                            }
                       }
                       while( state < 10); // конец цикла do while                       
                  }      
// входим в другой цикл             
BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Могу конечно выложить и весь мой код полностью, но врятли у кого то будет желание туда лезть

// ARDUINO REWORK v 0.3
/*Справа на блоке управления располагается кнопка СТОП (красного цвета). 
* С помощью данной кнопки можно в любой момент остановить процесс пайки. 
* При этом блок управления не выключается и продолжается отчет времени, но выключаются непосредственно нагревательные элементы.
* В правой части панели блока управления располагается 6 кнопк для настройки блока управления на пайку. 
* Крайняя левая верхняя кнопка вызывает МЕНЮ блока управления , две центральные кнопки управляют выбором и крайняя левая нижняя 
* (ВЫБОР) подтверждает выбранную позицию.
* Если в ходе пайки при достижении предполагаемой температуры оплавления шариков БГА оплавления не происходит 
* Вы можете тут же в ходе пайки прибавить температуру места пайки нажатием кнопки + и при необходимости убавить кнопкой -. 
* Соответственно Вам не придется ждать завершения текущего профиля и новой настройки. 
* При этом необходимо отметить, что после окончания процесса пайки эта температура не изменит сам установленный профиль пайки.
* При установке профиля пайки все изменяемые Вами значения (температура нижних нагревателей, температура пайки 
* и температура включения верхнего нагревателя, коэффициенты профиля) будут записаны в памяти контроллера
* и при следующей пайке примут установленные ранее Вами значения.
* Верхняя полочка ограничена 10 секундами (во избежание повреждения микросхемы). 
* Данной ограничение может быть изменено в пункте ДОПОЛНИТЕЛЬНЫЕ НАСТРОЙКИ и Вы можете выставить свою длительность.

 * Автоматический режим работы обеспечивает поддержание температуры 10-255 градусов через обратную связь с термопар. 
 * В ручном режиме мощность в каждом канале можно регулировать в диапазоне 0-99%.
*/
#include <Wire.h> // библиотека для управления устройствами по I2C 
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602
#include "max6675.h"
#include <PID_v1.h>

#define RELAYPIN1 1  //назначаем пин "НИЖНЕГО" нагревателя
#define RELAYPIN2 0  //назначаем пин "ВЕРХНЕГО" нагревателя

#define buzzerPin 3 // назначаем пин для пьезодинамика

LiquidCrystal_I2C lcd(0x3f, 20, 4); // присваиваем имя lcd для дисплея 20х4

//Назначаем пины кнопок управления
#define BUTTON_OK 10       // кнопка OK
#define BUTTON_LEFT 11     // кнопка LEFT
#define BUTTON_RIGHT 12    // кнопка RIGHT
#define BUTTON_UP 9        // кнопка UP 
#define BUTTON_DOWN 8      // кнопка DOWN
#define BUTTON_CANSEL 13    // кнопка CANSEL

//состояние кнопок по умолчанию
/*boolean State_Up = LOW;
boolean State_Down = LOW;
boolean State_Left = LOW;
boolean State_Right = LOW;
boolean State_Ok = LOW;
boolean State_Cansel = LOW;*/

boolean  button_state = false;
boolean  button_long_state = false;
byte ButtonPress = 0;
unsigned int time_Pressed;  // Переменные для работы со временем;
boolean MenuEnter;
boolean status_of_heater = 0; // флаг отображения меню
boolean thrState = 0;      // флаг установки работы "ВЕРХНЕГО" нагревателя

uint8_t arrow_up[8]  = {0x04, 0x0e, 0x15, 0x04, 0x04, 0x04, 0x04};
uint8_t arrow_down[8]  = {0x04, 0x04, 0x04, 0x04, 0x15, 0x0e, 0x04};
uint8_t arrow_m[8]  = {0x08, 0x0C, 0x0E, 0x0F, 0x0E, 0x0C, 0x08};
uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0};

unsigned int prevTCNT1;
unsigned int timeBlink = 1000;//в мсек  (максимум 4194ms)
unsigned int totalTic;//15625 ==> 1000ms;  65535; ==> 4194ms максимум

unsigned int prevmicros = 0;//переменная для хранения значений таймера
byte sek = 0; //значение секунд
byte minu = 0; //значение минут
boolean counter = false; // счетчик для полусекунд

#define PERIOD_PWM 1000UL // > 750

short kp1 = 0;  short kp2 = 0;
short kd1 = 0;  short kd2 = 0;
short ki1 = 0;  short ki2 = 0;

boolean flag = 0;  //флаг для фиксации стартовой температуры

double startTemp;
double setTemp1 = 0.0;
double setTemp2 = 0.0;
double tc1 = 0.0;
double tc2 = 0.0;
double outputPower1 = 0.0; // по умолчанию диапазон выходных значений для ШИМ устанавливается от 0 до 100
double outputPower2 = 0.0; // по умолчанию диапазон выходных значений для ШИМ устанавливается от 0 до 100
unsigned int lastTime = 0;

boolean state_top = 0; 
boolean state_bottom = 0;
unsigned int prev_top, prev_bottom;

PID myPID1(&tc1, &outputPower1, &setTemp1, kp1, ki1, kd1, DIRECT);
PID myPID2(&tc2, &outputPower2, &setTemp2, kp2, ki2, kd2, DIRECT);

#define thermoDO 7
#define thermoCLK 5
#define thermoCS_b 6
#define thermoCS_t 4
MAX6675 thermocouple_b(thermoCLK, thermoCS_b, thermoDO); //термопара "НИЖНЕГО" нагревателя
MAX6675 thermocouple_t(thermoCLK, thermoCS_t, thermoDO); //термопара "ВЕРХНЕГО" нагревателя

typedef void (*LCD_menu)();

LCD_menu const menu[] =
{
  setString,
  timing
};

enum switchVariants {	// Определения для переключателя в главном цикле;
  MAIN_MENU,
  MENU_MANUAL,
  MENU_AUTO,
  MENU_SETUP,
  MENU_INFORM,
};
switchVariants switchPointer = MAIN_MENU;	// С чего начнем цикл;

void setup() {
  lcd.begin();     // инициализация LCD дисплея
  lcd.backlight(); // включение подсветки дисплея

  lcd.setCursor(1, 1);
  lcd.print("ARDUINO REWORK v0.3");
  
  lcd.createChar(1, arrow_up);
  lcd.createChar(2, arrow_down);
  lcd.createChar(3, arrow_m);
  lcd.createChar(4, clock);

  //Мелодия приветствия
  tone(buzzerPin, 523);
  delay(200);
  tone(buzzerPin, 659);
  delay(200);
  tone(buzzerPin, 784);
  delay(200);
  tone(buzzerPin, 1046);
  delay(200); 
  noTone(buzzerPin);
  
  delay(1000); // wait for MAX chip to stabilize
  lcd.clear();

 /* pinMode (BUTTON_UP, INPUT);     digitalWrite(BUTTON_UP, HIGH); //подключаем подтягивающий резистор
  pinMode (BUTTON_DOWN, INPUT);   digitalWrite(BUTTON_DOWN, HIGH); //подключаем подтягивающий резистор
  pinMode (BUTTON_LEFT, INPUT);  digitalWrite(BUTTON_LEFT, HIGH); //подключаем подтягивающий резистор
  pinMode (BUTTON_RIGHT, INPUT); digitalWrite(BUTTON_RIGHT, HIGH); //подключаем подтягивающий резистор
  pinMode (BUTTON_OK, INPUT);     digitalWrite(BUTTON_OK, HIGH); //подключаем подтягивающий резистор
  pinMode (BUTTON_CANSEL, INPUT); digitalWrite(BUTTON_CANSEL, HIGH); //подключаем подтягивающий резистор*/
  
  DDRB = 0x00;
  PORTB = 0b00111111;
  
  //pinMode(RELAYPIN1, OUTPUT); // назначить пины реле на выход
  //pinMode(RELAYPIN2, OUTPUT);
  DDRC |= 1 << RELAYPIN1;
  DDRC |= 1 << RELAYPIN2;
  // 
  TCCR1A = 0;
  TCCR1B |= (1<<CS10)|(1<<CS12); //предделитель 1024; 1 тик = 64 мкс 
  totalTic = 1000UL * timeBlink / 64;//сколько тиков в 1000 мсек
  TCNT1 = 0; 
  //
  myPID1.SetSampleTime(1000); //  Время расчета выходного сигнала
  myPID1.SetOutputLimits(0, 100);
  myPID1.SetMode(AUTOMATIC);  //  ПИД-регулятор включен

  myPID2.SetSampleTime(1000); //  Время расчета выходного сигнала
  myPID2.SetOutputLimits(0, 100);
  myPID2.SetMode(AUTOMATIC);  //  ПИД-регулятор включен
  
  prev_top = millis();
  prev_bottom = millis();

}

void loop() {

  //Считываем состояние кнопок управления
  /*State_Up = digitalRead(BUTTON_UP);
  State_Down = digitalRead(BUTTON_DOWN);
  State_Left = digitalRead(BUTTON_LEFT);
  State_Right = digitalRead(BUTTON_RIGHT);
  State_Ok = digitalRead(BUTTON_OK);
  State_Cansel = digitalRead(BUTTON_CANSEL);*/
  //-------------------------------------/
  
  unsigned long Uptime = millis();
  unsigned long nextRead = millis();

  // тут добавить обработку кнопок настройки темп В и Н
  checkForSerial(); //???
    
  //Обработка нажатия кнопки Up
  if ( !(PINB&0b00000010) && (Uptime - time_Pressed) > 200) {
    time_Pressed = Uptime;
    // счетчик нажатий кнопки ButtonPress
    // с каждым нажатием ButtonPress++ пока ButtonPress<4
    ButtonPress++;
    if (ButtonPress > 3) ButtonPress = 0;
  }


   // Фиксируем нажатие кнопки Ok   
   if( !(PINB&0b00000100) && !button_state && ( Uptime - time_Pressed) > 100 ){
      button_state      = true;
      button_long_state = false;  
      time_Pressed        = Uptime;
   }
   
   // Фиксируем длинное нажатие кнопки Ok  
   if( !(PINB&0b00000100) && !button_long_state && ( Uptime - time_Pressed) > 2000 ){
      status_of_heater = true;   
   }
   
   // Фиксируем отпускание кнопки Ok  
   if( PINB&0b00000100 && button_state && ( Uptime - time_Pressed) > 50  ){
      button_state      = false;   
      time_Pressed        = Uptime;
      
      lcd.clear();
      //MenuEnter = true;
      ButtonClick(ButtonPress); // Вызывается функция обработки нажатия на кнопку

   }
   
  //Обработка нажатия кнопки Cansel
  if (!(PINB&0b00100000) && (Uptime - time_Pressed) > 200 ) {
    time_Pressed = Uptime;	// Запоминаем время нажатия кнопки;
    lcd.clear();
    
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    
    //button_long_state = true;
           
    //MenuEnter = false;
    //ButtonClick(ButtonPress); // Вызывается функция обработки нажатия на кнопку
    //switchPointer = MAIN_MENU; // Вход в меню
    //thrState = 0;
    // отключу реле пока такой код
    //digitalWrite(RELAYPIN1, LOW);
    //digitalWrite(RELAYPIN2, LOW);
  }

  switch (switchPointer)  // Все делаем в одном операторе и одной функции;
  {
    case MAIN_MENU:  /***************** Главное меню ***************/

      menu[0](); // включаем отображение стрелки выбора меню

      lcd.setCursor(1, 0); // 1 строка
      lcd.print("MANUAL"); // настройка
      lcd.setCursor(1, 1); // 2 строка
      lcd.print("AUTOMATIC"); // настройка
      lcd.setCursor(1, 2); // 3 строка
      lcd.print("SETUP"); // ручной режим
      lcd.setCursor(1, 3); // 4 строка
      lcd.print("INFORM"); // автоматический режим


      break;


    case MENU_MANUAL: /***************** Ручной режим ***************/
          
          lcd.setCursor(0, 0);	// Печатаем на ЖК;
          lcd.write(2);
          
          lcd.setCursor(1, 1);	// Печатаем на ЖК;
          lcd.print("TH:");
          lcd.print(tc1,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(11, 1);	// Печатаем на ЖК;
          lcd.print("TY:");
          lcd.print(setTemp1,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(13, 0);	// Печатаем на ЖК;
          lcd.print(outputPower1,0);
          lcd.print("\x99""%");
          
          lcd.setCursor(1, 3);	// Печатаем на ЖК;
          lcd.print("TB:");
          lcd.print(tc2,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(11, 3);	// Печатаем на ЖК;
          lcd.print("TY:");
          lcd.print(setTemp2,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(13, 2);	// Печатаем на ЖК;
          lcd.print(outputPower2,0);
          lcd.print("\x99""%");
          
          if (nextRead > lastTime + PERIOD_PWM) {
              lastTime = nextRead;
              tc1 = thermocouple_b.readCelsius();
              tc2 = thermocouple_t.readCelsius();
              myPID1.Compute(); // Расчет выходного сигнала
              myPID2.Compute(); // Расчет выходного сигнала
              
              //фиксируем стартовую температуру      
              if (flag == 0)
              {
                  startTemp = tc1;
                  flag = 1;
              }
               
                   
             if (!status_of_heater) {
                                   
                   lcd.setCursor(8, 0);	// Печатаем на ЖК;
                   lcd.print("EDIT");   // Режим редактирования температуры                                                                        
             }
             else {
                  
                  menu[1]();
                  
                  lcd.setCursor(8, 0);	// Печатаем на ЖК;
                  lcd.print("HEAT");   // Режим редактирования температуры

                  // запуск работы "ВЕРХА" сразу после догрева "НИЗОМ"
                  if (tc1 >= setTemp1) {
                       outputPower1 = 0; // !!! то что ПИД не даст перегреть
                       thrState = 1; //   флаг начала работы "ВЕРХНЕГО" нагревателя
                  }
                 
                  // алгоритм ШИМ с частотой 5 Гц  
                  if ((state_bottom == 0) && ((millis()-prev_bottom) >= 200 * (100 - outputPower1) / 100)) {
                      state_bottom = 1;
                      PORTC |= 1 << RELAYPIN1;
                      prev_bottom = millis();  
                  }
                  if ((state_bottom == 1) && ((millis()-prev_bottom) >= 200 * outputPower1 / 100)) {
                      state_bottom = 0;
                      PORTC &= ~(1 << RELAYPIN1);
                      prev_bottom = millis();
                  }
                  //digitalWrite(RELAYPIN1, state_bottom);
                  
                  // алгоритм ШИМ с частотой 5 Гц 
                  if (thrState && (state_top == 0) && ((millis() - prev_top) >= 200 * (100 - outputPower2) / 100)) {
                      state_top = 1;
                      PORTC |= 1 << RELAYPIN2;
                      prev_top = millis();
                  }
                  if (thrState && (state_top == 1) && ((millis() - prev_top) >= 200 * outputPower2 / 100)) {
                      state_top = 0;
                      PORTC &= ~(1 << RELAYPIN2);
                      prev_top = millis();
                  }
                  //digitalWrite(RELAYPIN2, state_top);  
                  
                  //if (tc1 > startTemp) {
                  if (tc2 >= setTemp2) {
                       tone(buzzerPin, 800, 2000); 
                       
                      /* static byte state = 0;                 
                       do { // начало цикла do while
                           if(TCNT1 - prevTCNT1 >= totalTic){
                              prevTCNT1 = TCNT1;
                              state++;
                              lcd.setCursor(8, 0);	// Печатаем на ЖК;
                              lcd.print("    ");   // Режим редактирования температуры
                              lcd.write(4);
                            }
                       }
                       while( state < 10); // конец цикла do while      */                 
                  }                  
             }
          }                  
    break;

    case MENU_AUTO: /***************** Автоматический режим ***************/
      
    break;

    case MENU_SETUP: /***************** Настройки ***************/

    break;

    case MENU_INFORM: /*********** Информация о станции *********/

    break;
   
  }



  /*
    while (x=1)
    {
      menu[1]();
    }
    break;
    } */

}

void setString()
{
  switch (ButtonPress) {
    case 1:
      lcd.setCursor(0, 0);
      lcd.write(32);
      lcd.setCursor(0, 1);
      lcd.write(62);
      break;

    case 2:
      lcd.setCursor(0, 1);
      lcd.write(32);
      lcd.setCursor(0, 2);
      lcd.write(62);
      break;

    case 3:
      lcd.setCursor(0, 2);
      lcd.write(32);
      lcd.setCursor(0, 3);
      lcd.write(62);
      break;

    default:
      lcd.setCursor(0, 3);
      lcd.write(32);
      lcd.setCursor(0, 0);
      lcd.write(62);
      break;
  }
}

void ButtonClick(byte ButtonId) {

  //if (MenuEnter) { // Если мы в меню
  if (ButtonId == 0)  switchPointer = MENU_MANUAL;   // Клик [Menu] Выход из меню
  else if (ButtonId == 1) switchPointer = MENU_AUTO;  //MenuCurent--;		// Клик [Prev] Позицию ниже
  else if (ButtonId == 2) switchPointer = MENU_SETUP; //MenuCurent++;		// Клик [Next] Позиция выше
  //MenuCurent = constrain(MenuCurent, 0, MenuCount - 1);	// Ограничиваем меню
  else if (ButtonId == 3) switchPointer = MENU_INFORM;//MenuItems[MenuCurent].on_click(1);	// Клик [+] Увеличиваем значение выбранного параметра
  //if (ButtonId == 5) MenuItems[MenuCurent].on_click(-1);	// Клик [-] Уменьшаем значение выбранного параметра
  //} else {
  //  switchPointer = MAIN_MENU; // Вход в меню
  //}
}



void timing()
{
  if (micros() - prevmicros > 500000)
   {
     prevmicros = micros();  //принимает значение каждые полсекунды
     counter=!counter;
     if (counter==false)
     {
       sek++;
       lcd.setCursor(4,0);
       lcd.print(":");         //выводим символ ":"между  минутами и секундами
     }
     if(sek>59)//если переменная секунда больше 59 ...
     {
       sek=0;//сбрасываем ее на 0
       minu++;//пишем +1 в переменную минута
     }
     if(minu>59)//если переменная минута больше 59 ...
     {
       minu=0;//сбрасываем ее на 0
     }

     lcd.setCursor(2,0);//выводим значение минут
     if (minu>=0 && minu<10) {
       lcd.print("0");
       lcd.print(minu);}//количество минут
       else lcd.print(minu);

     lcd.setCursor(5,0);//выводим значение секунд
     if (sek>=0 && sek<10) {
       lcd.print("0");
       lcd.print(sek);}//количество секунд
       else lcd.print(sek);
 }
}

void checkForSerial() {
  setTemp1 = 30.0;
  setTemp2 = 33.0;
  myPID1.SetTunings(kp1, ki1, kd1); // Настройка ПИД-регулятора во время работы
  myPID2.SetTunings(kp2, ki2, kd2); // Настройка ПИД-регулятора во время работы
  
  /* Тут настраиваются коэффициенты ПИД*/
  kp1 = 50;
  ki1 = 0;
  kd1 = 0;
  
  kp2 = 50;
  ki2 = 0;
  kd2 = 0;
}


 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Конкретнее скажу так timer0 отвечает за работу delay и millis поэтому смысла не вижу его трогать, поскольку эти функции у меня задействованы, хочется на 16 битном ТС1, чего мощным ресурсам контроллера простаивать впустую если можно их задействовать на пользу 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

BuonanotteMasha пишет:

Сразу отказался от millis() поскольку она уже задействована в выводе температуры и в обработке кнопок, она тормозит этот код. 

Спасибо, эта фраза сделала мой день.

bwn
Онлайн
Зарегистрирован: 25.08.2014

DIYMan пишет:

BuonanotteMasha пишет:

Сразу отказался от millis() поскольку она уже задействована в выводе температуры и в обработке кнопок, она тормозит этот код. 

Спасибо, эта фраза сделала мой день.

)))), Пора возвращатся к delay().

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Не вижу в этом смысла, ирония ваша понятна ( как любому новичку взявшему в руки микроконироллер)

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

BuonanotteMasha пишет:

Не вижу в этом смысла, ирония ваша понятна ( как любому новичку взявшему в руки микроконироллер)

ну, ок - чем, кроме твоих ошибочных умозаключений, подтверждено твоё утверждение, что миллис тормозит твою программу?

bwn
Онлайн
Зарегистрирован: 25.08.2014

Клапауций 298 пишет:

BuonanotteMasha пишет:

Не вижу в этом смысла, ирония ваша понятна ( как любому новичку взявшему в руки микроконироллер)

ну, ок - чем, кроме твоих ошибочных умозаключений, подтверждено твоё утверждение, что миллис тормозит твою программу?

Дык вызвать ее, потом вычитание, потом сравнение, потом присваивание, эт скоко тактищев то натикает.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Ну простите, к ночи голова тяжелая, поправлюсь. Не millis тормозит программу, она и работает как надо, дело в том что у меня вывод температуры постоянный с интервалом в секунду, тут меня угораздило придумать еще и срабатывание по достижению заданной температуры того фрагмента кода о котором я писал в #264. Но в нем использовать millis не уместно( события выполняютя несинхронно) . Поэтому то и хочу задейтвовать посекундный счет на ТС1 и вызвать прерывание по переполнению. 

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

bwn пишет:

эт скоко тактищев то натикает.

скоко?

bwn
Онлайн
Зарегистрирован: 25.08.2014

Клапа, оно ведь не у меня тормозит, не считал и не хочу. Эт у нас неофит решил по хайтеку мегаточные интервалы мегабыстро мерять. Дело хорошее, для самообразования самое то.

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

bwn пишет:

Клапа, оно ведь не у меня тормозит, не считал и не хочу. Эт у нас неофит решил по хайтеку мегаточные интервалы мегабыстро мерять. Дело хорошее, для самообразования самое то.

та, он тут #272 пытается оправдать своё странное поведение, но я ему, почему-то, не верю.

bwn
Онлайн
Зарегистрирован: 25.08.2014

BuonanotteMasha пишет:

 Но в нем использовать millis не уместно( события выполняютя несинхронно) . 

Во первых, что вы понимаете под словом "синхронно" при последовательном выполнении команд, ардуино "параллельно" не умеет. Насколько это "несинхронно", что вы умудряетесь его зафиксировать органами чувств данными от природы? От когда взять очумелые ручки, насытить бездумно код делаями, циклами, тонами, то потом  миллис виноват в "несинхронности", а хтож еще?
Хотите таймеры изучить, это одно дело, но пытаться ими закрыть косяки в проектировании программы, поверьте, не самое умное.

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

#define BUTTON_OK 10       // кнопка OK
#define BUTTON_LEFT 11     // кнопка LEFT
#define BUTTON_RIGHT 12    // кнопка RIGHT
#define BUTTON_UP 9        // кнопка UP 
#define BUTTON_DOWN 8      // кнопка DOWN
#define BUTTON_CANSEL 13    // кнопка CANSEL

а это зачем в коде

 

//Обработка нажатия кнопки Cansel
  if (!(PINB&0b00100000) && (Uptime - time_Pressed) > 200 ) {
    time_Pressed = Uptime;	// Запоминаем время нажатия кнопки;
    lcd.clear();
    
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);

 tone  временно выпильте ваш код ускорится=) и delay. как вариант создать отдельную функцию пищалки бузера, но без tone и вызывать ее когда вам надо

 
 
 

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Здравствуйте.

Ну во первых, bwn почитайте Многозадачность на ардуино (http://robotosha.ru/arduino/multi-tasking-arduino.html), там подробно описано с примерами что независимые события могут выполняться совместно. Xumuk спасибо поправлю. #define тут лишнее(забыл убрать), насет tone скажу так, пробовал заести отдельную функцию beep, и туда поместить этот фрагмент кода, убрать delay, но понял что это необязательно, прочтите ниже

Во вторых кашу всю заварил вот от чего, свой код я разрабатываю для контроллера инфракрасной паяльной станции. В нем должны работать 1) измерение температуры с 2 термопар с показам значений на дисплее каждую секунду, 2) опрос кнопок, 3) должно идти время в формате МИН:СЕК с начала пайки. 

Алгоритм такой, запустилься setup, на эране показалось "ARDUINO REWORK v0.3" на секунду( ну чуть больше), затем в loop мы переходим в MAIN_MENU и кнопками выбираем MANUAL, переходим в MENU_MANUAL, там начанается то о чем я уже писал ( вывод температуры каждую секунду и включение нагревателей)

Код до этого момента полностью рабочий и меня устраивает

#include <Wire.h> // библиотека для управления устройствами по I2C 
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602
#include "max6675.h"
#include <PID_v1.h>

#define RELAYPIN1 1  //назначаем пин "НИЖНЕГО" нагревателя
#define RELAYPIN2 0  //назначаем пин "ВЕРХНЕГО" нагревателя

#define buzzerPin 3 // назначаем пин для пьезодинамика

LiquidCrystal_I2C lcd(0x3f, 20, 4); // присваиваем имя lcd для дисплея 20х4

boolean  button_state = false;
boolean  button_long_state = false;
byte ButtonPress = 0;
unsigned int time_Pressed;  // Переменные для работы со временем;
boolean MenuEnter;
boolean status_of_heater = 0; // флаг отображения меню
boolean thrState = 0;      // флаг установки работы "ВЕРХНЕГО" нагревателя

uint8_t arrow_up[8]  = {0x04, 0x0e, 0x15, 0x04, 0x04, 0x04, 0x04};
uint8_t arrow_down[8]  = {0x04, 0x04, 0x04, 0x04, 0x15, 0x0e, 0x04};
uint8_t arrow_m[8]  = {0x08, 0x0C, 0x0E, 0x0F, 0x0E, 0x0C, 0x08};
uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0};

unsigned int prevTCNT1;
unsigned int timeBlink = 1000;//в мсек  (максимум 4194ms)
unsigned int totalTic;//15625 ==> 1000ms;  65535; ==> 4194ms максимум

unsigned int prevmicros = 0;//переменная для хранения значений таймера
byte sek = 0; //значение секунд
byte minu = 0; //значение минут
boolean counter = false; // счетчик для полусекунд

#define PERIOD_PWM 1000UL // > 750

short kp1 = 0;  short kp2 = 0;
short kd1 = 0;  short kd2 = 0;
short ki1 = 0;  short ki2 = 0;

boolean flag = 0;  //флаг для фиксации стартовой температуры

double startTemp;
double setTemp1 = 0.0;
double setTemp2 = 0.0;
double tc1 = 0.0;
double tc2 = 0.0;
double outputPower1 = 0.0; // по умолчанию диапазон выходных значений для ШИМ устанавливается от 0 до 100
double outputPower2 = 0.0; // по умолчанию диапазон выходных значений для ШИМ устанавливается от 0 до 100
unsigned int lastTime = 0;

boolean state_top = 0; 
boolean state_bottom = 0;
unsigned int prev_top, prev_bottom;

PID myPID1(&tc1, &outputPower1, &setTemp1, kp1, ki1, kd1, DIRECT);
PID myPID2(&tc2, &outputPower2, &setTemp2, kp2, ki2, kd2, DIRECT);

#define thermoDO 7
#define thermoCLK 5
#define thermoCS_b 6
#define thermoCS_t 4
MAX6675 thermocouple_b(thermoCLK, thermoCS_b, thermoDO); //термопара "НИЖНЕГО" нагревателя
MAX6675 thermocouple_t(thermoCLK, thermoCS_t, thermoDO); //термопара "ВЕРХНЕГО" нагревателя

typedef void (*LCD_menu)();

LCD_menu const menu[] =
{
  setString,
  timing
};

enum switchVariants {	// Определения для переключателя в главном цикле;
  MAIN_MENU,
  MENU_MANUAL,
  MENU_AUTO,
  MENU_SETUP,
  MENU_INFORM,
};
switchVariants switchPointer = MAIN_MENU;	// С чего начнем цикл;

void setup() {
  lcd.begin();     // инициализация LCD дисплея
  lcd.backlight(); // включение подсветки дисплея

  lcd.setCursor(1, 1);
  lcd.print("ARDUINO REWORK v0.3");
  
  lcd.createChar(1, arrow_up);
  lcd.createChar(2, arrow_down);
  lcd.createChar(3, arrow_m);
  lcd.createChar(4, clock);

  //Мелодия приветствия
  tone(buzzerPin, 523);
  delay(200);
  tone(buzzerPin, 659);
  delay(200);
  tone(buzzerPin, 784);
  delay(200);
  tone(buzzerPin, 1046);
  delay(200); 
  noTone(buzzerPin);
  
  delay(1000); // wait for MAX chip to stabilize
  lcd.clear();
  
  DDRB = 0x00;
  PORTB = 0b00111111;
  
  DDRC |= 1 << RELAYPIN1;
  DDRC |= 1 << RELAYPIN2;
  // 
  TCCR1A = 0;
  TCCR1B |= (1<<CS10)|(1<<CS12); //предделитель 1024; 1 тик = 64 мкс 
  totalTic = 1000UL * timeBlink / 64;//сколько тиков в 1000 мсек
  TCNT1 = 0; 
  //
  myPID1.SetSampleTime(1000); //  Время расчета выходного сигнала
  myPID1.SetOutputLimits(0, 100);
  myPID1.SetMode(AUTOMATIC);  //  ПИД-регулятор включен

  myPID2.SetSampleTime(1000); //  Время расчета выходного сигнала
  myPID2.SetOutputLimits(0, 100);
  myPID2.SetMode(AUTOMATIC);  //  ПИД-регулятор включен
  
  prev_top = millis();
  prev_bottom = millis();

}

void loop() {

  
  unsigned long Uptime = millis();
  unsigned long nextRead = millis();

  // тут добавить обработку кнопок настройки темп В и Н
  checkForSerial(); //???
    
  //Обработка нажатия кнопки Up
  if ( !(PINB&0b00000010) && (Uptime - time_Pressed) > 200) {
    time_Pressed = Uptime;
    // счетчик нажатий кнопки ButtonPress
    // с каждым нажатием ButtonPress++ пока ButtonPress<4
    ButtonPress++;
    if (ButtonPress > 3) ButtonPress = 0;
  }


   // Фиксируем нажатие кнопки Ok   
   if( !(PINB&0b00000100) && !button_state && ( Uptime - time_Pressed) > 100 ){
      button_state      = true;
      button_long_state = false;  
      time_Pressed        = Uptime;
   }
   
   // Фиксируем длинное нажатие кнопки Ok  
   if( !(PINB&0b00000100) && !button_long_state && ( Uptime - time_Pressed) > 2000 ){
      status_of_heater = true;   
   }
   
   // Фиксируем отпускание кнопки Ok  
   if( PINB&0b00000100 && button_state && ( Uptime - time_Pressed) > 50  ){
      button_state      = false;   
      time_Pressed        = Uptime;
      
      lcd.clear();
      //MenuEnter = true;
      ButtonClick(ButtonPress); // Вызывается функция обработки нажатия на кнопку

   }
   
  //Обработка нажатия кнопки Cansel
  if (!(PINB&0b00100000) && (Uptime - time_Pressed) > 200 ) {
    time_Pressed = Uptime;	// Запоминаем время нажатия кнопки;
    lcd.clear();
    
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    tone(buzzerPin, 1046);
    delay(100);
    noTone(buzzerPin);
    delay(100);
    
  }

  switch (switchPointer)  // Все делаем в одном операторе и одной функции;
  {
    case MAIN_MENU:  /***************** Главное меню ***************/

      menu[0](); // включаем отображение стрелки выбора меню

      lcd.setCursor(1, 0); // 1 строка
      lcd.print("MANUAL"); // настройка
      lcd.setCursor(1, 1); // 2 строка
      lcd.print("AUTOMATIC"); // настройка
      lcd.setCursor(1, 2); // 3 строка
      lcd.print("SETUP"); // ручной режим
      lcd.setCursor(1, 3); // 4 строка
      lcd.print("INFORM"); // автоматический режим


      break;


    case MENU_MANUAL: /***************** Ручной режим ***************/
          
          lcd.setCursor(0, 0);	// Печатаем на ЖК;
          lcd.write(2);
          
          lcd.setCursor(1, 1);	// Печатаем на ЖК;
          lcd.print("TH:");
          lcd.print(tc1,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(11, 1);	// Печатаем на ЖК;
          lcd.print("TY:");
          lcd.print(setTemp1,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(13, 0);	// Печатаем на ЖК;
          lcd.print(outputPower1,0);
          lcd.print("\x99""%");
          
          lcd.setCursor(1, 3);	// Печатаем на ЖК;
          lcd.print("TB:");
          lcd.print(tc2,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(11, 3);	// Печатаем на ЖК;
          lcd.print("TY:");
          lcd.print(setTemp2,0);
          lcd.print("\x99""C");
  
          lcd.setCursor(13, 2);	// Печатаем на ЖК;
          lcd.print(outputPower2,0);
          lcd.print("\x99""%");
          
          if (nextRead > lastTime + PERIOD_PWM) {
              lastTime = nextRead;
              tc1 = thermocouple_b.readCelsius();
              tc2 = thermocouple_t.readCelsius();
              myPID1.Compute(); // Расчет выходного сигнала
              myPID2.Compute(); // Расчет выходного сигнала
              
              //фиксируем стартовую температуру      
              if (flag == 0)
              {
                  startTemp = tc1;
                  flag = 1;
              }
               
                   
             if (!status_of_heater) {
                                   
                   lcd.setCursor(8, 0);	// Печатаем на ЖК;
                   lcd.print("EDIT");   // Режим редактирования температуры                                                                        
             }
             else {
                  
                  menu[1]();
                  
                  lcd.setCursor(8, 0);	// Печатаем на ЖК;
                  lcd.print("HEAT");   // Режим редактирования температуры

                  // запуск работы "ВЕРХА" сразу после догрева "НИЗОМ"
                  if (tc1 >= setTemp1) {
                       outputPower1 = 0; // !!! то что ПИД не даст перегреть
                       thrState = 1; //   флаг начала работы "ВЕРХНЕГО" нагревателя
                  }
                 
                  // алгоритм ШИМ с частотой 5 Гц  
                  if ((state_bottom == 0) && ((millis()-prev_bottom) >= 200 * (100 - outputPower1) / 100)) {
                      state_bottom = 1;
                      PORTC |= 1 << RELAYPIN1;
                      prev_bottom = millis();  
                  }
                  if ((state_bottom == 1) && ((millis()-prev_bottom) >= 200 * outputPower1 / 100)) {
                      state_bottom = 0;
                      PORTC &= ~(1 << RELAYPIN1);
                      prev_bottom = millis();
                  }
                  //digitalWrite(RELAYPIN1, state_bottom);
                  
                  // алгоритм ШИМ с частотой 5 Гц 
                  if (thrState && (state_top == 0) && ((millis() - prev_top) >= 200 * (100 - outputPower2) / 100)) {
                      state_top = 1;
                      PORTC |= 1 << RELAYPIN2;
                      prev_top = millis();
                  }
                  if (thrState && (state_top == 1) && ((millis() - prev_top) >= 200 * outputPower2 / 100)) {
                      state_top = 0;
                      PORTC &= ~(1 << RELAYPIN2);
                      prev_top = millis();
                  }
                  //digitalWrite(RELAYPIN2, state_top);  
                  
                  //if (tc1 > startTemp) {
                  if (tc2 >= setTemp2) {
                       tone(buzzerPin, 800, 2000); 
                       
                      /* static byte state = 0;                 
                       do { // начало цикла do while
                           if(TCNT1 - prevTCNT1 >= totalTic){
                              prevTCNT1 = TCNT1;
                              state++;
                              lcd.setCursor(8, 0);	// Печатаем на ЖК;
                              lcd.print("    ");   // Режим редактирования температуры
                              lcd.write(4);
                            }
                       }
                       while( state < 10); // конец цикла do while      */                 
                  }                  
             }
          }                  
    break;

    case MENU_AUTO: /***************** Автоматический режим ***************/
      
    break;

    case MENU_SETUP: /***************** Настройки ***************/

    break;

    case MENU_INFORM: /*********** Информация о станции *********/

    break;
   
  }


}

void setString()
{
  switch (ButtonPress) {
    case 1:
      lcd.setCursor(0, 0);
      lcd.write(32);
      lcd.setCursor(0, 1);
      lcd.write(62);
      break;

    case 2:
      lcd.setCursor(0, 1);
      lcd.write(32);
      lcd.setCursor(0, 2);
      lcd.write(62);
      break;

    case 3:
      lcd.setCursor(0, 2);
      lcd.write(32);
      lcd.setCursor(0, 3);
      lcd.write(62);
      break;

    default:
      lcd.setCursor(0, 3);
      lcd.write(32);
      lcd.setCursor(0, 0);
      lcd.write(62);
      break;
  }
}

void ButtonClick(byte ButtonId) {

  if (ButtonId == 0)  switchPointer = MENU_MANUAL;   // Клик [Menu] Выход из меню
  else if (ButtonId == 1) switchPointer = MENU_AUTO;  //MenuCurent--;		// Клик [Prev] Позицию ниже
  else if (ButtonId == 2) switchPointer = MENU_SETUP; //MenuCurent++;		// Клик [Next] Позиция выше
  else if (ButtonId == 3) switchPointer = MENU_INFORM;//MenuItems[MenuCurent].on_click(1);	// Клик [+] Увеличиваем значение выбранного параметра

}



void timing()
{
  if (micros() - prevmicros > 500000)
   {
     prevmicros = micros();  //принимает значение каждые полсекунды
     counter=!counter;
     if (counter==false)
     {
       sek++;
       lcd.setCursor(4,0);
       lcd.print(":");         //выводим символ ":"между  минутами и секундами
     }
     if(sek>59)//если переменная секунда больше 59 ...
     {
       sek=0;//сбрасываем ее на 0
       minu++;//пишем +1 в переменную минута
     }
     if(minu>59)//если переменная минута больше 59 ...
     {
       minu=0;//сбрасываем ее на 0
     }

     lcd.setCursor(2,0);//выводим значение минут
     if (minu>=0 && minu<10) {
       lcd.print("0");
       lcd.print(minu);}//количество минут
       else lcd.print(minu);

     lcd.setCursor(5,0);//выводим значение секунд
     if (sek>=0 && sek<10) {
       lcd.print("0");
       lcd.print(sek);}//количество секунд
       else lcd.print(sek);
 }
}

void checkForSerial() {
  setTemp1 = 30.0;
  setTemp2 = 33.0;
  myPID1.SetTunings(kp1, ki1, kd1); // Настройка ПИД-регулятора во время работы
  myPID2.SetTunings(kp2, ki2, kd2); // Настройка ПИД-регулятора во время работы
  
  /* Тут настраиваются коэффициенты ПИД*/
  kp1 = 50;
  ki1 = 0;
  kd1 = 0;
  
  kp2 = 50;
  ki2 = 0;
  kd2 = 0;
}


 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Насчет этого фрагмента //Обработка нажатия кнопки Cansel, оно несет такой смысл, по нажатию на эту кнопку планирую сделать короткий звуковой сигнал и переход в главное меню. Но послушайте программа не тормозит, она неправильно работает(вслушайтесь в то что опишу ниже) 

if (tc2 >= setTemp2) {
312                        tone(buzzerPin, 800, 2000);
313                        
314                       /* static byte state = 0;                
315                        do { // начало цикла do while
316                            if(TCNT1 - prevTCNT1 >= totalTic){
317                               prevTCNT1 = TCNT1;
318                               state++;
319                               lcd.setCursor(8, 0);  // Печатаем на ЖК;
320                               lcd.print("    ");   // Режим редактирования температуры
321                               lcd.write(4);
322                             }
323                        }
324                        while( state < 10); // конец цикла do while      */                
325                   }                 

Здесь я видимо непрвильно настроил таймер 1 и этот франгмент не дает исполняться остальной чати прогаммы конкретно ветке else

else {
272                   
273                   menu[1]();
274                   
275                   lcd.setCursor(8, 0);  // Печатаем на ЖК;
276                   lcd.print("HEAT");   // Режим редактирования температуры
277  
278                   // запуск работы "ВЕРХА" сразу после догрева "НИЗОМ"
279                   if (tc1 >= setTemp1) {
280                        outputPower1 = 0; // !!! то что ПИД не даст перегреть
281                        thrState = 1; //   флаг начала работы "ВЕРХНЕГО" нагревателя
282                   }
283                  
284                   // алгоритм ШИМ с частотой 5 Гц 
285                   if ((state_bottom == 0) && ((millis()-prev_bottom) >= 200 * (100 - outputPower1) / 100)) {
286                       state_bottom = 1;
287                       PORTC |= 1 << RELAYPIN1;
288                       prev_bottom = millis(); 
289                   }
290                   if ((state_bottom == 1) && ((millis()-prev_bottom) >= 200 * outputPower1 / 100)) {
291                       state_bottom = 0;
292                       PORTC &= ~(1 << RELAYPIN1);
293                       prev_bottom = millis();
294                   }
295                   //digitalWrite(RELAYPIN1, state_bottom);
296                   
297                   // алгоритм ШИМ с частотой 5 Гц
298                   if (thrState && (state_top == 0) && ((millis() - prev_top) >= 200 * (100 - outputPower2) / 100)) {
299                       state_top = 1;
300                       PORTC |= 1 << RELAYPIN2;
301                       prev_top = millis();
302                   }
303                   if (thrState && (state_top == 1) && ((millis() - prev_top) >= 200 * outputPower2 / 100)) {
304                       state_top = 0;
305                       PORTC &= ~(1 << RELAYPIN2);
306                       prev_top = millis();
307                   }
308                   //digitalWrite(RELAYPIN2, state_top); 
309                   
310                   //if (tc1 > startTemp) {
311                   if (tc2 >= setTemp2) {
312                        tone(buzzerPin, 800, 2000);
313                        
314                       /* static byte state = 0;                
315                        do { // начало цикла do while
316                            if(TCNT1 - prevTCNT1 >= totalTic){
317                               prevTCNT1 = TCNT1;
318                               state++;
319                               lcd.setCursor(8, 0);  // Печатаем на ЖК;
320                               lcd.print("    ");   // Режим редактирования температуры
321                               lcd.write(4);
322                             }
323                        }
324                        while( state < 10); // конец цикла do while      */                
325                   }                 
326              }
327           }                 

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Если исполняется условие в строке 311 программа находится в простое. Повторюсь до этого момента меня все устраивало. Спасибо за понимание. 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

BuonanotteMasha пишет:

bwn почитайте Многозадачность на ардуино (http://robotosha.ru/arduino/multi-tasking-arduino.html), там подробно описано с примерами что независимые события могут выполняться совместно. 

Не читал, но, либо Вы неправильно поняли автора той статьи (что скорее всего), либо это утверждение Вам лучше обсуждать не с bwn, а с автором и, возможно, его психиатром :))))

bwn
Онлайн
Зарегистрирован: 25.08.2014

BuonanotteMasha пишет:

Здравствуйте.

Ну во первых, bwn почитайте Многозадачность на ардуино (http://robotosha.ru/arduino/multi-tasking-arduino.html), там подробно описано с примерами что независимые события могут выполняться совместно. 

Пасибо, освежил. Только не обнаружил, что там противоречит сказанному мною. Если бы вы ответили на заданные мною вопросы, то поняли бы, что речь идет о "псевдопараллельности", код и действия все равно выполняются последовательно, только разрешение наших органов чувств не позволяет зафиксировать эти задержки (лампа накаливания светит равномерно, а на самом деле мигает, телевизор показывает картинку, а на самом деле рисует и т.д.), причем в приведенных мною примерах интервалы миллисов исчисляются десятками, нормальный луп выполняется за десятки-сотни микросов. Вы же умудрились на пяти кнопках и одном экране создать задержки которые начали доставлять неудобства, назначили виновным за них миллис и обратились к таймерам. "Эдак нам никаких Саратовых не хватит"("Брежнев"(с)). ИМХО.

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

а разве не всеравно сколько раз использовать милс в коде? вы же просто сравниваете свою переменную с милс, а сколько ваших переменных будет с ней сравнено без разницы, если ошибаюсь поправьте меня.

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

Использование функции Tone() помешает использовать ШИМ на портах вход/выхода 3 и 11

кстати она не как pulseIn() тормозит код?

arduinec
Offline
Зарегистрирован: 01.09.2015

Xumuk пишет:

Использование функции Tone() ... она не как pulseIn() тормозит код?

Рядом с tone() У него делеи стоят. Программа почти секунду стоит и только бибикает.

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

ну про делай это я понял=))) интересно про tone=)

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

BuonanotteMasha пишет:

Ну во первых, bwn почитайте Многозадачность на ардуино (http://robotosha.ru/arduino/multi-tasking-arduino.html), там подробно описано с примерами что независимые события могут выполняться совместно.

пока bwn изучает еретические манускрипты, хочу у тебя спросить на простом примере: как одновременно писать в пины? - что бы не по очереди записалось, а одновременно, т.е. "совместно"?

// так?
void loop() {
digitalWrite( 4, 1);
digitalWrite( 5, 1);
}

// или так?
void loop() {
digitalWrite( 5, 1);
digitalWrite( 4, 1);
}

// а, может так?
void loop() {
digitalWrite( 4, 1); digitalWrite( 5, 1);
}

// или, может так?
void loop() {
digitalWrite( 5, 1); digitalWrite( 4, 1);
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Клапауций 298 пишет:
как одновременно писать в пины? - что бы не по очереди записалось, а одновременно, т.е. "совместно"?

digitalWrite (5 and 4, 1); 

Не?

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

ЕвгенийП пишет:

Клапауций 298 пишет:
как одновременно писать в пины? - что бы не по очереди записалось, а одновременно, т.е. "совместно"?

digitalWrite (5 and 4, 1); 

Не?

да. или

digitalWrite (4 and 5, 1);

О_О

я же хочу пример многозадачности, как в манускрипте...

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Думаю пора расставить "все точки над i"

Уже заметил, что стал объектом насмешек.

bwn пишет:

Пасибо, освежил. Только не обнаружил, что там противоречит сказанному мною. Если бы вы ответили на заданные мною вопросы, то поняли бы, что речь идет о "псевдопараллельности", код и действия все равно выполняются последовательно, только разрешение наших органов чувств не позволяет зафиксировать эти задержки (лампа накаливания светит равномерно, а на самом деле мигает, телевизор показывает картинку, а на самом деле рисует и т.д.), причем в приведенных мною примерах интервалы миллисов исчисляются десятками, нормальный луп выполняется за десятки-сотни микросов. Вы же умудрились на пяти кнопках и одном экране создать задержки которые начали доставлять неудобства, назначили виновным за них миллис и обратились к таймерам. "Эдак нам никаких Саратовых не хватит"("Брежнев"(с)). ИМХО.

bwn, признаю был не прав.  Прекрасно понимаю, что процессор выполняет каждую операцию за определенное количество тактов, затем переходит к следующей. То есть чисто теоретически действия действительно выполняются последовательно, но человеку как существу медленному такты процессора не заметны. 

Вы правы и по поводу моей неграмотности в работе функций времени. Я постараюсь вникнуть.

/************************************/

От остальных уже подзатыльников получил.

Поймите меня правильно ведь вы тоже раньше были новичками и тоже совершали пускай и не такие, но ошибки. Но вы учились на ошибках. Я задавая здесь вопрос хочу не готовое решение, а совет более опытного коллеги. Это мой дипломный проект, и стараюсь понять смысл каждой строчки кода, при этом частенько беру готовые фрагменты, разбираюсь в их работе и переделываю под свои нужды. Теперь же понимаю что с миллис сильно упустил

bwn
Онлайн
Зарегистрирован: 25.08.2014

Клапауций 298 пишет:

да. или

digitalWrite (4 and 5, 1);

О_О

я же хочу пример многозадачности, как в манускрипте...

Узрей чудо - вот она истинная многозадачность (правда из другого манускрипта).

PORTD |=B00110000, правда количество задач ограничено восемью.))))

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

bwn пишет:

Узрей чудо - вот она истинная многозадачность (правда из другого манускрипта).

PORTD |=B00110000, правда количество задач ограничено восемью.))))

мне достаточно двух одновременно исполняемых функций - аппаратные хаки не пердлогать. О_О

void loop() {
f0();
f1();
}

 

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

BuonanotteMasha пишет:

Это мой дипломный проект...

звучит как оправдание - не виноватая я, меня пидагоги заставили.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

arduinec пишет:

Xumuk пишет:

Использование функции Tone() ... она не как pulseIn() тормозит код?

Рядом с tone() У него делеи стоят. Программа почти секунду стоит и только бибикает.

Существуют еще 2 варианта 1)cгенерировать необходимые частоты на 2 таймере; 2) через функцию analogWrite 

Постараюсь воспользоваться обеими и также избавиться от delay

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Клапауций 298 пишет:

BuonanotteMasha пишет:

Это мой дипломный проект...

звучит как оправдание - не виноватая я, меня пидагоги заставили.

Клапауций 298, можете так считать, но для меня будет нужнее исправить допущенные ошибки и изучить основные возможности моей atmega328 -uno

Клапауций 298
Клапауций 298 аватар
Offline
Зарегистрирован: 25.01.2018

BuonanotteMasha пишет:

но для меня будет нужнее исправить допущенные ошибки

ок. для меня нужнее выпить пива. О_О

bwn
Онлайн
Зарегистрирован: 25.08.2014

Клапауций 298 пишет:

BuonanotteMasha пишет:

Это мой дипломный проект...

звучит как оправдание - не виноватая я, меня пидагоги заставили.

Ладно, Клапа, хотя бы адекватный(ая), не знаю как правильно и умнеть начал. 

BuonanotteMasha - возьмите свой код, еще раз внимательно просмотрите. В критичных местах, сперва выполняем действия, а потом бибикаем-пиликаем. Если хотите подтверждать каждое нажатие, то ограничтесь интервалом 100мС или переписывайте без делеев.  Почитайте про миллис и вторую тему "...с комфортом", мне нравится. И давайте у Евгения завязывать, ну не нужны вам таймеры. Откройте тему в "Общих" и там уже дальше.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

 Мигаем без delay() с комфортом. Спасибо, нашел. Дальше продолжать обсуждения не буду

arduinec
Offline
Зарегистрирован: 01.09.2015

BuonanotteMasha пишет:

arduinec пишет:

Xumuk пишет:

Использование функции Tone() ... она не как pulseIn() тормозит код?

Рядом с tone() У него делеи стоят. Программа почти секунду стоит и только бибикает.

Существуют еще 2 варианта 1)cгенерировать необходимые частоты на 2 таймере; 2) через функцию analogWrite 

Постараюсь воспользоваться обеими и также избавиться от delay

Есть биперы с генератором, они звучат при подаче на них высокого уровня (tone не нужен). Частота у них правда одна, но бипать можно и несколько раз.

Green
Offline
Зарегистрирован: 01.10.2015

Можно и без генератора. При системном тике = полупериоду бипера, хоть 100-ю биперов можно запустить. Без тормозов.))