2014-12-16 2 views
0

Я пытаюсь получить поворотный датчик для управления скоростью 7-сегментного дисплея, отсчитываемого от 0-9, с помощью микропроцессора Atmel (ATmega328P Xplained mini). Моя проблема заключается в том, что всякий раз, когда я запускаю программу, дисплей просто подсчитывается все быстрее и быстрее, пока вы не увидите просто «8», иногда кажется, что я могу сохранить скорость, поворачивая поворотный энкодер CCW, а иногда и никакого эффекта вообще. Поскольку я не настолько разбираюсь в программировании, и особенно это не так, я надеюсь, что кто-то способен и хочет помочь.Atmel микропроцессор и скорость вращения поворотного энкодера 7-сегментного дисплея

Вот мой код:

#include <avr/io.h> 

void Display (uint8_t x) 
{ 
    static uint8_t tabel[] = 
    {0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010010,0b10000010,0b11111000,0b10000000,0b10010000}; 
    PORTD = tabel[x]; 
} 

int GetInput (void) 
{ 
    uint8_t x = PINC&1; 
    uint8_t y = (PINC>>1)&1; 
    if (x == 0 && y == 0) {return 0; } 
    else if (x == 1 && y == 0) {return 1;} 
    else if (x == 0 && y == 1) {return 2;} 
    else {return 3;} 
} 

int main(void) 
{ 
    DDRD = 0xFF; // set PortD as an output 
    DDRC = 0x00; // set PortC as an input 
    PORTB = 0x03; // Activate Pull-up resistors 

    float d = 9000; 
    int tick = 0; 
    int i = 0; 
    int input, state = 0; // initial state 
    int oldInput = 0; 

    while (1) 
    { 
     input = GetInput(); 
     if (oldInput == 0 && input == 1) 
     { 
      d = (d * 1.1); 
      //slower 
     }else if (oldInput == 0 && input == 2) 
     { 
      d = (d * 0.9); 
      //faster 
     }else if (oldInput == 1 && input == 0) 
     { 
      d = (d * 0.9); 
      //faster 
     }else if (oldInput == 1 && input == 3) 
     { 
      d = (d * 1.1); 
      //slower 
     }else if (oldInput == 2 && input == 0) 
     { 
      d = (d * 1.1); 
      //slower 
     }else if (oldInput == 2 && input == 3) 
     { 
      d = (d * 0.9); 
      //faster 
     }else if (oldInput == 3 && input == 1) 
     { 
      d = (d * 0.9); 
      //faster 
     }else if (oldInput == 3 && input == 2) 
     { 
      d = (d * 1.1); 
      //slower 
     } 
     oldInput = input; 

     switch (state) 
     { 
      case 0: //ini 
       Display(0); 
       state = 1; 
       break; 

      case 1: //count 
       if (i == 9) 
       { 
        i = 0; 
        Display(i); 
       } 
       else 
       { 
        i++; 
        Display(i); 
       } 
       state = 2; 
       break; 

      case 2: // delay 
       if (tick < d) 
       { 
        state = 2; 
        tick++; 
       } 
       else 
       { 
        state = 1; 
        tick = 0; 
       } 
       break; 

      case 3: //reset/destroy 
       break; 
     } 
    } 
} 
+0

Микро будет проходить через цикл много раз перед первым таймером, а умножение на 0,9 каждый раз быстро запустит d до 0. Как только он достигнет 0, независимо от того, сколько раз вы умножаетесь на 1.1, оно будет оставаться на 0 и вы больше никогда не будете ждать в «случае 2:». –

+0

Если вы можете объяснить, что означают битовые шаблоны для кодировщика и как вы хотите, чтобы они повлияли на время, я мог бы предложить альтернативу. –

+0

Между каждым нажатием на поворотный кодер значение бита проходит через: 2-3-1-0 для CW и 1-3-2-0 для CCW, оно должно просто считаться, например. На 10% быстрее при повороте CW и на 10% медленнее при повороте CCW. Фактически я просто хотел, чтобы он менялся один раз между каждым щелчком (например, если значение идет от 0-1 или 1-0), но расширило код, когда это не сработало, а затем я потерялся. – Nicolai

ответ

0

Я проверил вашу SW, но я не могу найти большую проблему мгновенно. Лучше проверить нижнюю часть.

  1. Если вы не трогали кодировщик, но скорость быстрее и быстрее : у вас есть возможности для проверки входного порта датчика шума, является ли вход от порта или нет.
  2. Если два входных порта стабильны, проверьте, что ваше значение также стабильно. : старый вход и новое входное значение должны быть одинаковыми. : проверка по протоколу или выходному переключателю неиспользуемого порта при изменении значения. вы можете отлаживать свой собственный код.
  3. Лучше добавить значение количества галочек, чем умножить непосредственно, чтобы значение d становилось 0.
  4. ваш процессор должен работать так же быстро, как изменение статуса порта порта в основном цикле. - Я думаю, что это возможно, если этот код является всей вашей системой.
1

Сначала попробуйте изменить функцию GetInput, чтобы вернуть более полезное значение. Обратите внимание, что бит 0 и бит 1 PINC уже объединяются, чтобы сформировать целое число, которое вы восстанавливаете.

int GetInput (void) 
{ 
    // array to convert grey scale bit patterns to direction indicators. 
    // Rows indexed by lastValue, columns indexed by thisValue, and the 
    // content is -1 for CCW, +1 for CW, 0 for no motion. Note that 0 is 
    // also used for an invalid transition (2 bits changed at once), but a 
    // different value could be used for fault detection. 
    static const int tableGreyToDirection[4][4] = 
    { 
     0 , -1, 1 , 0 ,      // lastValue==0 
     1 , 0 , 0 , -1,      // lastValue==1 
     -1, 0 , 0 , 1 ,      // lastValue==2 
     0 , 1 , -1, 0       // lastValue==3 
    }; 

    static uint8_t lastValue = 0;    // A valid default starting value 
    uint8_t thisValue = (PINC & 0b00000011); // Use the bottom two bits as a value from 0..3 
    int result = tableGreyToDirection[lastValue][thisValue]; 
    lastValue = thisValue; 
    return result; 
} 

После этого вы можете значительно упростить испытание в цикле.

while (1) 
{ 
    // Check the direction of the encoder: -1 = CCW, +1 = CW, anything else = no motion. 
    input = GetInput(); 
    if(0 < input) 
    { 
     // Motion is CW, so increment the delay (within reasonable bounds). 
     if(8900 > d) d += 100; 
    } 
    else if(0 > input) 
    { 
     // Motion is CCW, so decrement the delay (within reasonable bounds). 
     if(100 < d) d -= 100; 
    } 

    // Keep the rest as it is... 
} 

Было бы целесообразно, чтобы изменить d быть uint16_t и аккуратно его немного. Дальнейшие советы включают использование #define для предоставления читаемых имен для констант. Например. в моей таблице направлений вы можете использовать:

#define ENCODER_CW 1 
#define ENCODER_CCW -1 
#define ENCODER_NEITHER 0 

... 

static const int tableGreyToDirection[4][4] = 
{ 
    ENCODER_NEITHER, ENCODER_CCW, ENCODER_CW, ENCODER_NEITHER, // lastValue==0 
    ... 

Я уверен, что вы можете заполнить его самостоятельно.

Смежные вопросы