Skocz do zawartości

Silnik DC z enkoderem i Arduino - błędne wartości impulsów


Pomocna odpowiedź

Cześć wszystkim.

Otóż mam problem z impulsami (a  dokładniej z ich odczytem, tudzież wyliczeniem). Chodzi o to, że kupiłem kiedyś dwie sztuki silników JGB37-520 z  enkoderem, który ma 11 impulsów na obrót wału silnika na pojedynczym kanale. Ten enkoder ma dwa czujniki Halla i tak jak pisałem wyżej 11 imp. jest dla jednego czujnika. Sam silnik ponoć ma przełożenie 90:1 i 70RPM przy 6V i własnie coś tutaj mi nie gra. Ponieważ po przeliczeniu tych danych dla mojego silnika PPR (Pulses Per Revolution) wynoszą 11x90 = 990 (ewentualnie 22x90=1980).

W Arduino IDE odczytuje sygnały z dwóch czujników Halla (sygnały A i B) i na jeden obrót wału silnika zliczone impulsy to 22 -> czyli 11x2 i w serial monitorze odczytuje wartość impulsów na jeden obrót wału wyjściowego z przekładni i mam wynik ~1236 imp./obrót.Więc ten wynik (1236) nie jest równy wyliczeniom z "dokumentacji" mojego silnika. Nie wiem co jest grane, wydaje mi się, że albo silnik nie ma przełożenia 90:1 albo chochlik siedzi gdzieś indziej. Jedno jest pewne - na jeden czujnik Halla przypada 11 impulsów na obrót wału silnika. Robiłem też test odczytu tylko kanału A mojego enkodera i wynik na serial monitorze miałem ~ 618 (połowa 1236, ponieważ odczyt tylko z jednego kanału).

Myślę, że to już wszystkie dane. Mam nadzieję, że uda się rozwiązać problem.
Podaje link do tabeli silnika.

 

Edit:

Zrobiłem prosty test polegający na wyliczeniu RPM za pomocą odczytu jednego kanału enkodera (moje stałe to PPR = 990 -> 11x90 -> gear ratio 90:1)
Z obliczeń wyszło mi coś takiego - przykładowe wartości z serial monitora:

1788 pulse / 990 pulse per rotation x 60 seconds = 108 RPM
1787 pulse / 990 pulse per rotation x 60 seconds = 108 RPM
1783 pulse / 990 pulse per rotation x 60 seconds = 108 RPM

Wynik to 108 RPM przy 12V,  z kolei przy 6V mam 30 RPM..., a powinno być 70 RPM.

Edytowano przez aixI
Link to post
Share on other sites

Proponuję zmierzyć dokładnie ilość tych impulsów na jeden obrót i tą wartość stosować jako stałą odniesienia. Być może Twoje przełożenie jest nieco inne niż to podane w dokumentacji, może to jakiś inny typ silnika lub enkodera. Spróbuj ustalić ilość impulsów na każdym kanale dla jednego obrotu to będziesz miał punk wyjścia dla dalszych obliczeń.

Wyniki powinny uwzględniać oba kanały jednocześnie.

Link to post
Share on other sites

Tak też zrobiłem i wyniki prezentują się następująco:

Odczyt tylko z pierwszego kanału enkodera: około 618 imp./obrót wału wyjściowego.
Odczyt tylko z drugiego kanału enkodera: około  618 imp./obrót wału wyjściowego.
Z kolei odczyt z dwóch kanałów enkodera jednocześnie daje wynik około 1236 imp./obrót wału wyjściowego.
Oczywiście te odczyty były robione najdokładniej jak mogłem. Po trzy razy dla jednego kanału i tak samo dla obydwu. Wyniki były za każdym razem prawie takie same. Wyjściowy wał posiada pewien luz.
A dla jednego obrotu wału silnika każdy kanał enkodera zlicza 11 impulsów.

 

Link to post
Share on other sites

