External digital interrupt and dht11 - arduino

I have an Arduino Pro Mini 5v, 16 mhz and it is connected to a digital switch on pin 2. This switch is used to wake the Arduino from sleep using a external digital interrupt. I also have a DHT11 temperature sensor connected to pin 9. What I want to achieve is the when the Arduino is awake for 5 seconds and also when the switch on pin 2 is HIGH, I want to read the temperature sensor and return the temperature. I am using the DHT11 library by Tillart and when I do this, it returns a TIME_OUT error. The only possible explanation I have for this is that somehow the voltage is changed when both the DHT11 and the switch on pin 2 is being read together? Any pointers to a solution will be greatly appreciated. Thank you.
Edit 1: Added code
#include <LowPower.h>
#include <dht.h>
int pin2 = 2;
dht DHT;
#define DHT11_PIN 9
void pin2interrupt(void)
{
// Function called when awoken from sleep
// Detach interrupt to stop it from continuosly firing when in normal mode
}
void enterSleep(void)
{
attachInterrupt(0, pin2interrupt, HIGH);
Serial.println("Sleeping");
delay(100);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
Serial.println("Awake!");
}
void setup()
{
Serial.begin(115200);
pinMode(pin2, INPUT);
pinMode(DHT11_PIN, INPUT);
}
int seconds = 0;
void loop()
{
delay(1000);
seconds++;
Serial.println("Awake in the loop!");
Serial.println(seconds);
if (digitalRead(pin2) == LOW && seconds == 5)
{
seconds = 0;
Serial.println("No child detected, so going to sleep!");
delay(200);
enterSleep();
}
else if (seconds == 5)
{
Serial.print("DHT11, \t");
int chk = DHT.read11(DHT11_PIN);
switch (chk)
{
case DHTLIB_OK:
Serial.print("OK,\t");
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.print("Checksum error,\t");
break;
case DHTLIB_ERROR_TIMEOUT:
Serial.print("Time out error,\t");
break;
default:
Serial.print("Unknown error,\t");
break;
}
// DISPLAY DATA
Serial.println(DHT.temperature, 1);
delay(2000);
seconds = 0;
}
}
Edit 2: I also forgot to to mention that I am using the LowPower library by RocketScream to put the Arduino to sleep. The library can be found here: https://github.com/rocketscream/Low-Power

As discussed in the issues section on the official Github page of the DHT11 library by Rob Tillart, the problem is caused because some DHT11 sensors take longer to transfer data back to the board then the 50ms or so specified on the datasheet. Therefore, if you are encountering this problem try increasing the DHTLIB_TIMEOUT on the dht header file by reducing the the value dividing the F_CPU value to around 400 and try again. This allows the board to wait longer than 50ms for the board to receive data back from the sensor. If this fix doesn't work, you might want to try measuring the response time using an oscilloscope as it seems some DHT11 are built differently.

Related

Arduino IRremote Send and Receive simultaneously

