Introduction
Hydroponics is the science of growing plants without soil. Nutrients are fed directly to the plant via nutrient solution in a very carefully monitored environment. This level of control allows us to predict various parameters such as yield, time to bear fruit, etc.
There are certain requirements that need to be met in order to be able to control this environment successfully. Sensors need to be scanned periodically, data collected, stored and available on the cloud for viewing and monitoring from a remote location.
The MAX32630FTHR suits this requirement perfectly. An ARM processor which comfortably processes all the sensor activity, SD Card on board which is used here to set up the unit (configuration), a gyro and accelerometer to monitor and alert the user if any disturbances occur and BLE to be able to use a mobile phone or tablet to view data and also to upload the data to the cloud.
BOM
MAX32630FTHR
MAX7219 - 4 nos.
74HC164 - 5 nos.
Light Dependent Resistors - 9 nos.
MH-Z14 CO2 sensor - 1 no.
pH Electrode - 3 nos.
Water Level Sensor - 3 nos.
DHT-11 - Humidity/Temperature Sensor - 3 nos.
74HC4067 - ADC MUX - 2 nos.
Schematics
Instructions
Discussed in previous blogs
Video
Just a small clip to show most of the sensors hooked up and the actuators kicking in to light up the unit or switch on the fans. Also seen in the clip are the BLE notifications coming in from the unit. Since we are using custom characteristics, the values are not recognized in any particular format and are also not named since this is a proprietary software that I am using to check the notifications..
Source Code
Hydroponics is the science of growing plants without soil. Nutrients are fed directly to the plant via nutrient solution in a very carefully monitored environment. This level of control allows us to predict various parameters such as yield, time to bear fruit, etc.
There are certain requirements that need to be met in order to be able to control this environment successfully. Sensors need to be scanned periodically, data collected, stored and available on the cloud for viewing and monitoring from a remote location.
The MAX32630FTHR suits this requirement perfectly. An ARM processor which comfortably processes all the sensor activity, SD Card on board which is used here to set up the unit (configuration), a gyro and accelerometer to monitor and alert the user if any disturbances occur and BLE to be able to use a mobile phone or tablet to view data and also to upload the data to the cloud.
BOM
MAX32630FTHR
MAX7219 - 4 nos.
74HC164 - 5 nos.
Light Dependent Resistors - 9 nos.
MH-Z14 CO2 sensor - 1 no.
pH Electrode - 3 nos.
Water Level Sensor - 3 nos.
DHT-11 - Humidity/Temperature Sensor - 3 nos.
74HC4067 - ADC MUX - 2 nos.
Schematics
Instructions
Discussed in previous blogs
Video
Just a small clip to show most of the sensors hooked up and the actuators kicking in to light up the unit or switch on the fans. Also seen in the clip are the BLE notifications coming in from the unit. Since we are using custom characteristics, the values are not recognized in any particular format and are also not named since this is a proprietary software that I am using to check the notifications..
Source Code
Code (Text):
- #include "mbed.h"
- #include "max32630fthr.h"
- #include "shiftreg.h"
- #include "adc.h"
- #include "Dht11.h"
- #include "bmi160.h"
- #include "ble/BLE.h"
- #include "ble/services/BatteryService.h"
- #include "ble/services/EnvironmentalService.h"
- #include "DeviceInformationService.h"
- #include "FATFileSystem.h"
- #include "SDBlockDevice.h"
- #define MAX_RELAYS 8
- #define MAX_ADC 32
- #define MAX_SUBSYSTEMS 6 // temperature, humidity, pH, CO2, Oxygen, Water Level
- #define GYRO_TRIGGER 5.0 // no real need for this to be less than 20, really
- #define GYRO_SCAN_INTERVAL 1.0 // seconds - consider bumping this to 200ms
- #define ADC_SETTLE_TIME 20 // milliseconds
- #define ALL_GREEN_OFFSET 204
- #define QUAD1_OFFSET 1
- #define QUAD2_OFFSET 16
- #define QUAD3_OFFSET 32
- #define QUAD4_OFFSET 2
- //////////////////////////////////////
- //
- //ADC MUX INPUT DEFINITIONS
- #define T1HUM 0
- #define T2HUM 1
- #define T3HUM 2
- #define T1CO2 3
- #define T2CO2 4
- #define T3CO2 5
- #define T1pH 6
- #define T2pH 7
- #define T3pH 8
- #define T1WLEVEL 9
- #define T2WLEVEL 10
- #define T3WLEVEL 11
- #define T1L1 16
- #define T1L2 17
- #define T1L3 18
- #define T2L1 19
- #define T2L2 20
- #define T2L3 21
- #define T3L1 22
- #define T3L2 23
- #define T3L3 24
- //////////////////////////////////////
- //RELAYS DEFINITIONS
- #define RELAY_T1_LIGHT1 0
- #define RELAY_T1_LIGHT2 1
- #define RELAY_T1_LIGHT3 2
- #define RELAY_T2_LIGHT1 3
- #define RELAY_T2_LIGHT2 4
- #define RELAY_T2_LIGHT3 5
- #define RELAY_T3_LIGHT1 6
- #define RELAY_T3_LIGHT2 7
- #define RELAY_T3_LIGHT3 8
- #define RELAY_T1_FAN 9
- #define RELAY_T2_FAN 10
- #define RELAY_T3_FAN 11
- #define RELAY_T1_OXYPUMP 12
- #define RELAY_T2_OXYPUMP 13
- #define RELAY_T3_OXYPUMP 14
- #define RELAY_T1_CO2 15
- #define RELAY_T2_CO2 16
- #define RELAY_T3_CO2 17
- ////////////////////////////////////////////////////////////////////////////
- // BMI160 Initialization
- I2C i2cBus(P5_7, P6_0);
- BMI160_I2C imu(i2cBus, BMI160_I2C::I2C_ADRS_SDO_LO);
- BMI160::AccConfig accConfig;
- BMI160::GyroConfig gyroConfig;
- // Shift Register Initialization
- ShiftOut sr(P3_5,P3_2,P3_3,24); // CLK, DATA, CLR for the 3 74LS164's handling the relays
- ShiftOut adcmux(P5_4,P5_5,P5_3,8); // CLK, DATA, CLR for the single 164 handling the ADC signal multiplexers
- ShiftOut levelmon(P3_0,P3_1,P4_0,8); // CLK, DATA, CLR for the single 164 displaying level disturbances (dual LEDs)
- // DHT-11 Initialization
- Dht11 hum_sensor1(P5_6);
- Dht11 hum_sensor2(P5_6);
- Dht11 hum_sensor3(P5_6);
- // SPI Initialization - for MAX7219
- SPI spi(P5_1, P5_2, P5_0); // MOSI, MISO, SCLK - MISO not used here, though
- DigitalOut cs(P3_4); // Chip select (LOAD)
- // On board LED
- DigitalOut rLED(LED1, LED_OFF);
- DigitalOut gLED(LED2, LED_OFF);
- DigitalOut bLED(LED3, LED_OFF);
- //Level Monitor Reset Pin
- BatteryService *batteryServicePtr;
- DeviceInformationService *deviceInformationServicePtr;
- EnvironmentalService *environServicePtr;
- char config_buffer[128];
- const char DEVICE_NAME[] = "HYGROMAX630";
- const uint16_t uuid16_list[] = { GattService::UUID_BATTERY_SERVICE,
- GattService::UUID_DEVICE_INFORMATION_SERVICE,
- GattService::UUID_ENVIRONMENTAL_SERVICE};
- int mon_temperature = 77; // farenheit
- int mon_humidity = 85; // percentage
- int mon_pH = 75; // pH*10
- int mon_fans = 7; // powers of 2 format
- int mon_lights = 32; // powers of 2 format
- int mon_waterlevel = 80; // percentage
- int mon_oxygen = 1; // 1 or 0
- int mon_co2 = 99; // ppm
- int batteryPercentage = 100;
- Ticker sec_tick;
- Ticker fivesecs_tick;
- Ticker fifteensecs_tick;
- Ticker eighteensecs_tick;
- Ticker levelmon_tick;
- int mc_seconds = 0;
- int mc_minutes = 39;
- int mc_hours = 10;
- int mc_days = 17;
- int start_hours = 0;
- int start_minutes = 0;
- int lightintensitytrigger = 500; // probably needs further calibration
- // also, consider moving this to the SD card
- // along with the others
- int lightdutycycle = 0;
- int co2trigger = 0;
- int pHtrigger = 0;
- int lp_lights = 0;
- int lp_oxygen = 0;
- int lp_co2 = 0;
- int subsys_count = 0;
- int adc_int;
- float imuTemperature;
- BMI160::SensorData accData;
- BMI160::SensorData gyroData;
- BMI160::SensorTime sensorTime;
- int disturbed = 0;
- int QUAD1 = 0;
- int QUAD2 = 0;
- int QUAD3 = 0;
- int QUAD4 = 0;
- int RELAYS[MAX_RELAYS];
- int srcount = 0;
- int adc_count = 3; //0,1,2 - humidity
- int TWOPOWERS[] = {1,
- 2,
- 4,
- 8,
- 16,
- 32,
- 64,
- 128,
- 256,
- 512,
- 1024,
- 2048,
- 4096,
- 8192,
- 16384,
- 32768,
- 65536,
- 131072,
- 262144,
- 524288,
- 1048576,
- 2097152,
- 4194304,
- 8388608,
- 16777216};
- unsigned char ADC_SELECT[32] = {32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
- 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
- unsigned char BUFFER_MSB[4][8];
- unsigned char BUFFER_LSB[4][8];
- void periodicCallback(void)
- {
- }
- /* Restart Advertising on disconnection*/
- void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
- {
- BLE::Instance().gap().startAdvertising();
- }
- /* Connection */
- void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
- {
- }
- /**
- * This function is called when the ble initialization process has failed
- */
- void onBleInitError(BLE &ble, ble_error_t error)
- {
- /* Avoid compiler warnings */
- (void) ble;
- (void) error;
- /* Initialization error handling should go here */
- }
- /**
- * Callback triggered when the ble initialization process has finished
- */
- void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
- {
- BLE& ble = params->ble;
- ble_error_t error = params->error;
- if (error != BLE_ERROR_NONE) {
- /* In case of error, forward the error handling to onBleInitError */
- onBleInitError(ble, error);
- return;
- }
- /* Ensure that it is the default instance of BLE */
- if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
- return;
- }
- ble.gap().onDisconnection(disconnectionCallback);
- ble.gap().onConnection(connectionCallback);
- /* Setup primary service. */
- deviceInformationServicePtr = new DeviceInformationService(ble, "Maxim", "FTHR", "00001", "0.1", "0.0", "0.0");
- batteryServicePtr = new BatteryService(ble, batteryPercentage);
- environServicePtr = new EnvironmentalService(ble);
- /* Setup advertising */
- ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
- ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
- ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
- ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
- ble.gap().setAdvertisingInterval(250); /* 250ms */
- ble.gap().startAdvertising();
- }
- void ClearLoadPin()
- {
- cs = 0; // Set CS Low
- }
- void SetLoadPin()
- {
- cs = 1; // Set CS High
- }
- /// Send two bytes to SPI bus
- void SPI_Write2(unsigned char MSB, unsigned char LSB)
- {
- spi.write(MSB); // Send two bytes
- spi.write(LSB);
- }
- void ReadADC(int select)
- {
- float adc_f = 0.0;
- float adc_norm = 0.0;
- uint16_t adc_value;
- unsigned int overflow;
- ADC_StartConvert(ADC_CH_1_DIV_5, 0, 1); // AIN1 div 5
- overflow = (ADC_GetData(&adc_value) == E_OVERFLOW ? 1 : 0);
- printf("AIN1/5: 0x%04x%s %d %d\r\n", adc_value, overflow ? "*" : " ", ADC_SELECT[select], adc_value);
- adc_f = adc_value;
- adc_norm = (adc_f/1024.0)*100.0;
- adc_int = adc_norm;
- if(adc_int > 99)
- adc_int = 99;
- }
- /*
- void TestADCMUX()
- {
- ClearAllRelays();
- adcmux.setclr();
- if(adc_count==MAX_RELAYS)
- {
- adc_count = 3; //0,1,2 - humidity
- wait(1.0);
- }
- adcmux.write(ADC_SELECT[adc_count]);
- wait_ms(1);
- ReadADC(adc_count);
- SetRelay(adc_count);
- int relay_data = GetRelayData();
- sr.write(relay_data);
- wait(1);
- }
- */
- /// Send eight control bytes to SPI bus to 4 7219's
- void SPI_Write8(unsigned char MSB, unsigned char LSB)
- {
- ClearLoadPin();
- spi.write(MSB); // Send two bytes to 4
- spi.write(LSB);
- spi.write(MSB); // Send two bytes to 3
- spi.write(LSB);
- spi.write(MSB); // Send two bytes to 2
- spi.write(LSB);
- spi.write(MSB); // Send two bytes to 1
- spi.write(LSB);
- SetLoadPin();
- }
- /// Send eight bytes to SPI bus to 4 7219's
- void SPI_Write8BUF()
- {
- for(int digit=0;digit<8;digit++)
- {
- ClearLoadPin();
- spi.write(BUFFER_MSB[3][digit]); // Send two bytes to 3
- spi.write(BUFFER_LSB[3][digit]);
- spi.write(BUFFER_MSB[2][digit]); // Send two bytes to 2
- spi.write(BUFFER_LSB[2][digit]);
- spi.write(BUFFER_MSB[1][digit]); // Send two bytes to 1
- spi.write(BUFFER_LSB[1][digit]);
- spi.write(BUFFER_MSB[0][digit]); // Send two bytes to 4
- spi.write(BUFFER_LSB[0][digit]);
- SetLoadPin();
- }
- }
- void SPI_WriteToBuf(int bufslot, int digit, unsigned char MSB, unsigned char LSB)
- {
- BUFFER_MSB[bufslot][digit] = MSB;
- BUFFER_LSB[bufslot][digit] = LSB;
- }
- void Update_MAX7219()
- {
- SPI_Write8BUF();
- }
- /// MAX7219 initialisation
- void Init_MAX7219(void)
- {
- SPI_Write8(0x09, 0xFF); // Decoding on
- SPI_Write8(0x0A, 0x08); // Brightness to intermediate
- SPI_Write8(0x0B, 0x07); // Scan limit = 7
- SPI_Write8(0x0C, 0x01); // Normal operation mode
- SPI_Write8(0x0F, 0x0F); // Enable display test
- wait_ms(100); // 500 ms delay
- /*
- SPI_Write8(0x01, 0x00); // Clear row 0.
- SPI_Write8(0x02, 0x00); // Clear row 1.
- SPI_Write8(0x03, 0x00); // Clear row 2.
- SPI_Write8(0x04, 0x00); // Clear row 3.
- SPI_Write8(0x05, 0x00); // Clear row 4.
- SPI_Write8(0x06, 0x00); // Clear row 5.
- SPI_Write8(0x07, 0x00); // Clear row 6.
- SPI_Write8(0x08, 0x00); // Clear row 7.
- */
- SPI_Write8(0x0F, 0x00); // Disable display test
- wait_ms(100);
- }
- int GetRelayData()
- {
- int rd = 0;
- for(int i=0;i<MAX_RELAYS;i++)
- if(RELAYS[i])
- rd += TWOPOWERS[i];
- return(rd);
- }
- void ScanLight()
- {
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T1L1]);
- wait_ms(1);
- printf("Light T1L1 - ");
- ReadADC(T1L1);
- SPI_WriteToBuf(1,0,1,13);
- SPI_WriteToBuf(1,1,2,1);
- SPI_WriteToBuf(1,2,3,(adc_int/10));
- SPI_WriteToBuf(1,3,4,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T1L2]);
- wait_ms(1);
- printf("Light T1L2 -");
- ReadADC(T1L2);
- SPI_WriteToBuf(1,4,5,(adc_int/10));
- SPI_WriteToBuf(1,5,6,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T1L3]);
- wait_ms(1);
- printf("Light T1L3 - ");
- ReadADC(T1L3);
- SPI_WriteToBuf(1,6,7,(adc_int/10));
- SPI_WriteToBuf(1,7,8,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T2L1]);
- wait_ms(1);
- printf("Light T2L1 - ");
- ReadADC(T2L1);
- SPI_WriteToBuf(2,0,1,13);
- SPI_WriteToBuf(2,1,2,1);
- SPI_WriteToBuf(2,2,3,(adc_int/10));
- SPI_WriteToBuf(2,3,4,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T2L2]);
- wait_ms(1);
- printf("Light T2L2 - ");
- ReadADC(T2L2);
- SPI_WriteToBuf(2,4,5,(adc_int/10));
- SPI_WriteToBuf(2,5,6,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T2L3]);
- wait_ms(1);
- printf("Light T2L3 - ");
- ReadADC(T2L3);
- SPI_WriteToBuf(2,6,7,(adc_int/10));
- SPI_WriteToBuf(2,7,8,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T3L1]);
- wait_ms(1);
- printf("Light T3L1 - ");
- ReadADC(T3L1);
- SPI_WriteToBuf(3,0,1,13);
- SPI_WriteToBuf(3,1,2,1);
- SPI_WriteToBuf(3,2,3,(adc_int/10));
- SPI_WriteToBuf(3,3,4,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T3L2]);
- wait_ms(1);
- printf("Light T3L2 - ");
- ReadADC(T3L2);
- SPI_WriteToBuf(3,4,5,(adc_int/10));
- SPI_WriteToBuf(3,5,6,(adc_int%10));
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T3L3]);
- wait_ms(1);
- printf("Light T3L3 - ");
- ReadADC(T3L3);
- SPI_WriteToBuf(3,6,7,(adc_int/10));
- SPI_WriteToBuf(3,7,8,(adc_int%10));
- }
- void ScanHumidity()
- {
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T1HUM]);
- wait_ms(ADC_SETTLE_TIME);
- hum_sensor1.read();
- wait_ms(ADC_SETTLE_TIME);
- float ftemp1 = hum_sensor1.getFahrenheit();
- int ihum = hum_sensor1.getHumidity();
- printf("T: %f, H: %d\r\n",ftemp1 , ihum);
- SPI_WriteToBuf(1,0,1,12);
- SPI_WriteToBuf(1,1,2,10);
- SPI_WriteToBuf(1,2,3,(ihum/10));
- SPI_WriteToBuf(1,3,4,(ihum%10));
- int itemp = ftemp1;
- SPI_WriteToBuf(1,5,6,(itemp/10));
- SPI_WriteToBuf(1,6,7,(itemp%10));
- SPI_WriteToBuf(1,7,8,14);
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T2HUM]);
- wait_ms(ADC_SETTLE_TIME);
- hum_sensor2.read();
- wait_ms(ADC_SETTLE_TIME);
- float ftemp2 = hum_sensor2.getFahrenheit();
- ihum = hum_sensor2.getHumidity();
- printf("T: %f, H: %d\r\n",ftemp2 , ihum);
- SPI_WriteToBuf(2,0,1,12);
- SPI_WriteToBuf(2,1,2,10);
- SPI_WriteToBuf(2,2,3,(ihum/10));
- SPI_WriteToBuf(2,3,4,(ihum%10));
- itemp = ftemp2;
- SPI_WriteToBuf(2,5,6,(itemp/10));
- SPI_WriteToBuf(2,6,7,(itemp%10));
- SPI_WriteToBuf(2,7,8,14);
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T3HUM]);
- wait_ms(ADC_SETTLE_TIME);
- hum_sensor3.read();
- wait_ms(ADC_SETTLE_TIME);
- float ftemp3 = hum_sensor3.getFahrenheit();
- ihum = hum_sensor3.getHumidity();
- printf("T: %f, H: %d\r\n",ftemp3 , ihum);
- SPI_WriteToBuf(3,0,1,12);
- SPI_WriteToBuf(3,1,2,10);
- SPI_WriteToBuf(3,2,3,(ihum/10));
- SPI_WriteToBuf(3,3,4,(ihum%10));
- itemp = ftemp3;
- SPI_WriteToBuf(3,5,6,(itemp/10));
- SPI_WriteToBuf(3,6,7,(itemp%10));
- SPI_WriteToBuf(3,7,8,14);
- /*
- if((ftemp1>80.0)||(ftemp2>80.0)||(ftemp3>80))
- {
- RELAYS[21] = 1;
- RELAYS[22] = 1;
- RELAYS[23] = 1;
- }
- else
- {
- RELAYS[21] = 0;
- RELAYS[22] = 0;
- RELAYS[23] = 0;
- }
- int relay_data = GetRelayData();
- sr.write(relay_data);
- */
- }
- void ScanCO2()
- {
- adcmux.setclr();
- adcmux.write(ADC_SELECT[T1CO2]);
- wait_ms(1);
- printf("CO2 T1CO2 - ");
- ReadADC(T1CO2);
- SPI_WriteToBuf(1,0,1,14);
- SPI_WriteToBuf(1,1,2,14);
- SPI_WriteToBuf(1,2,3,10);
- SPI_WriteToBuf(1,3,4,(adc_int/10));
- SPI_WriteToBuf(1,4,5,(adc_int%10));
- SPI_WriteToBuf(2,0,1,14);
- SPI_WriteToBuf(2,1,2,14);
- SPI_WriteToBuf(2,2,3,10);
- SPI_WriteToBuf(2,3,4,(adc_int/10));
- SPI_WriteToBuf(2,4,5,(adc_int%10));
- SPI_WriteToBuf(3,0,1,14);
- SPI_WriteToBuf(3,1,2,14);
- SPI_WriteToBuf(3,2,3,10);
- SPI_WriteToBuf(3,3,4,(adc_int/10));
- SPI_WriteToBuf(3,4,5,(adc_int%10));
- }
- void ScanOxygen()
- {
- if(RELAYS[RELAY_T1_OXYPUMP] == 1)
- printf("Oxygen Flow is ON \r\n");
- else
- printf("Oxygen Flow is OFF \r\n");
- }
- void UpdateClock()
- {
- int sec_tens = mc_seconds / 10;
- int sec_units = mc_seconds % 10;
- int min_tens = mc_minutes / 10;
- int min_units = mc_minutes % 10;
- int hour_tens = mc_hours / 10;
- int hour_units = mc_hours % 10;
- int day_tens = mc_days / 10;
- int day_units = mc_days % 10;
- SPI_WriteToBuf(0,0,1,hour_tens);
- SPI_WriteToBuf(0,1,2,hour_units);
- SPI_WriteToBuf(0,2,3,min_tens);
- SPI_WriteToBuf(0,3,4,min_units);
- SPI_WriteToBuf(0,4,5,sec_tens);
- SPI_WriteToBuf(0,5,6,sec_units);
- SPI_WriteToBuf(0,6,7,day_tens);
- SPI_WriteToBuf(0,7,8,day_units);
- // Get our ADC mux to fire every 2 seconds without setting up an extra ticker for this
- if((mc_seconds % 2)==0)
- {
- if(subsys_count==MAX_SUBSYSTEMS)
- subsys_count = 0;
- int selected_disp = subsys_count % MAX_SUBSYSTEMS;
- switch (selected_disp)
- {
- case 0:
- //Light
- ScanLight();
- break;
- case 1:
- // Humidity Temperature
- ScanHumidity();
- break;
- case 2:
- // Oxygen
- //ScanOxygen();
- break;
- case 3:
- //CO2
- ScanCO2();
- break;
- case 4:
- //pH
- //ScanpH();
- break;
- case 5:
- //Water Level
- //ScanWaterLevel();
- break;
- }
- subsys_count++;
- } // mc_seconds % 2
- Update_MAX7219();
- Update_MAX7219();
- }
- void MonitorLevel()
- {
- imu.getGyroAccXYZandSensorTime(accData, gyroData, sensorTime, accConfig.range, gyroConfig.range);
- imu.getTemperature(&imuTemperature);
- if(!disturbed)
- {
- // QUADRANTS
- //
- // 2 1
- //
- // 3 4
- int xval = gyroData.xAxis.scaled;
- int yval = gyroData.yAxis.scaled;
- //int zval = gyroData.zAxis.scaled; // we'll come back for this some other day
- if((QUAD1!=0)||(QUAD2!=0)||(QUAD3!=0)||(QUAD4!=0))
- disturbed = 1;
- if(xval > GYRO_TRIGGER) // 3 or 4 lowered
- if(yval > GYRO_TRIGGER) // 4
- QUAD4 = 1;
- else if(yval < -(GYRO_TRIGGER)) //3
- QUAD3 = 1;
- else // 3 and 4
- QUAD3 = QUAD4 = 1;
- else if(xval < -(GYRO_TRIGGER)) // 1 or 2 lowered
- if(yval > GYRO_TRIGGER) // 1
- QUAD1 = 1;
- else if(yval < -(GYRO_TRIGGER)) //2
- QUAD2 = 1;
- else
- QUAD1 = QUAD2 = 1;
- else if(yval > GYRO_TRIGGER) // 1 and 4
- QUAD1 = QUAD4 = 1;
- else if(yval < -(GYRO_TRIGGER)) // 2 and 3
- QUAD2 = QUAD3 = 1;
- // else // basically, all is well - no disturbance
- // QUAD1 = QUAD2 = QUAD3 = QUAD4 = 0;
- } // if(!disturbed)
- levelmon.setclr();
- int level_pattern = ALL_GREEN_OFFSET;
- if(QUAD1==1)
- level_pattern += QUAD1_OFFSET;
- if(QUAD2==1)
- level_pattern += QUAD2_OFFSET;
- if(QUAD3==1)
- level_pattern += QUAD3_OFFSET;
- if(QUAD4==1)
- level_pattern += QUAD4_OFFSET;
- levelmon.write(level_pattern);
- }
- void SetRelay(int relno)
- {
- RELAYS[relno] = 1;
- }
- void ClearRelay(int relno)
- {
- RELAYS[relno] = 0;
- }
- void ClearAllRelays(){
- for(int i=0;i<MAX_RELAYS;i++)
- RELAYS[i] = 0;
- sr.setclr();
- }
- void TestAllRelays()
- {
- if(srcount==MAX_RELAYS)
- {
- srcount = 0;
- ClearAllRelays();
- }
- SetRelay(srcount);
- int relay_data = GetRelayData();
- sr.write(relay_data);
- printf("RELAYS SWITCHED ON - %d\r\n", relay_data);
- wait_ms(10);
- srcount++;
- }
- void EverySecond()
- {
- gLED = !gLED;
- bLED = !bLED;
- rLED = !rLED; /* Blink LED while we're waiting for BLE events */
- batteryServicePtr->updateBatteryLevel(batteryPercentage);
- environServicePtr->updateTemperature(mon_temperature);
- environServicePtr->updateHumidity(mon_humidity);
- environServicePtr->updatepH(mon_pH);
- environServicePtr->updateLights(mon_lights);
- environServicePtr->updateWaterLevel(mon_waterlevel);
- environServicePtr->updateOxygen(mon_oxygen);
- environServicePtr->updateFans(mon_fans);
- environServicePtr->updateCO2(mon_co2);
- /*
- printf("\033[H"); //home
- printf("\033[0J"); //erase from cursor to end of screen
- printf("ACC xAxis = %s%4.3f\r\n", "\033[K", accData.xAxis.scaled);
- printf("ACC yAxis = %s%4.3f\r\n", "\033[K", accData.yAxis.scaled);
- printf("ACC zAxis = %s%4.3f\r\n\n", "\033[K", accData.zAxis.scaled);
- printf("GYRO xAxis = %s%5.1f\r\n", "\033[K", gyroData.xAxis.scaled);
- printf("GYRO yAxis = %s%5.1f\r\n", "\033[K", gyroData.yAxis.scaled);
- printf("GYRO zAxis = %s%5.1f\r\n\n", "\033[K", gyroData.zAxis.scaled);
- printf("Sensor Time = %s%f\r\n", "\033[K", sensorTime.seconds);
- printf("Sensor Temperature = %s%5.3f\r\n", "\033[K", imuTemperature);
- printf("%d %d\r\n\n",QUAD2,QUAD1);
- printf("%d %d\r\n\n",QUAD3,QUAD4);
- */
- if(mc_seconds==59){
- mc_seconds=0;
- if(mc_minutes==59)
- {
- mc_minutes=0;
- if(mc_hours==23)
- {
- mc_hours=0;
- mc_days++;
- }
- else
- mc_hours++;
- }
- else
- mc_minutes++;
- }
- else
- mc_seconds++;
- UpdateClock();
- }
- void LevelResetFunc()
- {
- disturbed = 0;
- QUAD1 = QUAD2 = QUAD3 = QUAD4 = 0;
- }
- void LoadConfigParam(int entry)
- {
- int mc_int;
- mc_int = atoi(config_buffer);
- switch (entry)
- {
- case 0:
- //Current Time
- printf("Start with %d\r\n", mc_int);
- mc_days = mc_int % 100;
- mc_int = (mc_int - mc_days)/100;
- printf("Now at %d\r\n",mc_int);
- mc_seconds = mc_int % 100;
- mc_int = (mc_int - mc_seconds)/100;
- printf("Now at %d\r\n",mc_int);
- mc_minutes = mc_int % 100;
- mc_int = (mc_int - mc_minutes)/100;
- printf("Now at %d\r\n",mc_int);
- mc_hours = mc_int % 100;
- printf("System Clock Reset to %d hours, %d minutes, %d seconds (%d Days)\r\n", mc_hours, mc_minutes, mc_seconds, mc_days);
- break;
- case 1:
- // Cycle Start Time
- start_minutes = mc_int % 100;
- start_hours = (mc_int - start_minutes)/100;
- printf("Cycle Starts at %d hours and %d minutes\r\n", start_hours, start_minutes);
- break;
- case 2:
- //Light Duty Cycle
- lightdutycycle = mc_int;
- printf("Light Duty Cycle set at %d hours\r\n", mc_int);
- break;
- case 3:
- // CO2 PPM Trigger
- co2trigger = mc_int;
- printf("CO2 Trigger set at %d (ppm)\r\n", co2trigger);
- break;
- case 4:
- // pH Trigger
- pHtrigger = mc_int;
- printf("pH Trigger set at %d (Scale x10)\r\n",pHtrigger);
- break;
- case 5:
- // Lights - Low Power
- lp_lights = mc_int;
- printf("Lights on Low Power Mode - %d\r\n",lp_lights);
- case 6:
- // Oxygen - Low Power
- lp_oxygen = mc_int;
- printf("Oxygen on Low Power Mode - %d\r\n",lp_oxygen);
- break;
- case 7:
- // CO2 - Low Power
- lp_co2 = mc_int;
- printf("CO2 on Low Power Mode - %d\r\n",lp_co2);
- break;
- }
- }
- void ReadConfig()
- {
- SDBlockDevice sd(P0_5,P0_6,P0_4,P0_7); // mosi, miso, sclk, cs
- FATFileSystem fs("fs");
- printf("Mounting the filesystem on \"/fs\". ");
- fs.mount(&sd);
- FILE* fd = fopen("/fs/config.txt", "r");
- int entry = 0;
- while(fgets(config_buffer, 128, fd)) {
- LoadConfigParam(entry);
- entry++;
- }
- /*
- char ch = fgetc(fd);
- while(!feof(fd)){
- printf("%c",ch);
- ch = fgetc(fd);
- }
- fclose(fd);
- }
- int main()
- {
- uint32_t i = 0;
- LowPowerTicker ticker;
- BLE &ble = BLE::Instance();
- ble.init(bleInitComplete);
- /* SpinWait for initialization to complete. This is necessary because the
- * BLE object is used in the main loop below. */
- while (ble.hasInitialized() == false) { /* spin loop */ }
- sec_tick.attach(&EverySecond,1.0);
- //ticker.attach(periodicCallback, 1.5);
- // MAX32630FTHR Initialization
- MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
- // Initialize ADC
- ADC_Init();
- // BMI160 Initialization
- i2cBus.frequency(400000);
- cs = 1; // CS initially High
- spi.format(8,0); // 8-bit format, mode 0,0
- spi.frequency(1000000); // SCLK = 1 MHz
- Init_MAX7219(); // Initialize the LED controller
- uint32_t failures = 0;
- if(imu.setSensorPowerMode(BMI160::GYRO, BMI160::NORMAL) != BMI160::RTN_NO_ERROR)
- {
- printf("Failed to set gyroscope power mode\n");
- failures++;
- }
- wait_ms(100);
- if(imu.setSensorPowerMode(BMI160::ACC, BMI160::NORMAL) != BMI160::RTN_NO_ERROR)
- {
- printf("Failed to set accelerometer power mode\n");
- failures++;
- }
- wait_ms(100);
- //example of using getSensorConfig
- if(imu.getSensorConfig(accConfig) == BMI160::RTN_NO_ERROR)
- {
- printf("ACC Range = %d\r\n", accConfig.range);
- printf("ACC UnderSampling = %d\r\n", accConfig.us);
- printf("ACC BandWidthParam = %d\r\n", accConfig.bwp);
- printf("ACC OutputDataRate = %d\r\n\n", accConfig.odr);
- }
- else
- {
- printf("Failed to get accelerometer configuration\r\n");
- failures++;
- }
- //example of setting user defined configuration
- accConfig.range = BMI160::SENS_4G;
- accConfig.us = BMI160::ACC_US_OFF;
- accConfig.bwp = BMI160::ACC_BWP_2;
- accConfig.odr = BMI160::ACC_ODR_8;
- if(imu.setSensorConfig(accConfig) == BMI160::RTN_NO_ERROR)
- {
- printf("ACC Range = %d\r\n", accConfig.range);
- printf("ACC UnderSampling = %d\r\n", accConfig.us);
- printf("ACC BandWidthParam = %d\r\n", accConfig.bwp);
- printf("ACC OutputDataRate = %d\r\n\n", accConfig.odr);
- }
- else
- {
- printf("Failed to set accelerometer configuration\r\n");
- failures++;
- }
- if(imu.getSensorConfig(gyroConfig) == BMI160::RTN_NO_ERROR)
- {
- printf("GYRO Range = %d\r\n", gyroConfig.range);
- printf("GYRO BandWidthParam = %d\r\n", gyroConfig.bwp);
- printf("GYRO OutputDataRate = %d\r\n\n", gyroConfig.odr);
- }
- else
- {
- printf("Failed to get gyroscope configuration\r\n");
- failures++;
- }
- /////////////////////////////////////////////////////////////////////////////////////
- fivesecs_tick.attach(&LevelResetFunc,5.0);
- levelmon_tick.attach(&MonitorLevel,GYRO_SCAN_INTERVAL); // GYRO SCAN INTERVAL
- ReadConfig();
- while (1) {
- if (++i == 1000) {
- i = 0;
- }
- ble.waitForEvent();
- //int relay_data = GetRelayData();
- //sr.write(relay_data);
- } // while(1)
- }