Популярные микроконтроллеры Nuvoton серий М2354 и М251 со склада компании Смарт-ЭК

Таймер с энкодером на ATmega8

Новичок
 
Регистрация: 01.05.2020
Сообщений: 7
Репутация: 10
0 2
0 0
 
24.05.2020 14:53 #1
Доброго времени суток, Уважаемые! Такой вопрос. Собрал таймер на ATmega8 на кнопках все норм. все работает.


Тут на видео кнопочный вариант, для наглядности



Теперь пытаюсь Подружить его с энкодером. Т.е. вместо кнопок поставить энкодер. И недопонимаю что делаю не так. Таймер включается, отображает все нули, и вообще никак не реагирует на повороты энкодера. Может кто подскажет в чем я опять "протупил" ?

ИСХОДНИК (Atmel studio)

Код:
/*Используется семисегментный индикатор с общим АНОДОМ. т.е. на смену разрядов подается "+", а на сементы индикатора "-"
Эмиттеры транзисторов прицепить к "+" кллекторы к семисегментнику (к разрядам), базу через резистор к МК*/

#define F_CPU 1000000UL //Задаем частоту работы МК
#include<util/delay.h> //Библиотека задержек
#include <avr/interrupt.h> //Библиотека прерываний
#include <avr/io.h>

int NewState, OldState, upState, downState;

int start_sec = 0;

unsigned int R1=0, R2=0, R3=0, R4=0; //Переменные для разрядов семисегментника

unsigned int R_count =1; //Для постоянного переключения разрядов на семисегментнике

unsigned int cifri[10]={0b11000000, 0b11111001, 0b10100100, 0b10110000,
    0b10011001, 0b10010010, 0b10000010, 0b11111000, 0b10000000, 0b10010000}; //Цыфры 0-9
   
void start_otscheta (void) //Тут будут размещены все настроки 1-го таймер/счетчика
{
   TCCR1B &= ~(1<<CS12); //Устанавливаем бит в 0 (для настройки делителя частоты на 64)
   TCCR1B |= (1<<CS11)|(1<<CS10); //Устанавливаем биты в 1 (для настройки делителя частоты на 64)
   
   /*1000000/64 = 15625 т.е. на этой частоте будет работать МК. Далее для того чтобы получить ровно 12 сек. необходимо
   "убить" эти 15625 тактов. Это можно сделать настроив данный таймер/счетчик на прерывание при совпадении данного числа*/
   
   TIMSK |= (1<<OCIE1A); //Настраивает прерывания при совпадении.
   
   /*Далее в регистре сравнения необходимо записать в двоичной форме число 15625. Данный регист 16-ти битный,
    поэтому он сдвоенный*/
   
   OCR1AH = 0b00111101; //старший разряд
   OCR1AL = 0b00001001; //Младший разряд
   
   /*Когда произойдет совпадение, должно вызваться не только прерывание, но и сброс счетного регистра*/
   
   TCNT1 = 0; //Обнуление счетного регистра
   
   TCCR1B |= (1<<WGM12); //Активация сброса при совпадении.
   
   
}
   
void Chislo_celikom(unsigned int vsego_sekund) //Создаем функцию, будет разделять общее кол-во секунд на мин. и сек.
{
   R1 = vsego_sekund/60/10; //Десятки минут
   R2 = vsego_sekund/60%10; //Минуты (единицы)
   R3 = vsego_sekund%60/10; //десятки секунд
   R4 = vsego_sekund%60%10; //секунды (единицы)
}

ISR (TIMER0_OVF_vect)
{
   if (R_count == 1){PORTB = ~0b00000001;PORTD = cifri[R1];}
   
   if (R_count == 2){PORTB = ~0b00000010;PORTD = cifri[R2];}
   
   if (R_count == 3){PORTB = ~0b0000100; PORTD = cifri[R3];}
   
   if (R_count == 4){PORTB = ~0b00001000; PORTD = cifri[R4];}
   
   R_count++;
   if (R_count>4){R_count=1;}
      
      
 
NewState=PINC & 0b00000111;   //Для энкодера
if(NewState!=OldState)
{
switch(OldState)
   {
   case 2:
      {
      if(NewState == 3) upState++;
      if(NewState == 0) downState++;
      break;
      }
 
   case 0:
      {
      if(NewState == 2) upState++;
      if(NewState == 1) downState++;
      break;
      }
   case 1:
      {
      if(NewState == 0) upState++;
      if(NewState == 3) downState++;
      break;
      }
   case 3:
      {
      if(NewState == 1) upState++;
      if(NewState == 2) downState++;
      break;
      }
   }           
OldState=NewState;
}
         
         
         
         

   
}

