Dzisiaj przedstawię proces portowania biblioteki obsługującej MultiFunctionShield na Arduino R4 oraz krótko zademonstruję jej możliwości, czyli wyświetlanie danych na 7-segmentowym, 4-cyfrowym wyświetlaczu oraz kontrolę klawiatury i buzzera. Przy okazji też zobaczymy jak można zrealizować timer z przerwaniem na R4 przy użyciu FspTimer.h. To starczy do uruchomienia tego shielda z nowym Arduino.
MultiFunctionShield
Nakładka "wielofunkcyjna" jest jednym z najtańszych dodatków do Arduino jakie znam - można ją kupić za niecałe 10 zł i to na naszym polskim portalu wysyłkowym:
Grafika pochodzi z Githuba.
Schemat:
Rzeczywisty wygląd, kilka fotek ode mnie:
Można by się zastanowić zatem, co ona oferuje - zasadniczo niedużo:
Mamy tu:
- wyświetlacz 7-segmentowy o 4 cyfrach, sterowany przez dwa rejestry przesuwne 74HC595D połączone kaskadowo (więc potrzeba 3 GPIO na sterowanie)
- trzy przyciski
- buzzer
- kilka diod LED
- potencjometr
- wyprowadzony przycisk RESET
- dodatkowo sloty pod różne peryferia, pod odbiornik IR, czujnik temperatury DS18B20, jakieś inne rozszerzenia
Nieco podstawowych projektów można na tym zrealizować. To właśnie spróbujemy zaraz zrobić.
Uwaga! Jeśli nie wiesz, jak działa rejestr przesuwny lub jak działa wyświetlacz 7-segmentowy, to polecam zapoznać się z innymi materiałami na ten temat z naszego forum. Między innymi można odwiedzić mój stary temat, w którym uruchamiałem podobny wyświetlacz na Arduino Uno R3:
Wyświetlacz 7 segmentowy tunera, uruchomienie z Arduino, rejestr przesuwny
Tam też omawiałem shiftOut, które również tu jest użyte.
Instalacja Multi Function Shield
Na Arduino Uno R3, tym bazującym na Atmedze, cały proces jest bardzo prosty. Wystarczy zainstalować bibliotekę o nazwie takiej samej jak shield, jest dostępna w Library Manager:
Niestety na R4 nie jest ona wspierana. Nawet Arduino IDE ją specjalnie przed nami chowa, bo w ustawieniach biblioteki (plik library.properties) jest zaznaczone, że działa tylko na AVR:
Nawet jak ją na siłę otworzymy to i tak się nie skompiluje.
Będziemy musieli dokonać portowania jej na nową platformę, ale najpierw zapoznajmy się z kodem.
Biblioteka ta dostępna jest na Github pod adresem:
https://github.com/coderfls/Arduino_MultiFunctionShield
W tym temacie będę cytować kod tej biblioteki, jest to zgodne z jej licencją - CC0
Przegląd biblioteki MultiFunctionShield
Pobrane biblioteki rezydują w folderze Arduino, u mnie to:
C:\Users\Admin\Documents\Arduino\libraries\MultiFunctionShield\src
Mamy tam m. in. plik library.properties:
Zobaczmy jego zawartość:
name=MultiFunctionShield
version=1.5.3
author=Florian
maintainer=Florian
sentence=LED Display driver for Multi Function Shield
paragraph=for ATmega328, uses Timer1 => Pins 9 and 10 on Uno for PWM and analogWrite() are effected
category=Display
url=https://github.com/coderfls/Arduino_MultiFunctionShield
architectures=avr
includes=avr/interrupt.h
Zmodyfikować trzeba będzie wpis architectures. Teraz jeszcze przejrzyjmy foldery. W examples jest tylko przykładowy sketch:
Kod: C / C++
W powyższym kodzie raczej wszystko powinno być zrozumiałe, ale i tak go omówię:
Kod: C / C++
W powyższsym kodzie tworzony jest obiekt klasy MultiFunctionShield a następnie uruchamiany jest jej multipleksing wyświetlacza.
Kod: C / C++
Powyższy fragment po prostu wyświetla daną liczbę na wyświetlaczu shielda.
Warto pamiętać, że multipleksing wyświetlacza cały czas chodzi w tle, bo musi ręcznie odświeżać wyświetlacz.
Reszta demka tego shielda powinna być jasna, bo to już są zwykłe operacje na GPIO Arduino, do nich należy też kontrola buzzera.
Ok, wróćmy do kwestii portowania. Sprawdźmy najpierw kod źródłowy tej biblioteki:
Nagłówek klasy MultiFunctionShield:
Kod: C / C++
Tutaj załączany jest już nagłówek od przerwań AVR. Trzeba będzie to usunąć. Są też tu zdefiniowane piny (na sztywno, bo to jest pod ten konkretny shield, więc jak szukamy co jest gdzie podłączone to mamy tu ściągę), no i jest deklaracja klasy...
Implementacja klasy MultiFunctionShield:
Kod: C / C++
Tutaj widać, że do multipleksingu użyty został timer AVR. Ustawiany jest w tym fragmencie:
Kod: C / C++
Na AVR przerwanie timera woła funkcję ISR, tu użyty jest timer 1:
Kod: C / C++
Timer wywołuje funkcję ISRFunc, która wybiera pozycję segmentu na którą chcemy w danym momencie odświeżyć oraz zapętla indeks aktualnej cyfry, a potem odpowiednie wywołanie WriteNumberToSegment aktualizuje oba rejestry przesuwne, zarówno ten od wyboru cyfry, jak i ten od wyboru segmentów które zapalamy.
Portowanie na Arduino R4
Po prostu musimy przeportować timer. Na R4 mamy nagłówek:
Kod: C / C++
W nim rezyduje klasa o tej samej nazwie. Znalazłem w sieci przykład jej użycia. Możemy ustawić sobie częstotliwość naszego przerwania:
Kod: C / C++
Teraz wystarczy jeszcze podpiąć nową funkcję i... zasadniczo to tyle:
Kod: C / C++
Uruchamiamy, wgrywamy i... słyszymy przeraźliwy pisk - co jest z buzzerem? Czemu jest od razu włączony? Trzeba zrobić jeszcze poprawkę.
Zamieniamy:
Kod: C / C++
na:
Kod: C / C++
Najwyraźniej coś musiało się zmienić 'pod maską', już tego nie analizowałem, ale teraz wszystko działa:
Podsumowanie
Shield uruchomiony. Trzeba było zasadniczo tylko przerzucić timer na nową platformę. Okazało się, że było to prostsze, niż myślałem. SDK od Renesas ma gotową klasę FspTimer która zapewnia nam wszystko czego potrzebujemy.
Swoje zmiany umieściłem na Githubie:
https://github.com/openshwprojects/Arduino_MultiFunctionShield
Otworzyłem również pull request aby moje zmiany mogły w przyszłości być dostępne dla każdego:
https://github.com/coderfls/Arduino_MultiFunctionShield/pull/2/files
Zostało mi kilka pobocznych usprawnień do wykonania tam (poprawne #define itd), ale wszystko działa. Zapraszam do korzystania.
Czy widzicie jakiś potencjał dla tego wybitnie taniego shielda?
Fajne? Ranking DIY Pomogłem? Kup mi kawę.