first commit

This commit is contained in:
pandacraft 2025-03-21 16:04:17 +01:00
commit a5a0434432
1126 changed files with 439481 additions and 0 deletions

View file

@ -0,0 +1,61 @@
using System;
using Windows.Devices.I2c;
namespace GrovePi.I2CDevices
{
public interface IMiniMotorDriver
{
IMiniMotorDriver drive1(int Speed);
IMiniMotorDriver drive2(int Speed);
//IMiniMotorDriver getFault();
}
internal sealed class MiniMotorDriver : IMiniMotorDriver
{
internal MiniMotorDriver(I2cDevice Motor1Device, I2cDevice Motor2Device)
{
if (Motor1Device == null) throw new ArgumentNullException(nameof(Motor1Device));
motor1DirectAccess = Motor1Device;
if (Motor2Device == null) throw new ArgumentNullException(nameof(Motor2Device));
motor2DirectAccess = Motor2Device;
}
~MiniMotorDriver()
{
this.drive1(0);
this.drive2(0);
}
internal I2cDevice motor1DirectAccess { get; }
internal I2cDevice motor2DirectAccess { get; }
public IMiniMotorDriver drive1(int Speed)
{
byte regValue = 0x80;
motor1DirectAccess.Write(new byte[] { 0x1, regValue });
regValue = (byte)Math.Abs(Speed);
if (regValue > 63) regValue = 63;
regValue = (byte)(regValue * 4);
if (Speed < 0) regValue |= 0x01;
else regValue |= 0x02;
motor1DirectAccess.Write(new byte[] { 0x00, regValue});
return this;
}
public IMiniMotorDriver drive2(int Speed)
{
byte regValue = 0x80;
motor2DirectAccess.Write(new byte[] { 0x1, regValue });
regValue = (byte)Math.Abs(Speed);
if (regValue > 63) regValue = 63;
regValue = (byte)(regValue * 4);
if (Speed < 0) regValue |= 0x01;
else regValue |= 0x02;
motor2DirectAccess.Write(new byte[] { 0x00, regValue });
return this;
}
}
}

View file

