This entry's latest version is outdated and must be revised. Please see the documentation for the latest API.

Seeed Barometer SoftwareI2C driver by VGenev

Sep. 24, 2013   |   Snippet   |   Licensed as Apache 2.0   |   1265 views

Driver for Seeed Barometer module using the Software I2C for Y socket instead of I.

Comments or questions?   Discuss on the forum.



Author Version Date
VGenev 1 09/24 '13 at 10:29am
1 — Source
  1. using System;
  2. using System.Threading;
  3. using Microsoft.SPOT;
  4. using Microsoft.SPOT.Hardware;
  5.  
  6. using GT = Gadgeteer;
  7. using GTM = Gadgeteer.Modules;
  8. using GTI = Gadgeteer.Interfaces;
  9.  
  10.  
  11.  
  12. namespace Gadgeteer.Modules.Seeed
  13. {
  14. /// <summary>
  15. /// A Barometer Gadgeteer module, based on the Hope RF HP03M pressure sensor module.
  16. /// </summary>
  17. public class Barometer : GTM.Module {
  18.  
  19. private static GTI.SoftwareI2C softwarei2c;
  20. private static byte[] readRegisterData = new byte[2];
  21.  
  22. // Note: A constructor summary is auto-generated by the doc builder.
  23. /// <summary></summary>
  24. /// <param name="socketNumber">The socket that this module is plugged in to.</param>
  25. public Barometer(int socketNumber)
  26. {
  27. // This finds the Socket instance from the user-specified socket number.
  28. // This will generate user-friendly error messages if the socket is invalid.
  29. // If there is more than one socket on this module, then instead of "null" for the last parameter,
  30. // put text that identifies the socket to the user (e.g. "S" if there is a socket type S)
  31.  
  32. GTI.SoftwareI2C.ForceManagedPullUps = true;
  33. GTI.SoftwareI2C.ForceManagedSoftwareI2CImplementation = true;
  34.  
  35. Socket socket = Socket.GetSocket(socketNumber, true, this, null);
  36. socket.EnsureTypeIsSupported(new char[] {'X', 'Y'}, this);
  37.  
  38. this.XCLR = new GTI.DigitalOutput(socket, Socket.Pin.Three, false, this);
  39.  
  40. ReadFactoryCalibrationData(socket);
  41. // i2c = new GTI.I2CBus(socket, e, 100, this); // EE = ADC write Address, 0xEE >> 1 = 0x77, 0xA1 = EEProm, 0xEE >> 1 = 0x50
  42.  
  43. softwarei2c = new GTI.SoftwareI2C(socket, Socket.Pin.Eight, Socket.Pin.Nine, this);
  44.  
  45.  
  46. // softwareI2C.Write(ADC_ADDRESS,
  47. continuousTimer = new Gadgeteer.Timer(new TimeSpan(0, 0, 0, 0, 200));
  48. continuousTimer.Tick += new Timer.TickEventHandler(continuousTimer_Tick);
  49. }
  50.  
  51. //private GTI.I2CBus i2c;
  52. private GTI.DigitalOutput XCLR;
  53.  
  54. private Coefficients Coeff;
  55.  
  56. static byte ADC_ADDRESS = 0x77;
  57. static byte EEPROM_ADDR = 0x50;
  58.  
  59. private GT.Timer continuousTimer;
  60. private bool continuousMeasurement = false;
  61.  
  62. private enum Register : byte
  63. {
  64. COEFF = 0x10,
  65. DATD1 = 0xFF,
  66. DATD2 = 0xF0
  67. }
  68.  
  69. private byte[] _readBuffer8 = new byte[1];
  70. private byte[] _writeBuffer8 = new byte[1];
  71.  
  72. private byte[] _readBuffer16 = new byte[2];
  73. private byte[] _readBuffer144 = new byte[18];
  74.  
  75. private struct Coefficients
  76. {
  77. public int C1, C2, C3, C4, C5, C6, C7;
  78. public int A, B, C, D;
  79. }
  80.  
  81.  
  82. // This reads the calibration data stored in the onboard EEPROM
  83. // Needs only to be done once, on initialization.
  84. private void ReadFactoryCalibrationData(Gadgeteer.Socket socket)
  85. {
  86. // GTI.I2CBus eeprom_i2c = new GTI.I2CBus(socket, EEPROM_ADDR, 100, this);
  87. GTI.SoftwareI2C eepromi2c = new GTI.SoftwareI2C(socket, Socket.Pin.Eight, Socket.Pin.Nine, this);
  88.  
  89. XCLR.Write(false);
  90. Coeff = new Coefficients();
  91. // eeprom_i2c.Read(EEPROM_ADDR, _readBuffer144, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  92.  
  93.  
  94.  
  95. // Read(eeprom_i2c, Register.COEFF, _readBuffer144);
  96.  
  97. // Read(eeprom_i2c, Register.COEFF, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  98.  
  99. ReadEEProm (eepromi2c, Register.COEFF, _readBuffer144);
  100. Coeff.C1 = (_readBuffer144[0] << 8) + _readBuffer144[1];
  101. Coeff.C2 = (_readBuffer144[2] << 8) + _readBuffer144[3];
  102. Coeff.C3 = (_readBuffer144[4] << 8) + _readBuffer144[5];
  103. Coeff.C4 = (_readBuffer144[6] << 8) + _readBuffer144[7];
  104. Coeff.C5 = (_readBuffer144[8] << 8) + _readBuffer144[9];
  105. Coeff.C6 = (_readBuffer144[10] << 8) + _readBuffer144[11];
  106. Coeff.C7 = (_readBuffer144[12] << 8) + _readBuffer144[13];
  107. Coeff.A = _readBuffer144[14];
  108. Coeff.B = _readBuffer144[15];
  109. Coeff.C = _readBuffer144[16];
  110. Coeff.D = _readBuffer144[17];
  111.  
  112. }
  113.  
  114. private void ReadEEProm(GTI.SoftwareI2C eepromi2c, Register register, byte[] readBuffer)
  115. {
  116. _writeBuffer8[0] = (byte)register;
  117.  
  118. //int ack = softwarei2c.WriteRead(_writeBuffer8, readBuffer, 1000);
  119. int ack = eepromi2c.WriteRead(EEPROM_ADDR, _writeBuffer8, readBuffer, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  120.  
  121. }
  122.  
  123. private void Read(GTI.SoftwareI2C softwarei2c, Register register, byte[] readBuffer)
  124. {
  125. _writeBuffer8[0] = (byte)register;
  126.  
  127. //int ack = softwarei2c.WriteRead(_writeBuffer8, readBuffer, 1000);
  128. int ack = softwarei2c.WriteRead(ADC_ADDRESS, _writeBuffer8, readBuffer, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  129.  
  130. }
  131.  
  132.  
  133. /// <summary>
  134. /// Obtains a single measurement from the <see cref="Barometer"/> and raises the <see cref="MeasurementComplete"/> event when complete.
  135. /// </summary>
  136. public void RequestMeasurement()
  137. {
  138. double dUT, OFF, SENS, X;
  139. double P, T;
  140. int D1, D2;
  141.  
  142. /////////////////////////////////////////////////////////
  143. // Read the data
  144. /////////////////////////////////////////////////////////
  145.  
  146. // Pull xCLR High
  147. XCLR.Write(true);
  148.  
  149. // Get raw pressure value
  150. //int ack = softwarei2c.Write(new byte[] { 0xFF, 0xF0 }, 10);
  151. int ack = softwarei2c.Write(ADC_ADDRESS, new byte[] { 0xFF, 0xF0 }, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  152. Thread.Sleep(40);
  153. //ack = i2c.WriteRead(new byte[] { 0xFD }, _readBuffer16, 10);
  154. ack = softwarei2c.WriteRead(ADC_ADDRESS, new byte[] { 0xFD }, _readBuffer16, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  155. D1 = (_readBuffer16[0] << 8) | _readBuffer16[1];
  156.  
  157. // Get raw temperature value
  158. // ack = i2c.Write(new byte[] { 0xFF, 0xE8 }, 10);
  159. ack = softwarei2c.Write(ADC_ADDRESS, new byte[] { 0xFF, 0xE8 }, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  160.  
  161. Thread.Sleep(40);
  162. // ack = i2c.WriteRead(new byte[] { 0xFD }, _readBuffer16, 10);
  163. ack = softwarei2c.WriteRead(ADC_ADDRESS, new byte[] { 0xFD }, _readBuffer16, GTI.SoftwareI2C.LengthErrorBehavior.ThrowException);
  164.  
  165. D2 = (_readBuffer16[0] << 8) | _readBuffer16[1];
  166.  
  167. // pull low
  168. XCLR.Write(false);
  169.  
  170.  
  171. ////////////////////////////////////////////////////////////////
  172. // Calculate temperature and pressure based on calibration data
  173. ////////////////////////////////////////////////////////////////
  174.  
  175. // Step 1. Get temperature value.
  176.  
  177. // D2 >= C5 dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * A / 2^C
  178. if (D2 >= Coeff.C5)
  179. {
  180. dUT = D2 - Coeff.C5 - ((D2 - Coeff.C5) / System.Math.Pow(2, 7) * ((D2 - Coeff.C5) / System.Math.Pow(2, 7)) * Coeff.A / System.Math.Pow(2, Coeff.C));
  181. }
  182. // D2 < C5 dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * B / 2^C
  183. else
  184. {
  185. dUT = D2 - Coeff.C5 - ((D2 - Coeff.C5) / System.Math.Pow(2, 7) * ((D2 - Coeff.C5) / System.Math.Pow(2, 7)) * Coeff.B / System.Math.Pow(2, Coeff.C));
  186. }
  187.  
  188. // Step 2. Calculate offset, sensitivity and final pressure value.
  189.  
  190. // OFF=(C2+(C4-1024)*dUT/2^14)*4
  191. OFF = (Coeff.C2 + (Coeff.C4-1024)*dUT/System.Math.Pow(2, 14)) * 4;
  192. // SENS = C1+ C3*dUT/2^10
  193. SENS = Coeff.C1 + Coeff.C3 * dUT / System.Math.Pow(2, 10);
  194. // X= SENS * (D1-7168)/2^14 - OFF
  195. X = SENS * (D1 - 7168) / System.Math.Pow(2, 14) - OFF;
  196. // P=X*10/2^5+C7
  197. P = X * 10 / System.Math.Pow(2, 5) + Coeff.C7;
  198.  
  199. // Step 3. Calculate temperature
  200.  
  201. // T = 250 + dUT * C6 / 2 ^ 16-dUT/2^D
  202. T = 250 + dUT * Coeff.C6 / System.Math.Pow(2, 16) - dUT / System.Math.Pow(2, Coeff.D);
  203.  
  204.  
  205. SensorData sensData = new SensorData(T / 10, P / 10);
  206. OnMeasurementCompleteEvent(this, sensData);
  207. }
  208.  
  209.  
  210. /// <summary>
  211. /// Starts continuous measurements.
  212. /// </summary>
  213. /// <remarks>
  214. /// When this method is called, the <see cref="Barometer"/> begins taking continuous measurements.
  215. /// At each <see cref="ContinuousMeasurementInterval"/>, it calls the <see cref="RequestMeasurement"/> method,
  216. /// which raises the <see cref="MeasurementComplete"/> event.
  217. /// </remarks>
  218. public void StartContinuousMeasurements()
  219. {
  220. continuousMeasurement = true;
  221. continuousTimer.Start();
  222. }
  223.  
  224. /// <summary>
  225. /// Stops continuous measurements.
  226. /// </summary>
  227. public void StopContinuousMeasurements()
  228. {
  229. continuousMeasurement = false;
  230. continuousTimer.Stop();
  231. }
  232.  
  233. /// <summary>
  234. /// Gets or sets the interval at which continuous measurements are taken.
  235. /// </summary>
  236. /// <remarks>
  237. /// The default value for this property is 200 milliseconds.
  238. /// </remarks>
  239. public TimeSpan ContinuousMeasurementInterval
  240. {
  241. get
  242. {
  243. return continuousTimer.Interval;
  244. }
  245. set
  246. {
  247. continuousTimer.Stop();
  248. continuousTimer.Interval = value;
  249. if (continuousMeasurement) continuousTimer.Start();
  250. }
  251. }
  252.  
  253.  
  254. private void continuousTimer_Tick(Timer timer)
  255. {
  256. if (!continuousMeasurement)
  257. {
  258. timer.Stop();
  259. return;
  260. }
  261. RequestMeasurement();
  262. }
  263.  
  264. /// <summary>
  265. ///
  266. /// </summary>
  267. public class SensorData
  268. {
  269. /// <summary>
  270. /// The sensed temperature, in degrees Celsius.
  271. /// </summary>
  272. public double Temperature { get; private set; }
  273. /// <summary>
  274. /// The sensed atmospheric pressure, in hectopascals.
  275. /// </summary>
  276. public double Pressure { get; private set; }
  277.  
  278. /// <summary>
  279. /// A sensor reading, containing temperature and pressure measurements.
  280. /// </summary>
  281. /// <param name="temperature">The sensed temperature, in degrees Celsius.</param>
  282. /// <param name="pressure">The sensed atmospheric pressure, in hectopascals.</param>
  283. public SensorData(double temperature, double pressure)
  284. {
  285. this.Temperature = temperature;
  286. this.Pressure = pressure;
  287. }
  288.  
  289. /// <summary>
  290. /// Provides a string representation of the <see cref="SensorData"/> instance.
  291. /// </summary>
  292. /// <returns>A string describing the values contained in the object.</returns>
  293. public override string ToString()
  294. {
  295. return "Temperature: " + Temperature.ToString("f2") + " degrees Celsius. Pressure: " + Pressure.ToString("f2") + " hPa.";
  296. }
  297. }
  298.  
  299. /// <summary>
  300. /// Represents the delegate used for the <see cref="MeasurementComplete"/> event.
  301. /// </summary>
  302. /// <param name="sender">The object that raised the event.</param>
  303. /// <param name="sensorData">The <see cref="SensorData"/> object that contains the results of the measurement.</param>
  304. public delegate void MeasurementCompleteEventHandler(Barometer sender, SensorData sensorData);
  305.  
  306. /// <summary>
  307. /// Event raised when a measurement reading is completed.
  308. /// </summary>
  309. public event MeasurementCompleteEventHandler MeasurementComplete;
  310.  
  311. private MeasurementCompleteEventHandler _OnMeasurementComplete;
  312.  
  313. /// <summary>
  314. /// Raises the <see cref="MeasurementComplete"/> event.
  315. /// </summary>
  316. /// <param name="sender">The object that raised the event.</param>
  317. /// <param name="sensorData">The <see cref="SensorData"/> object that contains the results of the measurement.</param>
  318. protected virtual void OnMeasurementCompleteEvent(Barometer sender, SensorData sensorData)
  319. {
  320. if (_OnMeasurementComplete == null) _OnMeasurementComplete = new MeasurementCompleteEventHandler(OnMeasurementCompleteEvent);
  321. if (Program.CheckAndInvoke(MeasurementComplete, _OnMeasurementComplete, sender, sensorData))
  322. {
  323. MeasurementComplete(sender, sensorData);
  324. }
  325. }
  326.  
  327. }
  328. }