I am using FreeRTOS and would like to get the name of the task being executed and print it. How can I extract the name of the task being executed from the handler and print it. For example, I have the following task being executed. I tried printing out the name as follows -
void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;
TaskHandle_t xHandle;
TaskStatus_t xTaskDetails;
// initialize digital LED_BUILTIN on pin 13 as an output.
pinMode(LED_BUILTIN, OUTPUT);
for (;;) // A Task shall never return or exit.
{
xHandle = xTaskGetHandle( "Task_Name" );
Serial.println(xHandle);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
}
}
But I get the error - Compilation error: no matching function for call to 'println(TaskControlBlock_t*&)'
Edit - Apprarently, I had to update the USE_TRACE_FACILITY flag to 1 in FreeRTOSConfig.h as per this link but I now get the the error -
Blink_AnalogRead/Blink_AnalogRead.ino:80: undefined reference to `xTaskGetHandle'
Why the compilation error
It seems that you have a little confusion about how the xTaskGetHandle works. Per documentation
TaskHandle_t xTaskGetHandle( const char *pcNameToQuery );
And returns:
If a task that has the name passed in pcNameToQuery can be located then the handle of the task is returned, otherwise NULL is returned.
Now, apparently you already have the name of the task (in the universal conception that the name is a sequence of characters) and you are using, so it's unclear what you want to get.
Anyway, the function returns a TaskHandle_t which is not a string, hence when you pass such type to the println function the compilation fails because it is expecting a string like object.
Get task name
In order to get the task name from the handler you need the function vTaskGetInfo and the struct TaskStatus_t .
Here's how you do it in your function:
void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;
TaskHandle_t xHandle;
TaskStatus_t xTaskDetails;
// initialize digital LED_BUILTIN on pin 13 as an output.
pinMode(LED_BUILTIN, OUTPUT);
for (;;) // A Task shall never return or exit.
{
xHandle = xTaskGetHandle( "Task_Name" );
TaskStatus_t xTaskDetails;
/* Check the handle is not NULL. */
configASSERT( xHandle );
/* Use the handle to obtain further information about the task. */
vTaskGetInfo( /* The handle of the task being queried. */
xHandle,
/* The TaskStatus_t structure to complete with information
on xTask. */
&xTaskDetails,
/* Include the stack high water mark value in the
TaskStatus_t structure. */
pdTRUE,
/* Include the task state in the TaskStatus_t structure. */
eInvalid );
Serial.println(xTaskDetails.pcTaskName);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
}
}
Related
My goal is to test individual servos for a project I'm doing.
Which may have faulty servos or bad wiring,
though the program I created for testing simply asks and returns an integer from input, then attaches a servo to it. But fails to return the correct value.
Code:
#include <Servo.h>
Servo s;
int pin;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("Enter Pin");
}
void loop() {
// Getting Input
while (Serial.available() == 0) {}
pin = Serial.parseInt();
Serial.println(pin); // returns value given. <-- this is where it breaks and always returns "0".
//attaching servo
s.attach(pin);
// Testing Servo
s.write(90);
delay(1000);
s.write(0);
}
Your code works fine but it reads '\n' (EOL) character and parses it to 0.
Calling parseInt with SKIP_ALL and ignore '\n' helps to solve the issue:
pin = Serial.parseInt(SKIP_ALL, '\n');
I have an example piece of code and I want to print the variables to the log, specifically a variable named &results I wrote a line in the code at the end of void loop() to print the variable to the serial print out.
This isn't the full code but a large segment at least.
{
Serial.begin(9600);
Serial.println("IR Receiver Button Decode");
irrecv.enableIRIn(); // Start the receiver
}/*--(end setup )---*/
void loop() /*----( LOOP: RUNS CONSTANTLY )----*/
{
if (irrecv.decode(&results)) // have we received an IR signal? &results is
the variable
Serial.println(&results) //<-- My line of code
{
translateIR();
irrecv.resume(); // receive the next value
}
}/* --(end main loop )-- */
I expected the output to be the variable's content but it spat out no matching function for call to "println(decode_results*)" whilst compiling.
You can't simply use Arduino's print to print C structs. You can only print simple C data types like float, String, int, etc. So you need to print each field of your struct separately. I don't know decode_results but you can print its fields with something like this:
{
Serial.begin(9600);
Serial.println("IR Receiver Button Decode");
irrecv.enableIRIn(); // Start the receiver
} /*--(end setup )---*/
void loop() /*----( LOOP: RUNS CONSTANTLY )----*/
{
if (irrecv.decode(&results)) // have we received an IR signal? &results is the variable
{
Serial.print("Results: ");
Serial.print(results.field1); // first field
Serial.print(" , ");
Serial.println(results.field2); // second field
}
translateIR();
irrecv.resume(); // receive the next value
} /* --(end main loop )-- */
I'm having some trouble completely debouncing a button attached to to an interrupt. The goal is to have the statement in the void loop() run exactly once when the button is pressed/released.
What usually ends up happening is one of two things
The ISR flag is set once when the button is pressed. Releasing the button does nothing, as intended.
The ISR flag is set once when the button is pressed, and once more when the button is released.
Here is the exact code I have:
#define interruptPin 2
#define DBOUNCE 100
volatile byte state = LOW; //ISR flag, triggers code in main loop
volatile unsigned long difference;
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(115200);
}
void loop() {
if(state){ //If we have a valid interrupt
Serial.println(difference); //Print the time since the last ISR call
state = LOW; //Reset the flag
}
}
void ISR_0() {
static unsigned long last_interrupt = 0;
if(millis()-last_interrupt > DBOUNCE && digitalRead(interruptPin)){
difference=millis()-last_interrupt;
state = HIGH;
}
last_interrupt = millis(); //note the last time the ISR was called
}
This seems to be a popular way to debounce an interrupt, but for whatever reason it isn't working for me.
I was hoping on the first falling edge of the button release that digitalRead(interruptPin) would read low, so the state flag would not be set.
Since the ISR updates the last_interrupt time, the successive bounces after the first falling edge still seem to be successfully ignored. This leads me to believe the debouncing is not the issue, but the digitalRead(interruptPin) is.
The debouncing seems to take care of all but one state. When the button is released, the code still occasionally sets the state flag to HIGH.
Here's some sample output:
3643 (after waiting ~3.6 seconds from boot, I press the button, releasing it ~1 second later)
In the same scenario as above, the output occasionally looks like this:
3643
1018
This shows me pressing the button, but also releasing the button.
I'm using an UNO R3 and a momentary tactile push button with a 1k pull-down resistor.
I'm not sure what's going wrong at this point. I hope this is simple enough that anyone can easily test this on their arduino if they feel so inclined.
You can always do debouncing in the hardware
I've encountered bounce several times with buttons and encoders, and doing debouncing in the software can get messy and lead to unreadable code or logic errors.
The easiest thing you can do is add a 0.1 uF capacitor, as illustrated:
The Arduino has hysteresis inputs, and if you use 10K as your pullup then this works for bounce that is under 1ms. This is my favorite approach.
If you wanna get more serious, a wonderful pdf exists on the internet with lots of examples and explanations: A Guide to Debouncing
You use the internal pullup resistor of the Uno, but also a pulldown resistor on the button itself. That's not correct, you can only use one of of them.
Inside the if, you want the input to be high, so use the pulldown resistor and change INPUT_PULLUP into INPUT.
(to make things clear: the resistor is connected between input pin and ground, the button between input pin and +5V)
[edit]
I think when the ISR is called, the status of interruptPin might be changed again.
Due to the slowness of digitalRead, compared to the (possible) spike.
I'm not sure if this is what you want, but the example below is working.
(I've enabled the LED for testing purposes).
One thing: keep the button pressed at least the debounce time (100msec), otherwise it won't work.
Not ideal, but that's the price you have to pay if you want instantly response on a switch.
#define interruptPin 2
#define DBOUNCE 100
volatile byte state = LOW; //ISR flag, triggers code in main loop
volatile unsigned long difference;
bool hasPrinted = false;
void setup() {
pinMode(interruptPin, INPUT);
pinMode (13, OUTPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(115200);
}
void loop() {
digitalWrite(13, state);
if (!hasPrinted) {
Serial.println(difference);
hasPrinted = true;
}
}
void ISR_0() {
static unsigned long last_interrupt = 0;
if(millis()-last_interrupt > DBOUNCE){
state = !state;
hasPrinted = false;
difference = millis()-last_interrupt;
}
last_interrupt = millis(); //note the last time the ISR was called
}
Debouncing buttons/switches in interrupts is a hassle.
I faced a (sort of) similar situation with limit switches.
The moment a limit switch is hit, something has to occur - so interrupt.
However the interrupt would fire when the limit switch was released as well which was a problem. I had my interrupt set to fire on a FALLING edge.
Anyhow, I wound up debouncing outside of the interrupt, using flags.
The code explains it but:
Switch is hit, ISR runs (does what it needs to) and sets an ISR flag.
The ISR flag stops the ISR from actually doing anything until it's cleared.
In the main loop, call a debounce function if the ISR flag is set.
the debounce function will wait until a pin/switch is stable at the required state (HIGH/LOW) for a predefined time, then clear ISR flag, allowing the ISR to do something again.
#define interruptPin 2
#define DEBOUNCE_TIME 100L
volatile bool ISR_ACTIVATED = false;
volatile bool display_int_time = false;
bool debounce_started = false;
unsigned long Isr_debounce_pin_timer;
volatile unsigned long difference;
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(112500);
}
void loop() {
if (display_int_time) {
Serial.println(difference); //Print the time since the last ISR call
// Right, done with interrupt stuff. clear the interrupt flag
display_int_time = false;
}
// Call debounce ISR routine in main loop
if (ISR_ACTIVATED)
ISR_ACTIVATED = !debounce(interruptPin, HIGH, Isr_debounce_pin_timer);
}
bool debounce(int debounce_pin, bool state, unsigned long &state_latch_start) {
// debounce_pin - what pin are we debouncing?
// state - should the stable state be HIGH or LOW
// state_latch_start - when we 'latched' on to a (possibly) stable state
static bool current_state;
// Read the required pin
current_state = digitalRead(debounce_pin);
// Is the pin at the required state, and we have not yet 'latched' it?
if ((!debounce_started) && (current_state == state)) {
// 'latch' this state (ie take note of when the pin went to the required level)
state_latch_start = millis();
debounce_started = true;
}
// Have we 'latched', but the pin has bounced
if (debounce_started && (current_state != state))
// unlatch
debounce_started = false;
// Have we latched, the pin is at the required level and enough time has passed (ie pin is stable)
if (debounce_started && (current_state == state) && (((unsigned long)(millis() - state_latch_start)) >= DEBOUNCE_TIME)) {
// cool. unlatch
debounce_started = false;
// report back that all is goood.
return(true);
}
// Blast. Either the pin is at the wrong level, or is still bouncing. Tell the boss to try again later!
return(false);
}
void ISR_0() {
static unsigned long last_interrupt = 0;
if((millis()-last_interrupt > DEBOUNCE_TIME) && digitalRead(interruptPin) && !ISR_ACTIVATED){
difference=millis()-last_interrupt;
//state = HIGH;
ISR_ACTIVATED = true;
display_int_time = true;
}
last_interrupt = millis(); //note the last time the ISR was called
}
*** Just a note, edited my code to incorporate the debounce time in your original ISR to ensure that the interrupt is valid. I had not read the comment regarding your noisy environment
I suppose the main issue, as was said in the comments, is because you have no actual debounce.
So, after the button is released, it continues to bounce, causing logic level on the input pin to change. If at the moment, when the pin state is latched for the digitalRead(), the state was read as high, then the whole condition will be met and state = HIGH; will be performed.
I'm not an artist, but I did my best to draw this timing diagram:
So, to avoid this, you can utilize any simple approach to debounce. Most simple one is to read again the pin state after a little timeout, greater than the maximal expected bounce time.
For example, if you're waiting for the button to be pressed and got high logical level (or low if the button is connected to GND), just wait about 5ms and read the level again. Process the button press only if the level still high (low).
And as was said in the other answers, hardware debounce also will help. You can use a higher resistor (actually you need not use external resistor: connect the button to GND and enable the internal pull-up, which is about 35kOhm). And add a capacitor about 1nF, parallel to the button.
My final solution, thanks to #darrob
#define interruptPin 2
#define DEBOUNCE_TIME 50L
//ISR Flags
volatile bool ISR_DEACTIVATED = false;
volatile bool display_int_time = false;
bool debounce_started = false;
unsigned long Isr_debounce_pin_timer;
int x = 0;
void setup() {
pinMode(interruptPin, INPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISR_0, CHANGE);
Serial.begin(112500);
}
void loop() {
//This runs every time we press the button
if (display_int_time) {
Serial.print("X "); //Print the time since the last ISR call
x++;
(x%10==0)?Serial.println(x):Serial.println();
display_int_time = false; //Done with interrupt stuff. Clear the interrupt flag
}
//Debounce for the ISR routine in main loop
if (ISR_DEACTIVATED)
//Wait until the pin settles LOW to reactivate the ISR
ISR_DEACTIVATED = !debounce(interruptPin, LOW, Isr_debounce_pin_timer);
}
//Returns TRUE if pin is stable at desired state, FALSE if bouncing or other state
bool debounce(const int debounce_pin, const bool state, unsigned long &state_latch_start) {
// debounce_pin - what pin are we debouncing?
// state - should the stable state be HIGH or LOW
// state_latch_start - when we 'latched' on to a (possibly) stable state
//If you are calling this routine to debounce multiple pins in the same loop,
// this needs to be defined outside of the function, and passed in as a separate
// parameter for each debounce item (like unsigned long &state_latch_start)
static bool current_state;
// Read the required pin
current_state = digitalRead(debounce_pin);
// Is the pin at the required state, and we have not yet 'latched' it?
if ((!debounce_started) && (current_state == state)) {
// 'latch' this state (ie take note of when the pin went to the required level)
state_latch_start = millis();
debounce_started = true;
}
// Have we 'latched', but the pin has bounced
if (debounce_started && (current_state != state))
// unlatch
debounce_started = false;
// Have we latched, the pin is at the required level and enough time has passed (ie pin is stable)
if (debounce_started && (current_state == state) && (((unsigned long)(millis() - state_latch_start)) >= DEBOUNCE_TIME)) {
// cool. unlatch
debounce_started = false;
// report back that all is goood.
return(true);
}
//Either the pin is at the wrong level, or is still bouncing. Try again later!
return(false);
}
void ISR_0() {
if(!ISR_DEACTIVATED){
ISR_DEACTIVATED = true;
display_int_time = true;
}
}
I'm trying to test NRF24L01+ module with example I've found on web.
Here's my code:
/*
Copyright (C) 2011 J. Coliz <maniacbug#ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example for Getting Started with nRF24L01+ radios.
*
* This is an example of how to use the RF24 class. Write this sketch to two
* different nodes. Put one of the nodes into 'transmit' mode by connecting
* with the serial monitor and sending a 'T'. The ping node sends the current
* time to the pong node, which responds by sending the value back. The ping
* node can then see how long the whole cycle took.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);
//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
//
// Role management
//
// Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing.
//
// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
// The role of the current running sketch
role_e role = role_pong_back;
void setup(void)
{
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
//
// Setup and configure rf radio
//
radio.begin();
// optionally, increase the delay between retries & # of retries
radio.setRetries(15,15);
// optionally, reduce the payload size. seems to
// improve reliability
//radio.setPayloadSize(8);
//
// Open pipes to other nodes for communication
//
// This simple sketch opens two pipes for these two nodes to communicate
// back and forth.
// Open 'our' pipe for writing
// Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
//if ( role == role_ping_out )
{
//radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
//else
{
//radio.openWritingPipe(pipes[1]);
//radio.openReadingPipe(1,pipes[0]);
}
//
// Start listening
//
radio.startListening();
//
// Dump the configuration of the rf unit for debugging
//
radio.printDetails();
}
void loop(void)
{
//
// Ping out role. Repeatedly send the current time
//
if (role == role_ping_out)
{
// First, stop listening so we can talk.
radio.stopListening();
// Take the time, and send it. This will block until complete
unsigned long time = millis();
printf("Now sending %lu...",time);
bool ok = radio.write( &time, sizeof(unsigned long) );
if (ok)
printf("ok...");
else
printf("failed.\n\r");
// Now, continue listening
radio.startListening();
// Wait here until we get a response, or timeout (250ms)
unsigned long started_waiting_at = millis();
bool timeout = false;
while ( ! radio.available() && ! timeout )
if (millis() - started_waiting_at > 200 )
timeout = true;
// Describe the results
if ( timeout )
{
printf("Failed, response timed out.\n\r");
}
else
{
// Grab the response, compare, and send to debugging spew
unsigned long got_time;
radio.read( &got_time, sizeof(unsigned long) );
// Spew it
printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
}
// Try again 1s later
delay(1000);
}
//
// Pong back role. Receive each packet, dump it out, and send it back
//
if ( role == role_pong_back )
{
// if there is data ready
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
unsigned long got_time;
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( &got_time, sizeof(unsigned long) );
// Spew it
printf("Got payload %lu...",got_time);
// Delay just a little bit to let the other unit
// make the transition to receiver
delay(20);
}
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( &got_time, sizeof(unsigned long) );
printf("Sent response.\n\r");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
//
// Change roles
//
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
// Become the primary transmitter (ping out)
role = role_ping_out;
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
else if ( c == 'R' && role == role_ping_out )
{
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
// Become the primary receiver (pong back)
role = role_pong_back;
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
}
}
}
// vim:cin:ai:sts=2 sw=2 ft=cpp
My problem is that after I run this code, on serial port monitor (inside arduino IDE) I'm getting weird chars, it looks like that:
I've tried on two different Arduinos, Nano and Uno (both are Chinese copy), results are the same, so it's probably something with my code.
Can you tell me what is wrong with it?
Here is your mistake:
Serial.begin(57600);
Data rate in bits per seconds (baud) that you set for serial data transmission in Serial.begin() function must match the BAUD rate on the Serial monitor. Change the code to Serial.begin(9600) or the value in the bottom right corner of the serial monitor window to 57600.
I'm working on my first physical computing project with an arduino, well actually a seeduino stalker 2.1. I'm building a device to record water collection rates over time.
Getting the project set up and running hasn't been all that hard, until today that is. Inside the main loop I have a call to the a method that handles the logging. I also now an alarm delay to handle a timer repeat I need in order to summarize data and send it via SMS to a recipient number.
The issue is that when the alarm.repeat() is active it preempts the logging of the data. The question is: why is the logging method inside the loop not working when the alarm.delay is there?
void setup() {
Serial.begin(9600);
Wire.begin();
setTime(1,17,0,1,1,13); // set time
Alarm.timerRepeat(60, Repeats); //set repeater
}
void loop(){
logging(); //call logging
Alarm.delay(1300); //for repeater
}
void Repeats(){
Serial.println("the repeater fired"); // just to see it working
}
void logging(){
val = digitalRead(Sensor_Pin); // read Sensor_Pin
if (val == HIGH) {
// If Sensor N.C. (no with magnet) -> HIGH : Switch is open / LOW : Switch is closed
// If Sensor N.0. (nc with magnet) -> HIGH : Switch is closed / LOW : Switch is open
digitalWrite(Led_Pin, LOW); //Set Led low
//Serial.print("status -->");
//Serial.println("low");
//delay(500);
} else {
digitalWrite(Led_Pin, HIGH); //Set Led high
logdata();
}
}
void logdata(){
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File myFile = SD.open("datalog.txt", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
//DateTime now = RTC.now();
//String myString = readTimestamp(now);
time_t t = now();
String aDate = String(year(t))+"/"+String(month(t))+"/"+String(day(t))+" "+String(hour(t))+":"+String(minute(t))+":"+String(second(t));
myFile.println(aDate);
// close the file:
myFile.close();
Serial.println(aDate);
delay(500); } else {
// if the file didn't open, print an error:
// Serial.println("error opening DATALOG.TXT");
}
}
Q: Why must I use Alarm.delay() instead of delay()? A: Task scheduling
is handled in the Alarm.delay function. Tasks are monitored and
triggered from within the Alarm.delay call so Alarm.delay should be
called whenever a delay is required in your sketch. If your sketch
waits on an external event (for example, a sensor change), make sure
you repeatedly call Alarm.delay while checking the sensor.
From the FAQ of the Alarm library. So it looks like Alarm.Delay is just like the standard delay but can be interrupted by scheduled events. Your logging call isn't scheduled, it just happens at the start of the loop. ..is your logging not happening at all? It looks like it should be called at the start of each loop, then a 1300 delay with your repeater firing during the delay.
On your logdata() function you're calling delay(50) instead of Alarm.delay(50).
As caude pointed, you have to use Alarm.delay when a delay is needed, otherwise the delay will mess up with the alarms.
I think you could have done in other way using timer library. If you say the data has to be logged every second,it easier to done by timer.Example code
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
// a function to be executed periodically
void repeatMe() {
Serial.print("Uptime (s): ");
Serial.println(millis() / 1000);
}
void setup() {
Serial.begin(9600);
timer.setInterval(1000, repeatMe);
}
void loop() {
timer.run();
}