@ -0,0 +1,440 @@
/*
* Ten Wong (wangtengoo7@gmail.com) 2017 Seeed technology inc.
* Refer to: https://github.com/Seeed-Studio/OLED_Display_128X64
* MIT License
*/
using System;
using Windows.Devices.I2c;
namespace GrovePi.I2CDevices
{
public interface IOLEDDisplay128X64
{
void init();
void setNormalDisplay();
void setInverseDisplay();
void sendCommand(byte command);
void sendData(byte data);
void setPageMode();
void setHorizontalMode();
void setTextXY(byte row, byte column);
void clearDisplay();
void setBrightness(byte brightness);
void putChar(char c);
void putString(string str);
int putNumber(long n);
int putFloat(float floatNumber, byte deci);
int putFloat(float floatNumber);
void drawBitmap(byte[] bitmaparray, int bytes);
void setHorizontalScrollProperties(byte direction, byte startPage, byte endPage, byte scrollSpeed);
void activateScroll();
void deactivateScroll();
}
internal sealed class OLEDDisplay128X64: IOLEDDisplay128X64
{
private const byte SeeedOLED_Max_X = 127; //128 Pixels
private const byte SeeedOLED_Max_Y = 63; //64 Pixels
private const byte PAGE_MODE = 01;
private const byte HORIZONTAL_MODE = 02;
private const byte SeeedOLED_Address = 0x3c;
private const byte SeeedOLED_Command_Mode = 0x80;
private const byte SeeedOLED_Data_Mode = 0x40;
private const byte SeeedOLED_Display_Off_Cmd = 0xAE;
private const byte SeeedOLED_Display_On_Cmd = 0xAF;
private const byte SeeedOLED_Normal_Display_Cmd = 0xA6;
private const byte SeeedOLED_Inverse_Display_Cmd = 0xA7;
private const byte SeeedOLED_Activate_Scroll_Cmd = 0x2F;
private const byte SeeedOLED_Dectivate_Scroll_Cmd = 0x2E;
private const byte SeeedOLED_Set_Brightness_Cmd = 0x81;
private const byte Scroll_Left = 0x00;
private const byte Scroll_Right = 0x01;
private const byte Scroll_2Frames = 0x7;
private const byte Scroll_3Frames = 0x4;
private const byte Scroll_4Frames = 0x5;
private const byte Scroll_5Frames = 0x0;
private const byte Scroll_25Frames = 0x6;
private const byte Scroll_64Frames = 0x1;
private const byte Scroll_128Frames = 0x2;
private const byte Scroll_256Frames = 0x3;
// This font be freely used without any restriction(It is placed in public domain)
private byte[,] BasicFont = new byte[,]
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x5F,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00},
{0x00,0x14,0x7F,0x14,0x7F,0x14,0x00,0x00},
{0x00,0x24,0x2A,0x7F,0x2A,0x12,0x00,0x00},
{0x00,0x23,0x13,0x08,0x64,0x62,0x00,0x00},
{0x00,0x36,0x49,0x55,0x22,0x50,0x00,0x00},
{0x00,0x00,0x05,0x03,0x00,0x00,0x00,0x00},
{0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00},
{0x00,0x41,0x22,0x1C,0x00,0x00,0x00,0x00},
{0x00,0x08,0x2A,0x1C,0x2A,0x08,0x00,0x00},
{0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00},
{0x00,0xA0,0x60,0x00,0x00,0x00,0x00,0x00},
{0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00},
{0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00},
{0x00,0x20,0x10,0x08,0x04,0x02,0x00,0x00},
{0x00,0x3E,0x51,0x49,0x45,0x3E,0x00,0x00},
{0x00,0x00,0x42,0x7F,0x40,0x00,0x00,0x00},
{0x00,0x62,0x51,0x49,0x49,0x46,0x00,0x00},
{0x00,0x22,0x41,0x49,0x49,0x36,0x00,0x00},
{0x00,0x18,0x14,0x12,0x7F,0x10,0x00,0x00},
{0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00},
{0x00,0x3C,0x4A,0x49,0x49,0x30,0x00,0x00},
{0x00,0x01,0x71,0x09,0x05,0x03,0x00,0x00},
{0x00,0x36,0x49,0x49,0x49,0x36,0x00,0x00},
{0x00,0x06,0x49,0x49,0x29,0x1E,0x00,0x00},
{0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00},
{0x00,0x00,0xAC,0x6C,0x00,0x00,0x00,0x00},
{0x00,0x08,0x14,0x22,0x41,0x00,0x00,0x00},
{0x00,0x14,0x14,0x14,0x14,0x14,0x00,0x00},
{0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x00},
{0x00,0x02,0x01,0x51,0x09,0x06,0x00,0x00},
{0x00,0x32,0x49,0x79,0x41,0x3E,0x00,0x00},
{0x00,0x7E,0x09,0x09,0x09,0x7E,0x00,0x00},
{0x00,0x7F,0x49,0x49,0x49,0x36,0x00,0x00},
{0x00,0x3E,0x41,0x41,0x41,0x22,0x00,0x00},
{0x00,0x7F,0x41,0x41,0x22,0x1C,0x00,0x00},
{0x00,0x7F,0x49,0x49,0x49,0x41,0x00,0x00},
{0x00,0x7F,0x09,0x09,0x09,0x01,0x00,0x00},
{0x00,0x3E,0x41,0x41,0x51,0x72,0x00,0x00},
{0x00,0x7F,0x08,0x08,0x08,0x7F,0x00,0x00},
{0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00},
{0x00,0x20,0x40,0x41,0x3F,0x01,0x00,0x00},
{0x00,0x7F,0x08,0x14,0x22,0x41,0x00,0x00},
{0x00,0x7F,0x40,0x40,0x40,0x40,0x00,0x00},
{0x00,0x7F,0x02,0x0C,0x02,0x7F,0x00,0x00},
{0x00,0x7F,0x04,0x08,0x10,0x7F,0x00,0x00},
{0x00,0x3E,0x41,0x41,0x41,0x3E,0x00,0x00},
{0x00,0x7F,0x09,0x09,0x09,0x06,0x00,0x00},
{0x00,0x3E,0x41,0x51,0x21,0x5E,0x00,0x00},
{0x00,0x7F,0x09,0x19,0x29,0x46,0x00,0x00},
{0x00,0x26,0x49,0x49,0x49,0x32,0x00,0x00},
{0x00,0x01,0x01,0x7F,0x01,0x01,0x00,0x00},
{0x00,0x3F,0x40,0x40,0x40,0x3F,0x00,0x00},
{0x00,0x1F,0x20,0x40,0x20,0x1F,0x00,0x00},
{0x00,0x3F,0x40,0x38,0x40,0x3F,0x00,0x00},
{0x00,0x63,0x14,0x08,0x14,0x63,0x00,0x00},
{0x00,0x03,0x04,0x78,0x04,0x03,0x00,0x00},
{0x00,0x61,0x51,0x49,0x45,0x43,0x00,0x00},
{0x00,0x7F,0x41,0x41,0x00,0x00,0x00,0x00},
{0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00},
{0x00,0x41,0x41,0x7F,0x00,0x00,0x00,0x00},
{0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00},
{0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00},
{0x00,0x01,0x02,0x04,0x00,0x00,0x00,0x00},
{0x00,0x20,0x54,0x54,0x54,0x78,0x00,0x00},
{0x00,0x7F,0x48,0x44,0x44,0x38,0x00,0x00},
{0x00,0x38,0x44,0x44,0x28,0x00,0x00,0x00},
{0x00,0x38,0x44,0x44,0x48,0x7F,0x00,0x00},
{0x00,0x38,0x54,0x54,0x54,0x18,0x00,0x00},
{0x00,0x08,0x7E,0x09,0x02,0x00,0x00,0x00},
{0x00,0x18,0xA4,0xA4,0xA4,0x7C,0x00,0x00},
{0x00,0x7F,0x08,0x04,0x04,0x78,0x00,0x00},
{0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00},
{0x00,0x80,0x84,0x7D,0x00,0x00,0x00,0x00},
{0x00,0x7F,0x10,0x28,0x44,0x00,0x00,0x00},
{0x00,0x41,0x7F,0x40,0x00,0x00,0x00,0x00},
{0x00,0x7C,0x04,0x18,0x04,0x78,0x00,0x00},
{0x00,0x7C,0x08,0x04,0x7C,0x00,0x00,0x00},
{0x00,0x38,0x44,0x44,0x38,0x00,0x00,0x00},
{0x00,0xFC,0x24,0x24,0x18,0x00,0x00,0x00},
{0x00,0x18,0x24,0x24,0xFC,0x00,0x00,0x00},
{0x00,0x00,0x7C,0x08,0x04,0x00,0x00,0x00},
{0x00,0x48,0x54,0x54,0x24,0x00,0x00,0x00},
{0x00,0x04,0x7F,0x44,0x00,0x00,0x00,0x00},
{0x00,0x3C,0x40,0x40,0x7C,0x00,0x00,0x00},
{0x00,0x1C,0x20,0x40,0x20,0x1C,0x00,0x00},
{0x00,0x3C,0x40,0x30,0x40,0x3C,0x00,0x00},
{0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00},
{0x00,0x1C,0xA0,0xA0,0x7C,0x00,0x00,0x00},
{0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00},
{0x00,0x08,0x36,0x41,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00},
{0x00,0x41,0x36,0x08,0x00,0x00,0x00,0x00},
{0x00,0x02,0x01,0x01,0x02,0x01,0x00,0x00},
{0x00,0x02,0x05,0x05,0x02,0x00,0x00,0x00}
};
internal I2cDevice DirectAccess { get; }
internal byte addressingMode;
internal OLEDDisplay128X64(I2cDevice Device)
{
if (Device == null) throw new ArgumentNullException(nameof(Device));
DirectAccess = Device;
}
public void init()
{
sendCommand(SeeedOLED_Display_Off_Cmd); //display off
//delay(5);
sendCommand(SeeedOLED_Display_On_Cmd); //display on
//delay(5);
sendCommand(SeeedOLED_Normal_Display_Cmd); //Set Normal Display (default)
}
public void setNormalDisplay()
{
sendCommand(SeeedOLED_Normal_Display_Cmd);
}
public void setInverseDisplay()
{
sendCommand(SeeedOLED_Inverse_Display_Cmd);
}
public void sendCommand(byte command)
{
DirectAccess.Write(new byte[] { SeeedOLED_Command_Mode, command });
}
public void sendData(byte data)
{
DirectAccess.Write(new byte[] { SeeedOLED_Data_Mode, data });
}
public void setPageMode()
{
addressingMode = PAGE_MODE;
sendCommand(0x20); //set addressing mode
sendCommand(0x02); //set page addressing mode
}
public void setHorizontalMode()
{
addressingMode = HORIZONTAL_MODE;
sendCommand(0x20); //set addressing mode
sendCommand(0x00); //set horizontal addressing mode
}
public void setTextXY(byte row, byte column)
{
sendCommand((byte)(0xB0 + row)); //set page address
sendCommand((byte)(0x00 + (8 * column & 0x0F))); //set column lower address
sendCommand((byte)(0x10 + ((8 * column >> 4) & 0x0F))); //set column higher address
}
public void clearDisplay()
{
byte i, j;
sendCommand(SeeedOLED_Display_Off_Cmd); //display off
for (j = 0; j < 8; j++)
{
setTextXY(j, 0);
{
for (i = 0; i < 16; i++) //clear all columns
{
putChar(' ');
}
}
}
sendCommand(SeeedOLED_Display_On_Cmd); //display on
setTextXY(0, 0);
}
public void setBrightness(byte brightness)
{
sendCommand(SeeedOLED_Set_Brightness_Cmd);
sendCommand(brightness);
}
public void putChar(char c)
{
if (c < 32 || c > 127) //Ignore non-printable ASCII characters. This can be modified for multilingual font.
{
c = ' '; //Space
}
byte i = 0;
for (i = 0; i < 8; i++)
{
//read bytes from code memory
sendData(BasicFont[c-32, i]); //font array starts at 0, ASCII starts at 32. Hence the translation
}
}
public void putString(string str)
{
foreach (var c in str)
{
putChar(c);
}
}
public int putNumber(long long_num)
{
char[] char_buffer = new char[10];
int i = 0;
int f = 0;
if (long_num < 0)
{
f = 1;
putChar('-');
long_num = -long_num;
}
else if (long_num == 0)
{
f = 1;
putChar('0');
return f;
}
while (long_num > 0)
{
char_buffer[i++] = (char)(long_num % 10);
long_num /= 10;
}
f = f + i;
for (; i > 0; i--)
{
putChar((char)('0' + (int)(char_buffer[i - 1])));
}
return f;
}
public int putFloat(float floatNumber, byte deci)
{
int temp = 0;
float decy = 0.0F;
float rounding = 0.5F;
int f = 0;
if (floatNumber < 0.0F)
{
putString("-");
floatNumber = -floatNumber;
f += 1;
}
for (int i = 0; i < deci; ++i)
{
rounding /= 10.0F;
}
floatNumber += rounding;
temp = (int)floatNumber;
f += putNumber(temp);
if (deci > 0)
{
putChar('.');
f += 1;
}
decy = floatNumber - temp;//decimal part,
for (int i = 0; i < deci; i++)//4
{
decy *= 10;// for the next decimal
temp = (int)decy;//get the decimal
putNumber(temp);
decy -= temp;
}
f += deci;
return f;
}
public int putFloat(float floatNumber)
{
int deci= 2;
int temp = 0;
float decy = 0.0F;
float rounding = 0.5F;
int f = 0;
if (floatNumber < 0.0)
{
putString("-");
floatNumber = -floatNumber;
f += 1;
}
for (int i = 0; i < deci; ++i)
{
rounding /= 10.0F;
}
floatNumber += rounding;
temp = (int)floatNumber;
f += putNumber(temp);
if (deci > 0)
{
putChar('.');
f += 1;
}
decy = floatNumber - temp;//decimal part,
for (int i = 0; i < deci; i++)//4
{
decy *= 10;// for the next decimal
temp = (int)decy;//get the decimal
putNumber(temp);
decy -= temp;
}
f += deci;
return f;
}
public void drawBitmap(byte[] bitmaparray, int bytes)
{
byte localAddressMode = addressingMode;
if (addressingMode != HORIZONTAL_MODE)
{
//Bitmap is drawn in horizontal mode
setHorizontalMode();
}
for (int i = 0; i < bytes; i++)
{
sendData(bitmaparray[i]);
}
if (localAddressMode == PAGE_MODE)
{
//If pageMode was used earlier, restore it.
setPageMode();
}
}
public void setHorizontalScrollProperties(byte direction, byte startPage, byte endPage, byte scrollSpeed)
{
if (Scroll_Right == direction)
{
//Scroll Right
sendCommand(0x26);
}
else
{
//Scroll Left
sendCommand(0x27);
}
sendCommand(0x00);
sendCommand(startPage);
sendCommand(scrollSpeed);
sendCommand(endPage);
sendCommand(0x00);
sendCommand(0xFF);
}
public void activateScroll()
{
sendCommand(SeeedOLED_Activate_Scroll_Cmd);
}
public void deactivateScroll()
{
sendCommand(SeeedOLED_Dectivate_Scroll_Cmd);
}
}
}

