Skocz do zawartości

Program zliczający impulsy enkodera


miccaldo

Pomocna odpowiedź

Witam, muszę zrobić licznik impulsów enkodera. Jest to enkoder inkrementalny MHK40.

Program ma za zadanie w przerwaniu timera cały czas wykrywać zbocze pinu do którego podłączony jest kanał A enkodera, a jeśli pin zmienił stan, dodać +1 do licznika. Program nie działa jak bym chciał, bo zlicza najprawdopodobniej z każdym przepełnieniem licznika niezależnie od tego czy pin kanału A zmienił stan, jeśli powiedzmy ustawię preskaler na 1024, to jedynka zapali się dopiero po jakimś czasie. Jeśli ustawię na 8, zapali się zdecydowanie szybciej, chociaż tuleja enkodera stoi w miejscu. Oto program,

#define F_CPU 1000000L 
#include <avr/io.h> 
#include <avr/interrupt.h>

#define _BV(bit) (1 << (bit))

//wyświetlacz LED
static uint8_t DIGITS[10] = {0x80,0xE3,0x09,0x21,0x62,0x30,0x10,0xE1,0x00,0x20};
char licznik = 0;


void timer0()
{

TCCR0 |= _BV(CS00)| _BV(CS02); // preskaler 1024
TIMSK |= _BV(TOIE0);
TCNT0 = 0;

}

void init()
{

DDRC = _BV(0); // kanał A enkodera
DDRD = 0xff;
DDRB = 0xff;

PORTD = 0xff;
PORTB = 0x00;
PORTC = _BV(0);

}
int main(void)
{

timer0();
init();
sei();

while(1)
{

}
}

SIGNAL(SIG_OVERFLOW0)
{
if(PINC ^ 0x01)
{
	licznik += 1;
}
if(licznik == 10)
	{
	PORTD = DIGITS[1];
	}
}

Proszę o pomoc, pozdrawiam.

Link do komentarza
Share on other sites

Witaj, czy nie lepiej użyć do tego celu przerwania zewnętrzengo niż bawić się timerem?

Tutaj zamieszczam swój program, bogaty w komentarze.

/////////////OBSŁUGA_ENKODERA/////////////////// 

#include <avr/io.h> 
#include <util/delay.h> 
#include <avr/interrupt.h> 



int main() 
{ 
    /////////////////KONFIGURACJA_WE/WY/////////////////////////// 
    #define IN_1    (1<<PB2)      //wejscie enkodera Kanał A
    #define IN_2    (1<<PB3)    //wejscie enkodera Kanał B
    #define LED        (1<<PD0) 
    #define LED_ON    PORTD |=LED        //włącz diode 
    #define LED_OFF    PORTD &= ~LED     //wyłącz diode 
    DDRD |= (0<<IN_1)|(0<<IN_2);    // piny enkodera jako wejscie 
    DDRD |= (1<<LED); //dioda jako wyjscie 
    PORTD|= (1<<IN_1)|(1<<IN_2);    //załączenie pull-up 

    ////////////////////////////////////////////////////////////// 


    ////////////////////KONFIGURACJA_PRZERWANIA///////////////// 
    GICR |= (1<<INT0);    //aktywujemy przerwanie INT0 
    MCUCR |= (1<<ISC00)|(0<<ISC01);    //wyzwalanie dwoma zboczami 
    sei();    //zezwolenie na globalne przerwania 
    //////////////////////////////////////////////////////////// 


    while(1) 
    {    

    } 
} 

ISR(INT0_vect) 
{ 
    //przerwanie na INT0 wyzwolone (Kanał A)zboczem narastającym/opadającym 
    //sprawdzi czy wejscie IN_2 ma stan niski czy wysoki 
    if(PIND & (1<<IN_2))    LED_ON;    //jesli IN_2 ma stan wysoki to zapal diode 
    else LED_OFF;     //w przeciwnym razie zgaś LED 



} 
Link do komentarza
Share on other sites

Witam, tak ma Pan racje i już napisałem cały program z tym że utknąłem na pewnej rzeczy otóż w funkcji switch program powinien zapalać odpowiednie segmenty przy odpowiednich wartościach, ale zapala się jedynka i dwójka jednocześnie, właśnie nie wiem co by zrobić aby po kolei switch wybierało odpowiednie wartości. Oto program:

#define F_CPU 1000000L 
#include <avr/io.h> 
#include <avr/interrupt.h>
#include <util/delay.h>
#define _BV(bit) (1 << (bit))
#define DIGITS 0xFB
#define KANAL_A 0x04
#define DP 0x01

//wyświetlacz LED
volatile static uint8_t DIGITS_TAB[11] = {0x80,0xE3,0x09,0x21,0x62,0x30,0x10,0xE1,0x00,0x20,0x01};
volatile uint16_t licznik = 0;
volatile uint8_t obrot = 0;

void interrupt_init() //przerwania
{
MCUCR |= _BV(ISC00);
GICR |= _BV(INT0);
}

void init()
{
DDRD |= DIGITS | KANAL_A;
DDRB |= DP;
PORTD |= 0x80 | KANAL_A;
}

int main(void)
{

interrupt_init();

init();

sei();

while(1)
{
switch(licznik)
{
	case 200:

	PORTD = DIGITS_TAB[1];

	case 400:

	PORTD = DIGITS_TAB[2];
	break;
}

}
}

SIGNAL(SIG_INTERRUPT0)
{
licznik++;
}
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Ok, ale np. w tym kodzie w poglądzie zmiennej cnt widzę że jeśli równa się 100, to obrot=2 -.-

A z kolei jeśli podłącze normalnie z enkoderem to po jednym obrocie zapali się jedynka i tyle, koniec. Dlaczego to nie chce działać?

#define F_CPU 1000000L
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define _BV(bit) (1 << (bit))
#define DIGITS 0xFB
#define KANAL_A 0x04
#define DP 0x01
#define switch 1

//wyświetlacz LED
volatile static uint8_t DIGITS_TAB[11] = {0x80,0xE3,0x09,0x21,0x62,0x30,0x10,0xE1,0x00,0x20,0x01};
volatile uint16_t cnt = 0;
volatile uint8_t obrot = 0;
volatile uint8_t cnt_tr0 = 0;
volatile uint8_t czas = 0;

void init()
{
DDRD |= DIGITS | KANAL_A;
DDRB |= DP;
PORTD |= 0x80 | KANAL_A;
PORTB |= _BV(switch);

}

void interrupt_init()
{
MCUCR |= _BV(ISC00) | _BV(ISC01);
GICR |= _BV(INT0);
}

ISR(INT0_vect)
{
cnt++;
}

int main(void)
{
init();
interrupt_init();
sei();

while(1)
{
_delay_ms(1);
PORTD ^= KANAL_A;

if(cnt==100)
{
	obrot+=1;
}
if(czas==200)
{
	obrot+=1;
}
if(czas==300)
{
	obrot+=1;
}
}
}
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.