I'm having an issue with my circuit/code. when the code runs correctly it should: turn on the motor when the temperature is within range and the distance sensor 1 is within range and add one to the capacity number, turn on the motor when the distance sensor 2 is within range and subtract one from the capacity number, do not turn on the motor when the capacity is full or if the temperature reading is out of range. My issue is: the circuit only runs/works when the temperature sensor is unplugged, I'm not sure if it is something in my code or if the temperature sensor is causing interference with the other components. I have a video of my circuit, my code, and parts below.
Parts:
Arduino Uno R3
HC-SR04 Ultrasonic Distance Sensor (using 2)
TMP36 temperature sensor
1k Ohm Resistors
motor
power Transistor TIP120
0.96" OLED display
#define TRIG1 PB1 // pin 15
#define ECHO1 PB0 // pin 14
#define TRIG2 PB3 // pin 17
#define ECHO2 PB2 // pin 16
#define MOTOR_PIN PB4 // pin 18
#define RANGE_PER_CLOCK 1.098
#define CONVERT_CM_TO_IN 2.54 // Centimeters to Inches conversion
#define OCCUPANCY_RANGE_CM 5 // range within which a person is considered entering or exiting (1 foot in cm)
#define Vref 1.1
#define MAX_TEMPERATURE 99 // Maximum allowed body temperature for occupancy
#define MAX_OCCUPANCY 25 // Maximum room occupancy
#include <avr/io.h>
#include "i2c.h"
#include "SSD1306.h"
#include <util/delay.h>
#include <stdbool.h>
bool sensor1_detected = false;
bool sensor2_detected = false;
void disp_info(int, double, float, float); //void display on OLED
void timer0_init(); //initialize timer
double calculate_temp(unsigned int Vout);
void adc_init(void);
unsigned int get_adc(void);
// Display occupancy level on OLED
void disp_info(int occupancy, double temperature, float distance1, float distance2){
OLED_GoToLine(0);
OLED_DisplayString("Occupancy: ");
OLED_DisplayNumber(10, occupancy, 3);
OLED_GoToLine(2);
OLED_DisplayString("Temperature: ");
OLED_DisplayNumber(10, temperature, 2);
OLED_DisplayString(" F");
OLED_GoToLine(4);
OLED_DisplayString("Distance 1: ");
OLED_DisplayNumber(10, distance1, 2);
OLED_DisplayString(" cm");
OLED_GoToLine(6);
OLED_DisplayString("Distance 2: ");
OLED_DisplayNumber(10, distance2, 2);
OLED_DisplayString(" cm");
}
// Initialize timer
void timer0_init(){
TCCR0A = 0; //Normal mode (count up)
TCCR0B = 5; //Prescaler = 1024
TCNT0 = 0; //Load counter with 0
}
// Generate 10us pulse on TRIG pin
void trig_pulse(uint8_t pin){
PORTB |= (1<<pin); //TRIG to high
_delay_us(10); // 10us delay
PORTB &= ~(1<<pin); //TRIG to low
}
// Wait for ECHO pin to go high
unsigned char start_time(uint8_t pin){
while (!(PINB & (1<<pin))); // wait for ECHO to go high
return TCNT0; // return timer value
}
// Wait for ECHO pin to go low
unsigned char end_time(uint8_t pin) {
while ((PINB & (1<<pin))); // wait for ECHO to go low
return TCNT0; // return timer value
}
// Send pulse, measure time (pulse width), and calculate distance
float measure_distance(uint8_t trig_pin, uint8_t echo_pin) {
trig_pulse(trig_pin);
unsigned char start_clocks = start_time(echo_pin); //Timer value at start of echo
unsigned char end_clocks = end_time(echo_pin); // timer value at end of echo
if(end_clocks > start_clocks){
return (end_clocks - start_clocks) * RANGE_PER_CLOCK; //Calculating distance
} else {
return -1;
}
}
// Initialize ADC
void adc_init(void){
ADMUX = 0xc5; // Select ADC5 Vref=1.1V
ADCSRA = 0x87; // Enable ADC and setting speed to 125 KHz for 16 MHz clock
}
// Read ADC value
unsigned int get_adc(){
ADCSRA |= (1 << ADSC); //starting ADC conversion
while (!(ADCSRA & (1 << ADIF)));
return ADCL | (ADCH << 8); //read ADCL first
}
// calculating temperature function
double calculate_temp(unsigned int Vout){
double temperatureC = Vout*Vref/10.24 - 50;
return temperatureC; // converting to F
}
// Run Motor for 3 seconds
void run_motor(){
PORTB |= (1<<MOTOR_PIN); // Turn motor on
_delay_ms(3000); // Wait for 3 seconds
PORTB &= ~(1<<MOTOR_PIN); //Turn motor off
}
// Main Function
int main(void) {
OLED_Init();
DDRB |= (1<<TRIG1) | (1<<TRIG2) | (1<<MOTOR_PIN); // set TRIG pins and motor as output
PORTB &= ~((1<<TRIG1) | (1<<TRIG2)); // set TRIG pins to low
adc_init(); // Initialize ADC
timer0_init(); // Initialize timer
int occupancy = 0; // Initialize occupancy
while (1) {
double temperature = calculate_temp(get_adc()); // Calculate temperature
float distance1 = measure_distance(TRIG1, ECHO1); // Measure distance with the first sensor
_delay_ms(50);
float distance2 = measure_distance(TRIG2, ECHO2); // Measure distance with the second sensor
_delay_ms(50);
disp_info(occupancy, temperature, distance1, distance2); // Display occupancy and temperature
// Check if a person is detected by sensor1
if(distance1 < OCCUPANCY_RANGE_CM){
sensor1_detected = true;
} else {
sensor1_detected = false;
}
// Check if a person is detected by sensor2
if(distance2 < OCCUPANCY_RANGE_CM){
sensor2_detected = true;
} else {
sensor2_detected = false;
}
// Check if a person is entering
if(sensor1_detected && !sensor2_detected && occupancy < MAX_OCCUPANCY && temperature < MAX_TEMPERATURE){
// Wait for a short delay
_delay_ms(100);
// Check if the person is now detected by sensor2
distance2 = measure_distance(TRIG2, ECHO2);
if(distance2 < OCCUPANCY_RANGE_CM){
occupancy++;
run_motor();
sensor1_detected = false; // reset detection
sensor2_detected = false; // reset detection
}
}
// Check if a person is leaving
else if(sensor2_detected && !sensor1_detected && occupancy > 0){
// Wait for a short delay
_delay_ms(100);
// Check if the person is now detected by sensor1
distance1 = measure_distance(TRIG1, ECHO1);
if(distance1 < OCCUPANCY_RANGE_CM){
occupancy--;
run_motor();
sensor1_detected = false; // reset detection
sensor2_detected = false; // reset detection
}
}
}
return 0;
}