View file

@ -0,0 +1,450 @@
using System;
using Windows.Devices.I2c;
using GrovePi.Common;
using System.Diagnostics;
namespace GrovePi.I2CDevices
{
public interface IOLEDDisplay9696
{
IOLEDDisplay9696 initialize();
IOLEDDisplay9696 setNormalDisplay();
IOLEDDisplay9696 sendCommand(byte cmd);
IOLEDDisplay9696 sendData(byte Data);
IOLEDDisplay9696 setGrayLevel(byte grayLevel);
IOLEDDisplay9696 setVerticalMode();
IOLEDDisplay9696 setHorizontalMode();
IOLEDDisplay9696 setTextXY(byte Row, byte Column);
IOLEDDisplay9696 clearDisplay();
IOLEDDisplay9696 setContrastLevel(byte ContrastLevel);
IOLEDDisplay9696 putChar(char C);
IOLEDDisplay9696 putString(string text);
//IOLEDDisplay9696 putNumber();
//IOLEDDisplay9696 putFloat();
//IOLEDDisplay9696 putFloat();
IOLEDDisplay9696 drawBitmap(byte[] bitmaparray, int bytes);
IOLEDDisplay9696 setHorizontalScrollProperties(bool direction, byte startRow, byte endRow, byte startColumn, byte endColumn, byte scrollSpeed);
IOLEDDisplay9696 activateScroll();
IOLEDDisplay9696 deactivateScroll();
}
internal sealed class OLEDDisplay9696 : IOLEDDisplay9696
{
private const byte VERTICAL_MODE = 1;
private const byte HORIZONTAL_MODE = 2;
private const byte SeeedGrayOLED_Address = 0x3c;
private const byte SeeedGrayOLED_Command_Mode = 0x80;
private const byte SeeedGrayOLED_Data_Mode = 0x40;
private const byte SeeedGrayOLED_Display_Off_Cmd = 0xAE;
private const byte SeeedGrayOLED_Display_On_Cmd = 0xAF;
private const byte SeeedGrayOLED_Normal_Display_Cmd = 0xA4;
private const byte SeeedGrayOLED_Inverse_Display_Cmd = 0xA7;
private const byte SeeedGrayOLED_Activate_Scroll_Cmd = 0x2F;
private const byte SeeedGrayOLED_Dectivate_Scroll_Cmd = 0x2E;
private const byte SeeedGrayOLED_Set_ContrastLevel_Cmd = 0x81;
private const byte Scroll_Left = 0x00;
private const byte Scroll_Right = 0x01;
private const byte Scroll_2Frames = 0x7;
private const byte Scroll_3Frames = 0x4;
private const byte Scroll_4Frames = 0x5;
private const byte Scroll_5Frames = 0x0;
private const byte Scroll_25Frames = 0x6;
private const byte Scroll_64Frames = 0x1;
private const byte Scroll_128Frames = 0x2;
private const byte Scroll_256Frames = 0x3;
private byte grayH = 0;
private byte grayL = 0;
private byte addressingMode = 0;
private byte[,] BasicFont = new byte[,]
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x5F,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00},
{0x00,0x14,0x7F,0x14,0x7F,0x14,0x00,0x00},
{0x00,0x24,0x2A,0x7F,0x2A,0x12,0x00,0x00},
{0x00,0x23,0x13,0x08,0x64,0x62,0x00,0x00},
{0x00,0x36,0x49,0x55,0x22,0x50,0x00,0x00},
{0x00,0x00,0x05,0x03,0x00,0x00,0x00,0x00},
{0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00},
{0x00,0x41,0x22,0x1C,0x00,0x00,0x00,0x00},
{0x00,0x08,0x2A,0x1C,0x2A,0x08,0x00,0x00},
{0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00},
{0x00,0xA0,0x60,0x00,0x00,0x00,0x00,0x00},
{0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00},
{0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00},
{0x00,0x20,0x10,0x08,0x04,0x02,0x00,0x00},
{0x00,0x3E,0x51,0x49,0x45,0x3E,0x00,0x00},
{0x00,0x00,0x42,0x7F,0x40,0x00,0x00,0x00},
{0x00,0x62,0x51,0x49,0x49,0x46,0x00,0x00},
{0x00,0x22,0x41,0x49,0x49,0x36,0x00,0x00},
{0x00,0x18,0x14,0x12,0x7F,0x10,0x00,0x00},
{0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00},
{0x00,0x3C,0x4A,0x49,0x49,0x30,0x00,0x00},
{0x00,0x01,0x71,0x09,0x05,0x03,0x00,0x00},
{0x00,0x36,0x49,0x49,0x49,0x36,0x00,0x00},
{0x00,0x06,0x49,0x49,0x29,0x1E,0x00,0x00},
{0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00},
{0x00,0x00,0xAC,0x6C,0x00,0x00,0x00,0x00},
{0x00,0x08,0x14,0x22,0x41,0x00,0x00,0x00},
{0x00,0x14,0x14,0x14,0x14,0x14,0x00,0x00},
{0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x00},
{0x00,0x02,0x01,0x51,0x09,0x06,0x00,0x00},
{0x00,0x32,0x49,0x79,0x41,0x3E,0x00,0x00},
{0x00,0x7E,0x09,0x09,0x09,0x7E,0x00,0x00},
{0x00,0x7F,0x49,0x49,0x49,0x36,0x00,0x00},
{0x00,0x3E,0x41,0x41,0x41,0x22,0x00,0x00},
{0x00,0x7F,0x41,0x41,0x22,0x1C,0x00,0x00},
{0x00,0x7F,0x49,0x49,0x49,0x41,0x00,0x00},
{0x00,0x7F,0x09,0x09,0x09,0x01,0x00,0x00},
{0x00,0x3E,0x41,0x41,0x51,0x72,0x00,0x00},
{0x00,0x7F,0x08,0x08,0x08,0x7F,0x00,0x00},
{0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00},
{0x00,0x20,0x40,0x41,0x3F,0x01,0x00,0x00},
{0x00,0x7F,0x08,0x14,0x22,0x41,0x00,0x00},
{0x00,0x7F,0x40,0x40,0x40,0x40,0x00,0x00},
{0x00,0x7F,0x02,0x0C,0x02,0x7F,0x00,0x00},
{0x00,0x7F,0x04,0x08,0x10,0x7F,0x00,0x00},
{0x00,0x3E,0x41,0x41,0x41,0x3E,0x00,0x00},
{0x00,0x7F,0x09,0x09,0x09,0x06,0x00,0x00},
{0x00,0x3E,0x41,0x51,0x21,0x5E,0x00,0x00},
{0x00,0x7F,0x09,0x19,0x29,0x46,0x00,0x00},
{0x00,0x26,0x49,0x49,0x49,0x32,0x00,0x00},
{0x00,0x01,0x01,0x7F,0x01,0x01,0x00,0x00},
{0x00,0x3F,0x40,0x40,0x40,0x3F,0x00,0x00},
{0x00,0x1F,0x20,0x40,0x20,0x1F,0x00,0x00},
{0x00,0x3F,0x40,0x38,0x40,0x3F,0x00,0x00},
{0x00,0x63,0x14,0x08,0x14,0x63,0x00,0x00},
{0x00,0x03,0x04,0x78,0x04,0x03,0x00,0x00},
{0x00,0x61,0x51,0x49,0x45,0x43,0x00,0x00},
{0x00,0x7F,0x41,0x41,0x00,0x00,0x00,0x00},
{0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00},
{0x00,0x41,0x41,0x7F,0x00,0x00,0x00,0x00},
{0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00},
{0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00},
{0x00,0x01,0x02,0x04,0x00,0x00,0x00,0x00},
{0x00,0x20,0x54,0x54,0x54,0x78,0x00,0x00},
{0x00,0x7F,0x48,0x44,0x44,0x38,0x00,0x00},
{0x00,0x38,0x44,0x44,0x28,0x00,0x00,0x00},
{0x00,0x38,0x44,0x44,0x48,0x7F,0x00,0x00},
{0x00,0x38,0x54,0x54,0x54,0x18,0x00,0x00},
{0x00,0x08,0x7E,0x09,0x02,0x00,0x00,0x00},
{0x00,0x18,0xA4,0xA4,0xA4,0x7C,0x00,0x00},
{0x00,0x7F,0x08,0x04,0x04,0x78,0x00,0x00},
{0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00},
{0x00,0x80,0x84,0x7D,0x00,0x00,0x00,0x00},
{0x00,0x7F,0x10,0x28,0x44,0x00,0x00,0x00},
{0x00,0x41,0x7F,0x40,0x00,0x00,0x00,0x00},
{0x00,0x7C,0x04,0x18,0x04,0x78,0x00,0x00},
{0x00,0x7C,0x08,0x04,0x7C,0x00,0x00,0x00},
{0x00,0x38,0x44,0x44,0x38,0x00,0x00,0x00},
{0x00,0xFC,0x24,0x24,0x18,0x00,0x00,0x00},
{0x00,0x18,0x24,0x24,0xFC,0x00,0x00,0x00},
{0x00,0x00,0x7C,0x08,0x04,0x00,0x00,0x00},
{0x00,0x48,0x54,0x54,0x24,0x00,0x00,0x00},
{0x00,0x04,0x7F,0x44,0x00,0x00,0x00,0x00},
{0x00,0x3C,0x40,0x40,0x7C,0x00,0x00,0x00},
{0x00,0x1C,0x20,0x40,0x20,0x1C,0x00,0x00},
{0x00,0x3C,0x40,0x30,0x40,0x3C,0x00,0x00},
{0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00},
{0x00,0x1C,0xA0,0xA0,0x7C,0x00,0x00,0x00},
{0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00},
{0x00,0x08,0x36,0x41,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00},
{0x00,0x41,0x36,0x08,0x00,0x00,0x00,0x00},
{0x00,0x02,0x01,0x01,0x02,0x01,0x00,0x00},
{0x00,0x02,0x05,0x05,0x02,0x00,0x00,0x00}
};
internal OLEDDisplay9696(I2cDevice Device)
{
if (Device == null) throw new ArgumentNullException(nameof(Device));
DirectAccess = Device;
}
public IOLEDDisplay9696 initialize()
{
this.sendCommand(0xFD); // unlock IC MCU from entering command.
this.sendCommand(0x12);
this.sendCommand(0xAE); // Set display off
this.sendCommand(0xA8); // set multiplex ratio
this.sendCommand(0x5F); // 96
this.sendCommand(0xA1); // set display start line
this.sendCommand(0x00);
this.sendCommand(0xA2); // set display offset
this.sendCommand(0x60);
this.sendCommand(0xA0); // set remap
this.sendCommand(0x46);
this.sendCommand(0xAB); // set vdd internal
this.sendCommand(0x01); //
this.sendCommand(0x81); // set contrasr
this.sendCommand(0x53); // 100 nit
this.sendCommand(0xB1); // Set Phase Length
this.sendCommand(0X51); //
this.sendCommand(0xB3); // Set Display Clock Divide Ratio/Oscillator Frequency
this.sendCommand(0x01);
this.sendCommand(0xB9); //
this.sendCommand(0xBC); // set pre_charge voltage/VCOMH
this.sendCommand(0x08); // (0x08);
this.sendCommand(0xBE); // set VCOMH
this.sendCommand(0X07); // (0x07);
this.sendCommand(0xB6); // Set second pre-charge period
this.sendCommand(0x01); //
this.sendCommand(0xD5); // enable second precharge and enternal vsl
this.sendCommand(0X62); // (0x62);
this.sendCommand(0xA4); // Set Normal Display Mode
this.sendCommand(0x2E); // Deactivate Scroll
this.sendCommand(0xAF); // Switch on display
Delay.Milliseconds(100);
// Row Address
this.sendCommand(0x75); // Set Row Address
this.sendCommand(0x00); // Start 0
this.sendCommand(0x5f); // End 95
// Column Address
this.sendCommand(0x15); // Set Column Address
this.sendCommand(0x08); // Start from 8th Column of driver IC. This is 0th Column for OLED
this.sendCommand(0x37); // End at (8 + 47)th column. Each Column has 2 pixels(segments)
// Init gray level for text. Default:Brightest White
grayH = 0xF0;
grayL = 0x0F;
return this;
}
internal I2cDevice DirectAccess { get; }
public IOLEDDisplay9696 sendCommand(byte cmd)
{
DirectAccess.Write(new byte[] { SeeedGrayOLED_Command_Mode, cmd });
return this;
}
public IOLEDDisplay9696 setContrastLevel(byte ContrastLevel)
{
this.sendCommand(SeeedGrayOLED_Set_ContrastLevel_Cmd);
this.sendCommand(ContrastLevel);
return this;
}
public IOLEDDisplay9696 setHorizontalMode()
{
this.sendCommand(0xA0); // remap to
this.sendCommand(0x42); // horizontal mode
// Row Address
this.sendCommand(0x75); // Set Row Address
this.sendCommand(0x00); // Start 0
this.sendCommand(0x5f); // End 95
// Column Address
this.sendCommand(0x15); // Set Column Address
this.sendCommand(0x08); // Start from 8th Column of driver IC. This is 0th Column for OLED
this.sendCommand(0x37); // End at (8 + 47)th column. Each Column has 2 pixels(or segments)
return this;
}
public IOLEDDisplay9696 setVerticalMode()
{
this.sendCommand(0xA0); // remap to
this.sendCommand(0x46); // Vertical mode
return this;
}
public IOLEDDisplay9696 setTextXY(byte Row, byte Column)
{
//Column Address
this.sendCommand(0x15); /* Set Column Address */
this.sendCommand((byte)(0x08 + (Column * 4))); /* Start Column: Start from 8 */
this.sendCommand(0x37); /* End Column */
// Row Address
this.sendCommand(0x75); /* Set Row Address */
this.sendCommand((byte)(0x00 + (Row * 8))); /* Start Row*/
this.sendCommand((byte)(0x07 + (Row * 8))); /* End Row*/
return this;
}
public IOLEDDisplay9696 clearDisplay()
{
byte i, j;
for (j = 0; j < 48; j++)
{
for (i = 0; i < 96; i++) //clear all columns
{
this.sendData(0x00);
}
}
return this;
}
public IOLEDDisplay9696 sendData(byte Data)
{
DirectAccess.Write(new byte[] { SeeedGrayOLED_Data_Mode, Data });
return this;
}
public IOLEDDisplay9696 setGrayLevel(byte grayLevel)
{
grayH = (byte)((grayLevel << 4) & 0xF0);
grayL = (byte)(grayLevel & 0x0F);
return this;
}
public IOLEDDisplay9696 putChar(char C)
{
if (C < 32 || C > 127) //Ignore non-printable ASCII characters. This can be modified for multilingual font.
{
C = ' '; //Space
}
for (int i = 0; i < 8; i = i + 2)
{
for (int j = 0; j < 8; j++)
{
// Character is constructed two pixel at a time using vertical mode from the default 8x8 font
byte c = 0x00;
byte bit1 = (byte)((BasicFont[C - 32, i] >> j) & 0x01);
byte bit2 = (byte)((BasicFont[C - 32, i + 1] >> j) & 0x01);
// Each bit is changed to a nibble
c |= (byte)((bit1.Equals(0x01)) ? grayH : 0x00);
c |= (byte)((bit2.Equals(0x01)) ? grayL : 0x00);
this.sendData(c);
}
}
return this;
}
public IOLEDDisplay9696 putString(string text)
{
foreach (var C in text)
{
this.putChar(C);
}
return this;
}
public IOLEDDisplay9696 drawBitmap(byte[] bitmaparray, int bytes)
{
byte localAddressMode = this.addressingMode;
if (addressingMode != HORIZONTAL_MODE)
{
//Bitmap is drawn in horizontal mode
this.setHorizontalMode();
}
//for (int i = 0; i < bytes; i++)
foreach (var Byte in bitmaparray)
{
for (int j = 0; j < 8; j = j + 2)
{
byte c = 0x00;
byte bit1 = (byte)(Byte << j & 0x80);
byte bit2 = (byte)(Byte << (j + 1) & 0x80);
// Each bit is changed to a nibble
c |= (byte)((bit1.Equals(0x80)) ? grayH : 0x00);
// Each bit is changed to a nibble
c |= (byte)((bit2.Equals(0x80)) ? grayL : 0x00);
this.sendData(c);
}
}
if (localAddressMode == VERTICAL_MODE)
{
//If Vertical Mode was used earlier, restore it.
this.setVerticalMode();
}
return this;
}
public IOLEDDisplay9696 setHorizontalScrollProperties(bool direction, byte startRow, byte endRow, byte startColumn, byte endColumn, byte scrollSpeed)
{
/*
Use the following defines for 'direction' :
Scroll_Left
Scroll_Right
Use the following defines for 'scrollSpeed' :
Scroll_2Frames
Scroll_3Frames
Scroll_4Frames
Scroll_5Frames
Scroll_25Frames
Scroll_64Frames
Scroll_128Frames
Scroll_256Frames
*/
if (Scroll_Right.Equals(direction))
{
//Scroll Right
this.sendCommand(0x27);
}
else
{
//Scroll Left
this.sendCommand(0x26);
}
this.sendCommand(0x00); //Dummmy byte
this.sendCommand(startRow);
this.sendCommand(scrollSpeed);
this.sendCommand(endRow);
this.sendCommand((byte)(startColumn + 8));
this.sendCommand((byte)(endColumn + 8));
this.sendCommand(0x00); //Dummmy byte
return this;
}
public IOLEDDisplay9696 activateScroll()
{
this.sendCommand(SeeedGrayOLED_Activate_Scroll_Cmd);
return this;
}
public IOLEDDisplay9696 deactivateScroll()
{
this.sendCommand(SeeedGrayOLED_Dectivate_Scroll_Cmd);
return this;
}
public IOLEDDisplay9696 setNormalDisplay()
{
this.sendCommand(SeeedGrayOLED_Normal_Display_Cmd);
return this;
}
public IOLEDDisplay9696 setInverseDisplay()
{
this.sendCommand(SeeedGrayOLED_Inverse_Display_Cmd);
return this;
}
}
}