Ponieważ nie widzimy ani Twojego układu ani programu to pozostaje tylko wierzyć, że wszystko czego nie opisałeś w szczegółach działa dobrze i powtarzalnie. Mam tu na myśli m.in: samo wykrywanie impulsów, ich zliczanie, wyświetlanie, brak zbędnych opóźnień czy poziomy napięć i stromość zboczy. Radziłbym na wszelki wypadek upewnić się, że te wszystkie rzeczy są OK. Prostym testem jest spowolnienie (bo także nic nie napisałeś o warunkach pomiarów: czy silnik obracałeś powoli ręką, czy dawałeś mu jakieś napięcie, jakie i jak szybko obracał się, mniej więcej, jego wał licząc w imp/s) obrotów tak, by nawet kiepsko napisany program zdążył ze zliczaniem. Druga sprawa to wykrywanie samych zboczy. Po to enkoder ma dwa wyjścia kwadraturowe byś nie musiał martwić się o zjawiska odbić i wielokrotnych zliczeń na progach. Jeżeli bierzesz pod uwagę tylko jedno wyjście - a wygląda że traktujesz pracę jedno- i dwukanałową zupełnie zamiennie - to możesz się bardzo naciąć. Algorytm detekcji zdarzeń enkodera kwadraturowego jest dużo bardziej wyrafinowany niż zwykłe zliczanie impulsów i warto o tym wiedzieć i to zaimplementować w programie - o tym także nic nie napisałeś.

Oczywiście zawsze istnieje szansa, że przełożenie mechaniczne rzeczywiście jest inne niż zakładałeś, ale ja bym tak łatwo się nie poddawał i jednak zrobił pomiary najlepiej jak można.

EDIT: Czy przełożenie jakie wychodzi z Twoich obliczeń jest zgodne z którymś oferowanym dla tej serii silników/porzekładni?

Edytowano przez marek1707
Link to post
Share on other sites

Witaj Marku 🙂 Oczywiście nie chcę się poddać.

Już odpowiadam. Nie widzicie mojego układu, ponieważ jest to (wydaje mi się) prosty układ połączeń silnik+enkoder+Arduino Nano. Wyjścia enkodera (kanały A,B) podłączone mam do pinów Arduino, na których mogę zliczać impulsy - są to D2 oraz D3 (INT0, INT1). Sam enkoder zasilam napięciem 5V, a silnik 12V.
Co do samych pomiarów jakie wykonywałem, za obrót wału silnika stanowił mój palec, którym wprawiałem w ruch magnes enkodera, który osadzony jest na wale silnika. Z drugiej strony mam wał wyjściowy z przekładni a na nim zamocowane koło i wycięty z taśmy izolacyjnej wskaźnik oraz kartkę. na której zaznaczyłem krzyżyk, aby mieć jakiś punkt odniesienia.

Wrzucam też kod, w którym zliczam tylko impulsy i wysyłam ja na serial monitor, nic więcej.

 

/*
*    Red Wire - positive power supply of motor(+)(change positive and negative of motor the rotation will change)
*  White Wire - negative power supply of motor(-)(change positive and negative of motor the rotation will change))
* Yellow Wire - signal feedback (motor one turn has 11 signals)
*  Green Wire - signal feedback (motor one turn has 11 signals)
*   Blue Wire - positive of encoder power supply(+)(3.3-5V)
*  Black Wire - negative of encoder power supply(-)(3.3-5V)
*/


#define aPin 2  // Pin D2 INT0
#define bPin 3  // Pin D3 INT1

unsigned long lastTimer, timer = 0;

int counter = 0;

// Loop interval
int interval = 25;

void setup() {
  Serial.begin(115200);
  pinMode(aPin, INPUT_PULLUP);
  pinMode(bPin, INPUT_PULLUP);

  // Setting up interrupt
  attachInterrupt(digitalPinToInterrupt(aPin), ai0, RISING);
  attachInterrupt(digitalPinToInterrupt(bPin), ai1, RISING);
}

// Reading quadrature encoder
void ai0() {
  if(digitalRead(bPin)==LOW)
    counter++;
  else
    counter--;
}

void ai1() {
  if(digitalRead(aPin)==LOW)
    counter--;
  else
    counter++;
}

void loop() {
  timer = millis();

  // Main loop function
  if(timer - lastTimer > interval) {

    // Print (Serial monitor)
    Serial.print(counter);
    Serial.print(" pulses");
    
    lastTimer = timer;
  }
}

 

Oraz przykładowy wynik - koło zamocowane na wale wyjściowym zakręcone ręką w jedną i w drugą stronę.

