This is a “throw away” .NET nanoFramework application for investigating how Seeedstudio Grove HM3301 Inter Integrated Circuit bus(I²C) connectivity works.
My test setup is a simple .NET nanoFramework console application running on an STM32F7691 Discovery board.
The HM3301I2C application has lots of magic numbers from the HM3301 datasheet and is just a tool for exploring how the sensor works.
public static void Main()
{
I2cConnectionSettings i2cConnectionSettings = new(1, 0x40);
// i2cDevice.Dispose
I2cDevice i2cDevice = I2cDevice.Create(i2cConnectionSettings);
while (true)
{
byte[] writeBuffer = new byte[1];
byte[] readBuffer = new byte[29];
writeBuffer[0] = 0x88;
i2cDevice.WriteRead(writeBuffer, readBuffer);
//i2cDevice.WriteByte(0x88);
//i2cDevice.Read(readBuffer);
ushort standardParticulatePm1 = (ushort)(readBuffer[4] << 8);
standardParticulatePm1 |= readBuffer[5];
ushort standardParticulatePm25 = (ushort)(readBuffer[6] << 8);
standardParticulatePm25 |= readBuffer[7];
ushort standardParticulatePm10 = (ushort)(readBuffer[8] << 8);
standardParticulatePm10 |= readBuffer[9];
Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Standard particulate PM 1.0: {standardParticulatePm1} PM 2.5: {standardParticulatePm25} PM 10.0: {standardParticulatePm10} ug/m3");
ushort atmosphericPm1 = (ushort)(readBuffer[10] << 8);
atmosphericPm1 |= readBuffer[11];
ushort atmosphericPm25 = (ushort)(readBuffer[12] << 8);
atmosphericPm25 |= readBuffer[13];
ushort atmosphericPm10 = (ushort)(readBuffer[14] << 8);
atmosphericPm10 |= readBuffer[15];
Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Atmospheric particulate PM 1.0: {atmosphericPm1:3} PM 2.5: {atmosphericPm25} PM 10.0: {atmosphericPm10} ug/m3");
ushort particulateCountPm03 = (ushort)(readBuffer[16] << 8);
particulateCountPm03 |= readBuffer[17];
ushort particulateCountPm05 = (ushort)(readBuffer[18] << 8);
particulateCountPm05 |= readBuffer[19];
ushort particulateCountPm1 = (ushort)(readBuffer[20] << 8);
particulateCountPm1 |= readBuffer[21];
Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Particulate count PM 0.3: {particulateCountPm03:3} PM 0.5: {particulateCountPm05} PM 1.0: {particulateCountPm1} ug/m3");
ushort particleCountPm25 = (ushort)(readBuffer[22] << 8);
particleCountPm25 |= readBuffer[23];
ushort particleCountPm5 = (ushort)(readBuffer[24] << 8);
particleCountPm5 |= readBuffer[25];
ushort particleCountPm10 = (ushort)(readBuffer[26] << 8);
particleCountPm10 |= readBuffer[27];
Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Particle count/0.1L PM 2.5: {particleCountPm25} PM 5.0: {particleCountPm5} PM 10.0: {particleCountPm10} particles/0.1L");
byte checksum = 0;
for (int i = 0; i < readBuffer.Length - 1; i++)
{
checksum += readBuffer[i];
}
Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Checksum payload:{readBuffer[28]} calculated:{checksum}");
Console.WriteLine("");
Thread.Sleep(5000);
}
}
The unpacking of the value standard particulate, particulate count and particle count values is fairly repetitive, but I will fix it in the next version.
The checksum calculation isn’t great even a simple cyclic redundancy check(CRC) would be an improvement on summing the 28 bytes of the payload.