未验证 提交 452483d2 编写于 作者: F Florian Gschwandtner 提交者: GitHub

Add encoder support to Seesaw device (#1866)

* Added initial support for Seesaw Rotary Encoder

* Code cleanup

* Improve XML comments

* Code cleanup

* Update Seesaw README.md

* Rename EncoderDelta to GetEncoderDelta

* Use interrupt to detect position and push switch changes

* Update README.md to include encoder sample

* Add missing comments and finish all comments with a dot
上级 68e50c97
......@@ -76,6 +76,12 @@ This sample duplicates the functionality of the rpi-more-blinking-lights sample
![eesaw Sample Blinking Lights](SeesawSampleBlinkingLights_bb.png)
### Connecting to a Seesaw based rotary encoder sample
This sample connects a Raspberry Pi to an Adafruit I2C QT Rotary Encoder
![Seesaw sample encoder](SeesawSampleEncoder.png)
## Binding Notes
When using Seesaw devices with a Raspberry Pi it has been observed that errors sometimes happen on the I2C bus. The nature of this error may be the 'clock stretching' [bug](http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html) or may just be that the breakout board cannot accommodate the default I2C speed.
......@@ -96,4 +102,4 @@ In general the Seesaw technology allows user the embedding of the following type
* [X] EEPROM (although untested)
* [X] Capacitive Touch
* [ ] Keypad
* [ ] Rotary Encoder
* [X] Rotary Encoder

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
# Visual Studio Version 17
VisualStudioVersion = 17.2.32505.173
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{A15390DB-F07B-4014-9840-5F792089E026}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seesaw.Sample.BlinkingLights", "samples\Seesaw.Sample.BlinkingLights.csproj", "{413D2811-7A97-44AC-9D82-099209920BBE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Seesaw.Sample.BlinkingLights", "samples\Seesaw.Sample.BlinkingLights.csproj", "{413D2811-7A97-44AC-9D82-099209920BBE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seesaw.Sample.Capabilities", "samples\Seesaw.Sample.Capabilities.csproj", "{5807BB95-184F-47CC-A8A4-63519079B525}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Seesaw.Sample.Capabilities", "samples\Seesaw.Sample.Capabilities.csproj", "{5807BB95-184F-47CC-A8A4-63519079B525}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seesaw.Sample.SoilSensor", "samples\Seesaw.Sample.SoilSensor.csproj", "{164336C0-7E90-4082-B98D-0AEBB60717E3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Seesaw.Sample.SoilSensor", "samples\Seesaw.Sample.SoilSensor.csproj", "{164336C0-7E90-4082-B98D-0AEBB60717E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seesaw", "Seesaw.csproj", "{F87E6203-1DA1-4648-9A1C-AB39C0CDE7E7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Seesaw", "Seesaw.csproj", "{F87E6203-1DA1-4648-9A1C-AB39C0CDE7E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Seesaw.Sample.Encoder", "samples\Seesaw.Sample.Encoder.csproj", "{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
......@@ -22,9 +24,6 @@ Global
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{413D2811-7A97-44AC-9D82-099209920BBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{413D2811-7A97-44AC-9D82-099209920BBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
......@@ -74,10 +73,29 @@ Global
{F87E6203-1DA1-4648-9A1C-AB39C0CDE7E7}.Release|x64.Build.0 = Release|Any CPU
{F87E6203-1DA1-4648-9A1C-AB39C0CDE7E7}.Release|x86.ActiveCfg = Release|Any CPU
{F87E6203-1DA1-4648-9A1C-AB39C0CDE7E7}.Release|x86.Build.0 = Release|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Debug|x64.ActiveCfg = Debug|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Debug|x64.Build.0 = Debug|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Debug|x86.ActiveCfg = Debug|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Debug|x86.Build.0 = Debug|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Release|Any CPU.Build.0 = Release|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Release|x64.ActiveCfg = Release|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Release|x64.Build.0 = Release|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Release|x86.ActiveCfg = Release|Any CPU
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{413D2811-7A97-44AC-9D82-099209920BBE} = {A15390DB-F07B-4014-9840-5F792089E026}
{5807BB95-184F-47CC-A8A4-63519079B525} = {A15390DB-F07B-4014-9840-5F792089E026}
{164336C0-7E90-4082-B98D-0AEBB60717E3} = {A15390DB-F07B-4014-9840-5F792089E026}
{2AF6BC30-E051-45A3-AA35-9CBB7E6352BA} = {A15390DB-F07B-4014-9840-5F792089E026}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FAE88427-BD54-45C3-B93A-0FCBC92E93F0}
EndGlobalSection
EndGlobal
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Buffers.Binary;
namespace Iot.Device.Seesaw
{
public partial class Seesaw : IDisposable
{
/// <summary>
/// Read the current position of the encoder.
/// </summary>
/// <param name="encoder">Which encoder to use, defaults to 0.</param>
/// <returns>The encoder position as a 32 bit signed integer.</returns>
/// <exception cref="InvalidOperationException">The hardware does not support Adafruit SeeSaw encoder functionality.</exception>
public int GetEncoderPosition(byte encoder = 0)
{
if (!HasModule(SeesawModule.Encoder))
{
throw new InvalidOperationException($"The hardware on I2C Bus {I2cDevice.ConnectionSettings.BusId}, Address 0x{I2cDevice.ConnectionSettings.DeviceAddress:X2} does not support Adafruit SeeSaw encoder functionality");
}
return BinaryPrimitives.ReadInt32BigEndian(Read(SeesawModule.Encoder, SeesawFunction.EncoderPosition + encoder, 4, 8000));
}
/// <summary>
/// Set the current position of the encoder.
/// </summary>
/// <param name="position">Encoder position.</param>
/// <param name="encoder">Which encoder to use, defaults to 0.</param>
/// <exception cref="InvalidOperationException">The hardware does not support Adafruit SeeSaw encoder functionality.</exception>
public void SetEncoderPosition(int position, byte encoder = 0)
{
if (!HasModule(SeesawModule.Encoder))
{
throw new InvalidOperationException($"The hardware on I2C Bus {I2cDevice.ConnectionSettings.BusId}, Address 0x{I2cDevice.ConnectionSettings.DeviceAddress:X2} does not support Adafruit SeeSaw encoder functionality");
}
Span<byte> buffer = stackalloc byte[4];
BinaryPrimitives.WriteInt32BigEndian(buffer, position);
Write(SeesawModule.Encoder, SeesawFunction.EncoderPosition + encoder, buffer);
}
/// <summary>
/// The change in encoder position since it was last read.
/// </summary>
/// <param name="encoder">Which encoder to use, defaults to 0.</param>
/// <returns>The encoder change as a 32 bit signed integer.</returns>
/// <exception cref="InvalidOperationException">The hardware does not support Adafruit SeeSaw encoder functionality.</exception>
public int GetEncoderDelta(byte encoder = 0)
{
if (!HasModule(SeesawModule.Encoder))
{
throw new InvalidOperationException($"The hardware on I2C Bus {I2cDevice.ConnectionSettings.BusId}, Address 0x{I2cDevice.ConnectionSettings.DeviceAddress:X2} does not support Adafruit SeeSaw encoder functionality");
}
return BinaryPrimitives.ReadInt32BigEndian(Read(SeesawModule.Encoder, SeesawFunction.EncoderDelta + encoder, 4, 8000));
}
/// <summary>
/// Enable the interrupt to fire when the encoder changes position.
/// </summary>
/// <param name="encoder">Which encoder to use, defaults to 0.</param>
/// <exception cref="InvalidOperationException">The hardware does not support Adafruit SeeSaw encoder functionality.</exception>
public void EnableEncoderInterrupt(byte encoder = 0)
{
if (!HasModule(SeesawModule.Encoder))
{
throw new InvalidOperationException($"The hardware on I2C Bus {I2cDevice.ConnectionSettings.BusId}, Address 0x{I2cDevice.ConnectionSettings.DeviceAddress:X2} does not support Adafruit SeeSaw encoder functionality");
}
WriteByte(SeesawModule.Encoder, SeesawFunction.EncoderIntenset + encoder, 0x01);
}
/// <summary>
/// Disable the interrupt from firing when the encoder changes.
/// </summary>
/// <param name="encoder">Which encoder to use, defaults to 0.</param>
/// <exception cref="InvalidOperationException">The hardware does not support Adafruit SeeSaw encoder functionality.</exception>
public void DisableEncoderInterrupt(byte encoder = 0)
{
if (!HasModule(SeesawModule.Encoder))
{
throw new InvalidOperationException($"The hardware on I2C Bus {I2cDevice.ConnectionSettings.BusId}, Address 0x{I2cDevice.ConnectionSettings.DeviceAddress:X2} does not support Adafruit SeeSaw encoder functionality");
}
WriteByte(SeesawModule.Encoder, SeesawFunction.EncoderIntenclr + encoder, 0x01);
}
}
}
......@@ -138,6 +138,24 @@ namespace Iot.Device.Seesaw
/// <summary>Touch channel offset</summary>
TouchChannelOffset = 0x10,
// encoder functions
/// <summary>Status</summary>
EncoderStatus = 0x00,
/// <summary>Enable encoder interrupt</summary>
EncoderIntenset = 0x10,
/// <summary>Clear encoder interrupt</summary>
EncoderIntenclr = 0x20,
/// <summary>Encoder position</summary>
EncoderPosition = 0x30,
/// <summary>Encoder position delta</summary>
EncoderDelta = 0x40
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Device.Gpio;
using System.Device.I2c;
using Iot.Device.Seesaw;
const byte AdafruitSeesawRotaryEncoderI2cAddress = 0x36;
const byte AdafruitSeesawRotaryEncoderI2cBus = 0x1;
const byte AdafruitSeesawRotaryEncoderPushSwitchPin = 24;
const int EncoderPositionInitialValue = 100;
const int HostInterruptPin = 6;
using GpioController gpioController = new(PinNumberingScheme.Logical);
using Seesaw seesawDevice = new(I2cDevice.Create(new I2cConnectionSettings(AdafruitSeesawRotaryEncoderI2cBus, AdafruitSeesawRotaryEncoderI2cAddress)));
// set initial encoder position value
seesawDevice.SetEncoderPosition(EncoderPositionInitialValue);
// enable interrupt for position changes on Seesaw encoder
seesawDevice.EnableEncoderInterrupt();
// enable interrupt for rotary encoder push switch
uint encoderPushSwitchPinMask = 1U << (AdafruitSeesawRotaryEncoderPushSwitchPin);
seesawDevice.SetGpioPinMode(AdafruitSeesawRotaryEncoderPushSwitchPin, PinMode.InputPullUp);
seesawDevice.SetGpioInterrupts(encoderPushSwitchPinMask, true);
// enable host interrupt and register callback
gpioController.OpenPin(HostInterruptPin, PinMode.InputPullUp);
gpioController.RegisterCallbackForPinValueChangedEvent(HostInterruptPin, PinEventTypes.Falling, (s, e) =>
{
uint interruptFlags = seesawDevice.ReadGpioInterruptFlags();
if ((interruptFlags & encoderPushSwitchPinMask) > 0)
{
// interrupt for push switch pin -> push switch status changed
bool pushSwitchReleased = seesawDevice.ReadGpioDigital(AdafruitSeesawRotaryEncoderPushSwitchPin);
Console.WriteLine($"Encoder switch {(pushSwitchReleased ? "released" : "pressed")}");
return;
}
int encoderPosition = seesawDevice.GetEncoderPosition();
Console.WriteLine($"Encoder position changed: {encoderPosition}");
});
// press Enter to exit application
Console.ReadLine();
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(DefaultSampleTfms)</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
</PropertyGroup>
<ItemGroup>
<Compile Include="Seesaw.Sample.Encoder.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Seesaw.csproj" />
</ItemGroup>
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册