How to make 2 pieces of code run at the same time

Hello, I'm trying to record a short video for an experiment with an ArduCam Mini 5MP Plus, but the experiment involves having a servo turn on.

This event is the major catalyst for the experiment, so I need the camera to record it as the servo starts but I'm not sure how to get the servo code to not interrupt the camera recording. I've searched up how to use threads in C++, but the explanations are confusing and not really related to hardware.

Does anybody have any ideas on how I should go about coding this? I'm just a beginner so please forgive me if I don't understand right away. Thank you.

What is arduino board are you using?
Some boards has more than one core and can handle some tasks independently. But most cannot perform more than one task at the same time - then you need to use time sharing if your tasks allow it.

You can always use 2 arduinos

1 Like

I'm using an arduino uno with a data-logging shield

This experiment actually has to go into a reallllly tiny box because this is going to go on a rocket with 50 something other experiments, so I highly doubt I'll be able to find a microcontroller small enough for the little space I have left. If you have any ideas though, please let me know.

On Uno there is no way to execute two codes at the same time. The only option is to rewrite your two codes into one

You can easily control your servo with ATtiny85

What does at the same time mean ?

Why can you not have 1 piece of code run for 1ms then the other for 1ms . . . . . . . etc. :roll_eyes:

Perhaps @hk-47 could explain why none of the time worn methods for doing multiple things at the same time, or nearly so as @LarryD points out, will work in this case.

@hk-47 please share the two sketches that need to run "at the same time".

If simple software can't do it, then use multiple processors as @killzone_kid said. There are some very small boards that are only small in size, not capability.

a7

Well, for starters, there is only one port available and I'm not allowed to use batteries, so I'm not sure if the two microcontroller idea would even be feasible.

The first sketch which is the camera running is right here:

