first commit
This commit is contained in:
commit
a5a0434432
1126 changed files with 439481 additions and 0 deletions
61
Software/CSharp/GrovePi/I2CDevices/MiniMotorDriver.cs
Normal file
61
Software/CSharp/GrovePi/I2CDevices/MiniMotorDriver.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
440
Software/CSharp/GrovePi/I2CDevices/OLEDDisplay128X64.cs
Normal file
440
Software/CSharp/GrovePi/I2CDevices/OLEDDisplay128X64.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
450
Software/CSharp/GrovePi/I2CDevices/OLEDDisplay9696.cs
Normal file
450
Software/CSharp/GrovePi/I2CDevices/OLEDDisplay9696.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
78
Software/CSharp/GrovePi/I2CDevices/RgbLcdDisplay.cs
Normal file
78
Software/CSharp/GrovePi/I2CDevices/RgbLcdDisplay.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue