How can I implement interrupt for serial USART communication for ATmega328P/Arduino Nano? - arduino

I have a small project for school that requires me to load data in the EEPROM of an ATmega328P through the USART serial communication. I'm going to figure out the EEPROM read/write myself.
I have problems sending data using interrupts. Basically, I want to have the Arduino Nano loop through code and when I send something through the USART serial communication using the serial monitor of the Arduino IDE, an interruption will occur and the data that was send will be saved in a variable.
My clock is 16 MHz, with a baud rate of 9600; and as I've said I'm using the Arduino IDE.
Here is what I've tried so far:
#define USART_BAUDRATE 9600
#define MYUBRR (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
void setup() {
UCSR0B = (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes
UBRR0H = (MYUBRR >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRR0L = MYUBRR; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
UCSR0B |= (1 << RXCIE0); // Enable the USART Receive Complete interrupt (USART_RXC)
sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
}
// Interrupt on receive
ISR (USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR0; // Fetch the received byte value into the variable "ByteReceived"
UDR0 = ReceivedByte; // Echo back the received byte back to the computer
}
// Use the eeprom() function to read/write to EEPROM
void loop() {
}
I've copied and adapted the code from this site (first post).
(In the UCSR0C register, there is no URSEL bit that is mentioned in this post - the datasheet does not mention it and it gives me an error when I try to use it.)
But it seems that the interruption (as it is presented in the last part of the post) is not working for me. I've tested to see if I can read and write in the serial monitor using the following code:
while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte; // Echo back the received byte back to the computer
But this makes the controller wait for a data to be sent through the serial monitor, and then it prints it in the serial monitor. I do not want this behaviour.
Here is the datasheet that I've used to check my code: ATmega328P datasheet
Did I do something wrong? Did I forget something in my implementation of USART serial communication interrupt? What is actually wrong with my implementation? why is it not working?

I think you're going wrong here:
ISR (USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR0; // Fetch the received byte value into the variable "ByteReceived"
UDR0 = ReceivedByte; // Echo back the received byte back to the computer
}
In the above code you're basically saying UDR0 = UDR0. You need to give some time between these two lines of code in order to obtain the desired effect. If you take a look at the AVR freaks link you posted, they have this line in between:
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it

Related

How do make code compatible to ESP32 board?

I'm trying to get a GY-US-42 ultrasonic sensor working on the ESP32. However, I keep getting an error while compiling. For and Arduino Board it is not a problem, but for the ESP32.
My code:
#include "Wire.h"
//The Arduino Wire library uses the 7-bit version of the address, so the code example uses 0x70 instead of the 8-bit 0xE0
#define SensorAddress byte(0x70)
//The sensors ranging command has a value of 0x51
#define RangeCommand byte(0x51)
//These are the two commands that need to be sent in sequence to change the sensor address
#define ChangeAddressCommand1 byte(0xAA)
#define ChangeAddressCommand2 byte(0xA5)
void setup() {
Serial.begin(115200); //Open serial connection at 9600 baud
Wire.begin();
// changeAddress(SensorAddress,0x40,0);
}
void loop(){
takeRangeReading(); //Tell the sensor to perform a ranging cycle
delay(50); //Wait for sensor to finish
word range = requestRange(); //Get the range from the sensor
Serial.print("Range: "); Serial.println(range); //Print to the user
}
//Commands the sensor to take a range reading
void takeRangeReading(){
Wire.beginTransmission(SensorAddress); //Start addressing
Wire.write(RangeCommand); //send range command
Wire.endTransmission(); //Stop and do something else now
}
//Returns the last range that the sensor determined in its last ranging cycle in centimeters. Returns 0 if there is no communication.
word requestRange(){
Wire.requestFrom(SensorAddress, byte(2));
if(Wire.available() >= 2){ //Sensor responded with the two bytes
byte HighByte = Wire.read(); //Read the high byte back
byte LowByte = Wire.read(); //Read the low byte back
word range = word(HighByte, LowByte); //Make a 16-bit word out of the two bytes for the range
return range;
}
else {
return word(0); //Else nothing was received, return 0
}
}
Error:
sketch/GY-US42_I2C.ino.cpp.o:(.literal._Z12requestRangev+0x0): undefined reference to `makeWord(unsigned short)'
sketch/GY-US42_I2C.ino.cpp.o: In function `requestRange()':
/Users/Arduino/GY-US42_I2C/GY-US42_I2C.ino:42: undefined reference to `makeWord(unsigned short)'
collect2: error: ld returned 1 exit status
The word() is for casting a variable or literal into a 16-bit word, it does not add two bytes into a 16-bit word as you do word(HighByte, LowByte), I'm actually surprise this even compiled in Arduino.
To get the range value, you could do:
int range = HighByte * 256 + LowByte;
or:
int range = ((int)HighByte) << 8 | LowByte; //cast HighByte to int, then shift left by 8 bits.
But since Wire.read() is returning an int instead of a byte(you can see its function prototype definition here), therefore you code can actually be written like this:
int reading = Wire.read(); //read the first data
reading = reading << 8; // shift reading left by 8 bits, equivalent to reading * 256
reading |= Wire.read(); // reading = reading | Wire.read()
By the way, when you use #define, you don't need to specifically cast the const value into specific data type, the compiler will take care of the optimization and the right data type, so:
#define SensorAddress byte(0x70)
would be just fine by defining like this:
#define SensorAddress 0x70
You also do not need to cast const value with byte(2) or return word(0). In the latter case, your function prototype already expect the return would be a data type of word.

Don't display repeated data output on serial monitor of arduino

In this code i am taking the TID data(20bytes of 160bits) in the form of array according to the sparkfun(manufacture) documentation and RFID tag detection code and its working correctly and getting the output of RFID tags.
Now I just need your guidance that how can i stop displaying RFID tag ID which is already displayed on serial monitor of arduino. What should i have to do!
Arduino code:
/*Reading multiple RFID tags, simultaneously!
TIDs are 20 bytes, 160 bits*/
#include <SoftwareSerial.h> //Used for transmitting
SoftwareSerial softSerial(2, 3); //RX, TX
#include "SparkFun_UHF_RFID_Reader.h" //Library for controlling the M6E Nano module
RFID nano; //Create instance
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println();
Serial.println("Initializing...");
if (setupNano(38400) == false) //Configure nano to run at 38400bps
{
Serial.println("Module failed to respond. Please check wiring.");
while (1); //Freeze!
}
nano.setRegion(REGION_NORTHAMERICA); //Set to North America
nano.setReadPower(1000); //10.00 dBm.
nano.enableDebugging(); //Turns on commands sent to and heard from RFID module
}
void loop()
{
/*Serial.println(F("Get one tag near the reader. Press a key to read unique tag ID."));
while (!Serial.available()); //Wait for user to send a character*/
Serial.read(); //Throw away the user's character
byte response;
byte myTID[20]; //TIDs are 20 bytes
byte tidLength = sizeof(myTID);
//Read unique ID of tag
response = nano.readTID(myTID, tidLength);
if (response == RESPONSE_SUCCESS)
{
Serial.println("TID read!");
Serial.print("TID: [");
for(byte x = 0 ; x < tidLength ; x++)
{
if(myTID[x] < 0x10) Serial.print("0");
Serial.print(myTID[x], HEX);
Serial.print(" ");
}
Serial.println("]");
}
else
Serial.println("Failed read");
}
//Gracefully handles a reader that is already configured and already reading continuously
//Because Stream does not have a .begin() we have to do this outside the library
boolean setupNano(long baudRate)
{
nano.begin(softSerial); //Tell the library to communicate over software serial port
softSerial.begin(baudRate); //For this test, assume module is already at our desired baud rate
while(!softSerial); //Wait for port to open
while(softSerial.available()) softSerial.read();
nano.getVersion();
if (nano.msg[0] == ERROR_WRONG_OPCODE_RESPONSE)
{
//This happens if the baud rate is correct but the module is doing a ccontinuous read
nano.stopReading();
Serial.println(F("Module continuously reading. Asking it to stop..."));
delay(1500);
}
else
{
//The module did not respond so assume it's just been powered on and communicating at 115200bps
softSerial.begin(115200); //Start software serial at 115200
nano.setBaud(baudRate); //Tell the module to go to the chosen baud rate. Ignore the response msg
softSerial.begin(baudRate); //Start the software serial port, this time at user's chosen baud rate
}
//Test the connection
nano.getVersion();
if (nano.msg[0] != ALL_GOOD) return (false); //Something is not right
//The M6E has these settings no matter what
nano.setTagProtocol(); //Set protocol to GEN2
nano.setAntennaPort(); //Set TX/RX antenna ports to 1
return (true); //We are ready to rock
}
That is what you should do in your application program.
The basic specifications of the RFID reader and RFID tag are to notify all tags within the reading range when reading is requested.
Please incorporate the following procedures / functions into the application.
The tag data notified from the RFID reader is stored for each reading.
By the next reading, the tag data notified this time is compared with previously notified data.
Tag data that has already been received is not displayed.
Please decide the interval and the number of times to keep record of tag data and compare it according to your specifications and requirements.
In the case of tags conforming to ISO/IEC 18000-63, duplication notification can not be made within a certain period by specifying a parameter called S flag at the time of reading request.
However, since the detailed behavior depends on the specifications of individual tags and the operating environment, use of the S flag is not recommended.

Can UDR be written inside USART_RXC interrupt handler without checking the UDRE flag in AVR ATMega32?

I have been trying to understand this code which is supposed to echo each byte received on the AVR's USART interface using interrupt.
#include
#include
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
int main (void)
{
UCSRB = (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
UCSRB |= (1 << RCXIE); // Enable the USART Recieve Complete interrupt (USART_RXC)
sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
for (;;) // Loop forever
{
// Do nothing - echoing is handled by the ISR instead of in the main loop
}
}
ISR(USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
UDR = ReceivedByte; // Echo back the received byte back to the computer
}
I'm having troubles understanding this part
ISR(USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
UDR = ReceivedByte; // Echo back the received byte back to the computer
}
Why isnt the UDRE flag checked here to see if indeed new data can be written, without overwriting previous data? Since we do the same thing in the corresponding polling approach:
while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte; // Echo back the received byte back to the computer
Shouldn't there be a checking for the UDRE flag before the UDR = ReceivedByte; line inside the ISR too?
Any insights would be much appreciated.
Short answer is - yes: you can write UDR in any time you want, without any checks ahead.
But, if output buffer is full (the UDRE flag in UCSRA is not set) then written data will be ignored by the transmitter, or, in other words, it will be lost.
The USART module have a double output buffer. That means it is possible to write there two bytes ahead: one is being transmitted right now and one in the buffer will be transmitted later. UDRE flags show when the buffer byte is empty, while TXC flag shows when transmitting byte is pulled out.
So, if you have a way to be sure the transmitter buffer will not be overrun, then it is possible not to check that flag at all. Since receiving of the byte requires exactly the same time as transmitting, you can be sure that RXC interrupts will not be happened more often than bytes will be transmitted, so, it if UDR is not written elsewhere, it is possible to assume that output buffer can always accept at least one-byte, when RXC interrupt happens.
Still, if UDR is written somewhere else, it is possible that output buffer will not be empty, when RXC interrupt is happened, so transmitted echo byte will be lost.
At the other hand, the good programming practice is to leave interrupt handlers as soon as possible. Putting wait loops in the interrupt handler routine is a bad idea. In that case, if you can not be sure the output buffer will be empty on the RXC event, better to either have some kind of output buffer in RAM, which will be processed in UDRE interrupt, or to perform echo outside the RXC interrupt.

Programming Arduino with ADXL345 to raise interrupt on inactivity

I need to use a sparkfun breakout board ADXL345 to detect when my motor system has stopped vibrating. I am also using a Sparkfun RedBoard (Arduino uno).
Things I am doing to configure for this behavior:
enable INACTIVITY event
route INACTIVITY events to INT 1 (pin 2 on the RedBoard)
raise INACTIVITY interrupt without delay
set low threshold for INACTIVITY (rule out too high of a setting)
INACTIVITY considers all axes
clear interrupt data register
Having done all these things I do not receive interrupts after going from shaking the devise to setting it down.
//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>
//Assign the Chip Select signal to pin 10.
int CS=10;
//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D; //Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32; //X-Axis Data 0
char DATAX1 = 0x33; //X-Axis Data 1
char DATAY0 = 0x34; //Y-Axis Data 0
char DATAY1 = 0x35; //Y-Axis Data 1
char DATAZ0 = 0x36; //Z-Axis Data 0
char DATAZ1 = 0x37; //Z-Axis Data 1
char THRESH_ACT = 0x24; // Activity threshold
char THRESH_INACT = 0x38; // Inactivity threshold to 3g
char TIME_INACT = 0x26; // time before raising interrupt
char INT_ENABLE = 0x2E; // Enabling the interrupt lines
char INT_MAP = 0x2F;
char ACT_INACT_CTL = 0x27; // mask byte for controlling
char INT_SOURCE = 0x30;
//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;
void setup(){
//Initiate an SPI communication instance.
SPI.begin();
//Configure the SPI connection for the ADXL345.
SPI.setDataMode(SPI_MODE3);
//Create a serial connection to display the data on the terminal.
Serial.begin(9600);
//Set up the Chip Select pin to be an output from the Arduino.
pinMode(CS, OUTPUT);
//Before communication starts, the Chip Select pin needs to be set high.
digitalWrite(CS, HIGH);
// Create an interrupt that will trigger when inactivity is detected
attachInterrupt(0, interruptHandler, RISING);
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
writeRegister(DATA_FORMAT, 0x01);
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
writeRegister(POWER_CTL, 0x08); //Measurement mode
// Send the inactivity && activity to PIN 1
// 0xF7 && 0xEF
writeRegister(INT_MAP,0xF7 && 0xEF);
// Set the inactivity threshold to 3g (0x38)
// writeRegister(THRESH_INACT,0x38);
writeRegister(THRESH_INACT,1);
// Raise the inact interrupt immediately after going below threshold
writeRegister(TIME_INACT,0);
// Map INACT event (only) to PIN 1
writeRegister(ACT_INACT_CTL, 0x0F);
// Enab le inactivity to generate interrupts
writeRegister(INT_ENABLE, 0x08);
readRegister(INT_SOURCE, 1, values); // Clear the INT_SOURCE register
Serial.println("Waiting for interrupt!");
}
void interruptHandler(){
// readRegister(INT_SOURCE, 1, values); // Clear the INT_SOURCE register
Serial.println("something raise an interrupt!");
}
void loop(){
//Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
//The results of the read operation will get stored to the values[] buffer.
readRegister(DATAX0, 6, values);
//The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
//The X value is stored in values[0] and values[1].
x = ((int)values[1]<<8)|(int)values[0];
//The Y value is stored in values[2] and values[3].
y = ((int)values[3]<<8)|(int)values[2];
//The Z value is stored in values[4] and values[5].
z = ((int)values[5]<<8)|(int)values[4];
//Print the results to the terminal.
Serial.print(x, DEC);
Serial.print(',');
Serial.print(y, DEC);
Serial.print(',');
Serial.println(z, DEC);
delay(500);
}
//This function will write a value to a register on the ADXL345.
//Parameters:
// char registerAddress - The register to write a value to
// char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
//Set Chip Select pin low to signal the beginning of an SPI packet.
digitalWrite(CS, LOW);
//Transfer the register address over SPI.
SPI.transfer(registerAddress);
//Transfer the desired register value over SPI.
SPI.transfer(value);
//Set the Chip Select pin high to signal the end of an SPI packet.
digitalWrite(CS, HIGH);
}
//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
// char registerAddress - The register addresse to start the read sequence from.
// int numBytes - The number of registers that should be read.
// char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
//Since we're performing a read operation, the most significant bit of the register address should be set.
char address = 0x80 | registerAddress;
//If we're doing a multi-byte read, bit 6 needs to be set as well.
if(numBytes > 1)address = address | 0x40;
//Set the Chip select pin low to start an SPI packet.
digitalWrite(CS, LOW);
//Transfer the starting register address that needs to be read.
SPI.transfer(address);
//Continue to read registers until we've read the number specified, storing the results to the input buffer.
for(int i=0; i<numBytes; i++){
values[i] = SPI.transfer(0x00);
}
//Set the Chips Select pin high to end the SPI packet.
digitalWrite(CS, HIGH);
}
Here is a tutorial, arduino library and example sketch. If you haven't run through something like this, might be worth a try starting with someone else's code that is working (maybe you've already done that).
In the example sketch from above, they are enabling interrupts in the code, they just don't seem to tie them into the Arduino's external interrupt system. Once you verify that the example code is working, you can call attachInterrupt() and abandon the polling approach (as you are doing in your example).

xbee: receive messages from an interrupt

I intend to read the data received by the xbee in an interrupt handler.
But as the handler can not use delays, I can not use readPacket (100).
I have the following code:
#include <XBee.h>
#include <avr/power.h>
#include <avr/sleep.h>
XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
ZBRxResponse rx = ZBRxResponse();
int size;
uint8_t buffer[256];
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
xbee.begin(Serial1);
attachInterrupt(0, wake_up_now, LOW );
}
void wake_up_now() {
xbee.readPacket();
if(xbee.getResponse().isAvailable()){
if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
xbee.getResponse().getZBRxResponse(rx);
size = rx.getDataLength();
for (int i = 0; i < size; i++)
buffer[i] = rx.getData(i);
}
}
}
void sleepNow() {
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();
sleep_mode();
sleep_disable();
power_all_enable();
}
void loop() {
Serial.print("Awake");
Serial.println(size);
for (int i = 0; i < size; i++)
Serial.println(buffer[i]);
Serial.println("Entering Sleep mode");
delay(100);
sleepNow();
}
If you receive data the first time I can not read this data.
But later, when more data is received the data that was sent in the first message is read.
I really need to read the data in the handler, how can I solve this?
When I designed this ANSI C XBee Host library, I thought I could include frame processing as part of the serial interrupt handler on the Freescale HCS08 platform. I found that it just didn't work well, especially at a baud rate of 115,200.
The final design I went with was to keep a buffer of bytes from the serial port, and parse/dispatch frames in a "tick" function called in my main event loop. In one application, I was calling the "tick" function at least once every 50ms (IIRC).
As for forcing the XBee module to buffer serial data while you're sleeping, I think you'll have a hard time with that. You'd need to deassert RTS, but then wait to see if the XBee was still sending you a byte. My recollection is that I would still get multiple bytes (3 or 4?) after deasserting RTS. You'll also have to handle the condition of getting a partial packet while you're awake, and needing to decide whether you'll receive the whole frame then, or the next time you wake up.
You'd probably be better off using the XBee module's SPI interface, since the host controls when bytes are sent, and it might even be possible to have the XBee trigger a hardware interrupt on the host when it has bytes to send. You can also use high speeds (460kbps and up, I believe) to get the bytes quickly.

Resources