29.07.2012

STM32F4Discovery + NETMF żyje!

Postanowiłem napisać bardziej zaawansowany program niż mruganie jedną diodą. Mrugać będzie wszystkie 4 diody! To będzie taki Hello World dla .NET Micro Framework na STM32F4Discovery. Cztery diody na płytce będą się kręcić w lewo lub w prawo. Naciśniecie przycisku (User button) będzie zmieniać kierunek. Dodatkowo można podłączyć jeszcze jedną diodę led (jak na rysunku poniżej). Ta dioda będzie wskazywała kierunek obrotów.
Podłączenie diody led do STM32F4Discovery
Na początek trzeba zrobić klasę pomocniczą z definicjami pinów po to, aby za każdym razem ich nie liczyć, no i nie wpisywać na sztywno numerków. Dodatkowo klasę umieściłem w oddzielnej bibliotece. 'Worek' na dodatkowe funkcje i definicje zawsze się przydaje.
public class Stm32F4Discovery
{
    static Stm32F4Discovery()
    {
        HardwareProvider.Register(new Stm32F4DiscoveryHardwareProvider());
    }

    private sealed class Stm32F4DiscoveryHardwareProvider : HardwareProvider
    {
    }

    public class Pins
    {
        // ReSharper disable InconsistentNaming
        public const Cpu.Pin GPIO_NONE = Cpu.Pin.GPIO_NONE;

        public const Cpu.Pin PA0 = 0*16 + 0; //0
        public const Cpu.Pin PA1 = (Cpu.Pin) (0*16 + 1); //1 ADC0 COM2(rts)
        public const Cpu.Pin PA2 = (Cpu.Pin) (0*16 + 2); //2 ADC1 COM2(tx)
        public const Cpu.Pin PA3 = (Cpu.Pin) (0*16 + 3); //3 ADC2 COM2(rx)
        public const Cpu.Pin PA4 = (Cpu.Pin) (0*16 + 4); //4

        //...cała definicja pinów jest za długa żeby ją tutaj zmieścić        

        public const Cpu.Pin PE14 = (Cpu.Pin) (4*16 + 14); //78 PWM7
        public const Cpu.Pin PE15 = (Cpu.Pin) (4*16 + 15); //79
        // ReSharper restore InconsistentNaming
    }

    public class ButtonPins
    {
        public const Cpu.Pin User = Pins.PA0;
    }

    public class LedPins
    {
        public const Cpu.Pin Green = Pins.PD12; //60
        public const Cpu.Pin Orange = Pins.PD13; //61
        public const Cpu.Pin Red = Pins.PD14; //62
        public const Cpu.Pin Blue = Pins.PD15; //63
    }

    public class FreePins
    {
        // ReSharper disable InconsistentNaming
        public const Cpu.Pin PA1 = Pins.PA1;
        public const Cpu.Pin PA2 = Pins.PA2;

        //...cała definicja pinów jest za długa żeby ją tutaj zmieścić  

        public const Cpu.Pin PE14 = Pins.PE14;
        public const Cpu.Pin PE15 = Pins.PE15;
        // ReSharper restore InconsistentNaming
    }

    //... i jeszcze inne definicje
}
Następnie zrobiłem oddzielna klasę, która odpowiada tylko za sterowanie diodami led. Dokładnie chodzi o kręcenie ich w prawo lub w lewo:
internal class LedRotator
{
    int _currentIndex;
    private readonly OutputPort[] _leds;
    private readonly int _maxIndex;
    private bool _right = true;
    public bool Right
    {
        get { return _right; }
    }

    public LedRotator(params OutputPort[] leds)
    {
        if (leds == null) 
            throw new ArgumentNullException("leds");

        _maxIndex = leds.Length - 1;
        _leds = leds;
    }

    // ReSharper disable FunctionNeverReturns
    public void Run()
    {
        //krecimy diodamy
        for (;;)
        {
            _leds[_currentIndex].Write(true);
            Thread.Sleep(120);
            _leds[_currentIndex].Write(false);
            _currentIndex = GetNextIndex();
        }
    }
    // ReSharper restore FunctionNeverReturns

    private int GetNextIndex()
    {
        if(Right)
            return _currentIndex == _maxIndex ? 0 : _currentIndex + 1;

        return _currentIndex == 0 ? _maxIndex : _currentIndex - 1;
    }

    public void ChangeDirection()
    {
        _right = !_right;
    }
}
W głównej klasie Program mamy najpierw definicje dwóch portów: UserButton oraz DirectionLed. Port UserButton, jak popatrzymy do dokumentacji STM32F4Discovery, ma rezystor podpięty do masy - dlatego jest pull-down.
private static readonly InterruptPort UserButton = new InterruptPort(Stm32F4Discovery.ButtonPins.User,
                                                                     false,
                                                                     Port.ResistorMode.PullDown,
                                                                     Port.InterruptMode.InterruptEdgeLow);

private static readonly OutputPort DirectionLed = new OutputPort(Stm32F4Discovery.FreePins.PA15, false);
Natomiast w samej głównej procedurze Main jest deklaracja portów diod led zgrupowanych w tablicy. Tablica jest przekazywana do konstruktora klasy LedRotator. Dzięki temu można w łatwy sposób zmieniać liczbę diod do sterowania.
var leds = new[]
                {
                    new OutputPort(Stm32F4Discovery.LedPins.Green, true),
                    new OutputPort(Stm32F4Discovery.LedPins.Orange, true),
                    new OutputPort(Stm32F4Discovery.LedPins.Red, true),
                    new OutputPort(Stm32F4Discovery.LedPins.Blue, true)
                };

var rotator = new LedRotator(leds);
DirectionLed.Write(rotator.Right);
Kolejnym elementem jest podpięcie pod InterruptPort (User button) procedury obsługi. Definicja procedury jest zapisana przy użyciu wyrażenia lambda. Po każdym naciśnięciu przycisku zmieniany jest kierunek obrotów, oraz stan dodatkowej diody. Dodatkowa instrukcja (ClearInterrupt) powoduje skasowanie stanu portu, tak aby zareagował na kolejne zdarzenie.
UserButton.OnInterrupt += (u, data2, time) =>
                                {
                                    rotator.ChangeDirection();
                                    DirectionLed.Write(rotator.Right);
                                    UserButton.ClearInterrupt();
                                };

Blink(leds, 6);
rotator.Run();
Po definicji procedury obsługi przycisku jest uruchomienie LedRotatora. Dodatkowa procedura Blink, mruga wszystkimi diodami - to sekwencja startowa.
private static void Blink(OutputPort[] leds, int blinkCnt)
{
    //mrugamy diodami kilka razy (diody musza zgasnac)
    bool ledState = leds[0].Read();
    for (; blinkCnt > 0 || ledState; blinkCnt--)
    {
        ledState = !ledState;
        foreach (OutputPort led in leds)
            led.Write(ledState);

        Thread.Sleep(1000);
    }
}

Kot dostępny na: https://kodfilemon.googlecode.com/svn/trunk/STM32F4Discovery_Demo/DemoBlink1 ( Checkout )

Brak komentarzy:

Prześlij komentarz