| Ваш IP: 100.26.179.251 | Online(28) - гости: 9, боты: 19 | Загрузка сервера: 0.55 ::::::::::::

ATtiny2313 + энкодер

KY-040

Энкодеры KY-040 часто применяют в различных проектах. KY-040 как правило выполнен в виде модуля, который состоит из небольшой платы в которую установлен энкодер и 3 подтягивающих (к +5 В) резистора номиналом 10 кОм. При вращении ручки модуля мы получаем два сигнала (A и B), которые противоположны по фазе.  Каждый раз, когда сигнал А переходит от положительного уровня к нулю, мы считываем значение выхода В. Если В в этот момент находится в положительном состоянии, значит энкодер вращается по часовой стрелке, если В нуль, то энкодер вращается против часовой стрелки. Считывая оба выхода, можно определить направление вращения, и при помощи подсчета импульсов с А выхода — угол поворота.

Что бы безошибочно определять угол поворота и направление вращения необходимо постоянного опрашивать (считывать) состояние выходов A и B  (CLK и DT) энкодера, при этом содержимое скетча не должно влиять на период опроса. Этого можно добиться двумя путями, использовать внешние прерывания или при помощи таймера.

Для считывания показаний энкодера лучше использовать внешнее прерывание, так как таймер может понадобится для других целей. Для управления энкодером можно использовать входы ATtiny2313 для внешнего прерывания PCINT0…7. (Работа с прерываниями PCINT0…7)

Ниже показан простой скетч который позволяет осуществлять чтение данных энкодера, в качестве индикатора будет использован модуль индикатора TM1637 который представляет собой 4-х разрядный семисегментный дисплей на базе драйвера TM1637. На индикатор будут выводится показания энкодера.

Для проверки работы энкодера необходимо собрать следующую схему:

Перед загрузкой скетча рекомендую ознакомится со статьей — ATtiny2313 + Arduino IDE

volatile uint8_t _prevValueAB = 0;    
volatile uint8_t _currValueAB = 0;
volatile int16_t _counter = 0;
int position = -999;
int encoder;
 
void setup(){
  DDRB &= ~(1 << 2) | (1 << 3);
  GIMSK |= (1 << PCIE); 
  PCMSK |= (1 << PCINT2) | (1 << PCINT3); 
}
 
void loop() {  
  if(getPosition() != position){
    position = getPosition();
    encoder = encoder+getPosition();setPosition(0);}
 
    if(encoder>=0)print_time(encoder, 0, 7, 0);
    if(encoder<0)print_time(abs(encoder), 0, 7, 2);
}
//////// encoder ////////////////////////
ISR(PCINT_vect){ 
  bool pinA = ((PINB >> 2) & 1);
  bool pinB = ((PINB >> 3) & 1);
   _currValueAB  = pinA << 1;
   _currValueAB |= pinB;
   switch ((_prevValueAB | _currValueAB)){
    case 0b0001: _counter++;break;
    case 0b0100: _counter--;break;
  }
  _prevValueAB = _currValueAB << 2;     
  } 
 
int16_t getPosition(){
  return _counter;
}
 
void setPosition(int16_t position){
  _counter = position;
}
 
//////////// tm /////////////////// 
void tm_dec(byte dig) {
  for (int i = 0; i < 8; i++) {
    DDRB |= (1 << 0); del();
  if (dig & 0x01) DDRB &= ~(1 << 1);
    else DDRB |= (1 << 1); del();DDRB &= ~(1 << 0); del();
    dig = dig >> 1;}
    DDRB |= (1 << 0);
    DDRB &= ~(1 << 1); del();
    DDRB &= ~(1 << 0); del();
  if (((PINB >> 1) & 1) == 0) DDRB |= (1 << 1); del();DDRB |= (1 << 0); del();
}
 
void tm_stop() {
  DDRB |= (1 << 1); del();
  DDRB &= ~(1 << 0); del();
  DDRB &= ~(1 << 1); del();
}
 
void tm_start() {
  DDRB |= (1 << 1); del();
}
 
