Has anyone here used Arduino with Bosch 17025 Oxygen sensor. I am struggling with the look up table. Please help!!
/*
Example code compatible with the Lambda Shield 2
*/
//Define included headers.
#include <SPI.h>
#include <SD.h>
#include <U8g2lib.h>
//Define CJ125 registers used.
#define CJ125_IDENT_REG_REQUEST 0x4800 /* Identify request, gives revision of the chip. */
#define CJ125_DIAG_REG_REQUEST 0x7800 /* Dignostic request, gives the current status. */
#define CJ125_INIT_REG1_REQUEST 0x6C00 /* Requests the first init register. */
#define CJ125_INIT_REG2_REQUEST 0x7E00 /* Requests the second init register. */
#define CJ125_INIT_REG1_MODE_CALIBRATE 0x569D /* Sets the first init register in calibration mode. */
#define CJ125_INIT_REG1_MODE_NORMAL_V8 0x5688 /* Sets the first init register in operation mode. V=8 amplification. */
#define CJ125_INIT_REG1_MODE_NORMAL_V17 0x5689 /* Sets the first init register in operation mode. V=17 amplification. */
#define CJ125_DIAG_REG_STATUS_OK 0x28FF /* The response of the diagnostic register when everything is ok. */
#define CJ125_DIAG_REG_STATUS_NOPOWER 0x2855 /* The response of the diagnostic register when power is low. */
#define CJ125_DIAG_REG_STATUS_NOSENSOR 0x287F /* The response of the diagnostic register when no sensor is connected. */
#define CJ125_INIT_REG1_STATUS_0 0x2888 /* The response of the init register when V=8 amplification is in use. */
#define CJ125_INIT_REG1_STATUS_1 0x2889 /* The response of the init register when V=17 amplification is in use. */
//Define pin assignments.
#define CJ125_CS_PIN 10 /* Pin used for chip select in SPI communication to CJ125. */
#define LED_STATUS_POWER 7 /* Pin used for power the status LED, indicating we have power. */
#define LED_STATUS_HEATER 6 /* Pin used for the heater status LED, indicating heater activity. */
#define HEATER_OUTPUT_PIN 5 /* Pin used for the PWM output to the heater circuit. */
#define ANALOG_OUTPUT_PIN 3 /* Pin used for the PWM to the 0-1V analog output. */
#define UB_ANALOG_INPUT_PIN 2 /* Analog input for power supply.*/
#define UR_ANALOG_INPUT_PIN 1 /* Analog input for temperature.*/
#define UA_ANALOG_INPUT_PIN 0 /* Analog input for lambda.*/
//Define adjustable parameters.
#define SERIAL_RATE 100 /* Serial refresh rate in HZ (1-100). */
#define UBAT_MIN 150 /* Minimum voltage (ADC value) on Ubat to operate. */
//Global variables.
int adcValue_UA = 0; /* ADC value read from the CJ125 UA output pin */
int adcValue_UR = 0; /* ADC value read from the CJ125 UR output pin */
int adcValue_UB = 0; /* ADC value read from the voltage divider caluclating Ubat */
int adcValue_UA_Optimal = 0; /* UA ADC value stored when CJ125 is in calibration mode, λ=1 */
int adcValue_UR_Optimal = 0; /* UR ADC value stored when CJ125 is in calibration mode, optimal temperature */
int heaterOutput = 0; /* Current PWM output value (0-255) of the heater output pin */
int serial_counter = 0; /* Counter used to calculate refresh rate on the serial output */
int CJ125_Status = 0; /* Latest stored DIAG registry response from the CJ125 */
bool logEnabled = false; /* Variable used for setting data logging enable or disabled. */
unsigned long startTime = 0;
String txString; /* String for serial output. */
//PID regulation variables. /* Last position input. */
int iState; /* Integrator state. */
const int iMax = 2550; /* Maximum allowable integrator state. */
const float pGain = 5; /* Proportional gain. Default = 5*/
const float iGain = 0.1; /* Integral gain. Default = 0.2*/
//Define display.
U8G2_NULL u8g2(U8G2_R0);
//U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
//U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
//Lambda Conversion Lookup Table. (ADC 0-1023).
const PROGMEM uint16_t Lambda_Conversion[1023] {
650, 659, 668, 677, 687, 696, 705, 714, 724, 733, 742, 751, 761, 770, 779, 788, 798, 807, 816, 825, 835, 844, 853, 862, 872, 881, 890, 899, 909, 918, 927, 936, 946, 955, 964, 973, 983, 992, 1001, 1010, 1020, 1029, 1038, 1048, 1057, 1066, 1075, 1085, 1094, 1103, 1112, 1122, 1131, 1140, 1149, 1159, 1168, 1177, 1186, 1196, 1205, 1214, 1223, 1233, 1242, 1251, 1260, 1270, 1279, 1288, 1297, 1307, 1316, 1325, 1334, 1344, 1353, 1362, 1371, 1381, 1390, 1399, 1409, 1418, 1427, 1436, 1446, 1455, 1464, 1473, 1483, 1492, 1501, 1510, 1520, 1529, 1538, 1547, 1557, 1566, 1575, 1584, 1594, 1603, 1612, 1621, 1631, 1640, 1649, 1658, 1668, 1677, 1686, 1695, 1705, 1714, 1723, 1732, 1742, 1751, 1760, 1769, 1779, 1788, 1797, 1807, 1816, 1825, 1834, 1844, 1853, 1862, 1871, 1881, 1890, 1899, 1908, 1918, 1927, 1936, 1945, 1955, 1964, 1973, 1982, 1992, 2001, 2010, 2019, 2029, 2038, 2047, 2056, 2066, 2075, 2084, 2093, 2103, 2112, 2121, 2130, 2140, 2149, 2158, 2168, 2177, 2186, 2195, 2205, 2214, 2223, 2232, 2242, 2251, 2260, 2269, 2279, 2288, 2297, 2306, 2316, 2325, 2334, 2343, 2353, 2362, 2371, 2380, 2390, 2399, 2408, 2417, 2427, 2436, 2445, 2454, 2464, 2473, 2482, 2491, 2501, 2510, 2519, 2528, 2538, 2547, 2556, 2566, 2575, 2584, 2593, 2603, 2612, 2621, 2630, 2640, 2649, 2658, 2667, 2677, 2686, 2695, 2704, 2714, 2723, 2732, 2741, 2751, 2760, 2769, 2778, 2788, 2797, 2806, 2815, 2825, 2834, 2843, 2852, 2862, 2871, 2880, 2889, 2899, 2908, 2917, 2927, 2936, 2945, 2954, 2964, 2973, 2982, 2991, 3001, 3010, 3019, 3028, 3038, 3047, 3056, 3065, 3075, 3084, 3093, 3102, 3112, 3121, 3130, 3139, 3149, 3158, 3167, 3176, 3186, 3195, 3204, 3213, 3223, 3232, 3241, 3250, 3260, 3269, 3278, 3287, 3297, 3306, 3315, 3325, 3334, 3343, 3352, 3362, 3371, 3380, 3389, 3399, 3408, 3417, 3426, 3436, 3445, 3454, 3463, 3473, 3482, 3491, 3500, 3510, 3519, 3528, 3537, 3547, 3556, 3565, 3574, 3584, 3593, 3602, 3611, 3621, 3630, 3639, 3648, 3658, 3667, 3676, 3686, 3695, 3704, 3713, 3723, 3732, 3741, 3750, 3760, 3769, 3778, 3787, 3797, 3806, 3815, 3824, 3834, 3843, 3852, 3861, 3871, 3880, 3889, 3898, 3908, 3917, 3926, 3935, 3945, 3954, 3963, 3972, 3982, 3991, 4000, 4009, 4019, 4028, 4037, 4046, 4056, 4065, 4074, 4084, 4093, 4102, 4111, 4121, 4130, 4139, 4148, 4158, 4167, 4176, 4185, 4195, 4204, 4213, 4222, 4232, 4241, 4250, 4259, 4269, 4278, 4287, 4296, 4306, 4315, 4324, 4333, 4343, 4352, 4361, 4370, 4380, 4389, 4398, 4407, 4417, 4426, 4435, 4445, 4454, 4463, 4472, 4482, 4491, 4500, 4509, 4519, 4528, 4537, 4546, 4556, 4565, 4574, 4583, 4593, 4602, 4611, 4620, 4630, 4639, 4648, 4657, 4667, 4676, 4685, 4694, 4704, 4713, 4722, 4731, 4741, 4750, 4759, 4768, 4778, 4787, 4796, 4805, 4815, 4824, 4833, 4843, 4852, 4861, 4870, 4880, 4889, 4898, 4907, 4917, 4926, 4935, 4944, 4954, 4963, 4972, 4981, 4991, 5000, 5009, 5018, 5028, 5037, 5046, 5055, 5065, 5074, 5083, 5092, 5102, 5111, 5120, 5129, 5139, 5148, 5157, 5166, 5176, 5185, 5194, 5204, 5213, 5222, 5231, 5241, 5250, 5259, 5268, 5278, 5287, 5296, 5305, 5315, 5324, 5333, 5342, 5352, 5361, 5370, 5379, 5389, 5398, 5407, 5416, 5426, 5435, 5444, 5453, 5463, 5472, 5481, 5490, 5500, 5509, 5518, 5527, 5537, 5546, 5555, 5564, 5574, 5583, 5592, 5602, 5611, 5620, 5629, 5639, 5648, 5657, 5666, 5676, 5685, 5694, 5703, 5713, 5722, 5731, 5740, 5750, 5759, 5768, 5777, 5787, 5796, 5805, 5814, 5824, 5833, 5842, 5851, 5861, 5870, 5879, 5888, 5898, 5907, 5916, 5925, 5935, 5944, 5953, 5963, 5972, 5981, 5990, 6000, 6009, 6018, 6027, 6037, 6046, 6055, 6064, 6074, 6083, 6092, 6101, 6111, 6120, 6129, 6138, 6148, 6157, 6166, 6175, 6185, 6194, 6203, 6212, 6222, 6231, 6240, 6249, 6259, 6268, 6277, 6286, 6296, 6305, 6314, 6323, 6333, 6342, 6351, 6361, 6370, 6379, 6388, 6398, 6407, 6416, 6425, 6435, 6444, 6453, 6462, 6472, 6481, 6490, 6499, 6509, 6518, 6527, 6536, 6546, 6555, 6564, 6573, 6583, 6592, 6601, 6610, 6620, 6629, 6638, 6647, 6657, 6666, 6675, 6684, 6694, 6703, 6712, 6722, 6731, 6740, 6749, 6759, 6768, 6777, 6786, 6796, 6805, 6814, 6823, 6833, 6842, 6851, 6860, 6870, 6879, 6888, 6897, 6907, 6916, 6925, 6934, 6944, 6953, 6962, 6971, 6981, 6990, 6999, 7008, 7018, 7027, 7036, 7045, 7055, 7064, 7073, 7082, 7092, 7101, 7110, 7120, 7129, 7138, 7147, 7157, 7166, 7175, 7184, 7194, 7203, 7212, 7221, 7231, 7240, 7249, 7258, 7268, 7277, 7286, 7295, 7305, 7314, 7323, 7332, 7342, 7351, 7360, 7369, 7379, 7388, 7397, 7406, 7416, 7425, 7434, 7443, 7453, 7462, 7471, 7481, 7490, 7499, 7508, 7518, 7527, 7536, 7545, 7555, 7564, 7573, 7582, 7592, 7601, 7610, 7619, 7629, 7638, 7647, 7656, 7666, 7675, 7684, 7693, 7703, 7712, 7721, 7730, 7740, 7749, 7758, 7767, 7777, 7786, 7795, 7804, 7814, 7823, 7832, 7841, 7851, 7860, 7869, 7879, 7888, 7897, 7906, 7916, 7925, 7934, 7943, 7953, 7962, 7971, 7980, 7990, 7999, 8008, 8017, 8027, 8036, 8045, 8054, 8064, 8073, 8082, 8091, 8101, 8110, 8119, 8128, 8138, 8147, 8156, 8165, 8175, 8184, 8193, 8202, 8212, 8221, 8230, 8240, 8249, 8258, 8267, 8277, 8286, 8295, 8304, 8314, 8323, 8332, 8341, 8351, 8360, 8369, 8378, 8388, 8397, 8406, 8415, 8425, 8434, 8443, 8452, 8462, 8471, 8480, 8489, 8499, 8508, 8517, 8526, 8536, 8545, 8554, 8563, 8573, 8582, 8591, 8600, 8610, 8619, 8628, 8638, 8647, 8656, 8665, 8675, 8684, 8693, 8702, 8712, 8721, 8730, 8739, 8749, 8758, 8767, 8776, 8786, 8795, 8804, 8813, 8823, 8832, 8841, 8850, 8860, 8869, 8878, 8887, 8897, 8906, 8915, 8924, 8934, 8943, 8952, 8961, 8971, 8980, 8989, 8999, 9008, 9017, 9026, 9036, 9045, 9054, 9063, 9073, 9082, 9091, 9100, 9110, 9119, 9128, 9137, 9147, 9156, 9165, 9174, 9184, 9193, 9202, 9211, 9221, 9230, 9239, 9248, 9258, 9267, 9276, 9285, 9295, 9304, 9313, 9322, 9332, 9341, 9350, 9359, 9369, 9378, 9387, 9397, 9406, 9415, 9424, 9434, 9443, 9452, 9461, 9471, 9480, 9489, 9498, 9508, 9517, 9526, 9535, 9545, 9554, 9563, 9572, 9582, 9591, 9600, 9609, 9619, 9628, 9637, 9646, 9656, 9665, 9674, 9683, 9693, 9702, 9711, 9720, 9730, 9739, 9748, 9758, 9767, 9776, 9785, 9795, 9804, 9813, 9822, 9832, 9841, 9850, 9859, 9869, 9878, 9887, 9896, 9906, 9915, 9924, 9933, 9943, 9952, 9961, 9970, 9980, 9989, 9998, 10007, 10017, 10026, 10035, 10044, 10054, 10063, 10072, 10081, 10091, 10100, 10109, 10119};
//Oxygen Conversion Lookup Table. (ADC 304-1010).
const PROGMEM uint16_t Oxygen_Conversion[1023] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 7, 11, 14, 18, 22, 26, 29, 33, 37, 40, 44, 48, 52, 55, 59, 63, 66, 70, 74, 78, 81, 85, 89, 92, 96, 100, 104, 107, 111, 115, 119, 122, 126, 130, 133, 137, 141, 145, 148, 152, 156, 159, 163, 167, 171, 174, 178, 182, 185, 189, 193, 197, 200, 204, 208, 211, 215, 219, 223, 226, 230, 234, 238, 241, 245, 249, 252, 256, 260, 264, 267, 271, 275, 278, 282, 286, 290, 293, 297, 301, 304, 308, 312, 316, 319, 323, 327, 330, 334, 338, 342, 345, 349, 353, 357, 360, 364, 368, 371, 375, 379, 383, 386, 390, 394, 397, 401, 405, 409, 412, 416, 420, 423, 427, 431, 435, 438, 442, 446, 449, 453, 457, 461, 464, 468, 472, 476, 479, 483, 487, 490, 494, 498, 502, 505, 509, 513, 516, 520, 524, 528, 531, 535, 539, 542, 546, 550, 554, 557, 561, 565, 568, 572, 576, 580, 583, 587, 591, 595, 598, 602, 606, 609, 613, 617, 621, 624, 628, 632, 635, 639, 643, 647, 650, 654, 658, 661, 665, 669, 673, 676, 680, 684, 687, 691, 695, 699, 702, 706, 710, 714, 717, 721, 725, 728, 732, 736, 740, 743, 747, 751, 754, 758, 762, 766, 769, 773, 777, 780, 784, 788, 792, 795, 799, 803, 806, 810, 814, 818, 821, 825, 829, 833, 836, 840, 844, 847, 851, 855, 859, 862, 866, 870, 873, 877, 881, 885, 888, 892, 896, 899, 903, 907, 911, 914, 918, 922, 925, 929, 933, 937, 940, 944, 948, 952, 955, 959, 963, 966, 970, 974, 978, 981, 985, 989, 992, 996, 1000, 1004, 1007, 1011, 1015, 1018, 1022, 1026, 1030, 1033, 1037, 1041, 1044, 1048, 1052, 1056, 1059, 1063, 1067, 1071, 1074, 1078, 1082, 1085, 1089, 1093, 1097, 1100, 1104, 1108, 1111, 1115, 1119, 1123, 1126, 1130, 1134, 1137, 1141, 1145, 1149, 1152, 1156, 1160, 1164, 1167, 1171, 1175, 1178, 1182, 1186, 1190, 1193, 1197, 1201, 1204, 1208, 1212, 1216, 1219, 1223, 1227, 1230, 1234, 1238, 1242, 1245, 1249, 1253, 1256, 1260, 1264, 1268, 1271, 1275, 1279, 1283, 1286, 1290, 1294, 1297, 1301, 1305, 1309, 1312, 1316, 1320, 1323, 1327, 1331, 1335, 1338, 1342, 1346, 1349, 1353, 1357, 1361, 1364, 1368, 1372, 1375, 1379, 1383, 1387, 1390, 1394, 1398, 1402, 1405, 1409, 1413, 1416, 1420, 1424, 1428, 1431, 1435, 1439, 1442, 1446, 1450, 1454, 1457, 1461, 1465, 1468, 1472, 1476, 1480, 1483, 1487, 1491, 1494, 1498, 1502, 1506, 1509, 1513, 1517, 1521, 1524, 1528, 1532, 1535, 1539, 1543, 1547, 1550, 1554, 1558, 1561, 1565, 1569, 1573, 1576, 1580, 1584, 1587, 1591, 1595, 1599, 1602, 1606, 1610, 1613, 1617, 1621, 1625, 1628, 1632, 1636, 1640, 1643, 1647, 1651, 1654, 1658, 1662, 1666, 1669, 1673, 1677, 1680, 1684, 1688, 1692, 1695, 1699, 1703, 1706, 1710, 1714, 1718, 1721, 1725, 1729, 1732, 1736, 1740, 1744, 1747, 1751, 1755, 1759, 1762, 1766, 1770, 1773, 1777, 1781, 1785, 1788, 1792, 1796, 1799, 1803, 1807, 1811, 1814, 1818, 1822, 1825, 1829, 1833, 1837, 1840, 1844, 1848, 1851, 1855, 1859, 1863, 1866, 1870, 1874, 1878, 1881, 1885, 1889, 1892, 1896, 1900, 1904, 1907, 1911, 1915, 1918, 1922, 1926, 1930, 1933, 1937, 1941, 1944, 1948, 1952, 1956, 1959, 1963, 1967, 1970, 1974, 1978, 1982, 1985, 1989, 1993, 1997, 2000, 2004, 2008, 2011, 2015, 2019, 2023, 2026, 2030, 2034, 2037, 2041, 2045, 2049, 2052, 2056, 2060, 2063, 2067, 2071, 2075, 2078, 2082, 2086, 2090, 2144, 2199, 2254, 2309, 2364, 2419, 2474, 2529, 2584, 2639, 2694, 2749, 2804, 2859, 2913, 2968, 3023, 3078, 3133, 3188, 3243, 3298, 3353, 3408, 3463, 3518, 3573, 3628, 3682, 3737, 3792, 3847, 3902, 3957, 4012, 4067, 4122, 4177, 4232, 4287, 4342, 4397, 4452, 4506, 4561, 4616, 4671, 4726, 4781, 4836, 4891, 4946, 5001, 5056, 5111, 5166, 5221, 5275, 5330, 5385, 5440, 5495, 5550, 5605, 5660, 5715, 5770, 5825, 5880, 5935, 5990, 6045, 6099, 6154, 6209, 6264, 6319, 6374, 6429, 6484, 6539, 6594, 6649, 6704, 6759, 6814, 6868, 6923, 6978, 7033, 7088, 7143, 7198, 7253, 7308, 7363, 7418, 7473, 7528, 7583, 7637, 7692, 7747, 7802, 7857, 7912, 7967, 8022, 8077, 8132, 8187, 8242, 8297, 8352, 8407, 8461, 8516, 8571, 8626, 8681, 8736, 8791, 8846, 8901, 8956, 9011, 9066, 9121, 9176, 9230, 9285, 9340, 9395, 9450, 9505, 9560, 9615, 9670, 9725, 9780, 9835, 9890, 9945, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000};
//Function for transfering SPI data to the CJ125.
uint16_t COM_SPI(uint16_t TX_data) {
//Configure SPI for CJ125 controller.
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE1));
//Set chip select pin low, chip in use.
digitalWrite(CJ125_CS_PIN, LOW);
//Transmit request.
uint16_t Response = SPI.transfer16(TX_data);
//Set chip select pin high, chip not in use.
digitalWrite(CJ125_CS_PIN, HIGH);
return Response;
}
//Temperature regulating software (PI).
int Heater_PI_Control(int input) {
//Calculate error term.
int error = adcValue_UR_Optimal - input;
//Set current position.
int position = input;
//Calculate proportional term.
float pTerm = -pGain * error;
//Calculate the integral state with appropriate limiting.
iState += error;
if (iState > iMax) iState = iMax;
//Calculate the integral term.
float iTerm = -iGain * iState;
//Calculate regulation (PI).
int RegulationOutput = pTerm + iTerm;
//Set maximum heater output (full power).
if (RegulationOutput > 255) RegulationOutput = 255;
//Set minimum heater value (cooling).
if (RegulationOutput < 0.0) RegulationOutput = 0;
//Return calculated PWM output.
return RegulationOutput;
}
//Displays the AFR value on an external narrowband lambda gauge with an (RC-filtered) 0-1V PWM signal from ANALOG_OUTPUT_PIN. 0V = AFR 20.00. 1V = AFR 10.00.
void UpdateAnalogOutput() {
//Local constants.
const float AirFuelRatioOctane = 14.70;
const int maximumOutput = 51; /* 1V */
const int minimumOutput = 0; /* 0V */
//Local variables.
int analogOutput = 0;
float lambdaAFR = Lookup_Lambda(adcValue_UA) * AirFuelRatioOctane;
//Convert lambda value to PWM output.
analogOutput = map(lambdaAFR * 100, 2000, 1000, minimumOutput, maximumOutput);
//Make sure we do not exceed maximum values.
if (analogOutput > maximumOutput) analogOutput = maximumOutput;
if (analogOutput < minimumOutput) analogOutput = minimumOutput;
//Set PWM output.
analogWrite(ANALOG_OUTPUT_PIN, analogOutput);
}
//Convert ADC to Lambda.
float Lookup_Lambda(int Input_ADC) {
//Declare and set default return value.
float LAMBDA_VALUE = 0;
// Validate ADC range for lookup table
if (Input_ADC < 0) Input_ADC = 0; // Update with new range
if (Input_ADC > 1023) Input_ADC = 1023; // Update with new range
// Lookup Lambda Value (scaled)
LAMBDA_VALUE = pgm_read_word_near(Lambda_Conversion + Input_ADC) / 1000.0;
// Return value
return LAMBDA_VALUE;
}
// Convert ADC to Oxygen
float Lookup_Oxygen(int Input_ADC) {
// Declare and set default return value
float OXYGEN_CONTENT = 0;
// Validate ADC range for lookup table
if (Input_ADC < 0) Input_ADC = 0; // Update with new range
if (Input_ADC > 1023) Input_ADC = 1023; // Update with new range
// Lookup Oxygen Concentration (scaled)
OXYGEN_CONTENT = pgm_read_word_near(Oxygen_Conversion + Input_ADC) / 100.0;
// Return value
return OXYGEN_CONTENT;
}
//Function to set up device for operation.
void setup() {
//Set up serial communication.
Serial.begin(9600);
Serial.println("Test.");
startTime = millis(); // Initialize the start time
//Set up SPI.
SPI.begin(); /* Note, SPI will disable the bult in LED. */
//Set up digital output pins.
pinMode(CJ125_CS_PIN, OUTPUT);
pinMode(LED_STATUS_POWER, OUTPUT);
pinMode(LED_STATUS_HEATER, OUTPUT);
pinMode(HEATER_OUTPUT_PIN, OUTPUT);
//Set initial values.
digitalWrite(CJ125_CS_PIN, HIGH);
digitalWrite(LED_STATUS_POWER, LOW);
digitalWrite(LED_STATUS_HEATER, LOW);
analogWrite(HEATER_OUTPUT_PIN, 0); /* PWM is initially off. */
analogWrite(ANALOG_OUTPUT_PIN, 0); /* PWM is initially off. */
//Start of operation. (Test LED's).
digitalWrite(LED_STATUS_POWER, HIGH);
digitalWrite(LED_STATUS_HEATER, HIGH);
delay(200);
digitalWrite(LED_STATUS_POWER, LOW);
digitalWrite(LED_STATUS_HEATER, LOW);
//Initialize display.
u8g2.begin();
//Start main function.
start();
// Initialize startTime to 0 at the beginning
startTime = millis();
}
void start() {
//Wait until everything is ready.
while (adcValue_UB < UBAT_MIN || CJ125_Status != CJ125_DIAG_REG_STATUS_OK) {
//Read CJ125 diagnostic register from SPI.
CJ125_Status = COM_SPI(CJ125_DIAG_REG_REQUEST);
//Error handling.
if (CJ125_Status != CJ125_DIAG_REG_STATUS_OK) {
Serial.print("CJ125_ERROR_0x");
Serial.print(CJ125_Status, HEX);
Serial.print("\n\r");
}
//Read input voltage.
adcValue_UB = analogRead(UB_ANALOG_INPUT_PIN);
}
//Start of operation. (Start Power LED).
digitalWrite(LED_STATUS_POWER, HIGH);
//Set CJ125 in calibration mode.
COM_SPI(CJ125_INIT_REG1_MODE_CALIBRATE);
//Let values settle.
delay(500);
//Store optimal values before leaving calibration mode.
adcValue_UA_Optimal = analogRead(UA_ANALOG_INPUT_PIN);
adcValue_UR_Optimal = analogRead(UR_ANALOG_INPUT_PIN);
//Update analog output, display the optimal value.
adcValue_UA = adcValue_UA_Optimal;
UpdateAnalogOutput();
//Set CJ125 in normal operation mode.
COM_SPI(CJ125_INIT_REG1_MODE_NORMAL_V17); /* V=1 */
/* Heat up sensor. This is described in detail in the datasheet of the LSU 4.9 sensor with a
* condensation phase and a ramp up face before going in to PID control. */
//Calculate supply voltage.
float SupplyVoltage = (((float)adcValue_UB / 1023 * 5) / 10000) * 110000;
//Condensation phase, 2V for 5s.
int CondensationPWM = (2 / SupplyVoltage) * 255;
analogWrite(HEATER_OUTPUT_PIN, CondensationPWM);
int t = 0;
while (t < 5 && analogRead(UB_ANALOG_INPUT_PIN) > UBAT_MIN) {
//Flash Heater LED in condensation phase.
digitalWrite(LED_STATUS_HEATER, HIGH);
delay(500);
digitalWrite(LED_STATUS_HEATER, LOW);
delay(500);
t += 1;
}
//Ramp up phase, +0.4V / s until 100% PWM from 8.5V.
float UHeater = 8.5;
while (UHeater < 13.0 && analogRead(UB_ANALOG_INPUT_PIN) > UBAT_MIN) {
//Set heater output during ramp up.
CondensationPWM = (UHeater / SupplyVoltage) * 255;
if (CondensationPWM > 255) CondensationPWM = 255; /*If supply voltage is less than 13V, maximum is 100% PWM*/
analogWrite(HEATER_OUTPUT_PIN, CondensationPWM);
//Flash Heater LED in condensation phase.
digitalWrite(LED_STATUS_HEATER, HIGH);
delay(500);
digitalWrite(LED_STATUS_HEATER, LOW);
delay(500);
//Increment Voltage.
UHeater += 0.4;
}
//Heat until temperature optimum is reached or exceeded (lower value is warmer).
while (analogRead(UR_ANALOG_INPUT_PIN) > adcValue_UR_Optimal && analogRead(UB_ANALOG_INPUT_PIN) > UBAT_MIN) {
//Flash Heater LED in condensation phase.
digitalWrite(LED_STATUS_HEATER, HIGH);
delay(500);
digitalWrite(LED_STATUS_HEATER, LOW);
delay(500);
}
//Heating phase finished, hand over to PID-control. Turn on LED and turn off heater.
digitalWrite(LED_STATUS_HEATER, HIGH);
analogWrite(HEATER_OUTPUT_PIN, 0);
}
// Infinite loop
void loop() {
// Calculate elapsed time relative to startTime
unsigned long elapsedTime = millis() - startTime; // Elapsed time since the program started
// Update CJ125 diagnostic register from SPI
CJ125_Status = COM_SPI(CJ125_DIAG_REG_REQUEST);
// Update analog inputs
adcValue_UA = analogRead(UA_ANALOG_INPUT_PIN);
adcValue_UR = analogRead(UR_ANALOG_INPUT_PIN);
adcValue_UB = analogRead(UB_ANALOG_INPUT_PIN);
// Adjust PWM output by calculated PID regulation
if (adcValue_UR < 500 || adcValue_UR_Optimal != 0 || adcValue_UB > UBAT_MIN) {
// Calculate and set new heater output
heaterOutput = Heater_PI_Control(adcValue_UR);
analogWrite(HEATER_OUTPUT_PIN, heaterOutput);
} else {
// Turn off heater if we are not in PID control
heaterOutput = 0;
analogWrite(HEATER_OUTPUT_PIN, heaterOutput);
}
// If power is lost, "reset" the device
if (adcValue_UB < UBAT_MIN) {
// Indicate low power
Serial.print("Low power.\n");
// Turn off status LEDs
digitalWrite(LED_STATUS_POWER, LOW);
digitalWrite(LED_STATUS_HEATER, LOW);
// Reset the device and restart
start();
// Reset startTime when power is restored
startTime = millis();
}
// Display on serial port at defined rate
if ((1000 / SERIAL_RATE) == serial_counter) {
// Reset counter
serial_counter = 0;
// Calculate Lambda Value
float LAMBDA_VALUE = Lookup_Lambda(adcValue_UA);
// Calculate Oxygen Content
float OXYGEN_CONTENT = Lookup_Oxygen(adcValue_UA);
// Update analog output
UpdateAnalogOutput();
// Display information if no errors are reported
if (CJ125_Status == CJ125_DIAG_REG_STATUS_OK) {
// Construct CSV-formatted string
txString = String(elapsedTime / 1000.0, 3); // Elapsed time in seconds with 3 decimal places
txString += ",";
txString += String(OXYGEN_CONTENT, 2); // Oxygen concentration
txString += ",";
txString += String(LAMBDA_VALUE, 2); // Lambda value
txString += ",";
txString += String(adcValue_UB); // UB ADC
txString += ",";
txString += String(adcValue_UA); // UA ADC
txString += ",";
txString += String(adcValue_UR); // UR ADC
txString += ",";
txString += String(adcValue_UR_Optimal); // UR optimal
txString += ",";
txString += String(heaterOutput); // Heater output
// Output string
Serial.println(txString);
// Output display data
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_helvB24_tf);
u8g2.setCursor(0, 29);
u8g2.print(LAMBDA_VALUE * 14.70, 1);
u8g2.setCursor(0, 59);
u8g2.print(LAMBDA_VALUE, 1);
} while (u8g2.nextPage());
}
}
// Increment serial output counter and delay for next cycle
serial_counter++;
delay(1); // Adjust delay for better performance
}