ATTiny85 Serial communication with Bluetooth Module - arduino

For a simple project, I would like to use an ATTiny85 connected to an HC-06 Bluetooth module, so it can talk to my Android phone.
I wrote code for my Arduino Uno and it worked as expected. When I changed the code to use on my ATTiny85 I got an error saying that 'Serial' was not declared in this scope and assumed that the ATTiny does not support Hardware Serial.
I need to read a String when received and sleep the MCU when not receiving. I went to use SoftwareSerial and was not able to get a String, just the first char.
I approached it in some way, like defining a char string[10]; as global and string[i] = mySerial.read(); i++; inside the loop, but it keeps not working. Whether it is the sleep, or my work to read data, I couldn't make it work.
Can someone provide a way to put a ATTiny85 to sleep, wake up to receive a String through Serial and sleep until the next data through Serial, please?
To sleep I'm using
void sleep() {
GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts
PCMSK |= _BV(PCINT3); // Use PB3 as interrupt pin
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep
// woke up
cli(); // Disable interrupts
PCMSK &= ~_BV(PCINT3); // Turn off PB3 as interrupt pin
sleep_disable(); // Clear Sleep Enable bit
sei(); // Enable interrupts
}
ISR(PCINT3_vect) {
}
And my loop is something like
char inputString[10];
int i = 0;
void loop() {
sleep();
if (serial.available() > 0) {
char inputChar = serial.read();
if (inputChar == '2') { //Char to break
//Do something and reset i
} else {
inputString[i] = inputChar;
}
i++;
}
}
Thanks to all.

if (serial.available() > 0) {
That's a one-time thing. You should put this in a while loop.
while (serial.available() > 0) {
char inputChar = serial.read();
if (inputChar == '2') { //Char to break
//Do something and reset i
} else {
inputString[i] = inputChar;
}
i++;
}
Wouldn't hurt to check i after incrementing, too.

Related

Xbee Serial.read is not clearing buffer

I wrote a example program to test Serial read from xbee. I was expecting a message passed from transmitter to receiver every 5 sec's but in serial monitor of receiver I am observing a continuous stream of repeat messages. Can anyone what I am missing. FYI: Also attached link to serial monitor screenshot.
[1]: https://i.stack.imgur.com/Lgxx5.png
/* ~ Simple Arduino - xBee Transmitter sketch ~ Router
*/
int count = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
//Send the message:
count ++;
Serial.println(String("Hello World : " + String(count)));
delay(5000);
}
/* ~ Simple Arduino - xBee Receiver sketch ~ Coordinator
*/
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0){
Serial.write(Serial.read());
}
}
For the receiver, don't you just want to pass Serial.read() to print() instead of Serial.write()? If you have two serial ports, one to the console and one to the XBee, they should have different names.
Could you provide some more details on your serial connections? What are COM3 and COM6 attached to? Are you sharing serial port pins with the XBee and your console? it seems like that could be part of your problem, if either the Arduino or XBee can drive the RX pin of your receiver's serial port, you'd end up echoing your characters back to yourself.
Figured out a work around to address the issue. Here are the details:
https://i.stack.imgur.com/3qZMi.png
Circuit connections from Arduino to XBEE Shield:
D0/RX to TX
D1/TX to RX
5V to 5V
GND to GND
/* ~ Simple Arduino - xBee Transmitter sketch ~ Router
*/
void setup() {
Serial.begin(9600);
}
void loop() {
//Send the message:
Serial.print('<');
Serial.print("Hello World");
Serial.println('>');
delay(1000);
}
/* ~ Simple Arduino - xBee Receiver sketch ~ Coordinator
*/
bool started = false; //True: Message is strated
bool ended = false; //True: Message is finished
byte index; //Index of array
char character; //Variable to store the incoming byte
char msg[13]; //Message - array
void setup()
{
Serial.begin(9600);
}
void loop()
{
while (Serial.available())
{
character = Serial.read();
if (character == '<')
{
started = true;
index = 0;
msg[index] = '\0'; // Throw away any incomplete packet
}
//End the message when the '>' symbol is received
else if (character == '>')
{
ended = true;
break; // Done reading - exit from while loop!
}
//Read the message!
else
{
if (index < 11)
{ // Make sure there is room
msg[index] = character; // Add char to array
index++;
msg[index] = '\0'; // Add NULL to end
}
}
}
if (started && ended)
{
Serial.print("Message: ");
Serial.println(msg);
index = 0;
msg[index] = '\0';
started = false;
ended = false;
}
}

