Using arduino to control leds as a pattern - arduino

I have this code here which sends some keys to windows and also lights up an led attached under each button. I think its right so the led will toggle with the button. What I wanted to achieve ontop of this was so that if no button states hadn't changed for 30 seconds then it goes into a mode where all three leds flash rapidly 3 times then the leds randomly flashes (Like a pinball machine when its not in use). After any input then it goes back to the normal mode
/* Arduino USB Keyboard HID demo
* Cut/Copy/Paste Keys
*/
#define KEY_LEFT_CTRL 0x01
#define KEY_LEFT_SHIFT 0x02
#define KEY_RIGHT_CTRL 0x10
#define KEY_RIGHT_SHIFT 0x20
uint8_t buf[8] = {
0 }; /* Keyboard report buffer */
#define PIN_COPY 5
#define PIN_CUT 6
#define PIN_PASTE 7
#define LED_COPY 8
#define LED_CUT 9
#define LED_PASTE 10
int state = 1;
void setup()
{
Serial.begin(9600);
pinMode(PIN_COPY, INPUT);
pinMode(PIN_CUT, INPUT);
pinMode(PIN_PASTE, INPUT);
// Enable internal pull-ups
digitalWrite(PIN_COPY, 1);
digitalWrite(PIN_CUT, 1);
digitalWrite(PIN_PASTE, 1);
delay(200);
}
void loop()
{
state = digitalRead(PIN_CUT);
if (state != 1) {
buf[0] = KEY_LEFT_CTRL; // Ctrl
buf[2] = 27; // Letter X
// buf[2] = 123; // Cut key: Less portable
Serial.write(buf, 8); // Ssend keypress
digitalWrite(LED_CUT, HIGH);
releaseKey();
}
state = digitalRead(PIN_COPY);
if (state != 1) {
buf[0] = KEY_LEFT_CTRL; // Ctrl
buf[2] = 6; // Letter C
// buf[2] = 124; // Copy key: Less portable
Serial.write(buf, 8); // Send keypress
digitalWrite(LED_COPY, HIGH);
releaseKey();
}
state = digitalRead(PIN_PASTE);
if (state != 1) {
buf[0] = KEY_LEFT_CTRL; // Ctrl
buf[2] = 25; // Letter V
// buf[2] = 125; // Paste key: Less portable
Serial.write(buf, 8); // Send keypress
digitalWrite(LED_PASTE, HIGH);
releaseKey();
}
}
void releaseKey()
{
buf[0] = 0;
buf[2] = 0;
Serial.write(buf, 8); // Release key
delay(500);
digitalWrite(LED_COPY, LOW);
digitalWrite(LED_CUT, LOW);
digitalWrite(LED_PASTE, LOW);
}
For refrence this is the article I was using http://mitchtech.net/arduino-usb-hid-keyboard/

i recomend you to look for Finite State Machine in Google.
Here is one link to implement it in C++
http://www.drdobbs.com/cpp/state-machine-design-in-c/184401236
here is other link to implement it in Arduino
http://playground.arduino.cc/Code/SMlib
it's exactly what you need to do what you want.
i hope this help you!

Related

TMC2208 Stepper driver replacement with A4988 Trouble