I'm currently working on a lasertag game with several weapons.
I would like to use one arduino nano in each weapon. It should be able to receive the IR-signals of the opponents as well as send IR-signals if a button is triggered.
So now there comes my problem:
I implemented an interrupt for the IR-receiver pin, so that an opponent's shot is always detected even when I'm shooting.
When the button is permanently pressed, the IR LED will shoot every 300 milliseconds (the send-function takes approximately 70ms and I implemented a delay of 230ms).
Unfortunately, the Nano won't detect any signal of the receiver in those 300ms.
However, if I disconnect the IR-LED everything seems to work perfectly.
Now I'm wondering, why the IR-LEDs connection has an effect on the functionality of my code.
Do you know any way I could solve this problem?
Here you can see the entire code I implemented:
#define IR_SEND_PIN 3
#define BUTTON_PIN 10
#define LED_PIN 12
#include <IRremote.hpp>
#include <Arduino.h>
uint8_t sAddress = 0;
uint8_t sCommand = 0x59;
uint8_t sRepeats = 0;
volatile uint8_t hitData;
void setup() {
IrSender.begin();
IrReceiver.begin(IR_RECEIVE_PIN);
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IR_RECEIVE_PIN), HIT, CHANGE);
}
void HIT() {
if (IrReceiver.decode()) {
hitData = IrReceiver.decodedIRData.command;
}
IrReceiver.resume();
}
void loop() {
if (digitalRead(BUTTON_PIN) == LOW) {
IrSender.sendNEC(sAddress, sCommand, sRepeats);
delay(120);
}
if (hitData == sCommand) { // indicates received signal 0x59
hitData = 0x00;
IrReceiver.resume();
digitalWrite(LED_PIN, HIGH);
delay(8);
digitalWrite(LED_PIN, LOW);
}
}```

How to communicate with HM-19 BLE Module and scan using ultrasonic sensor

I am working on my senior project for school, and part of what I need to do is use an HM-19 Bluetooth 5.0 module to connect to another Bluetooth 5.0 module and establish a master slave connection.
I can do that just fine, but when I include the code needed for my ultrasonic sensor to do scan, my commands to my HM-19 don't return anything and I can't do any of the basic functions such as finding connections. I have tested it with and without the ultrasonic sensor code and the problem occurs when I use the sensor portion of the code.
TO BE CLEAR, all I am trying to do is just have my Bluetooth 5.0 chip connect to another and do normal commands while also inputting into my serial monitor a distance when I put my hand in front. THIS IS JUST A TEST, once I get that done I will move to what I really want to do.
IT'S JUST A STARTING POINT IN A PROJECT. I have a function call for my sensor and my bluetooth chip in the void loop, that's all that is in there.
I just want to know how to fix this issue. How can I scan with my ultrasonic sensor and send commands to my Bluetooth module? Any help would be greatly appreciated.
[Here are the results when the sensor is commented][1] and [here are the unsuccessful results that results in an infinite loop where I can't get to the portion of the code that returns what the chip says][2]. Lastly, although most of the links include stuff for the HM-10, the commands are basically the same for the HM-19. I'm adding more because stack overflow won't let me edit this post until there are more characters or something. I hope you have a good day/evening person reading this.
Here is my code:
// SerialIn_SerialOut_HM-10_01
//
// Uses hardware serial to talk to the host computer and AltSoftSerial for communication with the bluetooth module
//
// What ever is entered in the serial monitor is sent to the connected device
// Anything received from the connected device is copied to the serial monitor
// Does not send line endings to the HM-10
//
// Pins
// BT VCC to Arduino 5V out.
// BT GND to GND
// Arduino D8 (SS RX) - BT TX no need voltage divider
// Arduino D9 (SS TX) - BT RX through a voltage divider (5v to 3.3v)
//
#include <AltSoftSerial.h>
AltSoftSerial BTserial;
// https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
char c=' ';
boolean NL = true;
const int trigPin = 9;
const int echoPin = 10;
float duration, distance;
boolean wait_your_turn = false; //My attempt to make sure the sensor and the Bluetooth module don't interfere with each other
//if I'm sending data from the serial monitor to the bluetooth module and vice versa it switches to true and the bluetooth module
//does its thing, so the sensor doesn't get in the way.
void setup()
{
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(9600);
Serial.print("Sketch: "); Serial.println(__FILE__);
Serial.print("Uploaded: "); Serial.println(__DATE__);
Serial.println(" ");
BTserial.begin(9600);
Serial.println("BTserial started at 9600");
}
void loop()
{
Bluetooth();
Sensor();
}
void Sensor(){
if((wait_your_turn == true))
{}
else
{
Serial.println("Scanning for stuff.");
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration*.0343)/2;
if(distance <= 20)
{
Serial.println(distance);
delay(500);
}
}
}
void Bluetooth()
{
if (Serial.available())
{
if(wait_your_turn == false)
Serial.println("Serial is available");
wait_your_turn = true;
while(Serial.available()>0)
c = Serial.read();
Serial.write(c);
if(c!=10&c!=13)
BTserial.print(c);
}
if (BTserial.available())
{
// Serial.print("We are at the bluetooth portion.");
while(BTserial.available())
c = BTserial.read();
Serial.print(c);
wait_your_turn = false;
}
}
[1]: https://i.stack.imgur.com/Dn4i0.png
[2]: https://i.stack.imgur.com/s9Ifv.png
Sorry, I forgot about this question. I figured it out. What I did was have 1 Arduino control the Ultrasonic sensor and send a character to the other Arduino when something was in range of the sensor. The other Arduino would then read the character and based on the character send it would perform an action. Thank you everyone who commented and have a great rest of your days.

ESP8266 GPIO expander missing interrupts

I have a program that lets an LED pulse. I also connected the PC8574 GPIO expander with a push button. I want to evaluate the keypress. However, I can only read the status of the INT (interrupt) while the program is in the part between making the LED brighter and making it darker again (between the two for loops)
I know that the problem is the delays withing the for loops but I have no idea how to avoid that.
Would it be possible to evaluate the interrupt related code more often or like a real interrupt - always when the actual key is pressed? And if so, how?
I use this library: https://github.com/WereCatf/PCF8574_ESP
/*LED_Breathing.ino Arduining.com 20 AUG 2015
Using NodeMCU Development Kit V1.0
Going beyond Blink sketch to see the blue LED breathing.
A PWM modulation is made in software because GPIO16 can't
be used with analogWrite().
*/
#include <pcf8574_esp.h>
#include <Wire.h>
TwoWire testWire;
// Initialize a PCF8574 at I2C-address 0x20, using GPIO5, GPIO4 and testWire for the I2C-bus
PCF857x pcf8574(0x20, &testWire);
#define LED D1 // Led in NodeMCU at pin GPIO16 (D0).
#define BRIGHT 300 //max led intensity (1-500)
#define INHALE 1250 //Inhalation time in milliseconds.
#define PULSE INHALE*1000/BRIGHT
#define REST 1000 //Rest Between Inhalations.
#define PIN_INT D5
#define PIN_SDA D7
#define PIN_SCL D8
//----- Setup function. ------------------------
void setup() {
Serial.begin(115200);
Wire.pins(PIN_SDA, PIN_SCL);//SDA - D1, SCL - D2
Wire.begin();
pinMode(PIN_INT, INPUT_PULLUP);
pcf8574.begin( 0xFF);
pcf8574.resetInterruptPin();
pinMode(LED, OUTPUT); // LED pin as output.
}
bool CheckKey(byte key, byte num){ //0, 1, 2, 3
return key & (1 << num);
}
//----- Loop routine. --------------------------
void loop() {
//ramp increasing intensity, Inhalation:
for (int i=1;i<BRIGHT;i++){
digitalWrite(LED, LOW); // turn the LED on.
delayMicroseconds(i*10); // wait
digitalWrite(LED, HIGH); // turn the LED off.
delayMicroseconds(PULSE-i*10); // wait
delay(0); //to prevent watchdog firing.
}
if( digitalRead(PIN_INT)==LOW ){
delay(50);
byte b = pcf8574.read8();
Serial.println( "INT: " + String(b));
byte keys = ((~b)) & 0x0F;
if( CheckKey(keys, 8) ){
Serial.println( "KEY 7");
delay(2000);
}
}
//ramp decreasing intensity, Exhalation (half time):
for (int i=BRIGHT-1;i>0;i--){
digitalWrite(LED, LOW); // turn the LED on.
delayMicroseconds(i*10); // wait
digitalWrite(LED, HIGH); // turn the LED off.
delayMicroseconds(PULSE-i*10); // wait
i--;
delay(0); //to prevent watchdog firing.
}
delay(REST); //take a rest...
}
You could use the PCF8574 INT pin as an interrupt to the ESP8266 via Arduino's attachInterrupt() function, but you wouldn't gain much from that, since in order to detect which key was pressed you need to call pcf8574.read8(), and you can't do that from the interrupt handler.
The ESP8266 Arduino core is based on the Espressif NONOS SDK, so you can't have a separate thread to monitor key presses. I would suggest defining a helper function that checks if a key is currently being pressed, and then calling that function as often as you can in your main loop, e.g. at every iteration of each of your two for loops. The LED brightness ramps would be slightly disrupted when there is a key press, but I think it wouldn't be noticeable to the human eye.
So the helper function could be defined as:
byte GetKeyPress(void) {
if (digitalRead(PIN_INT) == LOW) {
return ~pcf8574.read8();
}
else {
return 0;
}
}
Then, at the beginning of the loop() function declare a static variable static byte keyPress;, and call the above function in each of the two for loops:
if (keyPress == 0) {
keyPress = GetKeyPress();
}
When you want to process a key press (e.g. between the two for loops like in your code), you can do like that:
if (keyPress) {
/* Do your stuff. */
keyPress = 0;
}

MicroSD reader causing RFID reader to fail

I have a sketch running a MFRC522 RFID reader which works fine but my aim is to log the card swipes on a microSD card.
The problem is that as soon as I add the SD card reader, whether it is initialised or not, the RFID reader stops working.
It seems to be a problem on the SPI bus. I have tried adding pull up resistors to the circuit and setting the chip select pins to HIGH before initialising either of the boards but nothing seems to work.
Here is my code:
#include <SPI.h>
#include <MFRC522.h>
#include <SD.h>
// RFID constants & objects
#define RFPin 10
#define resetPin 9
MFRC522 mfrc522(RFPin, resetPin);
// SD constants
#define SDPin 8
// Other global variables
String IDString;
byte IDList[4];
void setup() {
pinMode(2, OUTPUT);// For testing
// Set both chip select pins high
pinMode(SDPin, OUTPUT);
digitalWrite(SDPin, HIGH);
pinMode(RFPin, OUTPUT);
digitalWrite(RFPin, HIGH);
delay(10);
// Init serial bus
Serial.begin(9600);
// Wait for serial bus to open
while (!Serial);// Opens even when not USB connected
// Init SPI bus
SPI.begin();
// Initialise RFID board
mfrc522.PCD_Init();
delay(1000);// Just in case SPI is still busy
// Initialise SD card board
if (!SD.begin(SDPin)) {
// SD card board failed to initialise
Serial.println("SD failed");
return;
}
}
void loop() {
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
for(int i = 0; i < 4; i++) {
digitalWrite(2, HIGH);
delay(100);
digitalWrite(2, LOW);
delay(100);
}
IDString = "";
// Get 4 byte ID
for (int i = 0; i < 4; i++) {
IDList[i] = mfrc522.uid.uidByte[i];
// Serial.print(IDList[i], HEX);
if(IDList[i] < 16) {
IDString += "0" + String(IDList[i], HEX) + "-";
} else {
IDString += String(IDList[i], HEX) + "-";
}
}
mfrc522.PICC_HaltA(); // Stop reading
IDString = IDString.substring(0, IDString.length() - 1);
Serial.println(IDString);
.
.
.
Rest of code
Everything initialised ok but Once in the main loop, the program never gets past the first statement: to check if an RFID card is present.
Can anybody help?
Could it be de to the fact that the RFDI board is 3.3V driven and the SD board is 5V driven (but has a 3.3V regulator)? Each has it's own separate power wire
EDIT #1:
When the MicroSD board is plugged in but not powered the RFID board works fine
I have also tried adding a subroutine to pull both chip select pins high at the beginning of every loop to no avail.
EDIT #2:
The SD board works in this sketch and I can get the card details from it.
EDIT #3:
The RFID card works again once I remove the MISO line from the SD board.
Obviously the SD module isn't releasing the MISO line...
It's not the most elegant solution but I have it working now by attaching an NPN transistor between the MISO output of the SD board and the MISO line to pin 12. It takes one further pin to block/unblock the MISO line to be used by the SD board but it works.
As I said this is not elegant and I would still be eager to hear a better solution.

Arduino - Using interrupts freezes processing and serial output?

So, the interrupts seem to work insofar as "interrupting" when an event happens. My only problem is that I the interrupts will occur 2-3 times and everything essentially stops (Serial out, everything).
I was programming the board to output serially a calculated distance based on the output of the HC-SR04 distance IC. The distances are calculated accurately but, like I said earlier, everything seems to freeze. Below is both the code and an image of the serial monitor.
#define TRIGPIN 4
#define ECHOPIN 3
#define RED 2
#define GREEN 13
#define INTNUM 1 //interrupt pin 1 is digital pin 3 on the duemilanove
#define PULSE 10 //microseconds
#define CYCLETIME 50 //milliseconds
void ledWrite(int), trigPulse(), getTime();
int millisNow, millisPrev = 0;
int microsPrev;
boolean isHigh = false;
void setup() {
Serial.begin (9600);
pinMode(TRIGPIN, OUTPUT);
pinMode(ECHOPIN, INPUT);
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
attachInterrupt(INTNUM, getTime, CHANGE);
}
void loop() {
trigPulse();
// some other code while waiting on HC-SR04 to interrupt us when echo goes HIGH
}
void trigPulse(){
if( (millisNow = millis()) - millisPrev >= CYCLETIME){ //sufficient cycle time
digitalWrite(TRIGPIN, HIGH);
delayMicroseconds(PULSE);
digitalWrite(TRIGPIN, LOW);
millisPrev = millisNow; //reset clock
}
return;
}
void ledWrite(int dTime){
int distance = dTime/58.2;
if (distance < 4) {
digitalWrite(RED,HIGH);
digitalWrite(GREEN,LOW);
}
else {
digitalWrite(RED,LOW);
digitalWrite(GREEN,HIGH);
}
if (distance >= 200 || distance <= 0){
Serial.println("Out of range");
}
else {
Serial.print(distance);
Serial.println(" cm");
}
}
void getTime(){
int timeNow = micros();
Serial.println("Interrupted");
if(isHigh == false){
microsPrev = timeNow; //get time now, pin LOW->HIGH
isHigh = true;
Serial.println("Returning ..");
return;
}
else { //pin HIGH->lOW
ledWrite(timeNow - microsPrev);
isHigh = false;
microsPrev = micros();
Serial.println("Returning ..");
return;
}
return;
}
I know this is an old thread, but I just came by it having my own problems. The problem here is that you cannot use:
Serial.Print()
Within an interrupt service routine. The reason that the Serial.Print() doesn't work within an ISR is that it uses interrupts to pull the characters out of the serial buffer, but interrupts of a certain level are masked within the ISR. What basically happens is that the arduino throws out all other interrupts that are of a lower priority, which Serial.Read() falls into.
It is documented in a number of places: link1, link2, link3
I think you are getting interrupt while you are already processing interrupt. You should try disabling the interrupt as soon as you are in interrupt function and re-enable it again when you are done processing just before return. Hence I would advice to have just one return so that you don't have to repeat code of enabling interrupt. Also make sure the function which you are calling inside your interrupt code do not re-enable the interrupt. It may happen that the function micros() or any of the Serial function are re-enabling the interrupt.
I would suggest instead of calling function directly in you interrupt code try using some flags and set/reset in interrupt and use these flags in main loop to call your regular function.

Resources