Guest User

Build Inside The Box - MCU Code

a guest
May 7th, 2021
58
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <Arduino.h>
  2. #include <SPI.h>
  3. #include <Wire.h>
  4. #include <Adafruit_I2CDevice.h>
  5. #include <Adafruit_GFX.h>
  6. #include <Adafruit_SSD1306.h>
  7. #include <Adafruit_Sensor.h>
  8. #include <DHT.h>
  9. #include <Adafruit_VL53L0X.h>
  10.  
  11. void initScreen();
  12. uint8_t getUV();
  13. uint8_t getAirQ();
  14. void slowCycle();
  15. void display();
  16. void handleOptoEvent();
  17. float getAveragedSpeed();
  18. float intervalToSpeed(float interval);
  19. void measureToF();
  20. void initToF();
  21. uint16_t getLeftToF();
  22. uint16_t getRightToF();
  23. void alarm();
  24. void showText(String text, uint8_t size);
  25.  
  26.  
  27. Adafruit_VL53L0X leftToF = Adafruit_VL53L0X();
  28. Adafruit_VL53L0X rightToF = Adafruit_VL53L0X();
  29. VL53L0X_RangingMeasurementData_t leftMeasurement;
  30. VL53L0X_RangingMeasurementData_t rightMeasurement;
  31.  
  32. Adafruit_SSD1306 oled(128, 32, 2, 0, 1, 3, 4);
  33. DHT dht(A1, DHT11);
  34.  
  35. float temperature = 0;
  36. uint8_t uvindex = 0;
  37. uint8_t airq = 0;
  38. float speed = 0;
  39.  
  40. unsigned long timer_val = 0;
  41. uint16_t slowcycle_rate = 2200; //Slow cycle rate
  42.  
  43. //Wheel speed counter stuff
  44. #define wheel_circumference 414.7 //In centimeters
  45. #define avg_cycles 3
  46. volatile uint8_t curr_avgcycle = 0;
  47. volatile uint16_t counts[avg_cycles];
  48. volatile unsigned long last_timerval = 0;
  49.  
  50. //Alarm stuff
  51. uint8_t alarm_armed = 0; //0: off, 1: left, 2: right
  52. uint16_t alarm_distance = 0;
  53. #define tof_avg_cycles 10
  54. uint16_t distances[2][tof_avg_cycles];
  55. uint8_t tof_avg_cycle[2];
  56.  
  57. #define MCP9701_temp_limit 500 //Roughly 6 count per degree, at 25C reading is 290, therefore 60C is 500
  58.  
  59.  
  60. void setup() {
  61.   initScreen();
  62.   dht.begin();
  63.   pinMode(A6, INPUT); //UV Sensor
  64.   pinMode(A2, INPUT); //AirQ Sensor
  65.   pinMode(6, OUTPUT); //Left ToF
  66.   pinMode(A5, OUTPUT); //Right ToF
  67.   pinMode(5, INPUT_PULLUP);  //Optotransistor
  68.   pinMode(A4, INPUT);
  69.   attachInterrupt(digitalPinToInterrupt(5), handleOptoEvent, FALLING); //Opto interrupt
  70.   initToF();
  71.  
  72.   //DEBUG
  73.   Serial.begin(9600);
  74. }
  75.  
  76. void loop() {
  77.   if(alarm_armed == 0) {
  78.     while(analogRead(A4) > MCP9701_temp_limit) {
  79.       showText("Overtemp");
  80.       delay(10000);
  81.     }
  82.     //Slow cycle caller
  83.     if(millis() >= timer_val + slowcycle_rate) {
  84.       timer_val = millis();
  85.       slowCycle();
  86.     }
  87.     display();
  88.     speed = intervalToSpeed(getAveragedSpeed());
  89.     measureToF();
  90.     if(getLeftToF() < 30 && getRightToF() < 30) {
  91.       oled.clearDisplay();
  92.       oled.display();
  93.       delay(3000);
  94.       for(uint8_t i = 0; i < 20; i++) { measureToF(); }
  95.       if(getLeftToF() < 30 && getRightToF() >= 30) {
  96.         alarm_armed = 2;
  97.         alarm_distance = getRightToF();
  98.         showText("Right side armed", 1);
  99.         delay(1000);
  100.         oled.clearDisplay();
  101.         oled.display();
  102.       }
  103.       else if(getLeftToF() >= 30 && getRightToF() < 30) {
  104.         alarm_armed = 1;
  105.         alarm_distance = getLeftToF();
  106.         showText("Left side armed", 1);
  107.         delay(1000);
  108.         oled.clearDisplay();
  109.         oled.display();
  110.       }
  111.     }
  112.   }
  113.   else {
  114.     measureToF();
  115.     if(alarm_armed == 1) {
  116.       if(getLeftToF() > alarm_distance + 20 || getLeftToF() < alarm_distance - 20) {
  117.         alarm();
  118.       }
  119.     }
  120.     else {
  121.       if(getRightToF() > alarm_distance + 20 || getRightToF() < alarm_distance - 20) {
  122.         alarm();
  123.       }
  124.     }
  125.   }
  126.  
  127.  
  128.   delay(10);
  129. }
  130.  
  131. //Handle stuff here that doesn't need to(or can't) run as fast as loop() (DHT11, AirQ, UV)
  132. void slowCycle() {
  133.   uvindex = getUV();
  134.   airq = getAirQ();
  135.   temperature = dht.readTemperature();
  136.  
  137.   if(millis() - last_timerval > 5000) { //If no wheel rotations happened in last 5 seconds(plus a second or two due to this only running every 2.2 secs), reset speed
  138.     for(uint8_t i = 0; i < avg_cycles; i++) {
  139.     counts[i] = 0;
  140.   }
  141.   }
  142. }
  143.  
  144. void initScreen() {
  145.   oled.begin(SSD1306_SWITCHCAPVCC);
  146.   oled.clearDisplay();
  147.   oled.setTextSize(1);      // Normal 1:1 pixel scale
  148.   oled.setTextColor(SSD1306_WHITE); // Draw white text
  149.   oled.setCursor(0, 0);     // Start at top-left corner
  150.   oled.write("Hello World!");
  151.   oled.display();
  152. }
  153.  
  154. //Sensor output is linear, 0V = UV0, 1V = UV10
  155. uint8_t getUV() {
  156.   return analogRead(A6)/31;
  157. }
  158.  
  159. //Sensor output is linear, 0V = Clean Air, goes up to 2.64V(4V originally, but using a divider)
  160. uint8_t getAirQ() {
  161.   return 100 - analogRead(A2)/8.18;
  162. }
  163.  
  164. //Display all the stuff on the OLED
  165. void display() {
  166.   oled.clearDisplay();
  167.  
  168.   oled.setTextSize(1);
  169.   oled.clearDisplay();
  170.   oled.setCursor(96, 0);
  171.   oled.print(temperature, 1);
  172.   oled.print("C");
  173.  
  174.   oled.setCursor(56, 0);
  175.   oled.print("UV");
  176.   oled.print(uvindex);
  177.  
  178.   oled.setCursor(0, 0);
  179.   oled.print("AirQ");
  180.   oled.print(airq);
  181.  
  182.   oled.setCursor(22, 12);
  183.   oled.setTextSize(3);
  184.   oled.print(speed, 1);
  185.   oled.setCursor(oled.getCursorX() + 2, 24);
  186.   oled.setTextSize(1);
  187.   oled.print("km/h");
  188.  
  189.   oled.display();
  190. }
  191.  
  192. void handleOptoEvent() {
  193.   if(millis() - last_timerval > 100) {
  194.     counts[curr_avgcycle] = millis() - last_timerval;
  195.   if(curr_avgcycle >= avg_cycles-1) {
  196.     curr_avgcycle = 0;
  197.   }
  198.   else {
  199.     curr_avgcycle++;
  200.   }
  201.   last_timerval = millis();
  202.   }
  203. }
  204.  
  205. float getAveragedSpeed() {
  206.   uint16_t sum = 0;
  207.   for(uint8_t i = 0; i < avg_cycles; i++) {
  208.     sum += counts[i];
  209.   }
  210.   return (float)sum / avg_cycles;
  211. }
  212.  
  213. float intervalToSpeed(float interval) {
  214.   if(interval == 0) return 0;
  215.   return ((wheel_circumference/100) / (interval/1000)) * 3.6; //Convert wheel circumference to meters, interval to seconds, get m/s, and then convert to km/h
  216. }
  217.  
  218. void initToF() { //From Adafruit example
  219.   // all reset
  220.   digitalWrite(6, LOW);    
  221.   digitalWrite(A5, LOW);
  222.   delay(10);
  223.   // all unreset
  224.   digitalWrite(6, HIGH);
  225.   digitalWrite(A5, HIGH);
  226.   delay(10);
  227.  
  228.   // activating LOX1 and reseting LOX2
  229.   digitalWrite(6, HIGH);
  230.   digitalWrite(A5, LOW);
  231.  
  232.   // initing LOX1
  233.   if(!leftToF.begin(0x30)) {
  234.     Serial.println(F("Failed to boot first VL53L0X"));
  235.     while(1);
  236.   }
  237.   delay(10);
  238.  
  239.   // activating LOX2
  240.   digitalWrite(A5, HIGH);
  241.   delay(10);
  242.  
  243.   //initing LOX2
  244.   if(!rightToF.begin(0x31)) {
  245.     Serial.println(F("Failed to boot second VL53L0X"));
  246.     while(1);
  247.   }
  248. }
  249.  
  250. void measureToF() {
  251.   leftToF.rangingTest(&leftMeasurement, false);
  252.   rightToF.rangingTest(&rightMeasurement, false);
  253.   if(leftMeasurement.RangeStatus != 4) {
  254.     distances[0][tof_avg_cycle[0]] = leftMeasurement.RangeMilliMeter;
  255.     if(tof_avg_cycle[0] >= tof_avg_cycles-1) {
  256.       tof_avg_cycle[0] = 0;
  257.     }
  258.     else {
  259.       tof_avg_cycle[0]++;
  260.     }
  261.   }
  262.   if(rightMeasurement.RangeStatus != 4) {
  263.     distances[1][tof_avg_cycle[1]] = rightMeasurement.RangeMilliMeter;
  264.     if(tof_avg_cycle[1] >= tof_avg_cycles-1) {
  265.       tof_avg_cycle[1] = 0;
  266.     }
  267.     else {
  268.       tof_avg_cycle[1]++;
  269.     }
  270.   }
  271. }
  272.  
  273. uint16_t getLeftToF() {
  274.   uint32_t sum = 0;
  275.   for(uint8_t i = 0; i < tof_avg_cycles; i++) {
  276.     sum += distances[0][i];
  277.   }
  278.   return sum / tof_avg_cycles;
  279. }
  280.  
  281. uint16_t getRightToF() {
  282.   uint32_t sum = 0;
  283.   for(uint8_t i = 0; i < tof_avg_cycles; i++) {
  284.     sum += distances[1][i];
  285.   }
  286.   return sum / tof_avg_cycles;
  287. }
  288.  
  289. void alarm() {
  290.   showText("ALARM", 4);
  291.   analogWriteResolution(6);
  292.   while(true) {
  293.     for(byte i = 0; i < 64; i++) {
  294.       analogWrite(A0, i);
  295.     }
  296.     for(byte i = 63; i > 40; i--) {
  297.       analogWrite(A0, i);
  298.     }
  299.   }
  300. }
  301.  
  302. void showText(String text, uint8_t size) {
  303.   oled.clearDisplay();
  304.   oled.setCursor(0, 0);
  305.   oled.setTextSize(size);
  306.   oled.print(text);
  307.   oled.display();
  308. }
RAW Paste Data