View file

@ -0,0 +1,78 @@
using System;
using Windows.Devices.I2c;
using GrovePi.Common;
namespace GrovePi.I2CDevices
{
public interface IRgbLcdDisplay
{
IRgbLcdDisplay SetBacklightRgb(byte red, byte green, byte blue);
IRgbLcdDisplay SetText(string text);
}
internal sealed class RgbLcdDisplay : IRgbLcdDisplay
{
private const byte RedCommandAddress = 4;
private const byte GreenCommandAddress = 3;
private const byte BlueCommandAddress = 2;
private const byte TextCommandAddress = 0x80;
private const byte ClearDisplayCommandAddress = 0x01;
private const byte DisplayOnCommandAddress = 0x08;
private const byte NoCursorCommandAddress = 0x04;
private const byte TwoLinesCommandAddress = 0x28;
private const byte SetCharacterCommandAddress = 0x40;
internal RgbLcdDisplay(I2cDevice rgbDevice, I2cDevice textDevice)
{
if (rgbDevice == null) throw new ArgumentNullException(nameof(rgbDevice));
if (textDevice == null) throw new ArgumentNullException(nameof(textDevice));
RgbDirectAccess = rgbDevice;
TextDirectAccess = textDevice;
}
internal I2cDevice RgbDirectAccess { get; }
internal I2cDevice TextDirectAccess { get; }
public IRgbLcdDisplay SetBacklightRgb(byte red, byte green, byte blue)
{
//TODO: Find out what these addresses are for , set const.
RgbDirectAccess.Write(new byte[] {0, 0});
RgbDirectAccess.Write(new byte[] {1, 0});
RgbDirectAccess.Write(new byte[] { DisplayOnCommandAddress, 0xaa});
RgbDirectAccess.Write(new[] {RedCommandAddress, red});
RgbDirectAccess.Write(new[] {GreenCommandAddress, green});
RgbDirectAccess.Write(new[] {BlueCommandAddress, blue});
return this;
}
public IRgbLcdDisplay SetText(string text)
{
TextDirectAccess.Write(new[] {TextCommandAddress, ClearDisplayCommandAddress});
Delay.Milliseconds(50);
TextDirectAccess.Write(new[] {TextCommandAddress, (byte)(DisplayOnCommandAddress | NoCursorCommandAddress)});
TextDirectAccess.Write(new[] {TextCommandAddress, TwoLinesCommandAddress});
var count = 0;
var row = 0;
foreach (var c in text)
{
if (c.Equals('\n') || count == Constants.GroveRgpLcdMaxLength)
{
count = 0;
row += 1;
if (row == Constants.GroveRgpLcdRows)
break;
TextDirectAccess.Write(new byte[] {TextCommandAddress, 0xc0}); //TODO: find out what this address is
if (c.Equals('\n'))
continue;
}
count += 1;
TextDirectAccess.Write(new[] {SetCharacterCommandAddress, (byte) c});
}
return this;
}
}
}

