Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Arduino.h>
- #include <SPI.h>
- #include <Wire.h>
- #include <Adafruit_I2CDevice.h>
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- #include <Adafruit_Sensor.h>
- #include <DHT.h>
- #include <Adafruit_VL53L0X.h>
- void initScreen();
- uint8_t getUV();
- uint8_t getAirQ();
- void slowCycle();
- void display();
- void handleOptoEvent();
- float getAveragedSpeed();
- float intervalToSpeed(float interval);
- void measureToF();
- void initToF();
- uint16_t getLeftToF();
- uint16_t getRightToF();
- void alarm();
- void showText(String text, uint8_t size);
- Adafruit_VL53L0X leftToF = Adafruit_VL53L0X();
- Adafruit_VL53L0X rightToF = Adafruit_VL53L0X();
- VL53L0X_RangingMeasurementData_t leftMeasurement;
- VL53L0X_RangingMeasurementData_t rightMeasurement;
- Adafruit_SSD1306 oled(128, 32, 2, 0, 1, 3, 4);
- DHT dht(A1, DHT11);
- float temperature = 0;
- uint8_t uvindex = 0;
- uint8_t airq = 0;
- float speed = 0;
- unsigned long timer_val = 0;
- uint16_t slowcycle_rate = 2200; //Slow cycle rate
- //Wheel speed counter stuff
- #define wheel_circumference 414.7 //In centimeters
- #define avg_cycles 3
- volatile uint8_t curr_avgcycle = 0;
- volatile uint16_t counts[avg_cycles];
- volatile unsigned long last_timerval = 0;
- //Alarm stuff
- uint8_t alarm_armed = 0; //0: off, 1: left, 2: right
- uint16_t alarm_distance = 0;
- #define tof_avg_cycles 10
- uint16_t distances[2][tof_avg_cycles];
- uint8_t tof_avg_cycle[2];
- #define MCP9701_temp_limit 500 //Roughly 6 count per degree, at 25C reading is 290, therefore 60C is 500
- void setup() {
- initScreen();
- dht.begin();
- pinMode(A6, INPUT); //UV Sensor
- pinMode(A2, INPUT); //AirQ Sensor
- pinMode(6, OUTPUT); //Left ToF
- pinMode(A5, OUTPUT); //Right ToF
- pinMode(5, INPUT_PULLUP); //Optotransistor
- pinMode(A4, INPUT);
- attachInterrupt(digitalPinToInterrupt(5), handleOptoEvent, FALLING); //Opto interrupt
- initToF();
- //DEBUG
- Serial.begin(9600);
- }
- void loop() {
- if(alarm_armed == 0) {
- while(analogRead(A4) > MCP9701_temp_limit) {
- showText("Overtemp");
- delay(10000);
- }
- //Slow cycle caller
- if(millis() >= timer_val + slowcycle_rate) {
- timer_val = millis();
- slowCycle();
- }
- display();
- speed = intervalToSpeed(getAveragedSpeed());
- measureToF();
- if(getLeftToF() < 30 && getRightToF() < 30) {
- oled.clearDisplay();
- oled.display();
- delay(3000);
- for(uint8_t i = 0; i < 20; i++) { measureToF(); }
- if(getLeftToF() < 30 && getRightToF() >= 30) {
- alarm_armed = 2;
- alarm_distance = getRightToF();
- showText("Right side armed", 1);
- delay(1000);
- oled.clearDisplay();
- oled.display();
- }
- else if(getLeftToF() >= 30 && getRightToF() < 30) {
- alarm_armed = 1;
- alarm_distance = getLeftToF();
- showText("Left side armed", 1);
- delay(1000);
- oled.clearDisplay();
- oled.display();
- }
- }
- }
- else {
- measureToF();
- if(alarm_armed == 1) {
- if(getLeftToF() > alarm_distance + 20 || getLeftToF() < alarm_distance - 20) {
- alarm();
- }
- }
- else {
- if(getRightToF() > alarm_distance + 20 || getRightToF() < alarm_distance - 20) {
- alarm();
- }
- }
- }
- delay(10);
- }
- //Handle stuff here that doesn't need to(or can't) run as fast as loop() (DHT11, AirQ, UV)
- void slowCycle() {
- uvindex = getUV();
- airq = getAirQ();
- temperature = dht.readTemperature();
- 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
- for(uint8_t i = 0; i < avg_cycles; i++) {
- counts[i] = 0;
- }
- }
- }
- void initScreen() {
- oled.begin(SSD1306_SWITCHCAPVCC);
- oled.clearDisplay();
- oled.setTextSize(1); // Normal 1:1 pixel scale
- oled.setTextColor(SSD1306_WHITE); // Draw white text
- oled.setCursor(0, 0); // Start at top-left corner
- oled.write("Hello World!");
- oled.display();
- }
- //Sensor output is linear, 0V = UV0, 1V = UV10
- uint8_t getUV() {
- return analogRead(A6)/31;
- }
- //Sensor output is linear, 0V = Clean Air, goes up to 2.64V(4V originally, but using a divider)
- uint8_t getAirQ() {
- return 100 - analogRead(A2)/8.18;
- }
- //Display all the stuff on the OLED
- void display() {
- oled.clearDisplay();
- oled.setTextSize(1);
- oled.clearDisplay();
- oled.setCursor(96, 0);
- oled.print(temperature, 1);
- oled.print("C");
- oled.setCursor(56, 0);
- oled.print("UV");
- oled.print(uvindex);
- oled.setCursor(0, 0);
- oled.print("AirQ");
- oled.print(airq);
- oled.setCursor(22, 12);
- oled.setTextSize(3);
- oled.print(speed, 1);
- oled.setCursor(oled.getCursorX() + 2, 24);
- oled.setTextSize(1);
- oled.print("km/h");
- oled.display();
- }
- void handleOptoEvent() {
- if(millis() - last_timerval > 100) {
- counts[curr_avgcycle] = millis() - last_timerval;
- if(curr_avgcycle >= avg_cycles-1) {
- curr_avgcycle = 0;
- }
- else {
- curr_avgcycle++;
- }
- last_timerval = millis();
- }
- }
- float getAveragedSpeed() {
- uint16_t sum = 0;
- for(uint8_t i = 0; i < avg_cycles; i++) {
- sum += counts[i];
- }
- return (float)sum / avg_cycles;
- }
- float intervalToSpeed(float interval) {
- if(interval == 0) return 0;
- 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
- }
- void initToF() { //From Adafruit example
- // all reset
- digitalWrite(6, LOW);
- digitalWrite(A5, LOW);
- delay(10);
- // all unreset
- digitalWrite(6, HIGH);
- digitalWrite(A5, HIGH);
- delay(10);
- // activating LOX1 and reseting LOX2
- digitalWrite(6, HIGH);
- digitalWrite(A5, LOW);
- // initing LOX1
- if(!leftToF.begin(0x30)) {
- Serial.println(F("Failed to boot first VL53L0X"));
- while(1);
- }
- delay(10);
- // activating LOX2
- digitalWrite(A5, HIGH);
- delay(10);
- //initing LOX2
- if(!rightToF.begin(0x31)) {
- Serial.println(F("Failed to boot second VL53L0X"));
- while(1);
- }
- }
- void measureToF() {
- leftToF.rangingTest(&leftMeasurement, false);
- rightToF.rangingTest(&rightMeasurement, false);
- if(leftMeasurement.RangeStatus != 4) {
- distances[0][tof_avg_cycle[0]] = leftMeasurement.RangeMilliMeter;
- if(tof_avg_cycle[0] >= tof_avg_cycles-1) {
- tof_avg_cycle[0] = 0;
- }
- else {
- tof_avg_cycle[0]++;
- }
- }
- if(rightMeasurement.RangeStatus != 4) {
- distances[1][tof_avg_cycle[1]] = rightMeasurement.RangeMilliMeter;
- if(tof_avg_cycle[1] >= tof_avg_cycles-1) {
- tof_avg_cycle[1] = 0;
- }
- else {
- tof_avg_cycle[1]++;
- }
- }
- }
- uint16_t getLeftToF() {
- uint32_t sum = 0;
- for(uint8_t i = 0; i < tof_avg_cycles; i++) {
- sum += distances[0][i];
- }
- return sum / tof_avg_cycles;
- }
- uint16_t getRightToF() {
- uint32_t sum = 0;
- for(uint8_t i = 0; i < tof_avg_cycles; i++) {
- sum += distances[1][i];
- }
- return sum / tof_avg_cycles;
- }
- void alarm() {
- showText("ALARM", 4);
- analogWriteResolution(6);
- while(true) {
- for(byte i = 0; i < 64; i++) {
- analogWrite(A0, i);
- }
- for(byte i = 63; i > 40; i--) {
- analogWrite(A0, i);
- }
- }
- }
- void showText(String text, uint8_t size) {
- oled.clearDisplay();
- oled.setCursor(0, 0);
- oled.setTextSize(size);
- oled.print(text);
- oled.display();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement