PING sensor on RPI, start counting when less than 40cm? - c

I have a PING sensor (HC-SR04) hooked up to my RPI. I want it to start counting when the sensor sees less than 40 cm. It should stop counting again when the sensor again sees less than 40 cm, print out the time and start counting again.
How can I do this?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
#define TRUE 1
#define TRIG 5
#define ECHO 6
void setup() {
wiringPiSetup();
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
//TRIG pin must start LOW
digitalWrite(TRIG, LOW);
delay(30);
}
int getCM() {
//Send trig pulse
digitalWrite(TRIG, HIGH);
delayMicroseconds(20);
digitalWrite(TRIG, LOW);
//Wait for echo start
while(digitalRead(ECHO) == LOW);
//Wait for echo end
long startTime = micros();
while(digitalRead(ECHO) == HIGH);
long travelTime = micros() - startTime;
//Get distance in cm
int distance = travelTime / 58;
return distance;
}
int i;
int main(void) {
setup();
while (1)
{
printf("Distance: %dcm\n", getCM());
delay(250);
}
return 0;
}

The code doesn't measure the distance. It only measures the duration of the reflected signal. To get the distance you need to measure the delay between the beginning of ping, and the beginning of echo:
startTime = micros();
digitalWrite(TRIG, HIGH);
delayMicroseconds(20);
digitalWrite(TRIG, LOW);
//Wait for echo start
while(digitalRead(ECHO) == LOW);
long travelTime = micros() - startTime;
Of course, this is just a skeleton: you need to debounce the echo to guard yourself against background noises and other glitches.

Related

I²C Communication from Scratch in C on Raspberry Pi in Linux

I want to create a small library for communication with I²C devices, especially the MPU6050 accelerometer / gyroscope module from scratch in C. Technically, I could use a library like wiringPi, but.. where is the fun with that. Right now I'm trying to write a function which scans all possible 7 bit addresses (0 - 127) and reads the acknowledge bit to find all 'active' addresses of connected I²C devices. To do that, I wrote a small library which can control the GPIO pins by writing to the coresponding GPIO files in /sys/class/gpio. It can for example setup a pin, set its direction (input or output), set its digital output and read a digital input from a pin. I tested all of these functions and they work great and fast.
For communication with the MPU6050 I²C slave I connected the power and ground pins of the MPU board to the Raspberry's GPIO power and ground pins and the SDA and SCL lines to GPIO pins 14 and 15. I read a lot about I²C recently and I do understand how it works. The problem is, that my code to scan through all addresses does not work. Here's my code:
#include <stdio.h>
#include <unistd.h>
#include "string.h"
#include "gpio.h"
#define SCL 14
#define SDA 15
#define FREQ 100000
#define high 1
#define low 0
char binret[8];
void scanI2C();
void charToBin(unsigned char);
void delay();
int main () {
setupPin(SCL, OUTPUT);
setupPin(SDA, OUTPUT);
scanI2C();
}
void scanI2C() {
int addr = 0;
for (int i = 90; i < 128; i++) {
charToBin(i);
// Start Condition
setPin(SDA, high);
setPin(SCL, high);
delay();
setPin(SDA, low);
for (int j = 0; j < 9; j++) {
delay();
setPin(SCL, low);
delay();
setPin(SCL, high);
if (j < 7) {
setPin(SDA, binret[j+1]);
}
// WRITE Bit
if (j == 7) {
setPin(SDA, high);
}
// Listen for ACK bit
if (j == 8) {
setPinDirection(SDA, INPUT);
printf("Checking Address %d (%d%d%d%d%d%d%d%d)", i, binret[0], binret[1], binret[2], binret[3], binret[4], binret[5], binret[6], binret[7]);
if (readPin(SDA) <= 0.5) {
printf(" Bingo!");
}
setPinDirection(SDA, OUTPUT);
printf("\n");
}
}
// Stop Condition
setPin(SCL, low);
delay();
setPin(SDA, high);
delay();
setPin(SCL, high);
delay();
delay();
delay();
delay();
delay();
}
}
void charToBin(unsigned char a) {
memset(binret, 0, sizeof(binret));
int val = 128;
for (int i = 0; i < 8; i++) {
int bit = a & val;
if (bit != 0) {
binret[i] = 1;
}
val /= 2;
}
}
void delay() {
usleep(1000000.0/FREQ);
}
Since I do actually know the address of the MPU6050 I²C slave to be 0x69 or 105 in decimal, I would expect the output to be something like this:
...
Checking Address 103 (01100111)
Checking Address 104 (01101000)
Checking Address 105 (01101001) Bingo!
Checking Address 106 (01101010)
Checking Address 107 (01101011)
Checking Address 108 (01101100)
Checking Address 109 (01101101)
Checking Address 110 (01101110)
...
But no, I don't get a Bingo! at address 105, which means that my I²C communication is definitely not working. Advice on how to address this issue is very much appreciated! Thank you and have a nice day :)
Typically it is the LSB of the 8-bit "address" that is the R/W bit. If you have a device with address 105 I would expect it to respond when your 8-bit address is 210 or 211. Have you tried the entire address space?
Does readPin() return a float? If not, why are you comparing to a float?
It looks like you are changing SDA while SCL is high and you are sending the address bits. I don't think that is allowed.
Do you have a pullup resistor on SDA?
Have you verified signal levels and timing with an oscilloscope?