ISR (TIMER1_COMPA_vect) //Прерывания для первого таймера по сравнению. Чтобы отслеживать 1сек.
{
   start_sec--;
   
   if (start_sec < 0)
      start_sec = 0;
   
   
      /*Теперь когда изначальное значение снизилось до 0, включать пищалку*/
      
      if (start_sec == 0)
      {
         PORTC |= (1<<3);
      }
      
      else
      {
         PORTC &= ~(1<<3);
      }
   
}

int main(void)
{
   
   //TCCR0 |= (1<<1);
   //TCCR0 &= ~((1<<0)|(1<<2)); //Активация нулевого таймера (делим на 8)
   
   TCCR0 |= (1<<CS01);
   
   TCNT0 = 0; //Обнуляем (на всякий случай) нулевой таймер
   
   sei(); //Разрешаем выполнение прерываний
   
   TIMSK |= (1<<0); //Устанавливаем 1 в нулевой бит, т.е. Прерывания для нулевого таймера (TOIE0)
   
    DDRB = 0b00001111; //Выводы на выход
   DDRD = 0b01111111; //Выводы на выход
   
   DDRC |= (1<<3); //тут будет выход на пищалку.
   PORTC &=~(1<<3); //по умолчанию сигнал на пищалку не подается этот порт в 0-ле
   
   DDRC = 0b00000000; //Выводы на вход (тут кнопки)
   PORTC = 0b00000111; //Подтягивающие резисторы к кнопкам
   
   
   Chislo_celikom(start_sec);
    while (1)
    {
      Chislo_celikom(start_sec);
      
      
      /* для энкодера*/
      
   
      
      if (upState >=4)
      {
         start_sec++;
         upState = 0;
         
         if (start_sec>5999)
         {
            start_sec=0;
         }
      }
      
      
      if (downState >=4)
      {
         start_sec--;
         downState = 0;
         
         
         if (start_sec<0)
         {
            start_sec=5999;
         }
         
      }
      
      if (~PINC & (1<<2))
      {
         if (start_sec == 0)
         {
            PORTC &= ~(1<<3);
         }
         start_otscheta();
         _delay_ms(200);
      }
      
    }
}
Оценка
Продукция MOSO предназначена в основном для индустриальных приложений, использует инновационные решения на основе более 200 собственных патентов для силовой электроники и соответствует международным стандартам. LED-драйверы MOSO применяются в системах наружного освещения разных отраслей, включая промышленность, сельское хозяйство, транспорт и железную дорогу. В ряде серий реализована возможность дистанционного контроля и программирования работы по заданному сценарию. Разберем решения MOSO.
Специалист
 
Аватар для Vadzz
 
Регистрация: 12.11.2008
Адрес: Тирасполь
Сообщений: 2,172
Записей в дневнике: 22
Репутация: 419
407 86
0 0
Отправить сообщение для Vadzz с помощью ICQ
 
24.05.2020 23:10 #2
Энкодер правильно подключили? Какой энкодер?
К порту C, правильно?
Нет ошибки в строке:
NewState=PINC & 0b00000111; //Для энкодера
?
Может: NewState=PINC & 0b00000011; //Для энкодера
__________________
Уважаемые пассажиры, самолет ТУ-134 садится. У кого есть зарядка от ТУ-134, просьба пройти в кабину пилота.
Оценка
КОМПЭЛ продолжает поддерживать и расширять список складских позиций Hongfa, представленных электромеханическими реле. Продукция компании активно применяется в таких областях, как промышленность, энергетика, бытовые приборы, автомобильная отрасль и специальная техника, требующая высокой надежности и на сегодняшний момент может легко заменить электромеханические реле ушедших из РФ брендов.
Новичок
 
Регистрация: 01.05.2020
Сообщений: 7
Репутация: 10
0 2
0 0
 
25.05.2020 07:14 #3
Цитата:
Сообщение от Vadzz
Энкодер правильно подключили? Какой энкодер?
К порту C, правильно?
Нет ошибки в строке:
NewState=PINC & 0b00000111; //Для энкодера
?
Может: NewState=PINC & 0b00000011; //Для энкодера
Энкодер EC12D1564402 ALPS

Подключил правильно, в той строке ошибки нет, энкодер с кнопкой один из выводом МК для нее в единицу установлен. Уже пробовал просто убирать и единичку оттуда и обработчик нажатия кнопки, все равно без изменений...
Оценка
Эксперт
 
Аватар для DmitriyVDN
 