0 pulses
0 pulses
0 pulses
0 pulses
0 pulses
0 pulses
1 pulses
2 pulses
2 pulses
5 pulses
8 pulses
12 pulses
18 pulses
24 pulses
32 pulses
41 pulses
51 pulses
62 pulses
73 pulses
86 pulses
98 pulses
112 pulses
127 pulses
142 pulses
156 pulses
171 pulses
186 pulses
200 pulses
214 pulses
228 pulses
242 pulses
256 pulses
269 pulses
282 pulses
296 pulses
310 pulses
322 pulses
335 pulses
347 pulses
360 pulses
372 pulses
384 pulses
397 pulses
410 pulses
424 pulses
438 pulses
452 pulses
468 pulses
482 pulses
498 pulses
514 pulses
529 pulses
545 pulses
560 pulses
576 pulses
593 pulses
609 pulses
626 pulses
642 pulses
658 pulses
675 pulses
691 pulses
706 pulses
722 pulses
734 pulses
747 pulses
758 pulses
768 pulses
776 pulses
784 pulses
792 pulses
798 pulses
802 pulses
806 pulses
809 pulses
812 pulses
812 pulses
810 pulses
810 pulses
810 pulses
810 pulses
810 pulses
810 pulses
810 pulses
808 pulses
808 pulses
806 pulses
804 pulses
801 pulses
798 pulses
795 pulses
792 pulses
789 pulses
786 pulses
782 pulses
780 pulses
776 pulses
774 pulses
770 pulses
768 pulses
765 pulses
762 pulses
760 pulses
757 pulses
754 pulses
752 pulses
750 pulses
748 pulses
745 pulses
742 pulses
740 pulses
736 pulses
732 pulses
728 pulses
724 pulses
719 pulses
714 pulses
708 pulses
704 pulses
698 pulses
692 pulses
684 pulses
678 pulses
670 pulses
662 pulses
654 pulses
646 pulses
640 pulses
634 pulses
629 pulses
626 pulses
624 pulses
622 pulses
622 pulses
622 pulses
622 pulses
622 pulses
622 pulses
620 pulses
618 pulses
612 pulses
607 pulses
598 pulses
588 pulses
576 pulses
562 pulses
545 pulses
526 pulses
507 pulses
486 pulses
464 pulses
442 pulses
421 pulses
402 pulses
384 pulses
367 pulses
352 pulses
336 pulses
322 pulses
310 pulses
298 pulses
288 pulses
278 pulses
266 pulses
252 pulses
236 pulses
219 pulses
200 pulses
178 pulses
156 pulses
133 pulses
110 pulses
89 pulses
65 pulses
45 pulses
24 pulses
6 pulses
-12 pulses
-28 pulses
-45 pulses
-60 pulses
-74 pulses
-86 pulses
-98 pulses
-110 pulses
-122 pulses
-136 pulses
-150 pulses
-166 pulses
-182 pulses
-200 pulses
-218 pulses
-236 pulses
-254 pulses
-272 pulses
-288 pulses
-304 pulses
-318 pulses
-332 pulses
-344 pulses
-356 pulses
-366 pulses
-376 pulses
-384 pulses
-392 pulses
-399 pulses
-405 pulses
-411 pulses
-415 pulses
-419 pulses
-422 pulses
-425 pulses
-425 pulses
-425 pulses
-425 pulses
-425 pulses
-425 pulses
-425 pulses

 

42 minuty temu, marek1707 napisał:

EDIT: Czy przełożenie jakie wychodzi z Twoich obliczeń jest zgodne z którymś oferowanym dla tej serii silników/porzekładni?

Przy 12V było coś około 108RPM. Ale nie jestem w 100-u% pewny, że dobrze to "zbadałem".

Link to post
Share on other sites

Zabawa z enkoderami to pozornie łatwa sprawa jakby się wydawało. Sprawdzałem dalej, to co mi nie grało, czyli ilość impulsów na obrót koła oraz prędkość obrotu koła na minutę (po obliczeniu z dokumentacji silnika) i po moich testach wraz z Arduino.

