Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
0 / 0 / 0
Регистрация: 24.05.2020
Сообщений: 4
1

ATmega8 + Энкодер

25.05.2020, 09:34. Просмотров 380. Ответов 9
Метки нет (Все метки)

Доброго времени суток, Уважаемые! Такой вопрос. Собрал таймер на ATmega8 на кнопках все норм. все работает.

тут видео для наглядности (https://youtu.be/_f_8CG8Nkso)


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


Энкодер: EC12D1564402 ALPS


ИСХОДНИК (Atmel studio)
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*Используется семисегментный индикатор с общим АНОДОМ. т.е. на смену разрядов подается "+", а на сементы индикатора "-"
Эмиттеры транзисторов прицепить к "+" кллекторы к семисегментнику (к разрядам), базу через резистор к МК*/
 
#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);
      }
      
    }
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.05.2020, 09:34
Ответы с готовыми решениями:

Разница между ATMEGA8-16AI и ATMEGA8-16AU
Кто подскажет, в чем разница между ATMEGA8-16AI и ATMEGA8-16AU. Смотрю в Платане цены между ними...

Энкодер и кнопка
Всем привет. Делаю димер на тиньке 13А. Ног соответственно в обрез. На 2 последние прицепил...

Инкрементальный энкодер
В учебном курсе &quot;Инкрементальный энкодер&quot; пользователь с ником VEC7O выложил кусок кода на баскоме...

Энкодер и кое какие вопросы Pinboard
Здравствуйте, осваивать мк начал совсем недавно и появились вопросы, во общем хотел поиграться и...

9
901 / 541 / 81
Регистрация: 15.05.2012
Сообщений: 3,168
25.05.2020, 10:06 2
Алгоритм опишите (лениво ковырять текст программы).
0
0 / 0 / 0
Регистрация: 24.05.2020
Сообщений: 4
25.05.2020, 12:53  [ТС] 3
При вращении энкодера, биты микроконтроллера к которым он подключен (это PC0 и PC1 - для крутилки) могут принимать значения: 00, 01, 10, 11 т.е. если в десятичной системе: 2, 0, 1, 3. Еще один бит МК занят под кнопку энкодера (PC3).

отсюда (это прописано в нулевом таймере):
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
NewState=PINC & 0b00000011;   //Для энкодера
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;
}
т.е. по идее чтобы прибавить 1 секунду выставляемое значение времени нужно чтобы выполнилось приращения (upState++), также с уменьшением времени на 1 сек.

далее уже в теле цикла While:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* для энкодера*/
      
   
      
      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;
         }
         
      }
0
Модератор
8201 / 6071 / 811
Регистрация: 14.02.2011
Сообщений: 21,062
25.05.2020, 12:58 4
Geonov, ставте тэги правильно
для Си это тег CLANG
кнопочка "С" в шапке сообщения

C
1
int a;
[CLANG]int a;[/CLANG]
0
0 / 0 / 0
Регистрация: 24.05.2020
Сообщений: 4
25.05.2020, 16:48  [ТС] 5
Разобрался как ни странно сам))), но против советов возражать не буду. Если кому интересно публикую кусочек кода. Где то в сети нашел, в его то помощью и разобрался)).

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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
В таймере:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//функция опроса энкодера
           
               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;
0
125 / 43 / 12
Регистрация: 23.03.2018
Сообщений: 169
25.05.2020, 17:17 6
Я сажал энкодер на ножки, на которых можно настроить прерывание по входу - PORTD.2 и PORTD.3
И еще ножки подключал к резистору 100 ом и подтягивал к земле через конденсатор 102
Работал идеально.
1
Миниатюры
ATmega8 + Энкодер  
2514 / 1559 / 335
Регистрация: 09.09.2017
Сообщений: 6,301
26.05.2020, 12:33 7
Цитата Сообщение от Geonov Посмотреть сообщение
но против советов возражать не буду
За один оборот энкодер проходит 4 положения, а у вас увеличение идет только при полном проходе. Если крутилку будут дергать туда-сюда, получите отсутствие срабатывания. Попробуйте так:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
signed char encoder_update(){
  static uint8_t enc_state = 0;
  enc_state >>= 2;
  if( PIN_Enc & (1<<Pin1_Enc) )enc_state |= (1<<3);
  if( PIN_Enc & (1<<Pin2_Enc) )enc_state |= (1<<2);
  //биты 0,1 - предыдущее состояние, биты 2,3 - текущее. Вместе они образуют 16 состояний, из которых
  //четыре это движение вперед
  if( (enc_state == 0b0001) || (enc_state == 0b0111) || (enc_state == 0b1110) || (enc_state == 0b1000) )return 1;
  //еще четыре - движение назад
  if( (enc_state == 0b0010) || (enc_state == 0b1011) || (enc_state == 0b1101) || (enc_state == 0b0100) )return -1;
  //четыре (0b0000, 0b1111, 0b0101, 0b1010) - отсутствие движения
  //и четыре (0b0011, 0b1100, 0b0110, 0b1001) - смещение больше чем на 1 шаг, недопустимые состояния
  return 0;
}
0
0 / 0 / 0
Регистрация: 24.05.2020
Сообщений: 4
26.05.2020, 13:11  [ТС] 8
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
За один оборот энкодер проходит 4 положения, а у вас увеличение идет только при полном проходе. Если крутилку будут дергать туда-сюда, получите
Спасибо за совет! Но не совсем понимаю, у меня для увеличения нужно гораздо меньше одного оборота....

вот на видео можно увидеть (https://www.youtube.com/watch?v=NWGPziD3kG8

0
Модератор
8201 / 6071 / 811
Регистрация: 14.02.2011
Сообщений: 21,062
26.05.2020, 13:23 9
Geonov, для ссылки на ютуб нужно между тегами ввести число после равно по ссылке
вот ссылка
https://www.youtube.com/watch?v=NWGPziD3kG8
вот ролик

вот так он выглядит с тэгами

[YOUTUBE]NWGPziD3kG8[/YOUTUBE]
0
2514 / 1559 / 335
Регистрация: 09.09.2017
Сообщений: 6,301
26.05.2020, 13:56 10
Цитата Сообщение от Geonov Посмотреть сообщение
Спасибо за совет! Но не совсем понимаю, у меня для увеличения нужно гораздо меньше одного оборота....
В реальности оборот энкодера соответствует не одному циклу, а нескольким. Это сделано чтобы не пришлось крутить ручку дрелью, а хватало поворота на пару градусов.
В вашем примере получается увеличение на 1 за один цикл, причем если в середине цикла у пользователя дрогнула рука, придется крутить сначала. В моем же за 1 цикл идет 4 увеличения, причем учитывается только одно предыдущее состояние.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.05.2020, 13:56

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

Энкодер влияет на прерывания, хотя напрямую не подключен.
Attiny2313, к INT1 подключена оптопара в сборе как в мышке и пара резисторов на ней, если окно...

Atmega8
В Proteuse проблема после нажатия Плей. Помогите разобраться пожалуйста

ATMEGA8
Подскажите пожалуйста чем отличаються микроконтролер atmega8 от например етого ATmega8A-PU? И...

tsop1736 ATMega8
Доброго времени суток!!! Это мой первый проект с использованием микроконтроллеров (ATMiko8). Он...

ОМК ATmega8
Как в микроконтроллере ATmega8 описать входной сигнал такой,как синусоида и через какие входы?...

Залочился Atmega8
Всем привет! Есть ли шанс разлочить этот контроллер, при повторной прошивке прицепив на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.