void print_time(int t, byte pd_t, int br, byte mn) {
  tm_start(); tm_dec(0b10001000 + br); //tm_stop();tm_start();
  tm_dec(0x40); tm_stop(); tm_start();
 
  int data0;
  if(mn==1){data0 = 10;}
  else if(mn==2){data0 = 11;}
  else data0 = t / 1000;
  int data1 = t / 100 % 10;
  int data2 = t / 10 % 10;
  int data3 = t % 10;
 
  for (byte n = 0; n < 4; n++) {
    int data;
    switch (n) {
      case 0: data = data0; break;
      case 1: data = data1; break;
      case 2: data = data2; break;
      case 3: data = data3; break;
    }
 
    switch (data) {  // XGFEDCBA
      case 0:  data = 0b00111111; break;    // 0
      case 1:  data = 0b00000110; break;    // 1
      case 2:  data = 0b01011011; break;    // 2
      case 3:  data = 0b01001111; break;    // 3
      case 4:  data = 0b01100110; break;    // 4
      case 5:  data = 0b01101101; break;    // 5
      case 6:  data = 0b01111101; break;    // 6
      case 7:  data = 0b00000111; break;    // 7
      case 8:  data = 0b01111111; break;    // 8
      case 9:  data = 0b01101111; break;    // 9
      case 10: data = 0b00000000; break;    // пусто
      case 11: data = 0b01000000; break;    // -
    }
 
    if (n == 0) {data0 = data;}
    if (n == 1) {data1 = data;}
    if (n == 2) {data2 = data;}
    if (n == 3) {data3 = data;}
  }
  switch (pd_t) {
    case 1 : data2 = data2 + 0b10000000; break;
    case 2 : data1 = data1 + 0b10000000; break;
    case 3 : data0 = data0 + 0b10000000; break;
  }
  tm_dec(0xC0); tm_dec(data0); tm_dec(data1); tm_dec(data2); tm_dec(data3); tm_stop();
}
 
void del() {delayMicroseconds(200);}

Для считывания показаний энкодера используются входы внешнего прерывания PCINT2 и PCINT3, что соответствует входам микроконтроллера PB2 и PB3:

PCMSK |= (1 << PCINT2) | (1 << PCINT3);

Обработчик прерывания PCINT_vect при повороте ручки энкодера считывает логический уровень выходов энкодера CLK и DT, получая два сигнала (A и B).

