I am working with an Arduino on a project for which timing is very important. I use TimerOne to trigger timer interrupts and use micros() for delays (delayMicroseconds() was causing problems worse than the one explained below). The program is sending a manual PWM signal to an LED and it is very important that the signal is sent with an error that is less than 8 microseconds (ideally, the signal is sent at the same time in each period). My test code is shown below:
#include <TimerOne.h>
#include <SPI.h>
const int LED_PIN = 3;
const int CHIP_SELECT = 12;
const int PERIOD = 4000;
const double DUTY_CYCLE = .5;
const int HIGH_TIME = PERIOD * DUTY_CYCLE;
const int LOW_TIME = PERIOD - HIGH_TIME;
const int INITIAL_SIGNAL_DELAY = LOW_TIME / 2;
const int HIGH_TIME_TOTAL_DELAY = INITIAL_SIGNAL_DELAY + HIGH_TIME;
const int RESISTOR_VALUE = 255;
boolean triggered = false;
boolean data = false;
unsigned long triggeredTime;
unsigned long s;
unsigned long e;
boolean found;
int i = 0;
void setup()
{
s = micros();
Timer1.initialize(PERIOD);
Timer1.attachInterrupt(trigger);
pinMode(LED_PIN, 3);
pinMode(CHIP_SELECT, OUTPUT);
SPI.begin();
digitalWrite(CHIP_SELECT, LOW);
SPI.transfer(B00010001);
SPI.transfer(RESISTOR_VALUE);
digitalWrite(CHIP_SELECT, HIGH);
e = micros();
Serial.begin(115200);
Serial.print("s: ");
Serial.println(s);
Serial.print("e: ");
Serial.println(e);
}
void loop()
{
if(triggered)
{
while(micros() - triggeredTime < INITIAL_SIGNAL_DELAY)
{ }
s = micros();
digitalWrite(LED_PIN, data);
while(micros() - triggeredTime < HIGH_TIME_TOTAL_DELAY)
{ }
digitalWrite(LED_PIN, LOW);
data = !data;
triggered = false;
e = micros();
//micros();
if(s % 100 > 28 || s % 100 < 12)
{
found = true;
}
if(!found)
{
Serial.print("s: ");
Serial.println(s);
}
else
{
Serial.print("ERROR: ");
Serial.println(s);
}
//Serial.print("e: ");
//Serial.println(e);
}
}
void trigger()
{
triggeredTime = micros();
triggered = true;
}
(it should be noted that the first signal sent is always xx20, usually 5020).
So, with this code, I eventually get an error. I am not sure why, but this error occurs at the same point every single time:
.
.
.
s: 1141020
s: 1145020
s: 1149020
ERROR: 1153032
ERROR: 1157020
ERROR: 1161020
.
.
.
Now, the really weird part is if I remove the comments before micros() (the micros() right after e = micros()), there is no error (or at least there is not an error within the first 30 seconds). I was wondering if anybody could provide an explanation for why this happens. I have dedicated many hours trying to get the timing working properly and everything was working well until I encountered this error. Any help would be very much appreciated. Thank you!
Related
It's my first time learning arduino uno and I do not know what to do
const int ledPin = LED_BUILTIN;
int ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 1000;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
for(int interval = 500; interval >= 20; interval++)
previousMillis = currentMillis;
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(ledPin, ledState);
}
}
The delay for every interval the led turns On and Off increases by 1 seconds everytime the loop restarts.
Please make sure you ask your question in the question itself, not the title and also give us some more information about what you're trying to accomplish, what's working and what isn't working so we can help.
If I understand correctly, you want the LED to stay on longer and longer each time it blinks. First cycle 1 second, second cycle 2 seconds, third cycle 3 seconds, etc. You are pretty close, just need some tweaking of your logic.
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) { //Check if LED duration has expired
//Toggle LED
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
interval += 1000; //Increase the interval by 1 second
digitalWrite(ledPin, ledState); //Set the LED
previousMillis = currentMillis; //Set the time of the last transition to now
}
}
I wanted to make a servomotor oscilate between 0-90 degrees when i push a button, but when i push another one, it stops oscillating and then remains in its latest position.
i started with this:
#include <Servo.h>
Servo myservo;
int pos = 0;
const int button1 = 5;
const int button2 = 6;
int lastpos = pos;
void setup() {
myservo.attach(3);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
}
void loop() {
if(digitalRead(button1) == HIGH)
{for(pos = 0; pos <= 90; pos += 1)
{myservo.write(pos);
for(pos = 90; pos >= 0; pos -= 1)
{myservo.write(pos);
delay(36);
} } if(digitalRead(button2) == HIGH){ myservo.write(lastpos);}}}
To start, take a look at how to format code inside a question. It makes it a lot easier to read and help you out. See below for how I formatted for the site, but also readability.
Servo myservo;
int pos = 0;
const int button1 = 5;
const int button2 = 6;
int lastpos = pos;
void setup() {
myservo.attach(3);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
}
void loop() {
if(digitalRead(button1) == HIGH) {
for(pos = 0; pos <= 90; pos += 1) {
myservo.write(pos);
for(pos = 90; pos >= 0; pos -= 1) {
myservo.write(pos);
delay(36);
}
}
if(digitalRead(button2) == HIGH) {
myservo.write(lastpos);
}
}
}
There are several issues with your code based on your description of what you are trying to achieve. First, let's start with the button presses. You are ready the button state, but your code will only detect the button if it is pressed at the exact moment you are doing the digital read. Here's a good resource for reading up on how to properly implement buttons on Arduino: https://www.logiqbit.com/perfect-arduino-button-presses
The second objective is to have the servo sweep back and forth, but stop when you press a button. Your for loops won't let that happen. As currently written, you will always do a sweep to one end and back and then check the next button.
You should update the position of the servo once each time through the loop so you can check on the status of the buttons. In pseudo-code, what I suggest you do is:
void loop() {
//Check button statuses
if(button1), start sweep
if(button2), stop sweep
//Update sweep position
if(ascending && pos < 90) {
//You should be increasing in angle and you haven't reached 90 yet
ascending = TRUE;
pos += 1
myservo.write(pos);
delay(36); //Or whatever delay you need for the servo
} else if(pos > 0) {
//You already reached 90 and are coming back down to 0
ascending = FALSE;
pos -= 1;
delay(36);
}
I have some code that generates an acoustic timeseries using a 2nd order 1 dimensional differential equation.
I decided to use boost::odeint to integrate the equations, but because this is being used ina real-time simulation, I need to generate a small number of steps repeatedly.
The code is of the following form:
class Integrator
{
public:
typedef std::vector<double> state_type;
//This is how boost::odeint wants it to look
/* NOTE: We have to cast our second order diff eq into a set of first-order diff eqs
because ODEINT only handles first order ODEs.
*/
void operator() ( const state_type &x , state_type &dxdt , const double t )
{
dxdt[0] = x[1];
//... Bunch of calculations here to determine dxdt and ddxdt
dxdt[1] = ddxdtTerm;
}
state_type x_state;
state_type dxdt_state;
std::vector<double> x_buffer;
std::vector<double> time_buffer;
double time;
};
struct IntegrationObserver
{
std::vector<double> & xVals;
std::vector<double> & tVals;
IntegrationObserver(std::vector<double> & in_xVals,
std::vector<double> & in_tVals) :
xVals(in_xVals),
tVals(in_tVals)
{
}
void operator()( const std::vector<double> &x , double t )
{
xVals.push_back( x[0] );
tVals.push_back( t );
}
};
I then have an acoustics generation thread that generates 100ms of acoustic data once every tenth of a second (at 22050 Hz):
std::vector<Integrator> g_intVec;
void audioBufferGeneratorThread()
{
std::cout << "Hello from the audio buffer generator thread!" << std::endl;
Uint32 lastTime = SDL_GetTicks();
Uint32 thisTime = lastTime;
size_t acousticBufsize = 0.1 * 22050;
float* acousticWorkBuffer = new float[acousticBufsize];
memset(acousticWorkBuffer, 0, acousticBufsize * sizeof(float));
while(!g_terminating)
{
bool didWork = false;
//Check time elapsed, have we seen 0.10 seconds pass?
thisTime = SDL_GetTicks();
double t_add = (thisTime - lastTime) / 1000.0;
//For each integrator
if(t_add >= 0.1){
t_add = 0.1;
lastTime = thisTime;
didWork = true;
{
std::lock_guard<std::mutex> guard(g_integratorMutex);
int bubIdx = 0;
for(auto integrator : g_intVec)
{
//Only generate a maximum 1 second of acoustics for each integrator...
//Main thread deletes integrators once they reach
if(integrator.t_sec >= 1.0)
{
continue;
}
size_t steps;
boost::numeric::odeint::runge_kutta4<BubbleIntegrator::state_type> stepper;
//Generate some audio
steps = boost::numeric::odeint::integrate_const(stepper,
integrator,
integrator.x_state,
integrator.t_sec,
integrator.t_sec + t_add,
1.0/22050.,
integratorObserver(integrator.x_buffer, integrator.time_buffer );
integrator.t_sec += t_add;
bubIdx++;
}
//Sum all the audio together
g_integratorMutex.unlock();
}
{
// std::lock_guard<std::mutex> guard(g_audioBufferMutex);
//Push the audio to the audio buffer
}
memset(acousticWorkBuffer, 0, acousticBufsize * sizeof(float));
}
//Yield the thread if we didn't generate any acoustics.
else
{
std::this_thread::yield();
}
}
delete acousticWorkBuffer;
std::cout << "Goodbye from the audio buffer generator thread..." << std::endl;
}
As one can see, this code is meant to store the previous X and DXDT states, as well as the current time, so that the integrator can pick up where it left off later.
However, the problem appears to be that the integrator is calculating from t=0 every time, so each advance through the acoustics generator loop takes longer and longer until the code is no longer able to generate the acoustics in realtime (i.e. generate 100ms of acoustics in under 100ms of code time).
It appears that I'm using the odeint library incorrectly, but I am unable to find a proper example of how to do what I'm trying to do here: generate the first 100ms of data, then the next 100ms, then the next, etc...
So my question is thus:
How can I use boost::odeint to generate sequential chunks of the equation without it starting from t=0 each time?
The true time it takes from when I send the first bit to a serial port to when I receive the last bit it pings back I measured to be 6ms but ReadFile takes around 70-80ms. I'm wondering if this is expected, is this just Windows or is it my code at fault? Here's the function to send and read from the serial port, in my main I have declared and initialized the HANDLE and called that function.
int sendBytes(char* command, char* COM, HANDLE hSerial, int read) {
BOOL Write_Status;
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Write_Status = GetCommState(hSerial, &dcbSerialParams); //retreives the current settings
if (Write_Status == FALSE) {
printf("\n Error! in GetCommState()");
CloseHandle(hSerial);
return 1;
}
dcbSerialParams.BaudRate = CBR_57600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
Write_Status = SetCommState(hSerial, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Write_Status == FALSE)
{
CloseHandle(hSerial);
return 1;
}
///*----------------------------- Writing a Character to Serial Port----------------------------------------*/
int length = strlen(command);
char send[20];
strcpy(send, command);
send[length + 1] = 13;
send[length + 2] = 10;
DWORD dNoOFBytestoWrite; // No of bytes to write into the port
DWORD dNoOfBytesWritten = 0; // No of bytes written to the port
dNoOFBytestoWrite = length + 2; // Calculating the no of bytes to write into the port
if (!WriteFile(hSerial, send, dNoOFBytestoWrite, &dNoOfBytesWritten, NULL))
printf("Error writing text to %s\n", COM);
if (read) {
int maxChars = 100;
BOOL Read_Status; // Status of the various operations
DWORD dwEventMask; // Event mask to trigger
char SerialBuffer[100]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
///*------------------------------------ Setting Receive Mask ----------------------------------------------*/
Read_Status = SetCommMask(hSerial, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (Read_Status == FALSE)
printf("\n\n Error! in Setting CommMask");
// else
// printf("\n\n Setting CommMask successfull");
///*------------------------------------ Setting WaitComm() Event ----------------------------------------*/
// printf("\n\n Waiting for Data Reception");
Read_Status = WaitCommEvent(hSerial, &dwEventMask, NULL); //Wait for the character to be received
// /*-------------------------- Program will Wait here till a Character is received ------------------------*/
if (Read_Status == FALSE)
{
printf("\n Error! in Setting WaitCommEvent()");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
// printf("\n\n Characters Received \t");
clock_t begin = clock();
if (!ReadFile(hSerial, SerialBuffer, 24, &NoBytesRead, NULL))
{
printf("wrong character");
return 1;
}
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("time : %f\n",time_spent);
}
}
}
This is not how you measure timing with sub-second precision:
clock_t begin = clock();
// stuff
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
This is how you measure timing:
LARGE_INTEGER before, after, frequency;
QueryPerformanceCounter(&before);
// stuff
QueryPerformanceCounter(&after);
QueryPerformanceFrequency(&frequency);
double time_spent = (after.QuadPart - before.QuadPart) / (double)frequency.QuadPart;
CLOCKS_PER_SEC is imprecise, and then clock() can be even worse, often as bad as the scheduler quantum which is typically 10ms or 15ms.
I am working on an Arduino stopwatch, where it needs a start, stop, and reset button. To reset it, I am using a variable called starttime that is updated to equal to millis(), and then take the difference to display time. However, past thirty seconds, the starttime does not update correctly, and the resulting difference between starttime and millis() is equivalent to 65 seconds. Can someone explain why this is happening?
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int start = 8;
const int stp = 9;
const int reset = 10;
int seconds;
int minutes;
int timedif;
int starttime = -1;
int timestall = 0;
bool onoff = true;
void setup()
{
pinMode(start, INPUT);
pinMode(stp, INPUT);
pinMode(reset, INPUT);
lcd.begin(16, 2); //Initialize the 16x2 LCD
lcd.clear(); //Clear any old data displayed on the LCD
Serial.begin(9600);
}
void loop()
{
int bsta = digitalRead(start);//sees if start switch is pressed
int bstp = digitalRead(stp);//records if stop switch is pressed
int bres = digitalRead(reset);//records if reset switch is pressed
lcd.setCursor(0,0);
lcd.print("Stopwatch");//prints stopwatch top row
lcd.setCursor(0,1);
if (starttime == -1) { //if running first time, time dif is initiated
starttime = millis();
}
timedif = (millis() - starttime )/1000 + timestall; //will get difference in terms of seconds
minutes = floor(timedif/60); // divides by sixty, drops decimal
seconds = timedif%60; //gets remainder of divided by 60
lcd.print(minutes);
lcd.print(":");
lcd.print(seconds);
if (seconds < 10) {
lcd.setCursor(3,1);
lcd.print(' ');
}
if (bstp == HIGH) {
onoff = false;
while(onoff == false) {
if (digitalRead(start) == HIGH) {
onoff = true;
}
}
timestall = timedif;
starttime = millis();
}
if (bres == HIGH) {
delay(100);
timestall = 0;
starttime = millis();
timedif = 0;
lcd.clear();
Serial.println("stall:");
Serial.println(timestall);
Serial.println("dif");
Serial.println(timedif);
Serial.println("start");
Serial.println(millis() - starttime);
}
}
You should use long or unsigned long instead if int to declare variables that hold time values.
A int variable can only hold 32,767 millisecond hence the 32 sec. where a long variable can hold 2,147,483,647 millisecond which is something like 48 days. A unsigned long can hold double of that but can not hold a negative value.