View file

@ -0,0 +1,155 @@
using Windows.Devices.I2c;
namespace GrovePi.I2CDevices
{
/// <summary>
///
/// </summary>
public interface ISHTTemperatureAndHumiditySensor
{
double TemperatureInCelsius { get; }
double TemperatureInFahrenheit { get; }
double RelativeHumidity { get; }
void Measure();
}
/// <summary>
/// Specifies the model of sensor.
/// </summary>
public enum SHTModel
{
Sht31 = 0
}
/// <summary>
/// The repeatability setting influences the measurement duration and the current
/// consumption of the sensor.
/// </summary>
public enum MeasurementMode
{
HighRepeatClockStretch = 0,
MediumRepeatClockStretch,
LowRepeatClockStretch,
HighRepeat,
MediumRepeat,
LowRepeat
}
internal class SHTTemperatureAndHumiditySensor : ISHTTemperatureAndHumiditySensor
{
private readonly SHTModel _model;
internal I2cDevice _device;
private byte[] MeasureHighClockStretch = new byte[2] { 0x2C, 0x06 };
private byte[] MeasureMediumClockStretch = new byte[2] { 0x2C, 0x0D };
private byte[] MeasureLowClockStretch = new byte[2] { 0x2C, 0x10 };
private byte[] MeasureHigh = new byte[2] { 0x24, 0x00 };
private byte[] MeasureMedium = new byte[2] { 0x24, 0x0B };
private byte[] MeasureLow = new byte[2] { 0x24, 0x16 };
private byte[] ReadStatusRegisterCommandAddress = new byte[2] { 0xF3, 0x2D };
private byte[] ClearStatusRegisterCommandAddress = new byte[2] { 0x30, 0x41 };
private byte[] SoftResetCommandAddress = new byte[2] { 0x30, 0xA2 };
private byte[] EnableHeaterCommandAddress = new byte[2] { 0x30, 0x6D };
private byte[] DisableHeaderCommandAddress = new byte[2] { 0x30, 0x66 };
private byte[] BreakCommandAddress = new byte[2] { 0x30, 0x93 };
private byte[] _sensorData = new byte[6];
private byte[] _sensorCommand = new byte[4];
public double TemperatureInCelsius { get; set; }
public double TemperatureInFahrenheit { get; set; }
public double RelativeHumidity { get; set; }
internal SHTTemperatureAndHumiditySensor(I2cDevice sensorDevice, SHTModel model, MeasurementMode measureMode)
{
_device = sensorDevice;
_model = model;
switch (measureMode)
{
case MeasurementMode.HighRepeatClockStretch:
_sensorCommand = MeasureHighClockStretch;
break;
case MeasurementMode.MediumRepeatClockStretch:
_sensorCommand = MeasureMediumClockStretch;
break;
case MeasurementMode.LowRepeatClockStretch:
_sensorCommand = MeasureLowClockStretch;
break;
case MeasurementMode.HighRepeat:
_sensorCommand = MeasureHigh;
break;
case MeasurementMode.MediumRepeat:
_sensorCommand = MeasureMedium;
break;
case MeasurementMode.LowRepeat:
_sensorCommand = MeasureLow;
break;
default:
_sensorCommand = MeasureHigh;
break;
}
}
public void Measure()
{
_device.WriteRead(_sensorCommand, _sensorData);
TemperatureInCelsius = (((_sensorData[0] * 256) + _sensorData[1]) * 175.0) / 65535.0 - 45.0;
TemperatureInFahrenheit = (((_sensorData[0] * 256) + _sensorData[1]) * 315.0) / 65535.0 - 49.0;
RelativeHumidity = (((_sensorData[3] * 256) + _sensorData[4])) * 100.0 / 65535.0 - 6.0;
}
/// <summary>
/// This triggers the sensor to reset its system controller and reloads calibration data from the memory.
/// </summary>
public void Reset()
{
_device.Write(SoftResetCommandAddress);
}
/// <summary>
/// All flags (Bit 15, 11, 10, 4) in the status register can be cleared (set to zero)
/// </summary>
public void ClearStatusRegister()
{
_device.Write(ClearStatusRegisterCommandAddress);
}
/// <summary>
/// The status register contains information on the operational status of the heater, the alert mode and on
/// the execution status of the last command and the last write sequence.
/// </summary>
/// <returns>16bit status register response</returns>
public byte[] ReadStatusRegister()
{
var statusResponse = new byte[2];
_device.WriteReadPartial(ReadStatusRegisterCommandAddress, statusResponse);
return statusResponse;
}
/// <summary>
/// The heater can be switched on and off by command
/// </summary>
public void EnableHeater()
{
_device.Write(EnableHeaterCommandAddress);
}
public void DisableHeater()
{
_device.Write(DisableHeaderCommandAddress);
}
/// <summary>
/// It is rrecommended to stop the periodic data acquisition prior to sending another command using the break command.
/// Upon reception of the break command the sensor enters the single shot mode.
/// </summary>
internal void Break()
{
_device.Write(BreakCommandAddress);
}
}
}

