Как связана работа таймера с функцией цикла

CybSys
Offline
Зарегистрирован: 05.08.2019

Доброго времени суток. Что то уперся в одну вещь, но все попорядку.

собираю генератор на таймере Т1, с регулировкой скважности, этим занимается энкодер, токже его значение выводится на двух символьный семисегментный индикатор от нуля до 99.

Как бы все работает, но как оказалось что не все.

энкодер работает по прерыванию и на индикаторе все хорошо показывается, но при этом таймер 1 отказывается работать, как только выключаю функцию вывода на индикатор (void CellLed(int digit)), то таймер работает.

в функции вывода два цикла, они не бесконечные, что не так не пойму.

volatile int enc = 400;

bool Array [10] [8]=
{
  {1, 1, 0, 1, 1, 1, 1 },   //0
  {1, 0, 0, 1, 0, 0, 0 },   //1
  {1, 0, 1, 0, 1, 1, 1 },   //2
  {1, 0, 1, 1, 1, 0, 1 },   //3
  {1, 1, 1, 1, 0, 0, 0 },   //4
  {0, 1, 1, 1, 1, 0, 1 },   //5
  {0, 1, 1, 1, 1, 1, 1 },   //6
  {1, 0, 0, 1, 0, 0, 1 },   //7
  {1, 1, 1, 1, 1, 1, 1 },   //8
  {1, 1, 1, 1, 1, 0, 1 }    //9
  };

 byte DigSect1= 0;
 byte DigSect2= 0;
 
void setup()
{ 
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(13, OUTPUT);
pinMode(A5, INPUT);
digitalWrite(2,LOW); 
digitalWrite(3,LOW);
digitalWrite(4,LOW); 
digitalWrite(5,LOW);
digitalWrite(6,LOW); 
digitalWrite(7,LOW);
digitalWrite(8,LOW); 
digitalWrite(12,HIGH);
digitalWrite(11,HIGH);
digitalWrite(13,LOW); 
//digitalWrite(A5,HIGH);

Serial.begin(9600);
pinMode(A0,INPUT_PULLUP);
pinMode(A1,INPUT_PULLUP);
PCIFR=PCIFR; PCICR=1<<PCIE1; //разрешить прерывание
PCMSK1=1<<PCINT8 | 1<<PCINT9; //выбрать вход на котором сработает прерывание

pinMode(9, OUTPUT);      // установка порта на выход
TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(0<<COM1B1)|(1<<WGM11);
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10); //mode14 FastPwm*/
ICR1=800; //изменяет частоту // установленно 20кГц
OCR1A=400; //изменяет скважность
delay(2000);
//pinMode(A3, OUTPUT);
//digitalWrite(A3,HIGH);
}

void CellLed(int digit){
 if(digit<=9){DigSect1 = 0; DigSect2= digit;} 
 else
  {
    DigSect1= (digit/10) % 10;
    DigSect2= digit % 10;
    }
digitalWrite(11,LOW);
digitalWrite(12,HIGH);
for(byte i=0; i<8; i++){  
if (Array[DigSect1][i] == 0) digitalWrite(i+2, LOW); else digitalWrite(i+2,HIGH);   
}
delay(5);
digitalWrite(11,HIGH);
digitalWrite(12,LOW);
for(byte i=0; i<7; i++){
if (Array[DigSect2][i] == 0) digitalWrite(i+2, LOW); else digitalWrite(i+2,HIGH);   
}
delay(5);  
  }
 
ISR(PCINT1_vect){
static char EncPrev=0;      //предыдущее состояние энкодера
static char EncPrevPrev=0;  //пред-предыдущее состояние энкодера
  char EncCur = 0;
  if(!(PINC & (1 << PC0))){EncCur  = 1;} //опрос фазы 1 энкодера
  if(!(PINC & (1 << PC1))){ EncCur |= 2;} //опрос фазы 2 энкодера
  if(EncCur != EncPrev)             //если состояние изменилось,
  {
    if(EncPrev == 3 &&        //если предыдущее состояние 3
       EncCur != EncPrevPrev )      //и текущее и пред-предыдущее не равны,
    {
      if(EncCur == 2)          //если текущее состояние 2,
        enc--;            //шаг вверх
      else                          //иначе
        enc++;            //шаг вниз
    }
    EncPrevPrev = EncPrev;          //сохранение пред-предыдущего состояния
    EncPrev = EncCur;               //сохранение предыдущего состояния
    }
  }

void loop()
{ 
  if (digitalRead(A5)==1) {enc=0; digitalWrite(A3,HIGH);} 
  if (enc<0){ enc=0;digitalWrite(A3,HIGH);}
  if (enc>0){digitalWrite(A3,LOW);}
  if (enc>99) enc=99;
  //OCR1A = 800-(enc*4);
  OCR1A = (enc*4);
  CellLed(enc);
}

 