W każdym razie z moich testów wynika, że te silniki jakie mam są z przekładnią 56:1 (a nie 90:1), ponieważ przy 12V i 11-u sygnałach z jednego kanału enkodera na jeden pełny obrót wału silnika przypada mi ~616/618 impulsów - na jeden pełny obrót koła (56 x 11 = 616 według obliczeń). Przy czym dostaje ~170/172 RPM, co jest zbliżone w dokumentacji silnika (podają 56:1 @ 12V - 178RPM). Z kolei przy 6V dostaję wynik ~85RPM, kiedy w dokumentacji podają 100RPM.

Z jednej strony nie wiem, co dalej o tym myśleć. Z jednej wygląda dobrze, zaś z drugiej coś nadal jest nie do końca jasne.

Poza tym mam parę wątpliwości..
1. Kiedy posiadam silnik DC i sparowany z nim enkoder kwadraturowy, który posiada dwa wyjścia A i B przesunięte względem siebie o 90°, to mogę wiedzieć, w którą stronę obraca się silnik/koło, czy w prawo, czy w lewo. Ale jaki jest sposób odczytu z takiego enkodera? Czy (załóżmy mam 11 impulsów na każde wyjście), kiedy chce się dowiedzieć, w którą stronę obraca się silnik, to muszę robić pomiar nie z jednego kanału, tylko z dwóch, prawda? Aby, np. dostać wynik ze znakiem + i -. Tylko jak robię pomiary z dwóch kanałów, to czy te 11 impulsów jest stałe dla jednego enkodera/silnika? czy wtedy mam 22 impulsy łącznie? Co za tym idzie łączna wartość impulsów na obrót koła będzie 2x większa?

 

(test @ 12V)
PULSES: 1781	 SPEED: 172 RPM
PULSES: 1781	 SPEED: 172 RPM
PULSES: 1783	 SPEED: 173 RPM
PULSES: 1780	 SPEED: 172 RPM
PULSES: 1784	 SPEED: 173 RPM
PULSES: 1784	 SPEED: 173 RPM
PULSES: 1783	 SPEED: 173 RPM
PULSES: 1783	 SPEED: 173 RPM
PULSES: 1786	 SPEED: 173 RPM
PULSES: 1782	 SPEED: 173 RPM
PULSES: 1783	 SPEED: 173 RPM
PULSES: 1785	 SPEED: 173 RPM
PULSES: 1782	 SPEED: 173 RPM
(test @ 6V)
PULSES: 887	 SPEED: 86 RPM
PULSES: 883	 SPEED: 85 RPM
PULSES: 887	 SPEED: 86 RPM
PULSES: 889	 SPEED: 86 RPM
PULSES: 890	 SPEED: 86 RPM
PULSES: 890	 SPEED: 86 RPM
PULSES: 889	 SPEED: 86 RPM
PULSES: 887	 SPEED: 86 RPM
PULSES: 886	 SPEED: 86 RPM
PULSES: 892	 SPEED: 86 RPM
PULSES: 899	 SPEED: 87 RPM
PULSES: 891	 SPEED: 86 RPM
PULSES: 879	 SPEED: 85 RPM

Oraz kod, na którym testowałem.

// Motor encoder output pulse per rotation
#define ENC_COUNT_REV 618 // 616
 
// Encoder output to Arduino Interrupt pin
#define ENC_IN 3 
 
// Pulse count from encoder
volatile long encoderValue = 0;
 
// One-second interval for measurements
int interval = 1000;
 
// Counters for milliseconds during interval
long previousMillis = 0;
long currentMillis = 0;
 
// Variable for RPM measuerment
int rpm = 0;
 
void setup() {
  // Setup Serial Monitor
  Serial.begin(9600); 
  
  // Set encoder as input with internal pullup  
  pinMode(ENC_IN, INPUT_PULLUP); 
  
  // Attach interrupt 
  attachInterrupt(digitalPinToInterrupt(ENC_IN), updateEncoder, RISING);
  
  // Setup initial values for timer
  previousMillis = millis();
}
 
void loop() {
  
  // Update RPM value every second
  currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
 
 
    // Calculate RPM
    rpm = (float)(encoderValue * 60 / ENC_COUNT_REV);

      Serial.print("PULSES: ");
      Serial.print(encoderValue);
      Serial.print('\t');
      Serial.print(" SPEED: ");
      Serial.print(rpm);
      Serial.println(" RPM");
    
    encoderValue = 0;
  }
}
 
void updateEncoder() {
  // Increment value for each pulse from encoder
  encoderValue++;
}

 