I am using a version of an Arduino CNC board that is found here to drive 4 wheels on a small wheeled robot. The shield came with A4988 stepper drivers and I got them to work fine, however the motors were much louder than intended so I went searching for another driver and found the TMC2208. I saw that the pin-outs were the same as long as the boards themselves aligned the enable pins on the shield.
The problem however seems to be in the code though. I am using the Accelstepper library in my code and everything works fine with the A4988 driver board. When I swapped just the boards, nothing happened in my program. I went looking on the TMCStepper library git to try and find some help. I managed to at lease get the steppers working using a version of the 'Simple' example. I tried to take out as much as possible while still being able to move the motors so that I could use it in my actual program. I still am not having any luck.
When I run this program
#include <TMCStepper.h>
#define EN_PIN 8 // Enable
#define DIR_PIN1 5 // Direction
#define STEP_PIN1 2 // Step
#define DIR_PIN2 6 // Direction
#define STEP_PIN2 3
#define DIR_PIN3 7 // Direction
#define STEP_PIN3 4
#define DIR_PIN4 13 // Direction
#define STEP_PIN4 12
#define SW_RX1 55 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX1 60 // TMC2208/TMC2224 SoftwareSerial transmit pin
#define SW_RX2 56 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX2 61
#define SW_RX3 57 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX3 62
#define SW_RX4 58 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX4 63
#define R_SENSE 0.11f // Match to your driver
TMC2208Stepper driverX(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverY(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverZ(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverA(SW_RX1, SW_TX1, R_SENSE); // Software serial
void setup() {
pinMode(EN_PIN, OUTPUT);
pinMode(STEP_PIN1, OUTPUT);
pinMode(DIR_PIN1, OUTPUT);
pinMode(STEP_PIN2, OUTPUT);
pinMode(DIR_PIN2, OUTPUT);
pinMode(STEP_PIN3, OUTPUT);
pinMode(DIR_PIN3, OUTPUT);
pinMode(STEP_PIN4, OUTPUT);
pinMode(DIR_PIN4, OUTPUT);
digitalWrite(EN_PIN, LOW); // Enable driver in hardware
driverX.begin();
driverY.begin();
driverZ.begin();
driverA.begin(); // SPI: Init CS pins and possible SW SPI pins
// UART: Init SW UART (if selected) with default 115200 baudrate
driverX.microsteps(16); // Set microsteps to 1/16th
}
void loop() {
// Run 5000 steps and switch direction in software
for (uint16_t i = 5; i>0; i++) {
digitalWrite(STEP_PIN1, HIGH);
digitalWrite(STEP_PIN2, HIGH);
digitalWrite(STEP_PIN3, HIGH);
digitalWrite(STEP_PIN4, HIGH);
delayMicroseconds(160);
digitalWrite(STEP_PIN1, LOW);
digitalWrite(STEP_PIN2, LOW);
digitalWrite(STEP_PIN3, LOW);
digitalWrite(STEP_PIN4, LOW);
delayMicroseconds(160);
}
the motors just continuously spin, so I know that the drivers actually work.
My main code is below.
#include <AccelStepper.h>
#include <TMCStepper.h>
const int stepperCount = 4;
AccelStepper BLStepper(AccelStepper::DRIVER, 2, 5);
AccelStepper FLStepper(AccelStepper::DRIVER, 3, 6);
AccelStepper FRStepper(AccelStepper::DRIVER, 4, 7);
AccelStepper BRStepper(AccelStepper::DRIVER, 12, 13);
#define R_SENSE 0.11f
// define pins numbers
#define stepX_PIN 2
#define dirX_PIN 5
#define stepX_RX 55
#define dirX_TX 60
#define stepY_PIN 3
#define dirY_PIN 6
#define stepY_RX 56
#define dirY_TX 61
#define stepZ_PIN 4
#define dirZ_PIN 7
#define stepZ_RX 57
#define dirZ_TX 62
#define stepA_PIN 12
#define dirA_PIN 13
#define stepA_RX 58
#define dirA_TX 63
#define enPin_PIN 8
TMC2208Stepper driverX(stepX_RX, dirX_TX, R_SENSE);
TMC2208Stepper driverY(stepY_RX, dirY_TX, R_SENSE);
TMC2208Stepper driverZ(stepZ_RX, dirZ_TX, R_SENSE);
TMC2208Stepper driverA(stepA_RX, dirA_TX, R_SENSE);
//Front left wheel
//const int stepX_PIN = 2;
//const int dirX_PIN = 5;
//Front right wheel
//const int stepY_PIN = 3;
//const int dirY_PIN = 6;
//Back left wheel
//const int stepZ_PIN = 4;
//const int dirZ_PIN = 7;
//Back right wheel
//const int stepA_PIN = 12;
//const int dirA_PIN = 13;
//const int enPin_PIN = 8;
char split = ':'; //this is the character that would be used for seperating the different parts of your commands
//the syntax for commands would be: command:value1:value2
int listSize = 5; //the amount of commands in the list
String commands[] = {"hello", "add", "sub", "YMOV", "XMOV"}; //the list of every command name
void setup()
{
Serial.begin(115200); //sets the data transfer rate for the serial interface
//9600 is good for basic testing, but should be as high
//as possible for both devices
FRStepper.setMaxSpeed(300);
FRStepper.setAcceleration(200);
BRStepper.setMaxSpeed(300);
BRStepper.setAcceleration(200);
FLStepper.setMaxSpeed(300);
FLStepper.setAcceleration(200);
BLStepper.setMaxSpeed(300);
BLStepper.setAcceleration(200);
pinMode(stepX_PIN, OUTPUT);
pinMode(dirX_PIN, OUTPUT);
pinMode(stepY_PIN, OUTPUT);
pinMode(dirY_PIN, OUTPUT);
pinMode(stepZ_PIN, OUTPUT);
pinMode(dirZ_PIN, OUTPUT);
pinMode(stepA_PIN, OUTPUT);
pinMode(dirA_PIN, OUTPUT);
pinMode(enPin_PIN, OUTPUT);
digitalWrite(enPin_PIN, LOW);
digitalWrite(dirX_PIN, HIGH);
digitalWrite(dirY_PIN, HIGH);
digitalWrite(dirZ_PIN, HIGH);
digitalWrite(dirA_PIN, HIGH);
//digitalWrite(stepX_PIN, HIGH);
//digitalWrite(stepY_PIN, HIGH);
//digitalWrite(stepZ_PIN, HIGH);
//digitalWrite(stepA_PIN, HIGH);
driverX.begin();
driverY.begin();
driverZ.begin();
driverA.begin();
FRStepper.setEnablePin(enPin_PIN);
FLStepper.setEnablePin(enPin_PIN);
BRStepper.setEnablePin(enPin_PIN);
BLStepper.setEnablePin(enPin_PIN);
FRStepper.enableOutputs();
FLStepper.enableOutputs();
BRStepper.enableOutputs();
BLStepper.enableOutputs();
}
void loop()
{
CommCheck(); //checks serial buffer for data commands
runMotors();
}
void runMotors()
{
if ((FLStepper.distanceToGo() != 0) || (FRStepper.distanceToGo() != 0) || (BLStepper.distanceToGo() != 0) || (BRStepper.distanceToGo() != 0))
{
FRStepper.enableOutputs();
FLStepper.enableOutputs();
BRStepper.enableOutputs();
BLStepper.enableOutputs();
FLStepper.run();
BLStepper.run();
FRStepper.run();
BRStepper.run();
if ((FLStepper.distanceToGo() == 0) && (FRStepper.distanceToGo() == 0))
{
CommConfirm();
}
}
//if (movementComplete == true)
//{
//CommConfirm();
//}
//if (
//if ((FLStepper.distanceToGo() == 0) || (FRStepper.distanceToGo() == 0) || (BLStepper.distanceToGo() == 0) || (BRStepper.distanceToGo() == 0))
//{
//CommConfirm();
//}
}
void CommCheck()
{
if(Serial.available()) //checks to see if there is serial data has been received
{
//int len = Serial.available(); //stores the character lengh of the command that was sent
//this is used for command parsing later on
String command = Serial.readString(); //stores the command as a text string
int len = command.length();
//Serial.println(command);
Serial.flush();
//command.remove(len-2,1); //removes characters added by the pi's serial data protocol
//command.remove(0,2);
//len -= 3; //updates the string length value for parsing routine
int points[2] = {0, 0}; //offset points for where we need to split the command into its individual parts
for(int x = 0; x < len; x++) //this loop will go through the entire command to find the split points based on
{ //what the split variable declared at the top of the script is set to.
//Serial.print("Char ");
//Serial.print(x);
//Serial.print("- ");
//Serial.println(command[x]);
if(command[x] == split) //this goes through every character in the string and compares it to the split character
{
if(points[0] == 0) //if the first split point hasn't been found, set it to the current spot
{
points[0] = x;
}
else //if the first spot was already found, then set the second split point
{ //this routine is currently only set up for a command syntax that is as follows
points[1] = x; //command:datavalue1:datavalue2
}
}
}
CommParse(command, len, points[0], points[1]); //now that we know the command, command length, and split points,
} //we can then send that information out to a routine to split the data
} //into individual values.
void CommParse(String command, int len, int point1, int point2)
{
//Serial.print("Command Length: ");
//Serial.println(len);
//Serial.print("Split 1: ");
//Serial.println(point1);
//Serial.print("Split 2: ");
//Serial.println(point2);
String com = command; //copy the full command into all 3 parts
String val1 = command; //this is needed for the string manipulation
String val2 = command; //that follow
com.remove(point1, len - point1); //each of these use the string remove to delete
val1.remove(point2, len - point2); //the parts of the command that aren't needed
val1.remove(0, point1 + 1); //basically splitting the command up into its
val2.remove(0, point2 + 1); //individual pieces
val2.remove(val2.length()-1,1);
CommLookup(com, val1, val2); //these pieces are then sent to a lookup routine for processing
}
void CommLookup(String com, String val1, String val2)
{
int offset = 255; //create a variable for our lookup table's offest value
//we set this to 255 because there won't be 255 total commands
//and a valid command can be offset 0, so it's just to avoid
//any possible coding conflicts if the command sent doesn't
//match anything.
for(int x = 0; x < listSize; x++) //this goes through the list of commands and compares
{ //them against the command received
if(commands[x] == com)
{
offset = x; //if the command matches one in the table, store that command's offset
}
}
switch(offset) //this code compares the offset value and triggers the appropriate command
{
case 0: //essentially a hello world. | Syntax: hello:null:null
CommHello(); //this activates the hello world subroutine | returns Hello!
break;
case 1: //adds both values together and return the sum. | Syntax: add:value1:value2
CommAdd(val1.toInt(), val2.toInt()); //this activates the addition subroutine | returns value1 + value2
break;
case 2: //subtracts both values and return the difference | Syntax: subtract:value1:value2
CommSub(val1.toInt(), val2.toInt()); //this activates the subtraction subroutine | returns value1 - value2
break;
case 3:
yMovement(val1.toInt(), val2.toInt());
break;
case 4:
xMovement(val1.toInt(), val2.toInt());
default: //this is the default case for the command lookup and will only
Serial.println("Command not recognized"); //trigger if the command sent was not known by the arduino
break;
}
}
void CommHello() //each of these routines are what will be triggered when they are successfully processed
{
Serial.println("Hello!");
CommConfirm();
}
void CommAdd(int val1, int val2)
{
Serial.println(val1 + val2);
CommConfirm();
}
void CommSub(int val1, int val2)
{
Serial.println(val1 - val2);
CommConfirm();
}
void yMovement(int val1, int val2)
{
if (val1 < 0) {
//Serial.println("YMOVNEG");
int yMoveNew = (val1 * (-20.72));
//Serial.println(val1 * (-1));
//delay(500);
FRStepper.move(-yMoveNew);
BRStepper.move(-yMoveNew);
FLStepper.move(-yMoveNew);
BLStepper.move(-yMoveNew);
}
else {
//Serial.println(val1);
int yMoveNew = (val1 * (20.72));
//Serial.println(yMoveNew);
//Serial.println(val1);
//delay(500);
FRStepper.move(yMoveNew);
BRStepper.move(yMoveNew);
FLStepper.move(yMoveNew);
BLStepper.move(yMoveNew);
}
}
void xMovement(int val1, int val2)
{
if (val1 < 0) {
//Serial.println(val1);
int xMoveNew = (val1 * (-20.72));
//Serial.println(xMoveNew);
//Serial.println(val1 * (-1));
//delay(1000);
FLStepper.move(-xMoveNew);
BLStepper.move(xMoveNew);
FRStepper.move(xMoveNew);
BRStepper.move(-xMoveNew);
//delayMicroseconds(500);
}
else {
int xMoveNew = (val1 * (20.72));
//Serial.println(val1);
//delay(1000);
FLStepper.move(xMoveNew);
BLStepper.move(xMoveNew);
FRStepper.move(xMoveNew);
BRStepper.move(xMoveNew);
//delayMicroseconds(500);
}
}
void CommConfirm()
{
Serial.println("Done");
delay(750);
}
When I run my code, a Pi sends two values that equals step counts, however with the new drivers nothing happens. I tried also looking at and following the AccelStepper example on the git but I guess I have something wrong.
Any help would be appreciated.

How do I have this audio and LED activate ONLY when a button is held using an Arduino?

I have this code that I am using to play a sound effect where I used a program called wav2c to convert a .wav file to number values that I put into a header file that I use in the code to generate the sound. I currently have it programmed to play the audio upon uploading it to the Arduino with an LED being activated along with it and staying lit for just the duration of the sound effect. I am trying to program it so that the sound and LED only activate when I am pressing a button. I have the pin the button is plugged into already programmed in but I'm not sure how to have it control the audio and LED as stated above. I don't have much experience with programming or Arduino so any help is much appreciated! I am using an Arduino Mega 2560.
The code
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#define SAMPLE_RATE 20000
#include "Test.h"
int ledPin = 2;
int speakerPin = 9; // Can be either 3 or 11, two PWM outputs connected to Timer 2
const byte pinSwitch1 = 3;
volatile uint16_t sample;
byte lastSample;
void stopPlayback()
{
digitalWrite(ledPin, LOW);
// Disable playback per-sample interrupt.
TIMSK1 &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);
// Disable the PWM timer.
TCCR2B &= ~_BV(CS10);
digitalWrite(speakerPin, LOW);
}
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
if (sample >= sounddata_length) {
if (sample == sounddata_length + lastSample) {
stopPlayback();
}
else {
if(speakerPin==11){
// Ramp down to zero to reduce the click at the end of playback.
OCR2A = sounddata_length + lastSample - sample;
} else {
OCR2B = sounddata_length + lastSample - sample;
}
}
}
else {
if(speakerPin==11){
OCR2A = pgm_read_byte(&sounddata_data[sample]);
} else {
OCR2B = pgm_read_byte(&sounddata_data[sample]);
}
}
++sample;
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Set up Timer 2 to do pulse width modulation on the speaker
// pin.
// Use internal clock (datasheet p.160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Set fast PWM mode (p.157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
if(speakerPin==11){
// Do non-inverting PWM on pin OC2A (p.155)
// On the Arduino this is pin 11.
TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2A = pgm_read_byte(&sounddata_data[0]);
} else {
// Do non-inverting PWM on pin OC2B (p.155)
// On the Arduino this is pin 3.
TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0);
TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2B = pgm_read_byte(&sounddata_data[0]);
}
// Set up Timer 1 to send a sample every interrupt.
cli();
// Set CTC mode (Clear Timer on Compare Match) (p.133)
// Have to set OCR1A *after*, otherwise it gets reset to 0!
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// No prescaler (p.134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set the compare register (OCR1A).
// OCR1A is a 16-bit register, so we have to do this with
// interrupts disabled to be safe.
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Enable interrupt when TCNT1 == OCR1A (p.136)
TIMSK1 |= _BV(OCIE1A);
lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
sample = 0;
sei();
}
void setup()
{
pinMode( pinSwitch1, INPUT );
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
startPlayback();
}
void loop()
{
while (true);
}
The header file referenced in the code with the numeric values to create the audio.
#ifndef _HEADERFILE_H // Put these two lines at the top of your file.
#define _HEADERFILE_H // (Use a suitable name, usually based on the file name.)
const int sounddata_length=32000;
//const int sounddata_sampleRate=20000;
const unsigned char sounddata_data[] PROGMEM = {
15,1,49,0,150,0,138,0,219,255,133,0,176,0,15,1,210,
//There are many lines of more numbers in between that I cut out to save space
};
#endif // _HEADERFILE_H // Put this line at the end of your file.
The following changes will allow you to start playback whenever there is a falling edge on your switch pin. You may need to tweak to avoid switch 'bouncing'.
Firstly, add a global variable to record the last switch state:
int lastSwitchState;
Change your setup() to
void setup() {
pinMode(pinSwitch1, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
lastSwitchState = digitalRead(pinSwitch1);
}
and your loop() function to
void loop() {
delay(50);
int switchState = digitalRead(pinSwitch1);
if (switchState != lastSwitchState) {
lastSwitchState = switchState;
if (switchState == LOW) {
startPlayback();
}
}
}
Interrupts vs polling
Instead of polling the switch pin inside the main loop(), you could use interrupts. You would use attachInterrupt() to do this. Interrupts are only available on certain pins, however, and the above approach is conceptually simpler I think.

(Arduino Uno reflashed as USB HID) How to send Scroll Lock key?

I am having a hard time properly using USB HID buffers, and want to send the scroll lock key when I press the button.
I have tried sending what I thought was scroll lock (0x47) and it sends the ctrl, left alt, and right alt keys instead.
I used the table here for reference: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
This is loosely based off of http://mitchtech.net/arduino-usb-hid-keyboard/
/* Arduino USB Keyboard HID demo
* Cut/Copy/Paste Keys
*/
#define SCRLCK 0x47
//#define KEY_LEFT_SHIFT 0x02
//#define KEY_RIGHT_CTRL 0x10
//#define KEY_RIGHT_SHIFT 0x20
uint8_t buf[8] = {
0 }; /* Keyboard report buffer */
#define PIN_PTT 2
//#define PIN_CUT 6
//#define PIN_PASTE 7
int state = 1;
int prevState;
void setup()
{
Serial.begin(9600);
pinMode(PIN_PTT, INPUT);
//pinMode(PIN_CUT, INPUT);
//pinMode(PIN_PASTE, INPUT);
// Enable internal pull-ups
digitalWrite(PIN_PTT, 1);
//digitalWrite(PIN_CUT, 1);
//digitalWrite(PIN_PASTE, 1);
delay(200);
}
void loop()
{
state = digitalRead(PIN_PTT);
if (prevState != state) {
buf[0] = SCRLCK; // Scroll Lock
// buf[2] = 27; // Letter X
// buf[2] = 123; // Cut key: Less portable
Serial.write(buf, 8); // Send keypress
prevState = state;
releaseKey();
}
}
void releaseKey()
{
buf[0] = 0;
Serial.write(buf, 8); // Release key
delay(100);
}
I expect scroll lock to be sent, but upon using passmark KeyboardTest I see that ctrl, left alt, and right alt are sent instead.
You should send the first key code starting at offset 2:
buf[2] = SCRLCK;
Offset 0 is used for key modifier flags like ctrl, alt, etc.

microphone sph0645 with I2S less sensitive after watchdog sleep with Adafruit Feather M0

I am using the Adafruit Feather M0 RFM69 with the Adafruit I2S MEMS Microphone Breakout SPH0645. Every second I take a reading (sampleRate = 16000, bits per sample = 32) using the I2S library and send it over the radio. This all works fine.
My problem is that, when I want to save power, I am getting weird readings after I wake the board from sleep (using Adafruit_SleepyDog library). The microphone somewhat still works, although it is much less sensitive, only picks up loud sounds and also returns 60dB in a quiet room. When I don't put it to sleep, in the same sound setting, I get 40dB. However, if I put a delay of 250ms after waking up, the microphone works fine again, like before, but this is obviously not saving energy then.
I wonder why this is happening. Is there something I can do to get the microphone to work quicker? I checked the datasheet, but it only says: "When Vdd is applied the microphone senses the
CLOCK line, if the frequency is greater than 900KHz, the microphone enters the normal mode of operation." This should not even take a few ms though?
Thanks in advance
#include <I2S.h>
#include <Adafruit_SleepyDog.h>
#include <SPI.h>
#include <RH_RF69.h>
/************ Radio Setup ***************/
#define RF69_FREQ 433.0
#define SLEEP
//#if defined(ARDUINO_SAMD_FEATHER_M0) // Feather M0 w/Radio
#define RFM69_CS 8
#define RFM69_INT 3
#define RFM69_RST 4
#define LED 13
//#endif
// radio
// Singleton instance of the radio driver
RH_RF69 rf69(RFM69_CS, RFM69_INT);
int transmit_interval = 1000;
int time_counter = 0;
int packetnum = 0;
// MIC
#define SAMPLES 1024//2048 // make it a power of two for best DMA performance
int samples[SAMPLES];
int measurementsdB = 0;
int current_measure;
#define ADC_SOUND_REF 65
#define DB_SOUND_REF 41
int sampleRate1 = 16000;
int bitsPerSample1 = 32;
typedef struct
{
uint8_t measurementdB = 123;
uint8_t battery = 111;
uint8_t test = 222;
} RadioMessage;
RadioMessage struct_message;
void setup()
{
delay(2000); // Wait so its easier to program
Serial.begin(115200);
//while (!Serial) { delay(1); } // wait until serial console is open, remove if not tethered to computer
// Init Mic
if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate1, bitsPerSample1)) {
while (1); // do nothing
}
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
pinMode(RFM69_RST, OUTPUT);
digitalWrite(RFM69_RST, LOW);
Serial.println("Feather RFM69 TX Test!");
Serial.println();
// manual reset
digitalWrite(RFM69_RST, HIGH);
delay(10);
digitalWrite(RFM69_RST, LOW);
delay(10);
if (!rf69.init()) {
Serial.println("RFM69 radio init failed");
while (1);
}
Serial.println("RFM69 radio init OK!");
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
// No encryption
if (!rf69.setFrequency(RF69_FREQ)) {
Serial.println("setFrequency failed");
}
// If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
// ishighpowermodule flag set like this:
rf69.setTxPower(20, true); // range from 14-20 for power, 2nd arg must be true for 69HCW
// The encryption key has to be the same as the one in the server
uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
rf69.setEncryptionKey(key);
Serial.print("RFM69 radio #"); Serial.print((int)RF69_FREQ); Serial.println(" MHz");
//GCLK->GENCTRL.bit.RUNSTDBY=1; // !! can go
}
void loop() {
Serial.println("START");
///// MIC
//PM->APBCMASK.reg |= PM_APBCMASK_I2S;
int a = 0;
while (a == 0) a = I2S.available();
uint8_t current_measure = sample_audio_signal(samples);
///// RADIO
if (true)//((time_counter + transmit_interval) < millis())
{
struct_message.measurementdB = current_measure;
//struct_message.battery = measuredvbat;
// Send a message!
/*
Serial.print("Array content: ");
uint8_t* bla = (uint8_t*) &struct_message;
for (int i = 0; i < 3; i++)
{
Serial.println(bla[i]);
}*/
rf69.send((const uint8_t*) &struct_message, sizeof(struct_message));
rf69.waitPacketSent();
Serial.print("Wait for reply");
// Now wait for a reply
uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
if (rf69.waitAvailableTimeout(100)) {
// Should be a reply message for us now
if (rf69.recv(buf, &len)) {
Serial.print("Got a reply: ");
Serial.println((char*)buf);
} else {
Serial.println("Receive failed");
}
} else {
Serial.println("No reply, is another RFM69 listening?");
}
Serial.println("Radio sleeping");
rf69.sleep();
time_counter = millis();
}
// sleep time
#ifdef SLEEP
int sleepMS = Watchdog.sleep(10);
delay(250);
#else
delay(1000);
#endif
Serial.println("loop ended");
}
void Blink(byte PIN, byte DELAY_MS, byte loops) {
for (byte i=0; i<loops; i++) {
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
delay(DELAY_MS);
}
}
float sample_audio_signal(int samples[])
{
for (int i=0; i<SAMPLES; i++) {
int sample = 0;
while ((sample == 0) || (sample == -1) ) {
sample = I2S.read();
}
// convert to 18 bit signed
sample >>= 14;
samples[i] = sample;
}
// ok we have the samples, get the mean (avg)
float meanval = 0;
for (int i=0; i<SAMPLES; i++) {
meanval += samples[i];
}
meanval /= SAMPLES;
// subtract it from all samples to get a 'normalized' output
for (int i=0; i<SAMPLES; i++) {
samples[i] -= meanval;
}
// find the 'peak to peak' max
float maxsample, minsample;
minsample = 100000;
maxsample = -100000;
for (int i=0; i<SAMPLES; i++) {
minsample = min(minsample, samples[i]);
maxsample = max(maxsample, samples[i]);
}
int newdB = 20 * log10((float)maxsample / (float)ADC_SOUND_REF) + DB_SOUND_REF;
return newdB;
Ok, the best I got it down to is 3.8mA. I only got so far by leaving the voltage regulator and the internal oscillator (DFLL) on during sleeping.
After adding the following code to my setup routine, when board goes to sleep, the microphone still works after waking up:
SYSCTRL->DFLLCTRL.bit.RUNSTDBY=1;
SYSCTRL->VREG.bit.RUNSTDBY=1;
However, ideally I would like to get much less than that, but then the mic doesn't work...

Arduino - deleting variables after radio send doesn't work

I have tried so hard but i just can't understand why the two lines in my Tx code :
inputString = "";
stringComplete = false;
Stop my radio is working.
If I delete this code, it just keeps sending the values over and over without being able to stop it.
Tx:
/* YourDuinoStarter Example: nRF24L01 Transmit Joystick values
- WHAT IT DOES: Reads Analog values on A0, A1 and transmits
them over a nRF24L01 Radio Link to another transceiver.
- SEE the comments after "//" on each line below
- CONNECTIONS: nRF24L01 Modules See:
http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
1 - GND
2 - VCC 3.3V !!! NOT 5V
3 - CE to Arduino pin 9
4 - CSN to Arduino pin 10
5 - SCK to Arduino pin 13
6 - MOSI to Arduino pin 11
7 - MISO to Arduino pin 12
8 - UNUSED
-
Analog Joystick or two 10K potentiometers:
GND to Arduino GND
VCC to Arduino +5V
X Pot to Arduino A0
Y Pot to Arduino A1
- V1.00 11/26/13
Based on examples at http://www.bajdi.com/
Questions: terry#yourduino.com */
/*-----( Import needed libraries )-----*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define CE_PIN 9
#define CSN_PIN 10
// NOTE: the "LL" at the end of the constant is "LongLong" type
const uint64_t pipe = 0xE8E8F0F0E1LL; // Define the transmit pipe
/*-----( Declare objects )-----*/
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio
/*-----( Declare Variables )-----*/
String inputString = "";
boolean stringComplete = false;
int msg[1]; // 2 element array holding Joystick readings
int msgNum = 0;
void setup() /****** SETUP: RUNS ONCE ******/
{
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(pipe);
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
serialEvent();
if (stringComplete) {
inputString.trim();
String on1 = "onone";
on1.trim();
String on2 = "ontwo";
on2.trim();
String off1 = "offone";
off1.trim();
String off2 = "offtwo";
off2.trim();
if (inputString.equals(on1)) {
Serial.print("1 is On");
msg[0] = 111;
radio.write(msg, 1);
inputString = "";
stringComplete = false;
} else if (inputString.equals(off1)) {
Serial.print("1 Is Off");
msg[0] = 112;
radio.write(msg, 1);
inputString = "";
stringComplete = false;
} else if (inputString.equals(on2)) {
Serial.print("2 Is On");
msg[0] = 113;
radio.write(msg, 1);
inputString = "";
stringComplete = false;
} else if (inputString.equals(off2)) {
Serial.print("2 Is Off");
msg[0] = 114;
radio.write(msg, 1);
inputString = "";
stringComplete = false;
} else {
inputString = "";
stringComplete = false;
}
}
}//--(end main loop )---
/*-----( Declare User-written Functions )-----*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
delay(100);
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
//NONE
//*********( THE END )***********
Rx:
/* YourDuinoStarter Example: nRF24L01 Receive Joystick values
- WHAT IT DOES: Receives data from another transceiver with
2 Analog values from a Joystick or 2 Potentiometers
Displays received values on Serial Monitor
- SEE the comments after "//" on each line below
- CONNECTIONS: nRF24L01 Modules See:
http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
1 - GND
2 - VCC 3.3V !!! NOT 5V
3 - CE to Arduino pin 9
4 - CSN to Arduino pin 10
5 - SCK to Arduino pin 13
6 - MOSI to Arduino pin 11
7 - MISO to Arduino pin 12
8 - UNUSED
- V1.00 11/26/13
Based on examples at http://www.bajdi.com/
Questions: terry#yourduino.com */
/*-----( Import needed libraries )-----*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
/*-----( Declare Constants and Pin Numbers )-----*/
#define CE_PIN 9
#define CSN_PIN 10
int ledPin = 3;
// NOTE: the "LL" at the end of the constant is "LongLong" type
const uint64_t pipe = 0xE8E8F0F0E1LL; // Define the transmit pipe
/*-----( Declare objects )-----*/
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio
/*-----( Declare Variables )-----*/
int msg[1]; // 2 element array holding Joystick readings
int lastMsgNum;
void setup() /****** SETUP: RUNS ONCE ******/
{
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
delay(1000);
Serial.println("Nrf24L01 Receiver Starting");
radio.begin();
radio.openReadingPipe(1,pipe);
radio.startListening();;
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
if ( radio.available() )
{
// Read the data payload until we've received everything
bool done = false;
while (!done)
{
// Fetch the data payload
done = radio.read( msg, sizeof(msg) );
Serial.print(msg[0]);
if (msg[0] == 111) {
digitalWrite(3, HIGH);
} else if (msg[0] == 112) {
digitalWrite(3, LOW);
} else if (msg[0] == 113) {
digitalWrite(5, HIGH);
} else if (msg[0] == 114) {
digitalWrite(5, LOW);
}
}
}
else
{
//Serial.println("No radio available");
}
}//--(end main loop )---
/*-----( Declare User-written Functions )-----*/
//NONE
//*********( THE END )***********
I think that you don't understand why you must initialize/set your variables.
inputString and stringComplete are global variables, so when you changed it in serialEvent() you could see it in loop() so when you read a '\n' in serialEvent(). You understand that the sender has finished transmission so you must analize it. Once you finished the corresponding action, you must initialize the global variable again to start again. Unless you have done that, you see stringComplete == true so you start to analize it again in the next cycle of loop().
Usually we call this boolean variables as 'flag', you can see it in several places of code to 'sync' it. In this case, you set true when you have finished the reception and set false when you have finished the analisys.

Resources