Skocz do zawartości

FlyingDutch

Użytkownicy
  • Zawartość

    521
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    21

Wszystko napisane przez FlyingDutch

  1. Cześć, ostatnio dość dużo się mówi (także na Forbot.pl) o nowej otwartej architekturze RISC-V. Pojawia się coraz więcej różnych zestawów uruchomieniowych z tą architekturą. Oto kolejny przykład: Lichee Tang : https://www.banggood.com/Lichee-Tang-64Mbit-SDRAM-Onboard-FPGA-Downloader-Dual-Flash-RISC-V-Development-Board-p-1352386.html?rmmds=myorder&cur_warehouse=CN Właściwie to nie byłem zdecydowany w jakim dziale umieścić ten post, ale stwierdziłem, że najbardziej pasuje do tego działu. Skąd ta trudność w klasyfikacji: otóż jest to dość duży układ FPGA około 20 K logic units. Oparty na chipie FPGA - EG4S20 firmy Anlogic. Na tym układzie FPGA jest zaimplementowany jako soft-Core (podobnie jak opisywane Picoblaze, Microblaze, czy NIOSII) dwurdzieniowy CPU o architekturze RISC-V. Tutaj kilka linków dot. tej płytki: https://www.cnx-software.com/2018/09/04/licheetang-anlogic-eg4s20-fpga-board-targets-risc-v-development/ https://www.cnx-software.com/tag/anlogic/ https://www.elektroda.pl/rtvforum/topic3496915.html Zamówiłem tą płytkę, jak dotrze (pewnie około miesiąca) i będę miał chwilę wolnego czasu to podzielę się wrażeniami z uruchomienia. jedyne czego się obawiam to brak porządnej dokumentacji. Pozdrawiam BTW: zamieszczam jeszcze linki do dokładniejszego opisu i środowiska (IDE) do programowania układu: http://myosuploads3.banggood.com/products/20181113/20181113213840SipeedlicheeTangSpecificationsV1.0.pdf https://github.com/Lichee-Pi/Tang_E203_Mini Jeśli ktoś ma więcej informacji o tym zestawie to niech się podzieli nimi - z chęcią się zapoznam
  2. FlyingDutch

    LicheeTang Anlogic EG4S20 FPGA Board (RISC-V)

    Cześć Elvis, ja chciałbym jednak zacząć z tą płytką "LicheeTang Anlogic". Może natknąłeś się na miejsce w sieci gdzie można kupić te dedykowane programator JTAG dla "RISC-V". A może wiesz jaki typ programatora JTAG można użyć zastępczo (ktoś napisał w komentarzu, że ten dedykowany programator nie jest oparty na FTDI FT232, ale nie wiem, czy to prawda). Pozdrawiam
  3. Cześć, w pracy rozwijam (aktywny development) system oparty na MCU STM32F103VGTx. Jest to skomplikowany system embedded (trzy rodzaje modułów każdy ze wspomnianym MCU). Składa się z modułów sterujących i wykonawczych (te można łączyć szeregowo za pomocą magistrali CAN - do 6-ciu modułów). System (wprowadzanie danych ) może być sterowany w następujące sposoby: 1) 10-cio calowy monitor z interfejsem dotykowym 2) Dedykowane pulpity sterujące wytwarzane w firmie 3) Smartfon lub tablet z Androidem (komunikacja po Bluetooth) Wykorzystywane są w nim interfejsy komunikacyjne: CAN, SPI, RS485, RS422, Modbus RTU (po RS485), Bluetooth. Podstawowe moduły systemu powstały jako grant badawczy na UTP w Bydgoszczy (około 40% kodu). System jest napisany w nieobiektowym C z użyciem "Standard Peripheral Library". Cały czas są dodawane nowe funkcjonalności do systemu (dość skomplikowane) - około 60% kodu jest napisany przeze mnie (także w kilku miejscach "corowe" funkcjonalności). Niestety doszedłem do takiego etapu, gdzie dodanie nowych funkcjonalności powoduje czasami błędy w innych miejscach systemu. Doszedłem do wniosku, że jest najwyższy czas, aby objąć część kodu testami automatycznymi (Unit tests). Dotychczas w pracy zawodowej korzystałem z framework'ów do testów automatycznych dla języków Java (Junit) oraz C# (NUnit), natomiast nie mam doświadczenia z podobnymi rozwiązaniami dla języka C/C++. Zależałoby mi na rozwiązaniu które oferowałoby następujące opcje: 1) Możliwość zdefiniowania testów jednostkowych, oraz grup takich testów 2) Miałoby sensownie zdefiniowany zbiór asercji 3) Pozwalałoby wykonywać poszczególne testy lub grupy testów 4) Prezentowałoby (najlepiej także w sposób graficzny) wyniki przeprowadzonych testów Jako dodatkowe funkcje (im więcej z tych funkcji spełnia tym lepiej) oferowałoby co nastepuje: 1) Analiza statyczna kodu w C/C++ 2) Ocena zgodności kodu ze Standardem "MISRA C" 3) Ocena zgodności ze standardami bezpieczeństwa innych organizacji np. IEC 61508, ISO 26262 itp Do developmentu używam komercyjnej wersji IDE, kompilatora: "Ride7" + "RKit-ARM" firmy Raisonace . Wybór narzędzi programowych został dokonany wcześniej przez osoby które pisały "podwaliny" systemu, ale nie narzekam, bo dobrze mi się pracuje z tymi firmy Raisonance. Jak wspomniałem kod jest napisany w języku C (nie C++). Szukając narzędzia do automatyzacji testów dla języka C/C++ znalazłem w sieci Framework "Cantata": https://www.qa-systems.com/tools/cantata/ Jest to komercyjny system do automatyzacji testów dla języka C/C++ i ma budowę modułową. Spełnia (przynajmniej w teorii) wszystkie moje wymagania co do takiego systemu, niestety cena jest tak zaporowa, że mojej firmy nie będzie raczej stać na jego kupno. Przeglądałem stronę Wikipedii z listą takich frameworków open-source: https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C ale nie miałem z nimi doświadczenia. Może ktoś korzystał z niektórych z nich i może się podzielić doświadczeniami? Będę wdzięczny za opinie. BTW: jak na razie przyglądałem się trochę framework'om "Googletest" (Google) oraz "Boost" (IBM) ale z tego co zobaczyłem wynika, że oba są zorientowane raczej na kod w C++ a nie w C. Pozdrawiam
  4. FlyingDutch

    LicheeTang Anlogic EG4S20 FPGA Board (RISC-V)

    Cześć, właśnie kilka dni temu Chińczycy (ze skelpu Banggood.com) przysłali mi informację, że zamówiony przeze mnie jakiś miesiąc temu programator JTAG do "RISC-V" (płytka: LicheeTang Anlogic EG4S20 FPGA Board) nie jest już dostępny i oferują mi refundację kosztów. Niestety to znów opóźni moje próby z tym sprzętem. Spróbuję poszukać, czy ten programator można nabyć w innym miejscu. Pozdrawiam
  5. FlyingDutch

    Oscyloskop 2025CL dla hobbysty - czy warto?

    Cześć, nie mam doświadczenia z produktami tej konkretnej firmy, ale z opisu parametrów wygląda to nieźle, Ja bym się chyba na niego zdecydował. Poszukaj jeszcze w sieci jakich opinii o tym konkretnym modelu. Pozdrawiam
  6. FlyingDutch

    Instalacja Linux Mint 19.1 na laptopie "MSI GV62"

    Cześć Elvis, oczywiście instalacja nowego jądra (czy kompilacja), nie stanowi większego problemu Jednak człowiek, gdy robi się starszy to też zmienia nawyki.Podam przykład: od początku 2003 do połowy 2007 roku używałem zarówno w domu jak i w pracy (jako drugi OS) jedynie Gentoo Linux'a (żadnych innych distro). Wiesz doskonale ile czasu zajmowało utrzymanie tego systemu w dobrej kondycji przez długi czas , np. takie: emerge --update @world I chciało mi się. Teraz gdy jestem starszy zmieniłem podejście, uważam że Linux jest na tyle dojrzałym systemem, że powinien działać jak należy nawet z nowym sprzętem. I nie chce mi się kombinować z instalacją/ kompilacją nowego jądra (i walczyć później z zależnościami dla pakietów), o to powinni zadbać deweloperzy tej dystrybucji Linux'a (w Debianie jest jak należy, dało się). Jak mówi mój kierownik w pracy: "Ma działać, ma się nie psuć!" - i wydaje mi się, że to jest dobre podejście (dla mnie). Po drugie i najważniejsze po prostu nie mam na to czasu, musiałbym to zrobić kosztem innych zadań o większym priorytecie (chociaż oczywiście dobre przygotowanie sobie kompa do pracy to raczej priorytetowa sprawa - taki "paragraf 22"). Ale dobrze rozumiem twoje podejście i uważam je za rozsądne i bardzo dobre. Pozdrawiam
  7. Cześć, dostałem w pracy nowego laptopa firmy MSI (model GV62): https://www.x-kom.pl/p/448095-notebook-laptop-156-msi-gv62-i7-8750h-16gb-240-plus-1tb-gtx1050ti.html Z procesorem Intela ósmej generacji - i7-8750H (6 rdzeni fizycznych, 12 logicznych) i właśnie w związku z tym procesorem czekało mnie kilka niespodzianek: 1) okazało się, że Windows 7 PRO (64 bit) nie obsługuje procesorów Intela ósmej generacji (nie daje się uruchomić na tym procesorze) 2) w jądrze Linux'a Mint 19.1 Tessa LTS (Mate) jest jakiś błąd i ten procesor także nie jest obsługiwany poprawnie Tutaj zdjęcie laptopa: A tutaj zdjęcie z komunikatami błędów podczas ładowania z płytki DVD Minta 19.1 Mate: Jak widać na ekranie błąd był spowodowany przez Watchdog timer dla rdzenia nr. 2 - watchdog wykrywał zawieszenie tego procesora. Błąd tego typu trochę mnie zdziwił bo dotychczas nie miałem żadnych poważniejszych problemów z tą dystrybucją Na szczęście "Gentoo Linux" i najnowsza stabilna wersja "Debiana" (9.6.0) działają na tym laptopie bez błędów. Tak, że musiałem zainstalować na nowym laptopie Windows10 i Debiana 9.6.0. Mam zamiar przesłać opis błędów developerom Mint'a na forum dotyczącym tej dystrybucji Linux'a. Pozdrawiam
  8. FlyingDutch

    Instalacja Linux Mint 19.1 na laptopie "MSI GV62"

    Cześć Elvis, na to, że jest to problem spowodowany wersją jądra wpadłem. Tylko trochę, się rozczarowałem, że w najnowszej wersji Minta i to LTS jest starsze jądro Zainstalowałem już Debiana 9.6.0 i nie jestem pewien, czy chcę to teraz zmieniać. Dzięki za podpowiedź Pozdrawiam
  9. Cześć, temat wymaga trochę czasu, aby przeanalizować kod i dokumentację czujnika.Przebiegi na liniach SPI wyglądają (z grubsza na poprawne). Na szybko zrobił bym jedną rzecz - pomiędzy plus zasilania czujnika a masę dałbym kondensator 100 nF (jak najbliżej czujnika). Masy czujnika i zestawu uruchomieniowego połączone? Miałem identyczne objawy dla pamięci FRAM Fujitsu, gdy nie miałem kondensatora wygładzającego zasilanie blisko kostki pamięci - odczytywałem same zera. Więc tak na szybko zrobiłbym taką próbę. Pozdrawiam
  10. Cześć, jakiś czas temu zrobiłem próbę z pamięcią FRAM firmy Cypress typu: FM25L16B (Pamięć FRAM, szeregowa, 16Kb, 2Kbx8, interfejs SPI, obudowa SO8) z płytką "Arduino UNO". Link do postu tutaj: Docelowo potrzebowałem użyć tych pamięci w projekcie opartym na bibliotece SPL z MCU STM32F103VGTx. Pomimo poszukiwań w internecie nie znalazłem działającej biblioteki wykorzystującej ten typ pamięci z MCU STM32F103x i współpracującej z firmware STM32F1 opartym na "Standard Peripheral Library". Niestety "odziedziczyłem" część kodu dla systemu opartego na procesorach STM32F103 (kilka typów płytek połączonych magistralą CAN w jeden system) jako wynik grantu badawczego z UTP w moim mieście. System ten jest zbyt rozbudowany, żeby opłacało mi się przepisywać całość na HAL'a lub LL, zresztą nie widzę takiej potrzeby ponieważ kod jest dobrze napisany. Potrzebuję pamięci FRAM do rejestracji parametrów pracy systemu w długim czasie, oraz zapisu danych konfiguracyjnych. Właściwie to potrzebowałem obsłużyć dwa typy pamięci FRAM z interfejsem SPI różniących się pojemnościami - jedna 2Kx8bit, a druga 32Kx8bit (firm Cypress i Fujitsu : na jednym typie płytek jest mniejsza pamięć a na drugim ta o większej pojemności). Typy tych pamięci to: 1) FM25L16B firmy Cypress (2KB) 2) MB85RS256 firmy Fujitsu(32KB) Te dwa typy zostały wybrane ponieważ mają taką samą magistralę komunikacyjną SPI, zbliżone parametry elektryczne (także PINOUT i max. prędkość transmisji) oraz budowę programową (zgodność nawet co do kodów operacji). Tutaj wklejam datasheets dla tych dwóch typów pamięci: FM25L16B_FRAM_Cypress.pdf FRAM_MB85RS256fs.pdf Postanowiłem użyć jako punktu wyjścia biblioteki Adafruit do obsługi FRAM opisanej we wcześniejszym poście dot. Arduino. Ponieważ docelowe płytki projektu są bardzo skomplikowane, postanowiłem do prac nad wersją bibliotek dla STM32F103 (SPL) użyć zestawu uruchomieniowego STM32 NUCLEO-F103RB: https://botland.com.pl/pl/stm32-nucleo/2238-stm32-nucleo-f103rb-stm32f103rbt6-arm-cortex-m3.html Tutaj PINOUT dla tej płytki: Jako IDE i kompilator użyłem darmowego "System Workbench for STM32" (najnowsza wersja), pomocniczo używałem też aplikacji "STM32CubeMX" (najnowsza wersja) - OS Windows10. Ponieważ działająca wersja biblioteki dla FRAM Cypress była napisana obiktowo (klasa C++). Najpierw przerobiłem ten kod na wersję obiektową C++ dla podanego zestawu uruchomieniowego. Wybrałem SPI1 z STM32F103 - tutaj użyte piny: uint8_t FRAM_CS = 0; //port C - PC0 uint8_t FRAM_SCK = 5; //PA5 uint8_t FRAM_MISO = 6; //PA6 uint8_t FRAM_MOSI = 7; //PA7 Piny WP i HOLD (aktywne LOW) FRAM podpięte na stałe do VCC (+3,3V). Podaję kod biblioteki: 1) Adafruit_FRAM_SPI.h: #ifndef _ADAFRUIT_FRAM_SPI_H_ #define _ADAFRUIT_FRAM_SPI_H_ #include "stm32f1xx_it.h" #include "stm32f1xx_nucleo.h" #include "stm32f10x_conf.h" #include "stm32f10x_spi.h" #include <stdbool.h> typedef enum opcodes_e { OPCODE_WREN = 0b00000110, /* Write Enable Latch */ OPCODE_WRDI = 0b00000100, /* Reset Write Enable Latch */ OPCODE_RDSR = 0b00000101, /* Read Status Register */ OPCODE_WRSR = 0b00000001, /* Write Status Register */ OPCODE_READ = 0b00000011, /* Read Memory */ OPCODE_WRITE = 0b00000010, /* Write Memory */ OPCODE_RDID = 0b10011111 /* Read Device ID */ //Dla pamiÄ™ci FRAM firmy Cypress - niedostepne } opcodes_t; class Adafruit_FRAM_SPI { public: Adafruit_FRAM_SPI(); Adafruit_FRAM_SPI(int8_t cs); Adafruit_FRAM_SPI(int8_t clk, int8_t miso, int8_t mosi, int8_t cs); bool begin (); bool begin (uint8_t nAddressSizeBytes); bool begin (int8_t cs, uint8_t nAddressSizeBytes); void writeEnable (bool enable); void write8 (uint32_t addr, uint8_t value); void write (uint32_t addr, const uint8_t *values, size_t count); uint8_t read8 (uint32_t addr); void read (uint32_t addr, uint8_t *values, size_t count); void getDeviceID(uint8_t *manufacturerID, uint16_t *productID); uint8_t getStatusRegister(void); void setStatusRegister(uint8_t value); void setAddressSize(uint8_t nAddressSize); private: uint8_t SPItransfer(uint8_t x); void writeAddress(uint32_t addr); uint8_t spi_sendrecv(uint8_t byte); //Wyslij Odbierz dane po SPI void spiConfiguration(void); //Konfiguracja sprzetowa SPI bool _framInitialised; uint8_t _nAddressSizeBytes; int8_t _cs, _clk, _mosi, _miso; }; #endif 2) Adafruit_FRAM_SPI.cpp: #include <stdlib.h> #include <math.h> #include "Adafruit_FRAM_SPI.h" /*========================================================================*/ /* PRIVATE FUNCTIONS */ /*========================================================================*/ void Adafruit_FRAM_SPI::spiConfiguration(void) { GPIO_InitTypeDef gpio; SPI_InitTypeDef spi; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7; // SCK, MOSI gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_6; // MISO gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio); gpio.GPIO_Pin = GPIO_Pin_0; // CS gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &gpio); GPIO_SetBits(GPIOC, GPIO_Pin_0); SPI_StructInit(&spi); spi.SPI_Mode = SPI_Mode_Master; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; SPI_Init(SPI1, &spi); SPI_Cmd(SPI1, ENABLE); GPIO_ResetBits(GPIOC, GPIO_Pin_0); spi_sendrecv(0x40); GPIO_SetBits(GPIOC, GPIO_Pin_0); } /* OLD uint8_t Adafruit_FRAM_SPI::spi_sendrecv(uint8_t byte) { // poczekaj az bufor nadawczy bedzie wolny while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_SendData8(SPI1, byte); // poczekaj na dane w buforze odbiorczym while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_ReceiveData8(SPI1); } */ uint8_t Adafruit_FRAM_SPI::spi_sendrecv(uint8_t byte) { // poczekaj az bufor nadawczy bedzie wolny while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, byte); // poczekaj na dane w buforze odbiorczym while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); } /*========================================================================*/ /* CONSTRUCTORS */ /*========================================================================*/ /**************************************************************************/ /*! Constructor */ /**************************************************************************/ Adafruit_FRAM_SPI::Adafruit_FRAM_SPI() { _cs = _clk = _mosi = _miso = -1; _framInitialised = false; } Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t cs) { _cs = cs; _clk = _mosi = _miso = -1; _framInitialised = false; } Adafruit_FRAM_SPI::Adafruit_FRAM_SPI(int8_t clk, int8_t miso, int8_t mosi, int8_t cs) { _cs = cs; _clk = clk; _mosi = mosi; _miso = miso; _framInitialised = false; } /*========================================================================*/ /* PUBLIC FUNCTIONS */ /*========================================================================*/ /**************************************************************************/ /*! Initializes SPI and configures the chip (call this function before doing anything else) */ /**************************************************************************/ bool Adafruit_FRAM_SPI::begin() { return begin(_cs, 2); } bool Adafruit_FRAM_SPI::begin(uint8_t nAddressSizeBytes) { return begin(_cs, nAddressSizeBytes); } bool Adafruit_FRAM_SPI::begin(int8_t cs, uint8_t nAddressSizeBytes) { if (cs == -1) { //Serial.println("No cs pin specified!"); return false; } _cs = cs; setAddressSize(nAddressSizeBytes); /* Configure SPI */ // pinMode(_cs, OUTPUT); //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0); //CS this->spiConfiguration(); /* Everything seems to be properly initialised and connected */ _framInitialised = true; return true; } /**************************************************************************/ /*! @brief Enables or disables writing to the SPI flash @params[in] enable True enables writes, false disables writes */ /**************************************************************************/ void Adafruit_FRAM_SPI::writeEnable (bool enable) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS if (enable) { SPItransfer(OPCODE_WREN); } else { SPItransfer(OPCODE_WRDI); } //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Writes a byte at the specific FRAM address @params[in] addr The 32-bit address to write to in FRAM memory @params[in] i2cAddr The 8-bit value to write at framAddr */ /**************************************************************************/ void Adafruit_FRAM_SPI::write8 (uint32_t addr, uint8_t value) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_WRITE); writeAddress(addr); SPItransfer(value); /* CS on the rising edge commits the WRITE */ //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Writes count bytes starting at the specific FRAM address @params[in] addr The 32-bit address to write to in FRAM memory @params[in] values The pointer to an array of 8-bit values to write starting at addr @params[in] count The number of bytes to write */ /**************************************************************************/ void Adafruit_FRAM_SPI::write (uint32_t addr, const uint8_t *values, size_t count) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_WRITE); writeAddress(addr); for (size_t i = 0; i < count; i++) { SPItransfer(values[i]); } /* CS on the rising edge commits the WRITE */ //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Reads an 8 bit value from the specified FRAM address @params[in] addr The 32-bit address to read from in FRAM memory @returns The 8-bit value retrieved at framAddr */ /**************************************************************************/ uint8_t Adafruit_FRAM_SPI::read8 (uint32_t addr) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_READ); writeAddress(addr); uint8_t x = SPItransfer(0); //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS return x; } /**************************************************************************/ /*! @brief Read count bytes starting at the specific FRAM address @params[in] addr The 32-bit address to write to in FRAM memory @params[out] values The pointer to an array of 8-bit values to read starting at addr @params[in] count The number of bytes to read */ /**************************************************************************/ void Adafruit_FRAM_SPI::read (uint32_t addr, uint8_t *values, size_t count) { //digitalWrite(_cs, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_READ); writeAddress(addr); for (size_t i = 0; i < count; i++) { uint8_t x = SPItransfer(0); values[i] = x; } //digitalWrite(_cs, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } /**************************************************************************/ /*! @brief Reads the Manufacturer ID and the Product ID from the IC @params[out] manufacturerID The 8-bit manufacturer ID (Fujitsu = 0x04) @params[out] productID The memory density (bytes 15..8) and proprietary Product ID fields (bytes 7..0). Should be 0x0302 for the MB85RS64VPNF-G-JNERE1. */ /**************************************************************************/ void Adafruit_FRAM_SPI::getDeviceID(uint8_t *manufacturerID, uint16_t *productID) { uint8_t a[4] = { 0, 0, 0, 0 }; //uint8_t results; GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_RDID); a[0] = SPItransfer(0); a[1] = SPItransfer(0); a[2] = SPItransfer(0); a[3] = SPItransfer(0); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS /* Shift values to separate manuf and prod IDs */ /* See p.10 of http://www.fujitsu.com/downloads/MICRO/fsa/pdf/products/memory/fram/MB85RS64V-DS501-00015-4v0-E.pdf */ *manufacturerID = (a[0]); *productID = (a[2] << 8) + a[3]; } /**************************************************************************/ /*! @brief Reads the status register */ /**************************************************************************/ uint8_t Adafruit_FRAM_SPI::getStatusRegister(void) { uint8_t reg = 0; GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_RDSR); reg = SPItransfer(0); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS return reg; } /**************************************************************************/ /*! @brief Sets the status register */ /**************************************************************************/ void Adafruit_FRAM_SPI::setStatusRegister(uint8_t value) { GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS SPItransfer(OPCODE_WRSR); SPItransfer(value); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS } void Adafruit_FRAM_SPI::setAddressSize(uint8_t nAddressSize) { _nAddressSizeBytes = nAddressSize; } uint8_t Adafruit_FRAM_SPI::SPItransfer(uint8_t x) { return spi_sendrecv(x); /* if (_clk == -1) { //return SPI.transfer(x); return spi_sendrecv(x); } else { // Serial.println("Software SPI"); uint8_t reply = 0; for (int i=7; i>=0; i--) { reply <<= 1; //digitalWrite(_clk, LOW); GPIO_ResetBits(GPIOC, GPIO_Pin_0);; //CS //digitalWrite(_mosi, x & (1<<i)); if ((x & (1<<i)) > 0) GPIO_SetBits(GPIOA, GPIO_Pin_7); //MOSI else GPIO_ResetBits(GPIOA, GPIO_Pin_7); //MOSI //digitalWrite(_clk, HIGH); GPIO_SetBits(GPIOC, GPIO_Pin_0);; //CS //if (digitalRead(_miso)) if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == 1) reply |= 1; } return reply; } */ } void Adafruit_FRAM_SPI::writeAddress(uint32_t addr) { if (_nAddressSizeBytes>3) SPItransfer((uint8_t)(addr >> 24)); if (_nAddressSizeBytes>2) SPItransfer((uint8_t)(addr >> 16)); SPItransfer((uint8_t)(addr >> 8)); SPItransfer((uint8_t)(addr & 0xFF)); } 3) main.cpp; /** ****************************************************************************** * @file main.c * @author Ac6 * @version V1.0 * @date 01-December-2013 * @brief Default main function. ****************************************************************************** */ #include "stm32f10x.h" #include "stm32f1xx_nucleo.h" #include <stdlib.h> #include <math.h> #include "UART_Init.h" #include "Adafruit_FRAM_SPI.h" /* Example code to interrogate SPI FRAM chip for address size and storage capacity */ uint8_t FRAM_CS = 0; //port C //Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_CS); // use hardware SPI uint8_t FRAM_SCK = 5; uint8_t FRAM_MISO = 6; uint8_t FRAM_MOSI = 7; //Or use software SPI, any pins! Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_SCK, FRAM_MISO, FRAM_MOSI, FRAM_CS); uint8_t addrSizeInBytes = 2; //Default to address size of two bytes uint32_t memSize; int32_t readBack(uint32_t addr, int32_t data) { int32_t check = !data; int32_t wrapCheck, backup; fram.read(addr, (uint8_t*)&backup, sizeof(int32_t)); fram.writeEnable(true); fram.write(addr, (uint8_t*)&data, sizeof(int32_t)); fram.writeEnable(false); fram.read(addr, (uint8_t*)&check, sizeof(int32_t)); fram.read(0, (uint8_t*)&wrapCheck, sizeof(int32_t)); fram.writeEnable(true); fram.write(addr, (uint8_t*)&backup, sizeof(int32_t)); fram.writeEnable(false); // Check for warparound, address 0 will work anyway if (wrapCheck==check) check = 0; return check; } bool testAddrSize(uint8_t addrSize) { fram.setAddressSize(addrSize); if (readBack(16, 0xbeefbead) == 0xbeefbead) return true; return false; } //-------- Main loop ------------------------------------------------ int main(void) { Init_UART2(); //9600 bodow send_string("Program started. \r\n"); if (fram.begin(FRAM_CS, addrSizeInBytes)) { send_string("Found SPI FRAM\r\n"); } else { send_string("No SPI FRAM found ... check your connections\r\n"); //while (1); } //test of writing all memory 2K uint8_t value; for (uint16_t a = 0; a < 2048; a++) { fram.writeEnable(true); if ((a % 2) == 0) { value=0xAA; fram.write8(a,value); //0b10101010 } else { value=0x55; fram.write8(a, value); //0b01010101 } fram.writeEnable(false); } // dump the entire 2K of memory! ------------------------ fram.writeEnable(false); for (uint16_t a = 0; a < 2048; a++) { value = fram.read8(a); char buffer[10]; itoa (value,buffer,16); send_string(buffer); send_string("\r\n"); } for(;;); } Tutaj spakowany cały projekt dla zestawu uruchomieniowego dla "System Workbench for STM32" FRAMCypressF103SPI.zip Projekt został przetestowany dla pamięci FRAM FM25L16B firmy Cypress i działa poprawnie. Niestety do rozwoju docelowego projektu sprzętowego używam IDE "ride7" wraz z kompilatorem "RKit-ARM for Ride7". Cały projekt jest napisany nieobiektowo w C i ten kompilator słabo sobie radzi z "mieszanym" kodem w C i C++ (zresztą nie chciałem niepotrzebnie dodawać C++ do tego projektu), więc napisałem nieobiektową wersję biblioteki do obsługi FRAM (poprzez prostą zamianę klasy na strukturę). Ze względu na objętość postu nie będę już tutaj wklejał kodu źródłowego, tylko zamieszczam spakowane archiwum z tą nieobiektową wersją biblioteki: FRAM_SPI_Struct.zip A tutaj spakowany projekt dla "System Workbench for STM32": FRAMCypressF103SPIStruct.zip Ta nieobiektowa wersja biblioteki została przetestowana zarówno z pamięcią FRAM firmy Cypress jak i Fujitsu (z podanym wcześniej zestawem uruchomieniowym) i działa poprawnie. W pliku main.c w funkcji main dla obu pętli for należy zmienić zakres zmiennej sterującej na 2048 dla pamięci Cypress (mniejsza pojemność pamięći). Patrz ten kod: int main(void) { Init_UART2(); //9600 bodow send_string("Program started. \r\n"); Adafruit_FRAM_SPI2(fram, FRAM_SCK, FRAM_MISO, FRAM_MOSI, FRAM_CS); if (begin2(fram, FRAM_CS, addrSizeInBytes)) { send_string("Found SPI FRAM\r\n"); } else { send_string("No SPI FRAM found ... check your connections\r\n"); //while (1); } //test of writing all memory 2K uint8_t value; //int value; for (uint16_t a = 0; a < 32767; a++) { writeEnable(true); if ((a % 2) == 0) { value=0xAA; write8(fram, a,value); //0b10101010 } else { value=0x55; write8(fram, a, value); //0b01010101 } //send_string("writing\r\n"); /* value=0xAA; write8(fram, a,value); //0b10101010 send_string("writing\r\n"); char buffer[3]; itoa (value,buffer,16); send_string(buffer); send_string("\r\n"); */ writeEnable(false); } // dump the entire 2K of memory! ------------------------ writeEnable(false); for (uint16_t a = 0; a < 32767; a++) { value = read8(fram, a); //send_string("reading\r\n"); /* if ((a % 32) == 0) { Serial.print("\n 0x"); Serial.print(a, HEX); Serial.print(": "); } Serial.print("0x"); if (value < 0x1) Serial.print('0'); */ char buffer[3]; itoa (value,buffer,16); send_string(buffer); send_string("\r\n"); } for(;;); } //end main UWAGA: pamięci FRAM wymagają bardzo stabilnego zasilania - dla pamięci firmy Fujitsu bez kondensatora (10 nF) pomiędzy GND i +Vcc odczyty z zapisanej pamięci mogą być przekłamane. Warto umieścić kondensator wygładzający zasilanie dla obu tych typów pamieći na płytce blisko samej kostki pamięci. Jestem już po próbach obu typów pamięci w docelowych płytkach projektu i zapis i odczyt działa poprawnie. Zdaję sobie sprawę, że można było pewnie ładniej napisać kod źródłówy - chętnie dowiem się o propozycjach ulepszeń. Teraz mam zamiar dodać automatyczne obliczanie sum kontrolnych dla przesyłanych bloków pamięci, oraz dodać kod zapewniający integralność danych przechowywanych w pamięci. Tutaj wklejam taki prymitywny schemat połączenia pamięci z zestawem uruchomieniowym: W rzeczywistości piny WP i HOLD są podpięte do plusa zasilania przez rezystor 500 om. Gdyby ktoś musiał zmienić pin CS (chip select - pamięci to należy to zrobić w kodzie biblioteki). Mam nadzieję, że podany kod może się komuś przydać w jego projekcie BTW: właśnie wypróbowałem liczenie sumy kontrolnej CRC32 (dla bufora 16 x liczba 32 bity - uint32_t) i działa to bardzo fajnie. STM32F103 posiada sprzętowy moduł liczenia sumy kontrolnej (w 4 taktach zegara) CRC-32. Patrz ta dokumentacja "CRC calculation unit": https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf Dodam sprawdzanie sum kontrolnych podczas zapisu i odczytu danych do/z FRAM do tej biblioteki w najbliższym czasie. Poza tym może użyję też jakiegoś prostszego kodu korekcyjnego (który poza sprawdzeniem integralności danych będzie też w stanie "naprawić" dane w przypadku mniejszych błędów). Pozdrawiam
  11. Cześć ethanak, pewnie ,że jest wiele framework'ów do pisania aplikacji webowych. Może skupię się na zaletach (rzeczywistych lub wymaigowanych które ja widzę); 1) Bardzo mały "footprint" - mieści się w tak małej kostce jak ESP8266 (i nawet działa na niej wydajnie) 2) Jeden język (jedna spójna technologia) załatwia wszystkie aspekty pisania serwera WWW czy aplikacji serwerowej 3) non-blocking I/O model - łatwa wielowątkowość i duża wydajność 4) łatwa integracja z bazami No-SQL (często teraz wykorzystywanych w chmurze, których obsługa jest pisana w Javascript) 5) i chyba najważniejsze - łatwość nauki(w porównaniu do np. Django jest dużo łatwiejszy do nauki.) Widziałem już nawet ogłoszenia pracy dla programistów systemów embedded , gdzie jako najważniejszą umiejętność podawano dobrą znajomość "Node.js". Javascript też robi się coeraz popularniejszy, szczególnie wśród młodzieży. Ja popróbowałem "Node.js" zarówno na PC jak i na ESP8266 i bardzo mi się spodobał. Pozdrawiam
  12. Cześć SOYER, jeśli chcesz się dalej rozwijać w podanym kierunku - aplikacje internetowe "server side" to poczytaj sobie o "Node.js". Możesz w nim napisać w jednej technologi cały serwer WWW (czy aplikację serwerową). "Node.js" można naewet załadować (jako firmware) do ESP8266 i postawić na tym cały serwer WWW w cenie 20 PLN (nie mówiąc nawet o ESP32, czy wydajniejszych sprzętach). Potrzebna znajomość HTML, HTTP i Javascript. Oczywiście "Node.js" może się "nie podobać" wielu - co jest statystycznie uzasadnione Pozdrawiam
  13. FlyingDutch

    Timer liczący sygnał na digital IN

    Cześć, tak było ponieważ funkcja digitalWrite "pod spodem" korzysta z przerwań - sorki zapomniałem o tym (powinienem Ci o tym napisać). Gratuluję doprowadzenia programu do prawidłowego działania Pozdrawiam
  14. Cześć SOYER, są chmury (darmowe), które oferują dodatkowe funkcje. Ja np. korzystałem z chmury ThingSpeak (firmy Mathworks twórców MATLAB) z ESP8266). Tworzysz sobie za darmo "kanały" np. z wartościami pomiarów a czujników i zapisujesz je w nich (max. co 30 sekund w darmowej wersji). Masz dostęp z całego świata do strony wizualizującej twoje pomiary. Największą zaletą jest, że w tej chmurze jest dostępny MATLAB i możesz go użyć do obróbki (bardzo zaawansowanej) twoich danych pomiarowych. Możesz sobie np. liczyć sobie parametry statystyczne pomiarów i robić skomplikowane wizualizacje. Ja w 2012 i 2013 miałem ESP8266 z czujnikiem ciśnienia, temperatury, wilgotności itp. podłączonych do thingspeak.com i robiłem sobie predykcje tych parametrów za jakiś czas (prognozy) za pomocą "naiwnego klasyfikatora Bayesowski'ego" - prognozy były całkiem trafne. Podczas przeprowadzki układ z ESP8266 gdzieś mi zaginał, ale bardzo pozytywnie oceniam działanie tej chmury. Tutaj kilka linków: https://community.thingspeak.com/tutorials/arduino/send-data-to-thingspeak-with-arduino/ https://github.com/mathworks/thingspeak-arduino Pozdrawiam
  15. FlyingDutch

    Przetwarzanie sygnału z 4 enkoderów - robot mobilny

    Cześć, przerwania zewnętrzne mają swoje priorytety (patrz: dokumentacja - nie można ich zmienić). Najpierw są wykonywane przerwania o najwyższym priorytecie, gdy podczas procedury obsługi takiego przerwania wystąpi przerwanie o niższym priorytecie, aktualne przerwanie jest wykonywane do końca, a przerwania o niższych priorytetach są kolejkowane do wykonania (według ich priorytetów). Patrz linki: https://forum.arduino.cc/index.php?topic=375102.0 https://forum.arduino.cc/index.php?topic=375102.0 https://forum.arduino.cc/index.php?topic=287697.0 https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ Ja bym to jednak spróbował oprogramować na przerwaniach - dobrze napisane nie powinno Ci za bardzo obciążyć CPU. Pozrawiam
  16. FlyingDutch

    Nie mogę wgrać programu do Arduino UNO

    Zgadzam si ę z deshipu. Mi taki numery (z prawami dostępu do katalogów/plików Arduino IDE) robił "Windows Defender" - Windows 10. Wyłącz całkowicie ochronę systemu plików w Windows Defender. Pozdrawiam
  17. FlyingDutch

    Timer liczący sygnał na digital IN

    Cześć, z "pinoutu" dla "Arduino Mega 2560 " wynika, że dla pinu 2 jest przyporządkowane INT4 (ale to rzeczywiście nie powinno mieć dla Ciebie znaczenia). Możesz wykorzystać procedurę "tim3Callback" podpiętą do tej instancji timera także do innych obliczeń - trzeba tylko zmodyfikować kod. Teoretycznie możesz sobie zdefiniować kilka instancji timerów (nawet z innymi okresami), ale ich użycie musi być dobrze przemyślane w programie, bo możesz narobić sobie kłopotów i program nie będzie działał poprawnie (trzeba pamiętać, że to są przerwania). Pozdrawiam
  18. FlyingDutch

    Transformers 5 - Ostatni Rycerz

    Cześć, właśnie obejrzałem ostatnią część Transformers'ów "Ostatni Rycerz" - epic and awesome! Gorąco polecam Pozdrawiam
  19. Cześć, Przyznaję, że rozmiar i ciężar może być dużym problemem w przypadku Kinect'a. Głównie chodziło mi o ilość dostępnego w sieci kodu dla Kinect'a. Pozdrawiam
  20. FlyingDutch

    Raspbery Pi, SPI

    Cześć, jest biblioteka do RPI dla IC LS7366R do Pythona: https://github.com/fbolanos/LS7366R/ Trzeba by sprawdzić, czym różnią się modele z S i R na końcu. No i nie wiem, czy Python Ci odpowiada, ale przynajmniej będziesz wiedział jak obsłuzyć komunikację z tym układem. Pozdrawiam
  21. Cześć, Sygnały CW+ i CLK+ lączysz do pinów sterujących (digital OUT) Arduino. Sygnału EN możesz w ogóle nie używać (jeśli chcesz używać to EN+ łączysz do pinu sterującego Arduino). Wszystkie sygnały z "-" lączysz do masy GND układu (CW-, CLK-, EN-). na CLK+ podajesz sygnał prostokątny o odpowiednio dobranej do prędkości ruchu obrotowego częstotliwości (wypełnienie 50 %). Jeśli chcesz aby silnik obrócił się o określoną liczbę kroków odliczasz i podajesz na wejście CLK+ - po odliczeniu tej liczby kroków silnik się zatrzyma. Stan HIGH lub LOW na wejściu CW+ zmienia kierunek obrotów silnika. Wejścia EN+ możesz nie używać - można go użyć do blokowania ruchu silnika. Zobacz np. ten link: https://www.instructables.com/id/ARDUINO-UNO-TB6560-Stepper-motor-driver/ Pozdrawiam.
  22. Cześć, nie potrzebuję korepetycji z trygonometrii (tak się dziwnie składa, że w szkole średniej dostałem się do finału olimpiady matematycznej). Doskonale wiem co tu przedstawiłeś: podałeś po prostu sekwencję stanów impulsów przesuniętych w fazie z taką modyfikacją, że w niektórych momentach jest wartość prądu kroku określona poprzez PWM. Problem leży gdzie indziej: podajesz tą metodę użytkownikowi, który pyta o podstawowe sterowanie silników krokowych jako podstawową. efekt jest taki, że zadający pytanie nadal nie wie jak sterować swoim silnikiem. Takie metody stosuje się dla bardzo "biednych" silników jak przedstawiony (32 kroki). Naprawdę można wybrać za nieduże pieniądze silnik krokowy (razem ze sterownikiem), gdzie takie "sztuczki" nie są potrzebne. Poza tym w dzisiejszych czasach większość silników krokowych ma zintegrowane sterowniki, które zapewniają bardzo wygodne sterowanie, bez potrzeby stosowania sztuczek, typu PWM. Silniki których ostatnio używałem w projekcie mają, aż cztery tryby pracy: 1) "Pulse and Direction" - gdzie po prostu sterujemy liczbą impulsów prostokątnych na wejściu STEP 2) "Velocity" -gdzie definiujemy funkcję prędkości obrotowej w funkcji czasu (to o czym pisał Elvis mówiąc o obwiedni sygnału) a sterownik sam martwi się o zapewnienie odpowiedniego wysterowania 3) Tryb "SCL" - użycie specjalnego języka programowania silnika 4) Trub "Q programer" - alternatywna metoda programowania Czy zgodziłbyś się z uogólnieniem, że wszystkie silniki krokowe są tak sterowane - jestem pewien, że nie. Dlatego napisałem wyrażnie, że bez sensu jest opisywanie gołego silnika krokowego bez sterownika (ponieważ silniki krokowe mogą bardzo się różnic w swojej budowie wewnętrznej). Natomiast Ty podałeś sposób sterowania jednego modelu silnika (bardzo prymitywnego) z jeszcze prymitywnijszym sterownikiem (jesli można to tak nazwać) jako podstawową metodę sterowania wszystkich silników krokowych. Poza tym, wystawiłeś negatyw dla neutralnej wypowiedzi jako pierwszy. Potem dałeś komentarz, że nie udzielasz korepetycji z trygonometrii, a skąd wiesz, że ja nie znam trygonometrii. Sygnału PWM używam często w swoich projektach, głównie do sterowania silnikami DC, ale zrobiłem też np. DAc'a do płytki FPGA dla wyjścia audio (o niezbyt dobrych parametrach - ograniczone pasmo i dynamika - lepszych parametrów po prostu nie potrzebowałem). Doskonale rozumiem jak za pomocą PWM wygenerować przebieg o zadanym kształcie: po prostu wartość PWM musi być proporcjonalna do wartości chwilowej sygnału który chcemy odwzorować. Jeśli chodzi o trygonometrię to kilka razy używałem np. z projektami opartymi na FPGA algorytmu "CORDIC" i nie miałem najmniejszych problemów z obliczeniami i trygonometrią. Nadal twierdzę, że opisana przez Ciebie metoda sterowania silników krokowych nie jest metodą podstawową (wręcz dla dzisiejszyh silników niszową). Po drugie opisywanie "gołego" silnika bez zintegrowanego sterownika jest bez sensu. Często dzisiejsze bardziej zaawansowane silniki mają sterowniki wyposażone w procesor DPS - do np. zaawansowanego "wygładzania" ruchu, filtrowania sygnałów sterujących itp. Ja w swoim poście wyraźnie zaznaczyłem, że podana przeze mnie metoda sterowania jest ograniczona do silników ze zintegrowanym sterownikiem. O ile można się dowiedzieć z postu użytkownik zadający pytanie nie pytał o realizację "micro-steps" w podanym modelu silnika, tylko obsługą za pomocą zwykłych kroków. BTW: zobacz co za dziwna koincydencja czasowa? Zobacz post "Ploter laserowy 2.5W dwuosiowy sterowany Arduino" z ostatnich godzin: https://forbot.pl/forum/topic/13369-ploter-laserowy-25w-dwuosiowy-sterowany-arduino/ W projekcie tym są użyte dwa silniki krokowe i tutaj użytkownik w dokumentacji projektu ma opisane sygnały sterujące dla silników krokowych: Widzisz tu gdzieś sterowanie za pomocą metody, którą opisałeś jako uniwersalną dla silników krokowych (z wykorzystaniem PWM). Bo ja widzę 100 procentową kalkę tego co napisałem w tym temacie. Widać, że masz wiedzę, ale popełniasz wielki błąd uważając, że masz monopol na wiedzę - a w dzisiejszych czasach jest to po prostu niemożliwe. Widać to było np. w dyskusji z markiem, który jeśli chodzi o elektronikę (i nie tylko) jest chyba najlepszym fachowcem na tym forum i gdzie zupełnie niepotrzebnie robiłeś jakieś "osobiste wycieczki" pod jego adresem. Pozdrawiam Cześć, zobacz następny dzisiejszy post na Forbot.pl: "Zasilanie silnika krokowego": https://forbot.pl/forum/topic/13372-zasilanie-silnika-krokowego/ Tutaj kolega chce użyć takiego silnika krokowego: https://botland.com.pl/pl/silniki-krokowe/3607-silnik-krokowy-jk42hs34-0404-200-krokowobr-12v-04a-025nm.html i takiego sterownika Pololu: https://botland.com.pl/pl/sterowniki-silnikow-krokowych/148-pololu-a4988-sterownik-silnika-krokowego-reprap-35v2a.html?search_query=a4988&results=24 I znów sterowanie wygląda tak jak opisałem. Cena sterownika niecałe 22 PLN (a silnika 49 PLN). Nie są to chyba kwoty nieosiągalne dla amatora. Właściwie w temacie, którego dotyczyła dyskusja pierwszym co należał zrobić to polecić użycie podobnego silnika i sterownika: wtedy mamy bardzo proste sterowanie z którym poradzi sobie każdy użytkownik Arduino. Pozdrawiam
  23. FlyingDutch

    Timer liczący sygnał na digital IN

    Cześć, dla "Arduino Mega 2560" można użyć biblioteki "TimerThree" do odmierzania czasu. Oto link do niej: https://www.pjrc.com/teensy/td_libs_TimerOne.html Nie przejmuj się opisem dotyczącym pinów PWM (ta biblioteka może też automatycznie generować sygnał PWM), ciebie to w tej chwili nie dotyczy. Tu masz link do pobrania tej biblioteki na Github'ie: https://github.com/PaulStoffregen/TimerThree Przydałby się jeszcze jeden "feature" do twojego problemu: mianowicie Arduino MEGA (także UNO) ma kilka pinów, które można wykorzystać jako sygnały zewnętrznych przerwań. Oto link: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ Jak widzisz z opisu dla "Arduino Mega 2560" są to piny: 2, 3, 18, 19, 20, 21. Te przerwania są "nie-maskowalne", pinów jest trochę mało, czasami trzeba jeszcze więcej pinów wtedy można użyć przerwań maskowalnych PCINT, ale jest to trochę trudniejsze niż tych pinów z przerwaniami nie-maskowalnymi INT. Ja rozwiązał bym problem w następujący sposób: do jednego z wejść zewnętrznych przerwań (piny: 2, 3, 18, 19, 20, 21) przypisałbym funkcję obsługi przerwania i ustawiał bym jakąś globalną zmienna, która mówi, że impulsy z timera (co określony czas mają być zliczane). Oczywiście, zmienna pozwalająca na zliczanie impulsów aktywna gdy stan wejścia przerwania zewnętrznego ma właściwy poziom. Druga kwestia to timer: ustawiasz sobie czas co jaki ma być uruchamiane przerwanie od timera (np. co 100 us lub co 10 ms) i po prostu w procedurze obsługi timera aktualizujesz licznik w celu zliczania czasu. Aby zliczać czas tylko wtedy, gdy poziom na twoim wejściu przerwania zewnętrznego jest np. wysoki w przerwaniu od sygnału zewnętrznego ustawiasz sobie globalną zmienną, która mówi czy impulsy z timera mają być zliczane, czy nie. Kod programu wyglądałby mniej więcej tak: #include "TimerThree.h" #include <avr/interrupt.h> const int outerInt = 2; // INT4 - pin zewnetrznego przerwania volatile unsigned long licznik; //licznik impulsow - czasu volatile bool zezwalajLiczyc; //zmienna - true zliczaj impulsy , false nie zliczaj //---------------------- Interrupts and callbacks ------------------------------------ void tim3Callback() { if (zezwalajLiczyc) licznik++; if (licznik >= 300000UL) { //rób coś tam np. : digitalWrite(Pin, HIGH); // licznik=0UL; } } void outInterrupt() { if (digitalRead(outerInt) == LOW) { zezwalajLiczyc=true; } else { zezwalajLiczyc=false; } } //---------------------- Setup and program ------------------------------------ void setup() { pinMode(outerInt, INPUT_PULLUP); //zakladamy, ze zliczanie gdy wartosc LOW na pinie przerwania attachInterrupt(digitalPinToInterrupt(outerInt), outInterrupt, CHANGE); //procedura obslugi zewnetrznego przerwania //Ustawiamy timer Timer3.initialize(1000); // initialize timer3, and set a 1000 us (1ms)second period Timer3.attachInterrupt(tim3Callback); // przypisz funkcję obslugi Timera zezwalajLiczyc=false; licznik=0UL; } void loop() { //delay(10); } UWAGA: nie twierdzę, że jest to najlepszy sposób rozwiązania tego problemu. Odpowiadam, ponieważ nie było przez dość długi czas odpowiedzi. jeśli ktoś ma lepsze rozwiązanie, niech po prostu je poda. Nie mogłem sprawdzić kodu na "Arduino Mega 2560" bo aktualnie takim nie dysponuje, ale według mnie powyższy kod powinien działać. BTW: oczywiście bibliotekę "TimerThree" trzeba zainstalować w "Arduino IDE", tu link jak to się robi: https://www.arduino.cc/en/guide/libraries Pozdrawiam
  24. FlyingDutch

    Sterowanie silnikiem krokowym - 28byj-48 + ULN2003

    Cześć, pierwszym postem było pytanie niedoświadczonego użytkownika o typowe i najprostsze sposoby sterowania silnikiem krokowym za pomocą 'normalnych' kroków i trzeba było przedstawić to jako pierwsze (przebiegi przesunięte w fazie) - potem można było mówić o zaawansowanych sposobach zwiększania rozdzielczości takich silników. Ja wyraźnie zaznaczyłem, że silnik krokowy powinien być traktowany jako jeden układ razem ze swoim sterownikiem - co wyraźnie zaznaczyłem. Nie widzę sensu stosowania takich metod dla nowoczesnych silników krokowych, gdzie większość takich zadań spełnia sterownik zintegrowany z silnikiem (i ukrywa to przed użytkownikiem). Liczba kroków w takich silnikach jest w pełni wystarczająca i nie trzeba kombinować z mikro=krokami (połówkami, ćwiartkami, ósemkami itd.). Zawsze wychodzę z założenia, że podstawy trzeba przedstawić jako pierwsze w prosty sposób, a dopiero potem można mówić o zaawansowanych metodach poprawy parametrów takich silników. Pozdrawiam
  25. To może najpierw napisz jak się realizuję obsługę podstawowych "steps" - tam nigdy nie stosuje się PWM . Jak kupisz silniczek który ma 32 kroki to musisz się bawić w takie 'wynalazki'. Najpierw napisz niedoświadczonym adeptom jak się zapewnia podstawowe sposoby obsługi takiego silnika w zakresie "normalnych" króków. A jak wyłożysz podstawy to wtedy możesz opisać jak sztucznie zwiększać rozdzielczość takich silników za pomocą PWM realizują połówki, ćwiartki, szestnaski itd. Tak to mieszasz tylko ludziom w głowach. Po co mi reqalizacja "micro-steps" w silniku w którym liczsba kroków wynosi np. 25 000? Pozdrawiam
×