Link to post
Share on other sites

A nie przyszło Ci do głowy, że skoro enkoder ma 2 wyjścia A i B to może dobrze by było podłączyć go do dwóch pinów w arduino i na tej podstawie sprawdzać w którą stronę się kręci silnik?

Link to post
Share on other sites

@atMegaTona czemu zakładasz, że nie przyszło mi to do głowy? Przyszło i to nawet sprawdzałem, z tym że w tym samym momencie miałem "ogólny" problem ze zliczaniem impulsów. Ja pytałem Was jaki jest sposób odczytu. Czy podpinać taki enkoder z dwoma wyjściami do dwóch różnych pinów obsługujących przerwania, czy tylko jedno wyjście do pinu obsługującego przerwania, a drugie wyjście do normalnego pinu cyfrowego? Czy jeszcze jakoś inaczej?

W tym momencie mam podłączone jedno wyjście enkodera do pinu D2 - INT0 obsługującego przerwania, a drugie wyjście do zwykłego pinu cyfrowego - D7 - czy taki pomiar impulsów, przy takim podłączeniu jest poprawny? Z moich pomiarów wynika, że tak (wyniki mam praktycznie takie same jak w moim pierwszym poście). No chyba, że można to robić inaczej.

Na serial monitorze teraz dostaje wyniki ze znakiem + i -, kręcąc kołem w jedną lub drugą stronę. Jeden obrót wału silnika daje mi 22 impulsy. W tym momencie testuje tylko jeden silnik z enkoderem, stąd definicje w programie: ENCODER_1_A i ENCODER_1_B -> enkoder pierwszego silnika, kanały A i B.

Podsyłam kod:

#include <Wire.h>

#define ENCODER_1_A 2 // D2 INT0
#define ENCODER_1_B 7 // D7

volatile long counter = 0;

// interval for measurements
int interval = 25;

// Counters for milliseconds during interval
long previousMillis = 0;
long currentMillis = 0;

void setup() {
  // Setup Serial Monitor
  Serial.begin(115200);

  pinMode(ENCODER_1_A, INPUT_PULLUP);
  pinMode(ENCODER_1_B, INPUT_PULLUP);

  // Attach interrupt 
  attachInterrupt(digitalPinToInterrupt(ENCODER_1_A), readEncoder, CHANGE); // Syntax: attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)

  // Setup initial values for timer
  previousMillis = millis();
}

void loop() {
  currentMillis = millis();
    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      
      Serial.print("Position: ");
      Serial.println(counter, DEC);
    }
}

void readEncoder() {
  if (digitalRead(ENCODER_1_A) == HIGH) { // found a low-to-high on channel A
    if (digitalRead(ENCODER_1_B) == LOW)  // check channel B to see which way
        counter++;
    else
        counter--;
  } else {                                // found a high-to-low on channel A
    if (digitalRead(ENCODER_1_B) == LOW)  // check channel B to see which way
        counter--;
    else
        counter++;
  }
}

 

Link to post
Share on other sites
32 minuty temu, aixI napisał:

czy taki pomiar impulsów, przy takim podłączeniu jest poprawny?

Tak i nie.

Tak - bo prawidłowo odczytujesz kierunek z pinu B.

Nie - bo nie powinieneś mieć CHANGE tylko RISING (albo FALLING) w attachInterrupt (nie potrzebujesz czytania pinu A w przerwaniu).

Ewentualnie:

Tak - bo masz prawidłowe parametry w attachInterrupt

Nie - bo jeśli liczysz połówki impulsu kierunek zależy zarówno od stanu B jak i od A.

I jeszcze jedno: to że zmienna counter ma atrybut volatile (prawidłowo) nie oznacza wcale, że jej wartość będzie prawidłowa w println. Musisz zadbać o to, aby jej wartość nie mogła się zmienić w czasie pobierania jej wartości w loop() (wyłączenie przerwań, blok ATOMIC, no i jakaś zmienna pomocnicza).

Edytowano przez ethanak
Link to post
Share on other sites

@ethanak dzięki za odpowiedź. Zmieniłem trochę obecny program, dodałem obsługę przerwania dla drugiego wyjścia enkodera, który jest podpięty do pinu D3 (a nie do pinu D7 jak to było przedtem). Od razu go wrzuciłem na Arduino i włączyłem monitor szeregowy i odczytywałem wartości, tak jak wcześniej dostaje 22 impulsy na jeden obrót wału silnika.