View file

@ -0,0 +1,405 @@
using System;
using System.Linq;
using GrovePi.I2CDevices.Configuration;
using Windows.Devices.I2c;
using static System.Math;
namespace GrovePi.I2CDevices
{
public interface ISixAxisAccelerometerAndCompass
{
byte DeviceId();
double[] GetAcceleration();
double[] GetMagnetic();
double GetHeading();
double GetTiltHeading();
ISixAxisAccelerometerAndCompass Configure(Action<ISixAxisAccelerometerAndCompassConfiguration> configuration);
}
public interface ISixAxisAccelerometerAndCompassConfiguration
{
void AccelerationAxes(AccelerationAxes value);
void AccelerationDataRate(AccelerationDataRate value);
void AccelerationDataUpdateMode(AccelerationDataUpdateMode value);
void AccelerationScale(AccelerationScale value);
void MagneticDataRate(MagneticDataRate value);
void MagneticMode(MagneticMode value);
void MagneticResolution(MagneticResolution value);
void MagneticScale(MagneticScale value);
}
internal sealed class SixAxisAccelerometerAndCompass : ISixAxisAccelerometerAndCompass
{
private const int X = 0;
private const int Y = 1;
private const int Z = 2;
private const double Pow_2_15 = 32768;
private const byte WHO_AM_I = 0x0f;
private const byte CTRL_REG0 = 0x1F;
private const byte CTRL_REG1 = 0x20;
private const byte CTRL_REG2 = 0x21;
private const byte CTRL_REG3 = 0x22;
private const byte CTRL_REG4 = 0x23;
private const byte CTRL_REG5 = 0x24;
private const byte CTRL_REG6 = 0x25;
private const byte CTRL_REG7 = 0x26;
private const byte OUT_X_L_M = 0x08;
private const byte OUT_X_H_M = 0x09;
private const byte OUT_Y_L_M = 0x0A;
private const byte OUT_Y_H_M = 0x0B;
private const byte OUT_Z_L_M = 0x0C;
private const byte OUT_Z_H_M = 0x0D;
private const byte OUT_X_L_A = 0x28;
private const byte OUT_X_H_A = 0x29;
private const byte OUT_Y_L_A = 0x2A;
private const byte OUT_Y_H_A = 0x2B;
private const byte OUT_Z_L_A = 0x2C;
private const byte OUT_Z_H_A = 0x2D;
internal I2cDevice DirectAccess
{
get;
}
internal AccelerationAxes AccelerationAxes
{
get;
set;
} = AccelerationAxes.XYZ;
internal AccelerationDataRate AccelerationDataRate
{
get;
set;
} = AccelerationDataRate.Hz_50;
internal AccelerationDataUpdateMode AccelerationDataUpdateMode
{
get;
set;
} = AccelerationDataUpdateMode.Continuous;
internal AccelerationScale AccelerationScale
{
get
{
return accelerationScale;
}
set
{
accelerationScale = value;
switch (accelerationScale)
{
case AccelerationScale.G_2:
accelerationScaleFactor = 2.0;
break;
case AccelerationScale.G_4:
accelerationScaleFactor = 4.0;
break;
case AccelerationScale.G_6:
accelerationScaleFactor = 6.0;
break;
case AccelerationScale.G_8:
accelerationScaleFactor = 8.0;
break;
case AccelerationScale.G_16:
accelerationScaleFactor = 16.0;
break;
}
}
}
private AccelerationScale accelerationScale = AccelerationScale.G_2;
private double accelerationScaleFactor = 2.0;
internal MagneticDataRate MagneticDataRate
{
get;
set;
} = MagneticDataRate.Hz_50;
internal MagneticMode MagneticMode
{
get;
set;
} = MagneticMode.ContinousConversion;
internal MagneticResolution MagneticResolution
{
get;
set;
} = MagneticResolution.Low;
internal MagneticScale MagneticScale
{
get;
set;
} = MagneticScale.Gs_4;
internal SixAxisAccelerometerAndCompass(I2cDevice device)
{
if (device == null)
throw new ArgumentNullException(nameof(device));
DirectAccess = device;
Reconfigure();
}
public byte DeviceId() => ReadRegister(WHO_AM_I);
public double[] GetAcceleration()
{
// Windows is little-endian so read registers from low to high
var input = new[]
{
ReadRegister(OUT_X_L_A), ReadRegister(OUT_X_H_A),
ReadRegister(OUT_Y_L_A), ReadRegister(OUT_Y_H_A),
ReadRegister(OUT_Z_L_A), ReadRegister(OUT_Z_H_A)
};
// calculate two's complement value and scale by acceleration factor
var output = new[]
{
BitConverter.ToInt16(input, 0) / Pow_2_15 * accelerationScaleFactor,
BitConverter.ToInt16(input, 2) / Pow_2_15 * accelerationScaleFactor,
BitConverter.ToInt16(input, 4) / Pow_2_15 * accelerationScaleFactor
};
return output;
}
public double[] GetMagnetic()
{
// Windows is little-endian so read registers from low to high
var input = new[]
{
ReadRegister(OUT_X_L_M), ReadRegister(OUT_X_H_M),
ReadRegister(OUT_Y_L_M), ReadRegister(OUT_Y_H_M),
ReadRegister(OUT_Z_L_M), ReadRegister(OUT_Z_H_M)
};
// calculate two's complement value
var output = new[]
{
BitConverter.ToInt16(input, 0) / Pow_2_15,
BitConverter.ToInt16(input, 2) / Pow_2_15,
BitConverter.ToInt16(input, 4) / Pow_2_15
};
return output;
}
public double GetHeading()
{
var magnetic = GetMagnetic();
var heading = 180 * Atan2(magnetic[Y], magnetic[X]) / PI;
return (heading < 0) ? (heading + 360) : heading;
}
public double GetTiltHeading()
{
var acceleration = GetAcceleration();
var pitch = Asin(-acceleration[X]);
var roll = Asin(acceleration[Y] / Cos(pitch));
var magnetic = GetMagnetic();
var xh = magnetic[X] * Cos(pitch) + magnetic[Z] * Sin(pitch);
var yh = magnetic[X] * Sin(roll) * Sin(pitch) + magnetic[Y] * Cos(roll) - magnetic[Z] * Sin(roll) * Cos(pitch);
var heading = 180 * Atan2(yh, xh) / PI;
return (heading < 0) ? (heading + 360) : heading;
}
public ISixAxisAccelerometerAndCompass Configure(Action<ISixAxisAccelerometerAndCompassConfiguration> configuration)
{
if (configuration != null)
{
configuration(new SixAxisAccelerometerAndCompassConfiguration(this));
Reconfigure();
}
return this;
}
private byte ReadRegister(byte register)
{
var buffer = new byte[1];
DirectAccess.WriteRead(new[] { register }, buffer);
return buffer[0];
}
private void Reconfigure()
{
DirectAccess.Write(new[] { CTRL_REG0, (byte)0 }); // normal mode, FIFO disabled, high-pass filter disabled
DirectAccess.Write(new[] { CTRL_REG1, (byte)((byte)AccelerationDataRate | (byte)AccelerationDataUpdateMode | (byte)AccelerationAxes) });
DirectAccess.Write(new[] { CTRL_REG2, (byte)AccelerationScale });
DirectAccess.Write(new[] { CTRL_REG3, (byte)0 }); // interrupt 1 disabled
DirectAccess.Write(new[] { CTRL_REG4, (byte)0 }); // interrupt 2 disabled
DirectAccess.Write(new[] { CTRL_REG5, (byte)((byte)MagneticResolution | (byte)MagneticDataRate) });
DirectAccess.Write(new[] { CTRL_REG6, (byte)MagneticScale });
DirectAccess.Write(new[] { CTRL_REG7, (byte)MagneticMode });
}
}
internal sealed class SixAxisAccelerometerAndCompassConfiguration : ISixAxisAccelerometerAndCompassConfiguration
{
private readonly SixAxisAccelerometerAndCompass _sensor;
public SixAxisAccelerometerAndCompassConfiguration(SixAxisAccelerometerAndCompass sensor)
{
_sensor = sensor;
}
public void AccelerationAxes(AccelerationAxes value)
{
_sensor.AccelerationAxes = value;
}
public void AccelerationDataRate(AccelerationDataRate value)
{
_sensor.AccelerationDataRate = value;
}
public void AccelerationDataUpdateMode(AccelerationDataUpdateMode value)
{
_sensor.AccelerationDataUpdateMode = value;
}
public void AccelerationScale(AccelerationScale value)
{
_sensor.AccelerationScale = value;
}
public void MagneticDataRate(MagneticDataRate value)
{
if ((value == Configuration.MagneticDataRate.Hz_100) && (_sensor.AccelerationDataRate > Configuration.AccelerationDataRate.None) && (_sensor.AccelerationDataRate <= Configuration.AccelerationDataRate.Hz_50))
{
_sensor.AccelerationDataRate = Configuration.AccelerationDataRate.Hz_100;
}
_sensor.MagneticDataRate = value;
}
public void MagneticMode(MagneticMode value)
{
_sensor.MagneticMode = value;
}
public void MagneticResolution(MagneticResolution value)
{
_sensor.MagneticResolution = value;
}
public void MagneticScale(MagneticScale value)
{
_sensor.MagneticScale = value;
}
}
namespace Configuration
{
[Flags]
public enum AccelerationAxes : byte
{
None = 0,
X = 4,
Y = 2,
Z = 1,
XYZ = X | Y | Z
}
public enum AccelerationDataRate : byte
{
None = 0,
Hz_3_125 = 16,
Hz_6_25 = 32,
Hz_12_5 = 48,
Hz_25 = 64,
Hz_50 = 80,
Hz_100 = 96,
Hz_200 = 112,
Hz_400 = 128,
Hz_800 = 144,
Hz_1600 = 160
}
public enum AccelerationDataUpdateMode : byte
{
Continuous = 0,
OnRead = 8
}
public enum AccelerationScale : byte
{
G_2 = 0,
G_4 = 8,
G_6 = 16,
G_8 = 24,
G_16 = 32
}
public enum MagneticMode : byte
{
ContinousConversion = 0,
SingleConversion = 1,
PowerDown = 3
}
public enum MagneticDataRate : byte
{
Hz_3_125 = 0,
Hz_6_25 = 4,
Hz_12_5 = 8,
Hz_25 = 12,
Hz_50 = 16,
Hz_100 = 20
}
public enum MagneticResolution : byte
{
Low = 0,
High = 96
}
public enum MagneticScale : byte
{
Gs_2 = 0,
Gs_4 = 32,
Gs_8 = 64,
Gs_12 = 96
}
}
}

