I am working on a project for which I need to get a panel of 7 buttons to light up led strips on a display about 5m away. So far I have made it so I can control 1 led strip with one button and this works well. I am now confused on how to get the other 6 to connect to the same arduino via BLE. The idea is to have one arduino with all the buttons connected, then 1 arduino for each led strip. You press button 1 on the button arduino and this sends a signal to the display 1 arduino, lighting the display.
Here is my code so far, what would I need to do to it to add multiple buttons in ?
Thanks !!
//this code is loaded onto the board that is connected to the led strip
//if the code doesnt work it seems to kick start it by opening the serial monitor and then it will connect, not sure why this is
#include <ArduinoBLE.h>
#include <Adafruit_DotStar.h>
#include <SPI.h>
#define NUMPIXELS 144 // Number of LEDs in strip
#define BUTTON_PIN 9 //pin the button is on
#define DATAPIN 4 //the pin the data is plugged into
#define CLOCKPIN 5 //the pin the clock wire is plugged into
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // adress of the ledstrip that is referenced in the other set of code
Adafruit_DotStar strip(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BRG);
// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
const int ledPin = 2; // pin to use for the LED
void setup() {
// set LED pin to output mode
pinMode(ledPin, OUTPUT);
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
// set advertised local name and service UUID:
BLE.setLocalName("LED");
BLE.setAdvertisedService(ledService);
// add the characteristic to the service
ledService.addCharacteristic(switchCharacteristic);
// add service
BLE.addService(ledService);
// set the initial value for the characeristic:
switchCharacteristic.writeValue(0);
// start advertising
BLE.advertise();
Serial.println("BLE LED Peripheral");
strip.begin();
strip.show(); //pixels to 'off'
}
uint32_t white= strip.Color(255, 255, 255); //colour you want the lights
uint32_t off= strip.Color(0, 0, 0); //colour 'off'
void loop() {
// listen for BLE peripherals to connect:
BLEDevice central = BLE.central();
// if a central is connected to peripheral:
if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// while the central is still connected to peripheral:
while (central.connected()) {
// if the remote device wrote to the characteristic,
// use the value to control the LED:
if (switchCharacteristic.written()) {
if (switchCharacteristic.value()) { // any value other than 0
strip.fill(white, 0, 144); //fill(Color,first pixel,last pixel)
strip.setBrightness(5); //set the brightness of the leds here, would keep about 40, doesnt like anything above that
strip.show(); //update the leds
delay(7000); //time you want the LEDs
strip.fill(off, 0, 144); //turns off leds
strip.setBrightness(0);
strip.show();
} else { // a 0 value
strip.fill(off, 0, 144);
strip.setBrightness(0);
strip.show();
}
}
}
// when the central disconnects, print it out:
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
}
//this code gets loaded onto the button board
#include <ArduinoBLE.h>
// variables for button
const int buttonPin = 2;
int oldButtonState = LOW;
void setup() {
// configure the button pin as input
pinMode(buttonPin, INPUT);
// initialize the BLE hardware
BLE.begin();
Serial.println("BLE Central - LED control");
// start scanning for peripherals
BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214"); //Put the adress of what you want the button to control here
}
void loop() {
// check if a peripheral has been discovered
BLEDevice peripheral = BLE.available();
if (peripheral) {
// discovered a peripheral, print out address, local name, and advertised service
Serial.print("Found ");
Serial.print(peripheral.address());
Serial.print(" '");
Serial.print(peripheral.localName());
Serial.print("' ");
Serial.print(peripheral.advertisedServiceUuid());
Serial.println();
if (peripheral.localName() != "LED") {
return;
}
// stop scanning
BLE.stopScan();
controlLed(peripheral);
// peripheral disconnected, start scanning again
BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}
}
void controlLed(BLEDevice peripheral) {
// connect to the peripheral
Serial.println("Connecting ...");
if (peripheral.connect()) {
Serial.println("Connected");
} else {
Serial.println("Failed to connect!");
return;
}
// discover peripheral attributes
Serial.println("Discovering attributes ...");
if (peripheral.discoverAttributes()) {
Serial.println("Attributes discovered");
} else {
Serial.println("Attribute discovery failed!");
peripheral.disconnect();
return;
}
// retrieve the LED characteristic
BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1214");
if (!ledCharacteristic) {
Serial.println("Peripheral does not have LED characteristic!");
peripheral.disconnect();
return;
} else if (!ledCharacteristic.canWrite()) {
Serial.println("Peripheral does not have a writable LED characteristic!");
peripheral.disconnect();
return;
}
while (peripheral.connected()) {
// while the peripheral is connected
// read the button pin
int buttonState = digitalRead(buttonPin);
if (oldButtonState != buttonState) {
// button changed
oldButtonState = buttonState;
if (buttonState) {
Serial.println("button pressed");
// button is pressed, write 0x01 to turn the LED on
ledCharacteristic.writeValue((byte)0x01);
} else {
Serial.println("button released");
// button is released, write 0x00 to turn the LED off
ledCharacteristic.writeValue((byte)0x00);
}
}
}
Serial.println("Peripheral disconnected");
A typical way of doing this with BLE would be for the button to be the Peripheral and the LED strip to be the Central. The Central would connect to the Peripheral and subscribe to notifications on the "button" characteristic. Typically libraries/hardware aren't setup to have multiple Centrals connected at the same time to one Peripheral. This would seem to rule out doing it this way with your required hardware setup.
An alternative would be to have the buttons as the Central and the LED strips as the Peripheral. The Central would already know the details of the Peripheral device and initiate a connection and then do a write when a button is pressed. I would expect there to be a lot of lag between the button being pressed and something happening on the LED strip with this setup.
Another alternative is to do this with connection-less BLE, if security isn't a concern. The button board could act as a BLE beacon and you could encode information about which button has been pressed in the Service Data or the Manufacturer Data. The LED strips would be scanners reading the data from the beacon. I am not very familiar with BLE libraries on Arduino, there appears to be the command to set the Manufacturer Data but I couldn't find any command to read the data.
Related
I am trying to communicate Arduino UNO and Wecon(LX3v-0806MR) PLC with RS485. Here the arduino is the master and the plc is the slave. I want to now read the values from the input registers (04) of plc and present it on serial monitor. For that purpose I am using the following code.
#include <ModbusMaster.h>
/*!
We're using a MAX485-compatible RS485 Transceiver.
Rx/Tx is hooked up to the hardware serial port at 'Serial'.
The Data Enable and Receiver Enable pins are hooked up as follows:
*/
#define MAX485_DE 3
#define MAX485_RE_NEG 2
// instantiate ModbusMaster object
ModbusMaster node;
void preTransmission()
{
digitalWrite(MAX485_RE_NEG, 1);
digitalWrite(MAX485_DE, 1);
}
void postTransmission()
{
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
}
void setup()
{
pinMode(MAX485_RE_NEG, OUTPUT);
pinMode(MAX485_DE, OUTPUT);
// Init in receive mode
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
// Modbus communication runs at 115200 baud
Serial.begin(115200);
// Modbus slave ID 1
node.begin(1, Serial);
// Callbacks allow us to configure the RS485 transceiver correctly
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
bool state = true;
void loop()
{
uint8_t result;
uint16_t data[6];
// Toggle the coil at address 0x0002 (Manual Load Control)
result = node.writeSingleCoil(0x0002, state);
state = !state;
// Read 16 registers starting at 0x3100)
result = node.readInputRegisters(0x3100, 16);
if (result == node.ku8MBSuccess)
{
Serial.print("Vbatt: ");
Serial.println(node.getResponseBuffer(0x04)/100.0f);
Serial.print("Vload: ");
Serial.println(node.getResponseBuffer(0xC0)/100.0f);
Serial.print("Pload: ");
Serial.println((node.getResponseBuffer(0x0D) +
node.getResponseBuffer(0x0E) << 16)/100.0f);
}
delay(1000);
}
I tried the codes many a times but it is not working. If anyone knows how to do it please share the codes with me. I just want read int value from plc.
*Note: The sensor used is for TTL to rs485 is MAX485.
I have an AI Thinker A9G module connected to an ESP8266 D1 mini. I have the following script to send and receive AT commands to/from the module. The idea is to get a SMS with the Google maps GPS location of the module onto my mobile phone.
// GPS tracker with AI Thinker A9G module and AZ Delivery D1 Mini ESP8266 module
#include <SoftwareSerial.h>
#define rxPin D7
#define txPin D8
SoftwareSerial A9modem(rxPin, txPin); // Pins D7 Rx and D8 Tx are used as used as software serial pins
String incomingData; // For storing incoming serial data
String gpsData; // For storing location data
char msg;
char call;
void setup()
{
Serial.begin(115200); // Baud rate for serial monitor
A9modem.begin(115200); // Baud rate for GSM shield
Serial.println("GPS/GSM A9G BEGIN");
Serial.println("Enter character for control option: ");
Serial.println("h : to disconnect a call");
Serial.println("s : to send a message");
Serial.println("r : to receive a message");
Serial.println("c : to make a call");
Serial.println("l : to read location");
Serial.println("d : to disconnect gps");
Serial.println();
delay(100);
// Set SMS mode to text mode
A9modem.print("AT+CMGF=1\r");
delay(100);
// Set GSM module to TP show the output on serial out
A9modem.print("AT+CNMI=2,2,0,0,0\r");
delay(100);
}
void loop()
{
ReceiveMessage();
gpsData = incomingData.substring(33, 52);
Serial.print("Location: ");
Serial.println(gpsData);
delay(2000);
if (Serial.available() > 0)
switch(Serial.read())
{
case 's':
SendMessage();
break;
case 'r':
ReceiveMessage();
break;
case 'c':
MakeCall();
break;
case 'h':
HangupCall();
break;
case 'l':
ReadLocation();
break;
case 'd':
DisconnectGps();
break;
}
}
void ReceiveMessage()
{
if (A9modem.available() > 0)
{
incomingData = A9modem.readString(); // Get the data from the serial port
Serial.print(incomingData);
delay(100);
}
}
void SendMessage()
{
A9modem.println("AT+CMGF=1"); // Sets the GSM Module into text mode
delay(1000); // Delay of one second
A9modem.println("AT+CMGS=\"xxxxxxxxxxxxx\"\r"); // Replace your mobile number here
delay(1000);
String sms = "http://maps.google.com/maps?q=" + gpsData; // Create the SMS location string
A9modem.println(sms);
delay(100);
A9modem.println((char)26); // ASCII code of CTRL+Z
delay(1000);
}
void MakeCall()
{
A9modem.println("ATD+xxxxxxxxxxxxx;"); // Replace your mobile number here
Serial.println("Calling "); // Print response over serial port
delay(1000);
}
void HangupCall()
{
A9modem.println("ATH");
Serial.println("Hangup Call");
delay(1000);
}
void DisconnectGps()
{
A9modem.println("AT+GPS=0");
Serial.println("Disconnect GPS");
delay(1000);
}
void ReadLocation()
{
A9modem.println("AT+GPS=1");
delay(1000);
A9modem.println("AT+LOCATION=2"); // Check location every two seconds
delay(2000);
}
So if I use the commands "l" and "s" in Arduino IDE serial monitor everything is working well but I don't know how to change the code in a way that I get a fully automated GPS tracker. The idea is the following: Power on starts the tracker. When gpsData string is not empty the first SMS will be send to my mobile phone. The next SMS follows 20 minutes later and so on until power is switched off. Could you help please?
Thanks in advance!
Finally I came up with this solution but I'm not very happy with it (it is working but I have to restart the module from time to time because there are no GPS data). There are 3 reasons for this: There is no error handling for the GPS function, I set the delays in a more ore less random way to get everything working but I don't know if the values make sense and I don't know if the substring() function is the best way to get the location from the serial response.
// GPS tracker with AI Thinker A9G module and AZ Delivery D1 Mini
ESP8266 module
#include <SoftwareSerial.h>
#define rxPin D7
#define txPin D8
SoftwareSerial A9modem(rxPin, txPin); // Pins D7 Rx and D8 Tx are used as used as software serial pins
String incomingData; // For storing incoming serial data
String gpsData; // For storing location data
int runGps = 1;
int sendSms = 0;
void setup()
{
pinMode(LED_BUILTIN, OUTPUT); // Use builtin LED for correct GPS status
Serial.begin(115200); // Baud rate for serial monitor
A9modem.begin(115200); // Baud rate for GSM shield
// Set SMS mode to text mode
A9modem.print("AT+CMGF=1\r");
delay(300);
// Set GSM module to TP show the output on serial out
A9modem.print("AT+CNMI=2,2,0,0,0\r");
delay(1000);
Serial.end();
delay(500);
}
void loop()
{
Serial.begin(115200);
ReceiveMessage(); // Start a new serial stream
gpsData = incomingData.substring(33, 52); // Strip all unnessesary data from the stream
Serial.print("Location: "); // Check if the location data are correct
Serial.println(gpsData);
delay(1000);
if(runGps == 1) { // Start GPS
ReadLocation();
delay(20000); // Wait for GPS to be ready
}
if(gpsData.length() == 19 && sendSms == 0) { // If the location string is correct send SMS
if (isdigit(gpsData.charAt(0))) { // Check if the stream starts with a number
SendMessage();
digitalWrite(LED_BUILTIN, HIGH);
delay(300);
digitalWrite(LED_BUILTIN, LOW);
delay(300);
digitalWrite(LED_BUILTIN, HIGH);
delay(300);
digitalWrite(LED_BUILTIN, LOW);
delay(300);
digitalWrite(LED_BUILTIN, HIGH);
}
}
if(runGps == 0 && sendSms == 1) {
runGps = 1;
sendSms = 0;
delay(6000); // Make sure that all SMS serial communication is over
while (A9modem.available()) {
A9modem.read(); // Delete all data from serial buffer
}
delay(300000); // If SMS was sent wait 5 minutes before running the main loop again
Serial.end();
delay(500);
}
}
void ReceiveMessage()
{
if (A9modem.available() > 0)
{
incomingData = A9modem.readString(); // Get the data from the serial port
Serial.print(incomingData);
delay(500);
}
}
void SendMessage()
{
sendSms = 1; // Stop starting the SendMessage function
A9modem.println("AT+CMGF=1"); // Sets the GSM Module into text mode
delay(1000);
A9modem.println("AT+CMGS=\"xxxxxxxxxx\"\r"); // Replace your mobile number here
delay(1000);
String sms = "http://maps.google.com/maps?q=" + gpsData; // Create the SMS string
A9modem.println(sms);
delay(500);
A9modem.println((char)26); // ASCII code of CTRL+Z
delay(500);
}
void ReadLocation()
{
runGps = 0; // Stop starting the ReadLocation function
A9modem.println("AT+GPS=1");
delay(1000);
A9modem.println("AT+LOCATION=2"); // Check location every two seconds
delay(2000);
}
Try turning ON the NMEA stream from the A9G. Say you want to get the NMEA data every t seconds, you can add and then call the following function once in the void setup()
void TurnOnNMEA(int t)
{
if(t > 3600)
t = 3600; // Because the max time is 3600s
A9modem.print("AT+GPSRD=");
A9modem.println(t);
while(!A9modem.available()); // wait till the A9G sends a response
char c;
while(A9modem.available())
{
c = A9modem.read();
Serial.print(c);
delay(2); // Time needed for the next character
}
}
This will start the NMEA data stream every t seconds which you can print using the following function,
void ReadNMEA()
{
char c; // Read each character from the stream as it comes
if(A9modem.available())
{
c = A9modem.read();
Serial.print(c);
delay(2); // Time needed for the next character
}
}
Parsing and decoding the NMEA is a bit tricky thing to do. There is a lot of information inside it and the decoding depends on what you want to do with it. If you just want the location, you can parse the $GNGGA line.
When parsing the data, DO NOT USE Arduino String() class. It is a very bad idea when handling this kind of stream. Instead, use char array.
The Transmitter is working fine. But the receiver isn't working without a ttyUSB serial connection. I mean whenever I disconnected the PC from the receiver it's not showing the DATA it's getting from the Transmitter. I want it to work without the PC with just external power. What possibly went wrong?
It shows "Not Connected" when I add an external power source disconnecting the USB plug from PC
/*
SimpleReceive
This sketch displays text strings received using VirtualWire
Connect the Receiver data pin to Arduino pin 3 (default 11)
*/
#include <VirtualWire.h>
#include <TFT.h> // Arduino LCD library
#include <SPI.h>
// pin definition for the Uno
#define cs 10
#define dc 9
#define rst 8
// create an instance of the library
TFT TFTscreen = TFT(cs, dc, rst);
// char array to print to the screen
//char temperatureChar[4];
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen=VW_MAX_MESSAGE_LEN;
const int buzzer = 2; //buzzer to arduino pin 2
void setup()
{
// Put this line at the beginning of every sketch that uses the GLCD:
TFTscreen.begin();
// clear the screen with a black background
TFTscreen.background(0, 0, 0);
// write the static text to the screen
// set the font color to white
TFTscreen.stroke(255, 255, 255);
// set the font size
TFTscreen.setTextSize(1);
// write the text to the top left corner of the screen
TFTscreen.text("Temp :\n ", 5, 5);
// ste the font size very large for the loop
TFTscreen.setTextSize(2);
pinMode(buzzer, OUTPUT); // Set buzzer - pin 2 as an output
// Initialize the IO and ISR
//vw_set_ptt_inverted(true); // Required for DR3100
vw_setup(2000); // Bits per sec
vw_rx_start(); // Start the receiver
}
void loop()
{
if(vw_get_message(buf, &buflen)) //non-blocking
{
// set the font color
TFTscreen.stroke(255, 255, 255);
// print the sensor value
TFTscreen.text((char *)buf, 20, 20);
// wait for a moment
delay(1000);
// erase the text you just wrote
TFTscreen.stroke(0, 0, 0);
TFTscreen.text((char *)buf, 20, 20);
tone(buzzer, 2000); // Send 1KHz sound signal...
delay(1000);
noTone(buzzer);
}
else {
// set the font color
TFTscreen.stroke(255, 255, 0);
TFTscreen.setTextSize(1);
// print the sensor value
TFTscreen.text("Not connected", 20, 20);
// wait for a moment
delay(500);
// erase the text you just wrote
TFTscreen.stroke(0, 0, 0);
TFTscreen.setTextSize(1);
TFTscreen.text("Not connected", 20, 20);
}
}
Solved. The USB cable was actually working as an antenna (radio). When I disconnect it, it loses the connection.
I have bought a "APDS-9930" ambient light sensor, which communicates over I2C (TWI) protocol. I intend to read the the ambient light level from it, using ARDUINO Mega2560 development board. As I searched the net, I found a modified ARDUINO library, based on APDS-9960, which claims to work with APDS-9930 on ARDUINO UNO. However, when used with Mega2560, It gives me "Error initializing" error. Does anyone here know how to handle this error?
I have already used "Wire.h" library in many ways, to read "CH0 ADC data register" with address 0x14, which holds the ambient level value (according to datasheet). The code is as follows:
#define DUMP_REGS
#include <Wire.h>
#include <APDS9930.h>
// Global Variables
APDS9930 apds = APDS9930();
float ambient_light = 0; // can also be an unsigned long
uint16_t ch0 = 0;
uint16_t ch1 = 1;
void setup() {
//analogReference(EXTERNAL);
// Initialize Serial port
Serial.begin(9600);
Serial.println();
Serial.println(F("--------------------------------"));
Serial.println(F("APDS-9930 - Ambient light sensor"));
Serial.println(F("--------------------------------"));
// Initialize APDS-9930 (configure I2C and initial values)
//if ( apds.init() ) {
// Serial.println(F("APDS-9930 initialization complete"));
//} else {
// Serial.println(F("Something went wrong during APDS-9930 init!"));
// }
// Start running the APDS-9930 light sensor (no interrupts)
//if ( apds.enableLightSensor(false) ) {
// Serial.println(F("Light sensor is now running"));
// } else {
// Serial.println(F("Something went wrong during light sensor init!"));
// }
#ifdef DUMP_REGS
/* Register dump */
uint8_t reg;
uint8_t val;
for(reg = 0x00; reg <= 0x19; reg++) {
if( (reg != 0x10) && \
(reg != 0x11) )
{
apds.wireReadDataByte(reg, val);
Serial.print(reg, HEX);
Serial.print(": 0x");
Serial.println(val, HEX);
}
}
apds.wireReadDataByte(0x1E, val);
Serial.print(0x1E, HEX);
Serial.print(": 0x");
Serial.println(val, HEX);
#endif
// Wait for initialization and calibration to finish
delay(500);
}
void loop() {
// Read the light levels (ambient, red, green, blue)
if ( !apds.readAmbientLightLux(ambient_light) ||
!apds.readCh0Light(ch0) ||
!apds.readCh1Light(ch1) ) {
Serial.println(F("Error reading light values"));
} else {
Serial.print(F("Ambient: "));
Serial.print(ambient_light);
Serial.print(F(" Ch0: "));
Serial.print(ch0);
Serial.print(F(" Ch1: "));
Serial.println(ch1);
}
// Wait 1 second before next reading
delay(1000);
}
As discussed in the comments above, the issue is hardware related.
On the Arduino Mega 2560 board there are two resistances tying lines SDA and SCK (pins 20 and 21 on the connector) to +5V.
With those pull-up resistances, it's not possible to interface with sensors working at 3.3V directly.
The solution is to add a level shifter or remove the resistances on the board and install them externally connecting them to 5V or 3.3V as necessary depending on the sensor you want to interface to.
I'm trying to get my arduino GSM shield working with the example "Send SMS" code provided. However, when I upload and compile the program, the serial monitor displays "SMS Messages Sender" and nothing else occurs.
I am using Arduino uno r3 and gsm sim 900. powered gsm with 5V 1.5A. I have connected arduino pins 7&8 to pins 7&8 of gsm. I have connected the gsm to ground too.
When I use SoftwareSerial.h it works. But I wish to use GSM.h library which now isn't working. Any help please
// include the GSM library
#include <GSM.h>
// PIN Number for the SIM
#define PINNUMBER ""
// initialize the library instances
GSM gsmAccess;
GSM_SMS sms;
// Array to hold the number a SMS is retrieved from
char senderNumber[20];
void setup() {
// initialize serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("SMS Messages Receiver");
// connection state
bool notConnected = true;
// Start GSM connection
while (notConnected) {
if (gsmAccess.begin(PINNUMBER) == GSM_READY) {
notConnected = false;
} else {
Serial.println("Not connected");
delay(1000);
}
}
Serial.println("GSM initialized");
Serial.println("Waiting for messages");
}
void loop() {
char c;
// If there are any SMSs available()
if (sms.available()) {
Serial.println("Message received from:");
// Get remote number
sms.remoteNumber(senderNumber, 20);
Serial.println(senderNumber);
// An example of message disposal
// Any messages starting with # should be discarded
if (sms.peek() == '#') {
Serial.println("Discarded SMS");
sms.flush();
}
// Read message bytes and print them
while (c = sms.read()) {
Serial.print(c);
}
Serial.println("\nEND OF MESSAGE");
// Delete message from modem memory
sms.flush();
Serial.println("MESSAGE DELETED");
}
delay(1000);
}
i expected this code to enable me to receive message and i can modify it to store the message in variables
Your problem is probably the wiring.
Your board (Arduino UNO R3) has its UART (the one you intend to use when you define Serial.begin(9600) on pins 0 RX and 1 TX. See here for the schematic and picture below (top right corner with tags TX and RX).
Software emulated serial works because you're defining pins 7 and 8 to be the emulated UART TX and RX signals.