How to know if an Arduino restarted as a result of a WDT timeout?

I have Arduino code in which I have implemented an 8-second watchdog. To test I put a for loop and everything works correctly.
I want to know if it is possible to print a message when a watchdog timeout occurs in the Arduino, specifically what I want to do is send a message by XBee when a reset has occurred caused by the watch dog. I already have the XBee logic, how do I know when this reset occurs?
I already tried the solution raised here but it doesn't work for me:
link
My Code:
#include <avr/wdt.h>
void setup() {
Serial.begin(9600);
Serial.println("turning on");
delay(1000);
watchdogsetup();
}
void loop() {
for (int i = 0; i <= 9; i++) {
Serial.println();
delay(1000);
} //Test to activate watchdog
//My code ....
//....
wdt_reset(); // reset the watch dog to zero
}
Just an idea.
When the watchdog fires, it is uncertain if the time and resources you need to send a message via XBee are still available, so that message is probably best sent after the Arduino has reset and is running normally again.
I think the watchdog timer does set a flag that survives the reset itself, but it is cleared by the bootloader, so that information is lost if you use the bootloader.
So, you need to set your own flag, and read that flag back after the Arduino has reset. What you could try is writing an interrupt handler and add some other stuff to write a flag to EEPROM, something like this (untested):
#include <EEPROM.h>
int addr = 0; // Or whatever EEPROM address you like
setup() {
if (EEPROM.read(addr) == 1) { //If a WDT flag was set
// Send panicky message by XBee here
}
EEPROM.write(addr, 0); // Reset the WDT flag
// Rest of setup() goes here
}
ISR(WDT_vect) {
EEPROM.write(addr, 1); // Set the WDT flag
}
... and hope that the Arduino hasn't crashed beyond being able to write to the EEPROM when the watchdog fires.

How to initialize APDS-9930 ambient light / proximity sensor using ARDUINO Mega2560

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.

Arduino Serial Input to Stop and Start