Two timers to produce the same frequency but one of them is Looped 67 times

Pulse generation
#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
DDRB = 0xFF;
ICR1 = 3124;// set the 5Hz frequency at the output
TCCR1A |=( 1 <<WGM12);//set timer to CTC mode
TCCR1B |=( 1 << CS12)|( 1 << CS10);//set prescaler to 1024
sei();// set interrupt
while(1)
{
}
}
ISR(TIMER1_COMPA_vect)
{
//Action to be done over 200ms
TCCR2A = 0x63; // 0110 0011
TCCR2B = 0x08 | 6; // Prescale=256
OCR2A = 185-1; // TOP
OCR2B = (int) (OCR2A * 0.5);
pinMode(11, OUTPUT); // OC2a
pinMode(3, OUTPUT); // OC2b
}
I am using AVR Atmega328P, I would like to create a PWM pulse signal with two 5Hz frequencies generated from one Timer1, that will generate different duty cycles such that one of the frequencies has to be looped 67 times in one cycle of the other frequency. I have attached an image of how I'd like the pulses to look like on the oscilloscope. Would you please help me.
If you want 5 Hz and 335 Hz ("67 * 5 Hz") using a single timer, then you'd want to set the timer to the highest frequency and then have a divider in software (in the IRQ handler) to get the lower frequency.
However, for perfect square waves you want an IRQ for "rising edge" and another IRQ for "falling edge", so you'd want the timer's frequency to be double the highest frequency (e.g. 670 Hz, not 335 Hz).
For example, maybe something like:
ISR(TIMER1_COMPA_vect)
{
static counter1 = 1;
static counter2 = 1;
// Actions to be done 670 times per second
counter1--;
if(counter1 == 0) {
// Set output1 to "high"
counter1 = 134; // 670 Hz / 134 = 5 Hz
} else if(counter1 == 67) {
// Set output1 to "low"
}
counter2--;
if(counter2 == 0) {
// Set output2 to "high"
counter2 = 2; // 670 Hz / 2 = 335 Hz
} else if(counter2 == 1) {
// Set output2 to "low"
}
}

Write rate of DAC MCP4725

I have a buffer which contains 16000 PCM samples of 8Khz 8-bit mono. I am trying to play it using 12 bit MCP4725 DAC. I have tried using micros() to control the write interval for the DAC. Here's my code -
uint8_t soundData[16000] = { 234,206,79,255,249,....,210,222 }; // 8Khz 8-bit mono
void setup() {
Serial.begin(115200);
Wire.begin(D2, D1);
delay(100); // delay 100 ms
Serial.flush();
delay(1000);
}
void value_write(uint16_t temp){
Wire.beginTransmission(0x62);
Wire.write(64);
Wire.write(temp >> 4); // the 8 most significant bits...
Wire.write((temp & 15) << 4); // the 4 least significant bits...
Wire.endTransmission();
}
void loop() {
unsigned long currentMicros = micros();
// 125 uS sampling for 8KHz signal
if(currentMicros - previousMicros > 125) {
Serial.print("Index: ");
Serial.println(indx);
uint16_t temp = map(soundData[indx++], 0, 255, 0, 4095);
value_write(temp);
}
}
The write should logically be completed within 2 seconds but takes way more time. Any help regarding successfully writing the PCM values to the DAC at 8000Hz is greatly appreciated.

