Skocz do zawartości

[C] Problem z poprawnymi wynikami z enkoderów optycznych


Marcin_56

Pomocna odpowiedź

Witam,

przejdę od razu do sedna. Enkodery optyczne firmy pololu(https://www.pololu.com/product/2590), które mam podłączone(podłączenie widoczne na załączonym zdjęciu) nie dają poprawnych wyników, liczby są przesyłane przez bluetooth i odczytuję je na telefonie. Co do tych wyników to czasami skaczą obracając w jedną stronę mam liczbę dodatnią a po chwili pojawia się ujemna. Obracając w lewo a potem w prawo wyniki albo się zmniejszają albo zwiększają.

Całością steruje atmega128. W schemacie jest dzielnik napięcia z oporników do zasilenia komparatora, ale aktualnie w testach mam podłączony zasilacz z możliwością regulowania, aby dostosować odpowiednie napięcie i ostatecznie dobrać poprawne wartości oporników jak już wszystko będzie poprawnie działać 😉

Main.c

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

#include "hardware.h"
#include "uart.h"
#include "encoders.h"

volatile int encoder_R;

int main(void)
{

UART_init();
Encoder_init();

while(1)
{	
UART_putstr(" wynik ");
UART_putint(encoder_R);
UART_putstr("\n");
_delay_ms(10);	
}
}

encoders.h

/**
\file irleds.h
\brief Plik nagłówkowy biblioteki do obsługi enkoderow
*/
#ifndef ENCODERS_H_
#define ENCODERS_H_

#include <stdint.h>

/****************************************Defines**********************************************/

/// Rejestr obsługujący port do którego podłączone są enkodery
#define 	ENC_DDR     DDRE
/// Port do którego podłączeone są enkodery
#define 	ENC_PORT    PORTE
/// Maska lewego enkodera, wyjście A
#define		 ENC_LA		PE4
/// Maska lewego enkodera, wyjście B
#define		 ENC_LB		PE5
/// Maska prawego enkodera, wyjście A
#define		 ENC_RA		PE6
/// Maska prawego enkodera, wyjście B
#define		 ENC_RB     PE7

/*********************************Function Prototypes****************************************/

/**
\brief Funkcja inicjalizująca enkodery 
*/
void Encoder_init(void);

/**
\fn ISR(INT4_vect)
*/

#endif /* ENCODERS_H_ */

encoders.c

/**
\file encoders.c
@brief Plik źródłowy biblioteki do obsługi enkoderow
*/

#include "encoders.h"
#include "uart.h"
#include <avr/io.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/sfr_defs.h>
#include <avr/interrupt.h>

/*******************************Global Variables*****************************************************/

volatile int encoder_R=0;
volatile int encoder_L=0;

/************************************Functions*****************************************************/

void Encoder_init(void)
{
ENC_DDR &= ~(1<<ENC_LA) & ~(1<<ENC_LB) & ~(1<<ENC_RA) & ~(1<<ENC_RB); 
ENC_PORT |= (1<<ENC_LA) | (1<<ENC_LB) | (1<<ENC_RA) |(1<<ENC_RB);
EICRB |= (1<<ISC71) | (1<<ISC70) | (1<<ISC61) | (1<<ISC60) | (1<<ISC51) | (1<<ISC50) | (1<<ISC41) | (1<<ISC40);
EIMSK |= (1<<INT7) | (1<<INT6) | (1<<INT5) | (1<<INT4);

sei();
}

/*
ISR(INT4_vect)
{
if(( PINE & (1<<ENC_LA)) == 0 )
{
	encoder_R++;
	return;
}

if(( PINE & (1<<ENC_LA)))
{
	encoder_R--;
	return;
}
}

ISR(INT5_vect)
{
if(( PINE & (1<<ENC_LB)) == 0 )
{
	encoder_R++;
	return;
}

if(( PINE & (1<<ENC_LB)))
{
	encoder_R--;
	return;
}

}
*/

ISR(INT4_vect ) 
{ 
if(!bit_is_clear(PINE, PE5))
{ 
	encoder_R++;
} 
else
{ 
	encoder_R--;
} 
} 

ISR(INT5_vect ) 
{ 
if(!bit_is_clear(PINE, PE4))
{ 
	encoder_R++;
} 
else
{ 
	encoder_R--;
} 
} 

encoders.h

encoders.c

main.c

Link do komentarza
Share on other sites

1. Zrobiłeś transmisję przez radio itp bajery a zabrakło mi podstawowego zdania: sprawdziłem, że sygnały z enkoderów są poprawne. Po co grzebać w programie i śledzić kod skoro nie wiesz czy wejście jest w porządku? Nie masz czasem 4 diodek by podłączyć je (przez oporniki) wprost do wyjść komparatorów? Przez powolne kręcenie kółkiem mógłbyś zweryfikować sygnały. Bez tego nie ma sensu dalsza praca. Oczywiście oscyloskop byłby tu niezastąpiony, ale skoro do tej pory go nie użyłeś, to pewnie go nie masz. Jeżeli na schemacie są gdzieś jakieś wolne LEDy - ich możesz użyć do pośredniego sprawdzenia. Napisz prosty kod przepisujący stany z PE4-5 lub PE6-7 na te diodki. Żadnych przerwań itp bzdur.

2. Nie dobierzesz nigdy dobrze oporników, bo spaprałeś dzielnik. Przez szeregowy kondensator prąd nie płynie więc i spadek napięcia na opornikach jest zerowy. Niezależnie jakie oporniki wstawisz i tak komparatory zobaczą 5V i działać nie będą. C15 musi być podłączony wprost do ich wejść a R3 wprost do masy.

3. Czy używając typów int wiesz jakiej są one prawdziwej długości w kodzie wynikowym? W AVR GCC pewnie są 16-bitowe a to oznacza, że procesor 8-bitowy nie umie manipulować nimi w jednym strzale. O ile inkrementacje i dekrementacje robisz w przerwaniach więc to nie ma znaczenia i bo z definicji są to wtedy operacje atomowe (niepodzielne), o tyle pobranie do wypisania już nie. Zastanów się co się stanie gdy procesor już pobrał z pamięci pierwszy bajt zmiennej encoder_R a jeszcze nie wziął drugiego i przyjdzie przerwanie od enkodera zmieniające jej zawartość. Jeżeli będzie to operacja zmieniająca starszy bajt, leżysz. Wypisana zostanie jakaś niepoprawna wartość, przemyśl to. Wszelki dostęp do takich obiektów musi odbywać się atomowo. Ponieważ nie warto (i nie wolno) wyłączać przerwań na całe wypisywanie zmiennej, trzeba pomóc sobie dodatkową zmienną, której przerwanie nie dotyka:

 int volatile tmp;
cli()
tmp=encoder_R;
sei()
UART_putstr(" wynik ");
UART_putint(tmp);
UART_putstr("\n");

Żaby nie zaśmiecać kodu wstawkami cli/sei możesz napisać prostą funkcję, która w sposób atomowy czyta lub pisze do wskazanej, takiej "niebezpiecznej" zmiennej, np:

int get_atomic(int* object_ptr)
{
  int tmp;
  cli();
  tmp = *object_ptr;
  sei();
  return(tmp);
}

a potem w programie:

UART_putint(get_atomic(&encoder_R));

Kapujesz?

Link do komentarza
Share on other sites

1. Ma Pan rację z tym sprawdzeniem diodami. Jakoś nie wpadłem na pomysł, aby to w taki prosty sposób przetestować. Cały czas zastanawiałem się nad oscyloskopem, ale niestety go nie posiadam. Zastosowałem się do zaleceń producenta, że jak się nie ma oscyloskopu to optymalną odległością łopatek od czujników jest 0,5 mm i taką odległość zastosowałem.

2. Nie wiem czy dobrze zrozumiałem, ale chodzi Panu o coś takiego ?

3. Wydaje mi się, że sens całości zrozumiałem 😃

Zaraz postaram się zastosować do wskazówek i zobaczymy jak będzie 😉

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

🙂

A teraz opisz jak wyszły eksperymenty z wyświetlaniem na diodkach sygnałów z enkodera.

Pamiętaj, że to dopiero początek testów. Użyłeś komparatorów w najbardziej prymitywny sposób w jaki można sobie wyobrazić. W przypadku prostego wykrywania stanu to by zadziałało, ale gdy procesor ma liczyć zbocza możesz mieć problemy. Przejście napięcia z enkodera przez obszar aktywnej pracy komparatora (czyli przez okolicę napięcia odniesienia podawanego z dzielnika) będzie powodowało wiele wahnięć napięcia na pinie procesora i wiele przerwań. Moim zdaniem bez wprowadzenia histerezy się nie obejdzie. Przecież na sygnały z czujników optycznych będzie nałożonych mnóstwo śmieci, choćby pochodzących ze sztucznego oświetlenia w pomieszczeniu i nigdy nie będzie to przejście monotoniczne.

Tak więc następnym testem (bezoscyloskopowym) powinno być napisanie prostego programu wciągającego sygnał z jednego wejścia (np. PE4), czysto programowo wykrywającego zbocza i liczącego je. Jeśli przy wolnym obracaniu kółkiem zamiast spodziewanych np. 10 zliczeń dostaniesz 100 lub 1000, masz problem. Co prawda sama idea używania enkodera kwadraturowego i algorytm jego obsługi powinny być odporne na takie zjawiska, ale nawarstwianie się takiej ilości niepotrzebnych przerwań będzie bolesne dla procesora. I ciągle będziesz wiedział, że coś w sprzęcie jest nie tak - a to chyba nawet gorsze...

Czekam na wyniki.

Link do komentarza
Share on other sites

Ja ze swojej strony mogę dodać sugestię rzetelnego przećwiczenia jakiegoś kursu elektroniki. Tworzenie układów elektronicznych to nie jest zabawa w zgadywanie (vide 3x błędne podłączenie kondensatora w dzielniku).

Link do komentarza
Share on other sites

marek1707

Stwierdziłem, ze nie będę jak na razie testował obu enkoderów, zacznę od jednego. Podłączyłem do wyjść komparatora 2 diody.

Kręcąc w jedną stronę: L1 zgaszona, L2 zgaszona | L1 zgaszona, L2 zapalona | L1 zapalona, L2 zgaszona

Kręcąc w przeciwną: L1 zgaszona, L2 zgaszona | L1 zapalona, L2 zgaszona | L1 zgaszona, L2 zapalona

Ma Pan rację, ze światło trochę wpływa na działanie, ale jak już wszystko będzie działało przy nie zmieniającym się oświetleniu a w zmieniającym będą błędy to mam zamiar osłonić te enkodery aby pracowały w ciemności 🙂

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.