Hello everyone, I am trying to program 9 clock signals in Arduino UNO or Arduino Mega:
Each clock signal depends on two Inputs (one general switch and one particular switch for each signal).
I need that the frequencies could change from 5k to 8 kHz with a potentiometer.
I need that the program last for many hours.
So, the problems begin here:
I was using delays to keep the High or Low state for each signal, but I realized too late that the delay function is not recommendable because stops all the process of the Arduino which affects every frequency, duty cycle and period of the signals.
Then I decided to use the function micros in different loop functions (called by the main void loop) to avoid the problem that I mentioned above. The program with only 9 different signals worked well, but when I added the conditionals for each clock, the Low and High times were affected, giving a wrong frequency again (For a theorical 5 kHz, the oscilloscope shows a 2.6 kHz frequency approximately).
I suppose that the time in which the conditionals instructions are read is too long that affects my High and Low times. Is there any other option to reduce these times? or the problem is something completely different? In addition, I haven't put the code for the analog read from the potentiometer, and I supposse that this will affect the signals too.
I'm using an unsigned long variable to save the value of the micros() function, but this only can reach to the 4,294,967,295 number right? which means 4,294,967,295 microseconds or 1.19 hours. How can I avoid this time restriction? The added code will affect the times of the signals too, right?
Thank you everyone in advance.
This is my program:
int Delay_uSec=80;
int ON=1;
int OFF=0;
//______________Uno____________________
// IDE Physical Pin
int General_Enable=19; // Digital19, An5 28
int Input1=0; // Digital0 2
int Input2=1; // Digital1 3
int Input3=2; // Digital2 4
int Input4=3; // Digital3 5
int Input5=4; // Digital4 6
int Input6=5; // Digital5 11
int Input7=6; // Digital6 12
int Input8=7; // Digital7 13
int Input9=8; // Digital8 14
int Output1=18; // Digital18, Analog4 27
int Output2=17; // Digital17, Analog3 26
int Output3=16; // Digital16, Analog2 25
int Output4=15; // Digital15, Analog1 24
int Output5=14; // Digital14, Analog0 23
int Output6=12; // Digital12 18
int Output7=11; // Digital11 17
int Output8=10; // Digital10 16
int Output9=9; // Digital9 15
void setup()
{
pinMode(General_Enable,INPUT);
pinMode(Input1,INPUT);
pinMode(Input2,INPUT);
pinMode(Input3,INPUT);
pinMode(Input4,INPUT);
pinMode(Input5,INPUT);
pinMode(Input6,INPUT);
pinMode(Input7,INPUT);
pinMode(Input8,INPUT);
pinMode(Input9,INPUT);
pinMode(Output1,OUTPUT);
pinMode(Output2,OUTPUT);
pinMode(Output3,OUTPUT);
pinMode(Output4,OUTPUT);
pinMode(Output5,OUTPUT);
pinMode(Output6,OUTPUT);
pinMode(Output7,OUTPUT);
pinMode(Output8,OUTPUT);
pinMode(Output9,OUTPUT);
}
void loop()
{
loop_1();
loop_2();
loop_3();
loop_4();
loop_5();
loop_6();
loop_7();
loop_8();
loop_9();
}
void loop_1()
{
static unsigned long t_last_change=0; //64 bits, 4,294,967,295 us, 1.19 hours
static int HLState=OFF;
unsigned long t_now=micros();
if ( (digitalRead(General_Enable)==HIGH) && (digitalRead(Input1)==LOW)&& (t_now-t_last_change > Delay_uSec))
{
t_last_change=t_now;
HLState=!HLState;
digitalWrite(Output1,HLState);
}
}
// ...
void loop_9()
{
static unsigned long t_last_change=0;
static int HLState=OFF;
unsigned long t_now=micros();
if ( (digitalRead(General_Enable)==HIGH) && (digitalRead(Input9)==LOW)&& (t_now-t_last_change > Delay_uSec))
{
t_last_change=t_now;
HLState=!HLState;
digitalWrite(Output9,HLState);
}
}
Do you mean that each clock will be individually adjustable (9 potentiometers), or will they all have the same frequency (1 potentiometer)?
Your code seems to allow for only 1 frequency, controlled by Delay_uSec, but has a t_last_change variable for each of the 9 clocks. This means the clocks will be almost but not exactly in phase with each other.
Are the phases of the 9 clocks important at all, assuming they are all the same frequency?
Using 9 loopN() functions, each with its own t_last_change variable is inefficient, if all the clocks are the same frequency, and phase does not matter. This could be why you can't achieve the higher frequencies.
A much, much easier way to achieve this could be to use the tone() function. However, only one pin can be used with tone() at any time. A couple of external chips like 74hc595 could be used to create up to 16 clocks that have same frequency & phase but are individually controllable on/off.
Should should not use pins 0 & 1 on Uno/Mega. They are used for uploading your sketch and the serial monitor. Attaching external circuits to them can cause malfunctions or even damage if you do not know exactly what you are doing.
Also, your sketch is 9 times longer than it should be. You should learn to use arrays.
Bear in mind that only using analogRead, this is going to be very difficult, if not impossible, because the maximum rate you can read an analogue input is just less than 9kHz.
(A workaround is possible)
You could read enable pin once before all loops instead of in each loop. That would save you 8 digitalRead.
You can read multiple inputs in one go by reading the register. That saves a lot of time, but your code will only work on one specific type of controller then.
Same with digitalwrite...
If you want to go this way you should not make an array but store your output and states in a byte (since you have 9, you will need two bytes or one int).
You can save the state HLstate in a bool or byte (an int is two bytes and a 8 bit processor will need multiple clock cycles to process an int (compiler may be able to take shortcuts here).
The issue with analogRead() is that it takes about 100 microseconds. As said, it can be speeded up, but having it in your program will slow things down.
I think I understand what changes you made, but no-one else can test or improve on your code if you don't post the whole code.
Did you read my post #4?
You could avoid using pins 0 & 1 if you can save a few pins. One way to do that would be to connect your switches in a 3x3 matrix. If they are SPDT switches, you will need to wire a small diode (e.g 1N4148) in series with each switch. Using a matrix will save you 3 pins, so no need to use pins 0 & 1.
How important is it that your clock signals are steady, with low or no jitter? If that's important, you may need to use a hardware timer to control the output pins. That way, the code to create the clock signals can continue in the background independent of the the rest of your code which is reading analog inputs, scanning a key matrix etc.
Using hardware timers and fast gpio libraries will make your code less portable to other types of Arduino. Even moving from Uno to Mega may require some adjustments. This could be the price you have to pay to achieve your project.
the timer condition is met every PeriodUsec (80). each output has a tic counter which decremented to zero toggles the output. the Tics() macro determines the # of tics -- timer events -- for toggling each output.
5kHz has a period of 200 usec and toggled every 100usec. 100 usec / PeriodUsec is 1. so with this crude timing, that output would be toggled every timer expiration or every 80 usec (which isn't very accurate). 8kHz requires 62.5 usec
you could have separate timers for each output, but then how much processing can be performed while achieving some minimal loop timing.
knowing the exact frequencies of each output may determine a particular value that works for all outputs