DHT sensor with RGB LED

I have a DHT11 that outputs temperature and humidity values. I'm trying to Serial.print the colour of the light based on the set temperature conditions. So far I only get 1s and 0s. How can I change these integer values to output string say RED, GREEN or BLUE? Is this possible or do I just need a Serial.print("RED"); in each loop to get it done?
Code
#include <dht.h>
dht DHT;
#define DHT11_PIN A5
int redPin = 10; // Red LED, connected to digital pin 10
int grnPin = 9; // Green LED, connected to digital pin 9
int bluPin = 8; // Blue LED, connected to digital pin 8
void setup(){
Serial.begin(9600);
pinMode(redPin, OUTPUT);// Sets the pins as output for RGB LED
pinMode(grnPin, OUTPUT);
pinMode(bluPin, OUTPUT);
}
void loop() {
int chk = DHT.read11(DHT11_PIN);
int t = DHT.temperature;
int h = DHT.humidity;
Serial.print("Temperature = ");
Serial.print(t);
Serial.print( "," );
Serial.print("Humidity = ");
Serial.print(h);
Serial.print("\n");
delay(60000);
if((DHT.temperature < 26) && (DHT.temperature >= 23.2)) {
// Writing the LED colour pins HIGH or LOW to set colours
digitalWrite(redPin, HIGH); // yellow
digitalWrite(grnPin, HIGH);
delay(100);
digitalWrite(bluPin, LOW);
}
if((DHT.temperature < 23) && (DHT.temperature > 20.2)) {
digitalWrite(grnPin, HIGH); // green
delay(100);
digitalWrite(redPin, LOW);
digitalWrite(bluPin, LOW);
}
if((DHT.temperature < 20) && (DHT.temperature > 17.2)) {
digitalWrite(grnPin, HIGH); // aqua
digitalWrite(bluPin, HIGH);
delay(100);
digitalWrite(redPin, LOW);
}
if(DHT.temperature <= 17) {
digitalWrite(bluPin, HIGH); // blue
delay(100);
digitalWrite(grnPin, LOW);
digitalWrite(redPin, LOW);
}
delay(1000);
// Sensor shouldn't be read too frequently so delay of 1s
}
I will be grateful if I can get some help. Thanks!

Why doesn't the LED turn off?

I have a program (copied below) that has an alarm that starts in 10 seconds, which starts a LED that blinks every two seconds. I would like to push a button that turns off the alarm / LED. The LED blinks as intended but does not turn off when I push the button. Any idea why? Code below:
#include <Time.h>
#include <TimeAlarms.h>
#define buttonPin 2 // assigns pin 2 as buttonPin
#define ledPin 13 // assigns pin 13 as ledPin
int buttonState; // variable for reading the pushbutton status
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
Serial.begin(9600); // start Serial Monitor
setTime(0, 0, 0, 1, 1, 2018); // set time to 00:00:00 Jan 1 2018
Alarm.alarmRepeat(0, 0, 10, DailyAlarm); // Alarm triggered in 10 sec
pinMode(ledPin, OUTPUT); // assigns ledPin as led output pin.
pinMode(buttonPin, INPUT); // assigns buttonPin as input pin
// digitalWrite(ledPin, ledState); // LED is off initially
}
void loop() {
digitalClockDisplay();
Alarm.delay(1000); // wait one second between clock display
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = HIGH;
Serial.print(buttonState);
}
}
}
void DailyAlarm() {
Serial.println("Alarm");
while (buttonState == LOW) {
blink(2000); // blink every 2s
}
}
void blink(int period) {
digitalWrite(ledPin, HIGH);
delay(period / 2);
digitalWrite(ledPin, LOW);
delay(period / 2);
}
void digitalClockDisplay() {
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.println();
}
void printDigits(int digits) {
Serial.print(":");
if (digits < 10)
Serial.print('0');
Serial.print(digits);
}
int buttonState; // variable for reading the pushbutton status
You haven't initialized the button state
Try
boolean buttonState = LOW
And Don't mix integers and booleans
use this
boolean lastButtonState = LOW;
instead of
int lastButtonState = LOW;

Resources