View file

@ -0,0 +1,91 @@
using System;
using GrovePi.I2CDevices.Configuration;
using Windows.Devices.I2c;
namespace GrovePi.I2CDevices
{
public interface IThreeAxisAccelerometerADXL345
{
IThreeAxisAccelerometerADXL345 Initialize();
double[] GetAcclXYZ();
}
internal sealed class ThreeAxisAccelerometerADXL345 : IThreeAxisAccelerometerADXL345
{
struct Acceleration
{
public double X;
public double Y;
public double Z;
};
private const byte ACCEL_I2C_ADDR = 0x53; /* 7-bit I2C address of the ADXL345 with SDO pulled low */
private const byte ACCEL_REG_POWER_CONTROL = 0x2D; /* Address of the Power Control register */
private const byte ACCEL_REG_DATA_FORMAT = 0x31; /* Address of the Data Format register */
private const byte ACCEL_REG_X = 0x32; /* Address of the X Axis data register */
private const byte ACCEL_REG_Y = 0x34; /* Address of the Y Axis data register */
private const byte ACCEL_REG_Z = 0x36; /* Address of the Z Axis data register */
internal I2cDevice DirectAccess { get; }
internal ThreeAxisAccelerometerADXL345(I2cDevice Device)
{
if (Device == null) throw new ArgumentNullException(nameof(Device));
DirectAccess = Device;
}
public IThreeAxisAccelerometerADXL345 Initialize()
{
/*
* Initialize the accelerometer:
*
* For this device, we create 2-byte write buffers:
* The first byte is the register address we want to write to.
* The second byte is the contents that we want to write to the register.
*/
byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */
byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */
/* Write the register settings */
DirectAccess.Write(WriteBuf_DataFormat);
DirectAccess.Write(WriteBuf_PowerControl);
return this;
}
public double[] GetAcclXYZ()
{
const int ACCEL_RES = 1024; /* The ADXL345 has 10 bit resolution giving 1024 unique values */
const int ACCEL_DYN_RANGE_G = 8; /* The ADXL345 had a total dynamic range of 8G, since we're configuring it to +-4G */
const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G; /* Ratio of raw int values to G units */
byte[] RegAddrBuf = new byte[] { ACCEL_REG_X }; /* Register address we want to read from */
byte[] ReadBuf = new byte[6]; /* We read 6 bytes sequentially to get all 3 two-byte axes registers in one read */
/*
* Read from the accelerometer
* We call WriteRead() so we first write the address of the X-Axis I2C register, then read all 3 axes
*/
DirectAccess.WriteRead(RegAddrBuf, ReadBuf);
/*
* In order to get the raw 16-bit data values, we need to concatenate two 8-bit bytes from the I2C read for each axis.
* We accomplish this by using the BitConverter class.
*/
short AccelerationRawX = BitConverter.ToInt16(ReadBuf, 0);
short AccelerationRawY = BitConverter.ToInt16(ReadBuf, 2);
short AccelerationRawZ = BitConverter.ToInt16(ReadBuf, 4);
/* Convert raw values to G's */
double[] accel = new double[3];
accel[0] = (double)AccelerationRawX / UNITS_PER_G;
accel[1] = (double)AccelerationRawY / UNITS_PER_G;
accel[2] = (double)AccelerationRawZ / UNITS_PER_G;
return accel;
}
}
}