I am trying to wait for user input to start a program operation and then when the user sends a stop command, the loop stops running. I have been unable to get the Serial port to keep reading an input while the loop is running.
So I want the user to Press 1 and then it'll go into the loop and will display the data from the interrupt. But I want it to keep monitoring the Serial Input so when I type in 2, I will get out of the loop and stop printing to the Serial Port.
The serial port isn't registering my second input.
I left out some of the code, but the important stuff should be there.
int userStart = 0; // Holder for user input to start program
int userStop = 0; // Holder for user input to stop program
void setup() {
Serial.begin(115200);
pinMode(motorEncoderA, INPUT);
digitalWrite(motorEncoderA, HIGH); // Pull up resistor
pinMode(motorEncoderB, INPUT);
digitalWrite(motorEncoderB,HIGH); // Pull up resistor
// Interrupt on change of Pin A
attachInterrupt(digitalPinToInterrupt(2), encoderFunc, CHANGE);
Serial.print("Press 1 to start the Process & 2 to Stop");
}
void loop() {
if (Serial.available() > 0)
{
userStart = Serial.read();
if (userStart = 1) {
Serial.print('\n');
while(userStop != 2) {
unsigned long timee = millis();
// Only update if the shaft has moved
if (encoderPositionLast != rotationCounter) {
Serial.print("Time: ");
Serial.print(timee);
Serial.print(" Count: ");
Serial.print (rotationCounter);
Serial.print('\n');
encoderPositionLast = rotationCounter;
Serial.print(userStart);
}
if (Serial.available() > 0) {
userStop = Serial.read();
Serial.print(userStop);
}
}
}
}
Well, I think your problem is that userStart and userStop should not be 1 and 2, but '1' and '2'.
That said, there are some things in your code I dislike.
First of all why is everybody using int as the base type for all numeric variables? If one single byte is enough, use it. On 32bit machines int and byte are almost the same, but on 8bit ones working with ints wastes space and time.
Secondly, I highly discourage you to block the loop function, otherwise you won-t be able to do anything else. Instead, use a variable to track wheter you are running or not, update it with the serial interface, and then execute the code if you are running.
This code should do it. And IMHO it is much better than blocking the loop:
bool running = false;
void setup()
{
...
running = false;
}
void loop()
{
if (Serial.available() > 0)
{
switch(Serial.read())
{
case '1':
running = true;
Serial.print('\n');
break;
case '2':
running = false;
Serial.print("stopped");
break;
}
}
if (running)
{
unsigned long timee = millis();
// Only update if the shaft has moved
if (encoderPositionLast != rotationCounter) {
Serial.print("Time: ");
Serial.print(timee);
Serial.print(" Count: ");
Serial.print (rotationCounter);
Serial.print('\n');
encoderPositionLast = rotationCounter;
Serial.print("running");
}
}
}

Initializing Xbee S1 by an Arduino mini pro

I am trying to configurate my XBee module by an Arduino pro mini that is connected to my computer by de FTDI basic from sparkfun.
I already can write and send data from the Xbee to another Xbee module by the Arduino.
My problem is that I want to configure the Xbee by the arduino. I am sending ‘+++’ with the arduino to my Xbee and want to receive the ‘OK’ from the Xbee with the serial monitor from the arduino editor. The problem is that I can send it but never receive and ‘OK’, and when I am trying to configure the Xbee the configuration never happened. So I cant reach the Xbee command line.
uint8_t pinRx = 0, pinTx = 1; //Initialise pins on the Arduino
char GotChar;
long BaudRate = 4800;
int incomingByte=0;
SoftwareSerial mySerial( pinRx , pinTx ); //Initialise SoftwareSerial
void init_USB()
{
Serial.begin(BaudRate);
Serial.println("Start");
mySerial.begin(BaudRate);
}
void init_XBee()
{
Serial.begin(9600);
int check = 0;
while(T_XBEE_CONTROLLER_CheckOK() == 0)
{
Serial.println("CheckOK");
Serial.write("+++");
delay(2000);
}
Serial.println("ATCH 8\r");
delay(2000);
Serial.write("ATID 1234\r");
delay(2000);
Serial.write("+++");
delay(2000);
Serial.write("ATPL 0\r");
delay(2000);
Serial.write("+++");
delay(2000);
Serial.write("ATAP 2\r");
delay(2000);
}
int T_XBEE_CONTROLLER_CheckOK()
{
char ch[2];
ch[0] = 0x00;
while(! ((ch[0] == 'O' ) && (ch[1] == 'K') ))
{
ch[0] = mySerial.read();
ch[1] = mySerial.read();
if((ch[0] != 'O') && (ch[1] != 'K') && (ch[2] != '\r'))
{
Serial.println("FAILED");
return 0;
}
Serial.println("SUCCES");
return 1;
}
return 0;
}
it is a stupid answer but first of all, you should check that your Xbee is configured as AT device instead of API device. If it is API mode, the module wont understand the messages.
To do that you just have to use X-CTU application and read the configuration of the module, and change it to AT device.
Hope that helps.
Thanks for the response and the help, and also sorry for the late response.
I already solved the problem. The problem was the function write(). If you want to reach the command mode from the XBee you should only send "+++". If there is some kind of character behind the "+++" you can't reach the command line. The function write put a (for me) unknown character behing the "+++". So that's the problem for not reaching the command line.
To resolve this problem just use the function print("+++"). After using this function it is possible to reach the command line.
You have to read from the serial right after you send the +++ command, because this is where the xbee writes 'OK'. Also a better way to respect the guard times is to wait for a reply, and test to see if it is 'OK'.
Here is my code, I don't remember if it was working the last time I checked but I will just paste it here and you can modify it as you like. All it does is broadcast A1, B2, C3, etc.
There's a lot of commenting out where I was experimenting, but the regular comments are informative. Make sure you go through it step by step, it's quite simple when you get your head around it. Don't forget to change the destination address low to 0xFFFF if you want to broadcast.
In the end you'll come to the same realisation I did that AT mode is not suitable for configuring the xbee by writing programs.
For example I had an xbee constantly transmitting the number '2', and when another xbee was entering command mode using this code, it would receive the number 2 from the remote xbee when it should have received the 'OK' message from the local xbee, thus the program didn't acknowledge it being in command mode and breaking. When entering command mode you'd think an xbee would turn it's receiver off, but that's not the case so you can easily get into trouble.
If you want to do it the right way, have a look at API mode. I have series 1 xbee's so I'm implementing the Digimesh protocol, which so far I haven't seen anyone online do, but it's almost identical to the Zigbee so it's easy. If you'd like I can give you my code for that which can serve as a simple example.
/*
unicast_configure
Configure an XBee for unicast transmission and transmit
some characters to test
*/
#include <SoftwareSerial.h>
// Pins on Bees Shield:
SoftwareSerial xbee(2, 3); // TX, RX
boolean configured;
char c = 'A';
boolean configureRadio() {
// Set the data rate for the SoftwareSerial port:
xbee.begin(9600);
// Put the radio in command mode:
Serial.write("Entering command mode\r");
delay(1000);
while(xbee.available()>0) {xbee.read();}
xbee.write("+++");
while(xbee.available()>0) {xbee.read();}
//delay(1000);
//while(xbee.available() > 0) {Serial.write(xbee.read());}
String ok_response = "OK\r"; // The response we expect
// Read the text of the response into the response variable
// This satisfies the guard time by waiting for the OK message
String response = String("");
while (response.length() < ok_response.length()) {
if (xbee.available() > 0) {
response += (char) xbee.read();
}
}
Serial.println("response1: " + response);
// If we got received OK, configure the XBee and return true:
if (response.equals(ok_response)) {
Serial.println("Enter command mode successful");
// Restore to default values:
Serial.println("Restoring default values before making changes");
xbee.write("ATRE\r");
Serial.println("Setting addr high");
xbee.write("ATDH0\r"); // Destination high
//while(xbee.available() > 0) {Serial.write(xbee.read());}
Serial.println("Setting addr low");
xbee.write("ATDL1\r"); // Destination low-REPLACE THIS
//while(xbee.available() > 0) {Serial.write(xbee.read());}
Serial.println("Setting MY address");
xbee.write("ATMYFFFF\r");
// Apply changes:
Serial.println("Applying changes");
xbee.write("ATAC\r");
/*
///////////////////////////////////////////////
// Write to non-volatile memory:
// Use similar technique as above to satisfy guard time
Serial.write("Saving\r");
xbee.write("ATWR\r");
String response2 = String("");
//while (xbee.available() > 0) {Serial.write(xbee.read());}
while (response2.length() < ok_response.length()) {
if (xbee.available() > 0) {
response2 += (char) xbee.read();
}
}
Serial.println("response2: " + response2);
if (response2.equals(ok_response)) {
Serial.println("Save successful");
}
else { Serial.println("Save not successful");
return false;
}
// And reset module:
Serial.println("Resetting");
xbee.write("ATFR\r");
///////////////////////////////////////////////
*/
Serial.write("Exit command mode\r");
xbee.write("ATCN\r"); // Exit command mode
//while(xbee.available() > 0) {Serial.write(xbee.read());}
Serial.write("Finished\r");
return true;
} else {
return false; // This indicates the response was incorrect
}
}
void setup() {
Serial.begin(9600); // Begin serial
configured = configureRadio();
}
void loop() {
// Test transmission:
if (configured) {
xbee.print(c);
Serial.print(c);
c = c + 1;
if (c > 'Z') { c = 'A'; }
}
else {
Serial.println("Not configured (in loop)");
delay(5000);
Serial.println("Retrying configuration");
configured = configureRadio();
}
delay(1500);
}

Resources