CybSys
Offline
Зарегистрирован: 05.08.2019

Похоже нашел.

Ошибка в условии цикла for, по условию цикла он делает 8 шагов, а надо делать 6 в противном случае 9 и 10 выводы перекрываются рабочим телом цикла.

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

CybSys пишет:
9 и 10 выводы
Только 9, но это по идее не должно влиять, хотя ...

У Вас в коде очень много ошибок и вылезти может всё, что угодно. Например, в строке №111 Вы выводите на экран коэффициент заполнения. Он у Вас от 0 до 99. При этом Вы в OCR1A пихаете его же, умноженный на 4 (строка №110). И что Вы при этом надеетесь получить? Реально Вы получаете, что при enc==0 у Вас коэффициент заполнения почти 100%, а при enc==99 - примерно 50%. Проверьте осциллографом. 

Это то, что Вы хотели получить?

Если нет, то ... знаете, я постоянно говорю новичкам - ЕШЬТЕ СЛОНА ПО ЧАСТЯМ - не валите всё в кучу! Вот у Вас тут и PCINT, и таймер, и вывод на экран - всё в одной куче и, если что-то не работает, то хрен его разберёт что и почему - чёрт ногу сломает.

Давайте, я покажу Вам как это делается.

Я просто взял Вашу программу и за полминуты (не более) выбросил из неё ВСЁ, что не касается непосредственно регулировки коэффициента заполнения - ВСЁ ВЫБРОСИЛ. А вместо энкодера вставил потенциометр с пересчётом его значений из 0-1023 в 0-99 как у Вас (чтобы убрать PCINT и всю байду, заменив на единственную строку чтения потенциометра). В итоге получил КОРОТЕНЬКУЮ программу в которой нет ничего, кроме регулировки коэффициента заполнения. Вот она

void setup() {
	Serial.begin(57600);
	pinMode(9, OUTPUT);      // установка порта на выход
	TCCR1A = (1 << COM1A1) | (1 << COM1A0) | (0 << COM1B1) | (1 << WGM11);
	TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); //mode14 FastPwm*/
	ICR1 = 800; //изменяет частоту // установленно 20кГц
	OCR1A = 400; //изменяет скважность
}

void loop() {
	const int enc = map(analogRead(A5), 0, 1023, 0, 99);
	Serial.println(enc);
	OCR1A = (enc * 4);
	delay(1000);
}

Это Ваша программа, только в ней удалено всё, кроме одной операции.

Теперь Вы можете спокойно отладить эту программу - Вам ничто не мешает, никакие циклы ни на что не влияют, всё на одном экране. Потом Вы её вставите в большую, когда уже будете в ней полностью уверены.

Точно также следует поступить и с работой с энкодером - выбросить ВСЁ, кроме неё, отладить, и только потом использовать.

Вы думаете профессионалы сразу пишут огромные портянки и они у них работают? Нет - профессионалы не настолько круты - они по частям отлаживают. Только начинающие настолько круты, чтобы писать и отлаживать всё и сразу  :-)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Неистово плюсую предыдущего аратора. 

CybSys
Offline
Зарегистрирован: 05.08.2019

Спасибо за ответы.

Мне больше 50% заполнения не надо. И то в последствии может придется уменьшать (ограничивать). 

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

Изначально так и было как привили вы в своем примере,  просто генератор с изменением скважности переменным резистором. 

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

Ну, если Вы именно так и хотите (при реальном 100 показывать 0, а при реальном 50 показывать 99), значит всё нормально, я просто хотел обратить Ваше внимание на это.

CybSys
Offline
Зарегистрирован: 05.08.2019

Я вас понял :)

Таким образом я ограничиваю мощность своего устройства (чтобы избежать взрывов транзисторов и прочей периферии), а пользователь будет видеть то что она задал от 0 до 99 % мощности.

Мой пост в большей степени говорит о невнимательности. С этим наверное столкнулся не только я.

nik182
Offline
Зарегистрирован: 04.05.2015

Строки 52-55 и 56 не противоречат друг другу? Таймер 1 используется для работы с delay и millis и изменение его регистров прямо влияет на счёт времени.  

CybSys
Offline
Зарегистрирован: 05.08.2019

Вроде как Т0 работает с функциями delay и millis. Или нет?

nik182
Offline
Зарегистрирован: 04.05.2015

Точно! Извини, что то с просыпу первый таймер первым в списке пригрезился. Забыл что ещё ноль в ряду есть.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

del