1 godzinę temu, ethanak napisał:

I jeszcze jedno: to że zmienna counter ma atrybut volatile (prawidłowo) nie oznacza wcale, że jej wartość będzie prawidłowa w println. Musisz zadbać o to, aby jej wartość nie mogła się zmienić w czasie pobierania jej wartości w loop() (wyłączenie przerwań, blok ATOMIC, no i jakaś zmienna pomocnicza).

Chodzi o to, aby podczas pobierania jej wartości wyłączyć globalne zezwolenie na przerwania "cli()", a później włączyć zezwolenie na globalne przerwania "sei()"? 
Teraz nawet w funkcji "setup()" nie włączam globalnego zezwolenia na przerwania i chyba jest to błędem, tak?
Bloku ATOMIC nigdy nie używałem - coś o tym kiedyś słyszałem, ale nie wiem jak z tego korzystać.

Obecny program:

#include <Wire.h>

// Encoder 1 output A, B to Arduino Interrupt pin 2, 3
#define ENCODER_1_A 2 // D2 INT0
#define ENCODER_1_B 3 // D3 INT1

volatile long counter = 0;

// interval for measurements
int interval = 25;

// Counters for milliseconds during interval
long previousMillis = 0;
long currentMillis = 0;

void setup() {
  // Setup Serial Monitor
  Serial.begin(115200);

  pinMode(ENCODER_1_A, INPUT_PULLUP);
  pinMode(ENCODER_1_B, INPUT_PULLUP);

  // Attach interrupt - Syntax: attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)
  attachInterrupt(digitalPinToInterrupt(ENCODER_1_A), readEncoder0, RISING);
  attachInterrupt(digitalPinToInterrupt(ENCODER_1_B), readEncoder1, RISING);

  // Setup initial values for timer
  previousMillis = millis();
}

void loop() {
  currentMillis = millis();
    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      
      Serial.print("Position: ");
      Serial.println(counter, DEC);
    }
}

void readEncoder0() {
  if (digitalRead(ENCODER_1_B) == LOW)
    counter++;
  else
    counter--;
}

void readEncoder1() {
  if (digitalRead(ENCODER_1_A) == LOW)
    counter--;
  else
    counter++;
}

 

Link to post
Share on other sites
32 minuty temu, aixI napisał:

dodałem obsługę przerwania dla drugiego wyjścia enkodera, który jest podpięty do pinu D3

W jakim celu? Potrzebujesz aż takiej dokładności? No to jeszcze możesz ją podwoić (jako ćwiczenie napisz sobie program który to robi). A drugi enkoder od drugiego silnika to podłączysz do drugiego Arduino?

( @atMegaTona wiem co chcesz powiedzieć ale poczekaj, zobaczymy co kolega wymyśli).

35 minut temu, aixI napisał:

Chodzi o to, aby podczas pobierania jej wartości wyłączyć globalne zezwolenie na przerwania "cli()", a później włączyć zezwolenie na globalne przerwania "sei()"? 

Tak.

35 minut temu, aixI napisał:

Teraz nawet w funkcji "setup()" nie włączam globalnego zezwolenia na przerwania i chyba jest to błędem, tak?

I tak są włączone - przecież gdyby nie były to Twój program by nie działał, prawda? Gdybyś programował w czystym C/C++ to musiałbyś gdzieś na początku main() to włączyć - a prolog w Arduino robi to za Ciebie. I nie, nie jest błędem korzystanie z tego co daje Arduino IDE i jego biblioteki.

35 minut temu, aixI napisał:

Bloku ATOMIC nigdy nie używałem - coś o tym kiedyś słyszałem, ale nie wiem jak z tego korzystać.

Spróbuj - dobra rzecz 🙂

A tu masz opis: https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html

Tak przy okazji... nie dalej jak parę dni temu pisałem o przerwaniach, blokowaniu, o ATOMIC, nawet się tu z jednym kolegą pokłóciliśmy... ale nie, po co czytać inne wątki, przecież tam na pewno nic ciekawego nie ma, prawda?

 

Link to post
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

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • 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.