Функция getPosition(выдает показания энкодера, а функция setPosition(int16_t position) позволяет установить любое первоначальное значение показаний энкодера.

Для примера использования энкодера на базе микроконтроллера ATtiny2313 можно собрать простой терморегулятор. В терморегуляторе в качестве датчика используется цифровой датчик температуры DS18B20, энкодер позволяет изменять температуру регулирования.

Основные параметры терморегулятора:

  • Диапазон измеряемых температур от 0 до 125 °С
  • Диапазон регулирования температуры от 0 до 125 °С
  • Интервал измерения температуры 5 секунд
  • Гистерезис 0,1 °С (можно изменить в скетче)
  • Шаг регулировки и измерения температуры 0,1 °С

При включении терморегулятора на индикатор в течении 5 секунд выводится температура регулирования, далее выводится измеряемая температура. Если нажать на кнопку энкодера, то снова на 5 секунд выводятся показания температуры регулирования, если повернуть ручку энкодера, то можно изменить температуру регулирования. Температура регулирования заносится в энергонезависимую память. Выход микроконтроллера PD5 используется для управления нагревательным элементом.

byte bb,w;
volatile uint8_t _prevValueAB = 0;    
volatile uint8_t _currValueAB = 0;
volatile int16_t _counter = 0;
int position = -999;
int t_reg,t_dig;
unsigned long time_i=0,time_i2=0,time_i3=0;
const int gis = 1;//0.1 гр. Цельсия
 
 
void setup(){
  cli();
////// timer 1 //////////  
  TCCR1A = 0;   
  TCCR1B = 0;   
  OCR1A = 18750; // 0.1 s
  TCCR1B |= (1 << WGM12); 
  TCCR1B |= (1 << CS11) | (1 << CS10);  // 64  
  TIMSK |= (1 << OCIE1A);  
//////////////////////////  
  DDRB &= ~(1 << 2) | (1 << 3);
  DDRD &= ~(1 << 6);
  DDRD |= (1 << 5);
  GIMSK |= (1 << PCIE); 
  PCMSK |= (1 << PCINT2) | (1 << PCINT3); 
  t_reg = EEPROM_read(0)*10+EEPROM_read(1);
  sei();
}
 
void loop() {
     if(((PIND >> 6) & 1) == 0){time_i2=0;time_i3=0;}
 
  if(getPosition() != position){
    position = getPosition();
    t_reg = t_reg+getPosition();setPosition(0);w=1;time_i=0;time_i2=0;time_i3=0;
    if(t_reg<0){t_reg=0;}if(t_reg>1250){t_reg=1250;}}
 
    if(time_i2<=50){
    if(t_reg>999){print_time(t_reg, 1, 7, 0);}else{print_time(t_reg, 1, 7, 1);}}
 
    if(time_i3>50){t_dig = read_temp();time_i3=0;}
 
    if(w==1&&time_i>50){w=0;EEPROM_write(0,t_reg/10);EEPROM_write(1,t_reg%10);delay(100);}
    if(time_i2>50){
    if(t_dig>999){print_time(t_dig, 1, 7, 0);}else{print_time(t_dig, 1, 7, 1);}}
 
    if(t_reg >= t_dig + gis){PORTD |= (1 << 5);}
    if(t_reg <= t_dig - gis){PORTD &= ~(1 << 5);}
 
}
//////// encoder ////////////////////////
ISR(PCINT_vect){ 
  bool pinA = ((PINB >> 2) & 1);
  bool pinB = ((PINB >> 3) & 1);
   _currValueAB  = pinA << 1;
   _currValueAB |= pinB;
   switch ((_prevValueAB | _currValueAB)){
    case 0b0001: _counter++;break;
    case 0b0100: _counter--;break;
  }
  _prevValueAB = _currValueAB << 2;     
  } 
 
int16_t getPosition(){
  return _counter;
}
 
void setPosition(int16_t position){
  _counter = position;
}
 
//////////// tm /////////////////// 
void tm_dec(byte dig) {
  for (int i = 0; i < 8; i++) {
    DDRB |= (1 << 0); del();
  if (dig & 0x01) DDRB &= ~(1 << 1);
    else DDRB |= (1 << 1); del();DDRB &= ~(1 << 0); del();
    dig = dig >> 1;}
    DDRB |= (1 << 0);
    DDRB &= ~(1 << 1); del();
    DDRB &= ~(1 << 0); del();
  if (((PINB >> 1) & 1) == 0) DDRB |= (1 << 1); del();DDRB |= (1 << 0); del();
}
 
void tm_stop() {
  DDRB |= (1 << 1); del();
  DDRB &= ~(1 << 0); del();
  DDRB &= ~(1 << 1); del();
}
 
void tm_start() {
  DDRB |= (1 << 1); del();
}
 
void print_time(int t, byte pd_t, int br, byte mn) {
  tm_start(); tm_dec(0b10001000 + br); //tm_stop();tm_start();
  tm_dec(0x40); tm_stop(); tm_start();
 
  int data0;
  if(mn==1){data0 = 10;}
  else if(mn==2){data0 = 11;}
  else data0 = t / 1000;
  int data1 = t / 100 % 10;
  int data2 = t / 10 % 10;
  int data3 = t % 10;
 
  for (byte n = 0; n < 4; n++) {
    int data;
    switch (n) {
      case 0: data = data0; break;
      case 1: data = data1; break;
      case 2: data = data2; break;
      case 3: data = data3; break;
    }
 
    switch (data) {  // XGFEDCBA
      case 0:  data = 0b00111111; break;    // 0
      case 1:  data = 0b00000110; break;    // 1
      case 2:  data = 0b01011011; break;    // 2
      case 3:  data = 0b01001111; break;    // 3
      case 4:  data = 0b01100110; break;    // 4
      case 5:  data = 0b01101101; break;    // 5
      case 6:  data = 0b01111101; break;    // 6
      case 7:  data = 0b00000111; break;    // 7
      case 8:  data = 0b01111111; break;    // 8
      case 9:  data = 0b01101111; break;    // 9
      case 10: data = 0b00000000; break;    // пусто
      case 11: data = 0b01000000; break;    // -
    }
 
    if (n == 0) {data0 = data;}
    if (n == 1) {data1 = data;}
    if (n == 2) {data2 = data;}
    if (n == 3) {data3 = data;}
  }
  switch (pd_t) {
    case 1 : data2 = data2 + 0b10000000; break;
    case 2 : data1 = data1 + 0b10000000; break;
    case 3 : data0 = data0 + 0b10000000; break;
  }
  tm_dec(0xC0); tm_dec(data0); tm_dec(data1); tm_dec(data2); tm_dec(data3); tm_stop();
}
 
void del() {delayMicroseconds(200);}
 
////////// eeprom ////////////////////
unsigned char EEPROM_read(unsigned int uiAddress){
  while(EECR & (1<<EEPE));
    EEAR = uiAddress;
    EECR |= (1<<EERE);
    return EEDR;
}
 
void EEPROM_write(unsigned int uiAddress, unsigned char ucData){
    while(EECR & (1<<EEPE));
      EEAR = uiAddress;
      EEDR = ucData;
      EECR |= (1<<EEMPE);
      EECR |= (1<<EEPE);
} 
 
//////////// timer 1 /////////////
ISR(TIMER1_COMPA_vect){time_i++; time_i2++;time_i3++;}
 
///////////// 18b20 ////////////////
uint8_t therm_reset(){
    uint8_t i;
    PORTB &= ~(1 << 4);
    DDRB |= (1 << 4);
    delayMicroseconds(480);  
    DDRB &= ~(1 << 4);
    delayMicroseconds(60);
    i=((PINB >> 4) & 1);
    delayMicroseconds(420);
    return i;
}
// write bit
void therm_write_bit(uint8_t bit){
    PORTB &= ~(1 << 4);
    DDRB |= (1 << 4);
    delayMicroseconds(1);
    if(bit) DDRB &= ~(1 << 4);
    delayMicroseconds(60);
    DDRB &= ~(1 << 4);
}
// read bit
uint8_t therm_read_bit(void){
    uint8_t bit=0;
    PORTB &= ~(1 << 4);
    DDRB |= (1 << 4);
    delayMicroseconds(1);
    DDRB &= ~(1 << 4);
    delayMicroseconds(14);
    if(PINB & (1 << 4)) bit=1;
    delayMicroseconds(45);
    return bit;
}
 
// read byte
uint8_t therm_read_byte(void){
    uint8_t i=8, n=0;
    while(i--){n>>=1;n|=(therm_read_bit()<<7);}
    return n;
}
 
// write byte
void therm_write_byte(uint8_t byte){
    uint8_t i=8;
    while(i--){therm_write_bit(byte&1);byte >>= 1;
    }
}
// read temp
int read_temp(){
    uint8_t temperature[2];
    int temper;
    therm_reset();
    therm_write_byte(0xCC);
    therm_write_byte(0x44);
    while(!therm_read_bit());
    therm_reset();
    therm_write_byte(0xCC);
    therm_write_byte(0xBE);
    temperature[0]=therm_read_byte();
    temperature[1]=therm_read_byte();
    therm_reset();
    temper = (temperature[1] << 8 | temperature[0])*10/16;
    return temper;
}

Скетч использует 1802 байт (87%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 32 байт (25%) динамической памяти, оставляя 96 байт для локальных переменных. Максимум: 128 байт.

Версия платы в Arduino IDE 1.2.5

Форум — http://forum.rcl-radio.ru/viewtopic.php?id=285

Добавить комментарий

Войти с помощью: 

Случайные статьи

  • Узел настройки УКВ-ЧМ приемника

    Узел настройки УКВ_ЧМ приемника представляет собой синтезатор напряжения для электронной настройки УКВ_ЧМ приемника и как дополнительное уст-во — электронную линейную шкалу напряжения для контроля напряжения подаваемого на варикапы приемника. Напряжение настройки приемника устанавливается при помощи полевого транзистора VT1, в его затворной цепи включен С1, при нажатии S1 или S2 С1 …Подробнее...
  • Стерео усилитель класса D 2*25Вт на базе TDA7490

    Стерео усилитель класса D 2*25Вт на базе TDA7490

    Микросхема TDA7490 имеет защиту от перенапряжения, тепловую и защиту от КЗ, так же микросхема имеет встроенные функции MUTE и STAND-BY. Усилитель на TDA7490 имеет следующие технические характеристики: Напряжение питания от +/-10В до +/-25В (номинальное напряжение +/-21В) Ток покоя от 70 до 120мА в зависимости от  напряжения питания Выходная мощность 25Вт …Подробнее...
  • Усилитель мощности звуковой частоты класса D на ИМС MAX9709

    Усилитель мощности звуковой частоты класса D на ИМС MAX9709

    Усилитель мощности звуковой частоты класса D на ИМС MAX9709 обеспечивает выходную мощность до 25Вт на канал (стерео) при нагрузке 8 Ом и 50Вт в режиме моно при нагрузке 4 Ом. ИМС MAX9709 обеспечивает высокую производительность (КПД 87%), при этом используется небольшой радиатор охлаждения. Напряжение питания усилителя от 10 до 22В. MAX9709  имеет …Подробнее...
  • Простой испытатель тиристоров

    Простой испытатель тиристоров

    Из подручных радиоэлементов можно собрать простой испытатель тиристоров, который состоит из трансформатора со вторичной обмоткой на 6,3В (0,5А), диода, конденсатора, лампы и трех переключателей. Выбор постоянного или переменного тока осуществляется переключателем SA2. Электроды тиристора подключаются при помощи зажимов, индикатор служит лампа накаливания 6,3Вх0,28А. Для проверки тиристора постоянным током переведите переключатель …Подробнее...
  • УМЗЧ на 50Вт на полевых MOSFET транзисторах

    УМЗЧ на 50Вт на полевых MOSFET транзисторах

    На рисунке показана схема 50 Вт усилителя с выходными полевыми MOSFET транзисторами. Первый каскад усилителя представляет собой дифференциальный усилитель на транзисторах VT1 VT2. Второй каскад усилителя состоит из транзисторов VT3 VT4. Оконечный каскад усилителя состоит из МОП-транзисторов IRF530 и IRF9530. Выход усилителя через катушку L1 соединен с нагрузкой 8 Ом. Цепь состоящий …Подробнее...