// This sketch modifies the example: ArduCAM_Mini_2MP_Plus_Multi_Capture2SD
#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include <SD.h>
#include "memorysaver.h"
//This demo can only work on OV5640_MINI_5MP_PLUS or OV5642_MINI_5MP_PLUS platform.
#if !(defined (OV2640_MINI_2MP_PLUS))
#error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif
#define FRAMES_NUM 0x06
// set pin 7 as the slave select for the digital pot:
const int CS = 7;
//ETCG Note -- Modify this for what your shield/module for the SD Card
#define SD_CS 10
bool is_header = false;
int total_time = 0;
#if defined (OV2640_MINI_2MP_PLUS)
ArduCAM myCAM( OV2640, CS );
#endif
uint8_t read_fifo_burst(ArduCAM myCAM);
//ETCG Note -- RTC/ Real Time Clock Code
#include <DS3231.h>
DS3231 rtc(SDA, SCL);
void setup() {
//ETCG Note -- RTC/ Real Time Clock Code
rtc.begin();
uint8_t vid, pid;
uint8_t temp;
#if defined(SAM3X8E)
Wire1.begin();
#else
Wire.begin();
#endif
Serial.begin(115200);
Serial.println(F("ArduCAM Start!"));
// set the CS as an output:
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
// initialize SPI:
SPI.begin();
//Reset the CPLD
myCAM.write_reg(0x07, 0x80);
delay(100);
myCAM.write_reg(0x07, 0x00);
delay(100);
while (1) {
//Check if the ArduCAM SPI bus is OK
myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
temp = myCAM.read_reg(ARDUCHIP_TEST1);
if (temp != 0x55)
{
Serial.println(F("SPI interface Error!"));
delay(1000); continue;
} else {
Serial.println(F("SPI interface OK.")); break;
}
}
#if defined (OV2640_MINI_2MP_PLUS)
while (1) {
//Check if the camera module type is OV2640
myCAM.wrSensorReg8_8(0xff, 0x01);
myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 ))) {
Serial.println(F("ACK CMD Can't find OV2640 module!"));
delay(1000); continue;
}
else {
Serial.println(F("ACK CMD OV2640 detected.")); break;
}
}
#endif
//Initialize SD Card
while (!SD.begin(SD_CS))
{
Serial.println(F("SD Card Error!")); delay(1000);
}
Serial.println(F("SD Card detected."));
//Change to JPEG capture mode and initialize the OV5640 module
myCAM.set_format(JPEG);
myCAM.InitCAM();
myCAM.clear_fifo_flag();
myCAM.write_reg(ARDUCHIP_FRAMES, FRAMES_NUM);
unsigned long start = millis ();
while(millis () - start <= 660000) { // for 11 minutes
// put your main code here, to run repeatedly:
myCAM.flush_fifo();
myCAM.clear_fifo_flag();
#if defined (OV2640_MINI_2MP_PLUS)
myCAM.OV2640_set_JPEG_size(OV2640_1600x1200);
#endif
//Start capture
myCAM.start_capture();
Serial.println(F("start capture."));
total_time = millis();
while ( !myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
Serial.println(F("CAM Capture Done."));
total_time = millis() - total_time;
Serial.print(F("capture total_time used (in miliseconds):"));
Serial.println(total_time, DEC);
total_time = millis();
read_fifo_burst(myCAM);
total_time = millis() - total_time;
Serial.print(F("save capture total_time used (in miliseconds):"));
Serial.println(total_time, DEC);
//Clear the capture done flag
myCAM.clear_fifo_flag();
delay(5000);
}
}
void loop(){
//empty
}
uint8_t read_fifo_burst(ArduCAM myCAM)
{
uint8_t temp = 0, temp_last = 0;
uint32_t length = 0;
static int i = 0;
static long k = 0;
char str[16];
File outFile;
byte buf[256];
length = myCAM.read_fifo_length();
Serial.print(F("The fifo length is :"));
Serial.println(length, DEC);
if (length >= MAX_FIFO_SIZE) //8M
{
Serial.println("Over size.");
return 0;
}
if (length == 0 ) //0 kb
{
Serial.println(F("Size is 0."));
return 0;
}
myCAM.CS_LOW();
myCAM.set_fifo_burst();//Set fifo burst mode
i = 0;
while ( length-- )
{
temp_last = temp;
temp = SPI.transfer(0x00);
//Read JPEG data from FIFO
if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
{
buf[i++] = temp; //save the last 0XD9
//Write the remain bytes in the buffer
myCAM.CS_HIGH();
outFile.write(buf, i);
//Close the file
outFile.close();
Serial.println(F("OK"));
is_header = false;
myCAM.CS_LOW();
myCAM.set_fifo_burst();
i = 0;
}
if (is_header == true)
{
//Write image data to buffer if not full
if (i < 256)
buf[i++] = temp;
else
{
//Write 256 bytes image data to file
myCAM.CS_HIGH();
outFile.write(buf, 256);
i = 0;
buf[i++] = temp;
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
}
else if ((temp == 0xD8) & (temp_last == 0xFF))
{
is_header = true;
myCAM.CS_HIGH();
//ETCG Note -- Create Filename
long timeStamp = rtc.getUnixTime(rtc.getTime());
timeStamp = timeStamp - 1600000000;
Serial.println(timeStamp);
String fileName = String(timeStamp) + ".jpg";
Serial.println(fileName);
//Open the new file
outFile = SD.open(fileName, O_WRITE | O_CREAT | O_TRUNC);
if (! outFile)
{
Serial.println(F("File open failed"));
while (1);
}
myCAM.CS_LOW();
myCAM.set_fifo_burst();
buf[i++] = temp_last;
buf[i++] = temp;
}
}
myCAM.CS_HIGH();
return 1;
}

The second piece of code is the servo and lights turning on:

#include <Servo.h>
Servo servo;
int LEDs_pin = 8;
void setup() {
servo.attach(9);
pinMode(LEDs_pin, OUTPUT);
digitalWrite(LEDs_pin, HIGH);
}
void loop() {
for(int i=0;i<180; i++){
servo.write(i);
delay(7);
}
for(int i=180; i>0; i--){
servo.write(i);
delay(7);
}
}

I had no idea you could run one code and then run another for 1ms without resetting either of the codes, so I'm sorry if my questions might have seemed stupid. Would any of you mind showing me an example of how to do this?

Entertain yourself with your friend google

arduino blink without delay

and

arduino two things at once

and

arduino finite state machine

and

arduino finite state machine traffic lights

No time spent doing that will be a waste.

I would have said right away, but "everyone" was just saying it couldn't be done. Which I assumed meant I was missing something about the particular burdens the two things you trying to do would present.

a7

What?

When you post your code, please use code tags as mentioned in the sticky.

Which ones??

I know about esp32 and rp2040.
There may be others

1 Like

Then what is your power source? Windmills?

When you post your code, please use CTRL-T as mentioned in the sticky to autoformat your code indentations.

The ESP32 has 2 processors. The main processor has 2 cores. The OS of the ESP32 is freeRTOS a multi tasking / multi processing OS.

I'm trying to do the same thing. I want my arduino to run a song through the buzzer and move forward at the same time. I'm using an arduino uno on a chassis with motors. I'm using a battery. Any suggestions? (BTW, I'm using arduino 1.8.16, because I can't use 2.0)

Then, start your own thread. See the sticky post at the top of the forum "how to post a question".

I see that in your sketch you have a while loop that runs for 11 minutes. You could do the same in loop() and after 11 minutes enter an infinite while loop. This would make it easier to manage running the servo at the same time.

You will need to use millis() to determine when to execute the camera code vs servo movement. However, you have to make sure that the camera code DOES NOT take more than 7 milliseconds!
If it does you may have to create another cycle timer and split it into 2 parts. In simplest terms you would have something like:

const unsigned long totalMs = 660000;  // 11 minutes
const unsigned long cameraCycleMs = 5000;
const unsigned long servoCycleMs = 7;
unsigned long startMs;
unsigned long prevCameraMs;
unsigned long prevServoMs;

void setup()
{
  // All of your setup stuff
  startMs = millis();
  prevCameraMs = millis();
  prevServoMs = millis();
}

void loop() 
{
  unsigned long currMs = millis();
  
  // Check to see if we are done
  if (currMs - startMs > totalMs) while(1);
  
  // Time to do camera stuff?
  if (currMs - prevCameraMs > cameraCycleMs)
  {
    prevCameraMs = currMs;
    // do camera stuff
    // !!! Make sure camera stuff doesn't take more than servoCycleMs!!!
  }

  // Time to do servo stuff?
  if (currMs - prevServoMs > servoCycleMs)
  {
    prevServoMs = currMs;
    
    // do camera stuff
  }
}