Регистрация: 08.11.2009
Сообщений: 2,310
Репутация: 641
621 131
34 9
 
25.05.2020 07:42 #4
как-то у вас опрос энкодера через опу выглядит может как-то так надо:
Код:
void encoder_read(void)
{unsigned char tempPORTB;	
 static unsigned char encoder_TEMP,Count; 
    tempPORTB=PORTB;
    encoder_TEMP<<=2;
    encoder_TEMP|=(tempPORTB&((1<<1)|(1<<0)));
    encoder_TEMP&=0x0F;

      switch (encoder_TEMP) {
     
      // UP  
      case 2:
      case 4:
      case 11:
      case 13:          
             Count++;
        break;
        

      // DOWN 
 
      case 1:
      case 7:
      case 8:
      case 14:
             Count--;
        break;
         default:
         break;
      }   // switch encoder 8 state
          if (Count == 8)              // Если был шаг энкодера влево
             {
             txt++;   // <<--  нужное действие
                Count = 4;
             }

          else if (Count == 0)         // Если был шаг энкодера вправо
             {
             txt--;   // <<--  нужное действие
                Count = 4;
             }

}//end void encoder_read(void)
Оценка
Новичок
 
Регистрация: 01.05.2020
Сообщений: 7
Репутация: 10
0 2
0 0
 
25.05.2020 09:15 #5
Цитата:
Сообщение от DmitriyVDN
как-то у вас опрос энкодера через опу выглядит может как-то так надо:
Так тоже не получается. Теперь на старте вместо нулей отображается 1. Энкодер точно рабочий, пробовал конструкцию if ... else писать для опроса при повороте "крутилки" вообще какие то непонятные цифры отображаться начинают и с большой скоростью прибывать или убывать... Вряд ли это только из за "дребезга".
Оценка
Эксперт
 
Аватар для DmitriyVDN
 
Регистрация: 08.11.2009
Сообщений: 2,310
Репутация: 641
621 131
34 9
 
25.05.2020 15:09 #6
вы в железе проверяете? 1.тогда на энкодер поставьте внешние подтяжки по 4.7к и проверьте правильность подключения самого энкодера
2. при передаче цифр в прерывание не выполняется атомарность доступа.
Оценка
Новичок
 
Регистрация: 01.05.2020
Сообщений: 7
Репутация: 10
0 2
0 0
 
25.05.2020 16:41 #7
Все разобрался!! Всем спасибо!! С помощью кусочка чужого кода, найденного в интернете, но все же понял в чем дело )))


Если кому то интересно:

Код:
#define PORT_Enc 	PORTC
#define PIN_Enc 	PINC
#define DDR_Enc 	DDRC
#define Pin1_Enc 	0
#define Pin2_Enc 	1
#define RIGHT_SPIN 0x01
#define LEFT_SPIN 0xff
#define SetBit(port, bit) port|= (1<<bit)
#define ClearBit(port, bit) port&= ~(1<<bit)
#define b00000011 3
#define b11010010 210
#define b11100001 225
и в таймере:

Код:
//функция опроса энкодера
		   
			   static unsigned char stateEnc; 	//хранит последовательность состояний энкодера
			   unsigned char tmp;
			   unsigned char currentState = 0;

			   //проверяем состояние выводов микроконтроллера
			   if ((PIN_Enc & (1<<Pin1_Enc))!= 0) {SetBit(currentState,0);}
			   if ((PIN_Enc & (1<<Pin2_Enc))!= 0) {SetBit(currentState,1);}

			   //если равно предыдущему, то выходим
			   tmp = stateEnc;
			   if (currentState == (tmp & b00000011)) return;

			   //если не равно, то сдвигаем и сохраняем в озу
			   tmp = (tmp<<2)|currentState;
			   stateEnc = tmp;

			   //сравниваем получившуюся последовательность
			   if (tmp == b11100001) start_sec--; //минусуем секунду
			   if (tmp == b11010010) start_sec++; //Плюсуем секунду
			   return;
А в "железе" работает примерно так: https://www.youtube.com/watch?v=NWGPziD3kG8
Оценка
Новичок
 
Регистрация: 12.12.2010
Адрес: Санкт-Петербург
Сообщений: 11
Репутация: 10
0 3
0 0
 
29.05.2020 20:34 #8
Вообще о чём идёт речь ??? Где схема, где? где?
Оценка
Ответ
Похожие темы
Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход
Электронные компоненты. Скидки, кэшбэк и бесплатная доставка от ТМ Электроникс
Часовой пояс GMT +3, время: 23:33.
Обратная связь РадиоЛоцман Вверх