Hello!
I am working with the code below (the full code at the bottom of the post). It strobes a light on and off at a set frequency, which is displayed on a screen in hz (flashes per second)
The length of time the led is on per flash cycle is known as the "duty-cycle". In the code it is referred to as the 'pulse-length'.
So if it is set to 1hz, that is 1 flashes per second. A 50% duty-cycle means it will flash on for .5 seconds, and off for .5 seconds. A 10% duty cycle means it would flash on for .1 seconds, then turn off for the remaining .9 seconds.
Right now, to help achieve a true 'strobe' effect, the code is setup to not let the duty-cycle go over 10%. For the purpose of my project, I need the duty-cycle to always be 50%.
In addition, it looks like the current duty cycle is based on a set length in microseconds, and doesn't change along with the hz adjustment. So for example, if it is set to 1hz, and the duty-cycle is set to 64mu...
If I change it to 10hz, the duty-cycle will still be 64mu, not a % of the cycle duration.
byte len=5; //pulselength in units of 64 microseconds
//set frequency in Hz, pulse length in units of 64mus
void setfreq(int f, int len){
//calculate what to put into the timing registers
long unsigned int ticks=(160000000+f/2)/f; // f_clock/0.1f
unsigned int ps=1;
if (ticks> 0xFFFF)ps= 8;
if (ticks> 8*0xFFFF)ps= 64;
if (ticks> 64*0xFFFF)ps= 256;
if (ticks>256*0xFFFF)ps=1024;
unsigned int val_ICR1=ticks/ps-1;
unsigned int val_OCR1B=len*(1024/ps)-1;
unsigned int val_TCCR1B=B00011001;
if (ps== 8) val_TCCR1B=B00011010;
if (ps== 64) val_TCCR1B=B00011011;
if (ps== 256) val_TCCR1B=B00011100;
if (ps==1024) val_TCCR1B=B00011101;
//set the actual values in the timing registers
//noInterrupts();
if (TCNT1>val_ICR1)TCNT1=0; //do not allow timer to exceed 'top'
ICR1=val_ICR1;
OCR1B=val_OCR1B;
TCCR1B=val_TCCR1B;
//interrupts();
}
What I'd like to do:
I would like to alter this code so that the duty-cycle is always 50% of the total cycle. Any idea where a starting point is for this?
I admit, I'm a bit lost with what the author of this code is doing with the timers, and where he is getting the current 'len', so I am open and appreciative of any ideas, thank you!
// Stroboscope with 4-digit 7-segment display
// The display can be directly soldered to the Arduino Nano on pins A0-A5, D4-D9
// the frequency can be changed with two push-buttons
// the pulselength can be changed by pressing both buttons simultaneously
//for common anode display
#define DIGON HIGH
#define DIGOFF LOW
#define SEGON LOW
#define SEGOFF HIGH
//for common cathode display
//#define DIGON LOW
//#define DIGOFF HIGH
//#define SEGON HIGH
//#define SEGOFF LOW
const byte ndig=4;
const byte nseg=8;
//breadboard setup
const byte digs[ndig] = { 9, 6, 5,A0}; // digs 1 2 3 4
const byte segs[nseg] = { 8, 4, A2, A4, A5, 7,A1, A3}; // segs ABCDEFGH
//nano setup
//const byte digs[ndig] = { 4, 7, 8,A0}; // digs 1 2 3 4
//const byte segs[nseg] = { 5, 9,A2,A4,A5, 6,A1,A3}; // segs ABCDEFGH
const byte button_up=12;
const byte button_dw=11;
//translate number into corresponding segements
const byte val2seg[12]={
B11111100, //0
B01100000, //1
B11011010, //2
B11110010, //3
B01100110, //4
B10110110, //5
B10111110, //6
B11100000, //7
B11111110, //8
B11110110, //9
B00000000, //nothing
B01001110, //mu
};
int freq=50; //frequency in units of 0.1Hz
byte len=5; //pulselength in units of 64 microseconds
void setup() {
//setup TIMER1B for fast PWM with (output on pin D10)
TCCR1A=B00100010;
TCCR1B=B00011000;
setfreq(freq,len);
pinMode(10,OUTPUT);
// set to output and switch off all digits
for (byte idig=0; idig<ndig; idig++){
pinMode(digs[idig], OUTPUT);
digitalWrite(digs[idig],DIGOFF);
}
// set to output and switch off all segments
for (byte iseg=0; iseg<nseg; iseg++){
pinMode(segs[iseg], OUTPUT);
digitalWrite(segs[iseg],SEGOFF);
}
//set the pushbuttons to input with pull-up
pinMode(button_up,INPUT_PULLUP);
pinMode(button_dw,INPUT_PULLUP);
}
//set frequency in Hz, pulse length in units of 64mus
void setfreq(int f, int len){
//calculate what to put into the timing registers
long unsigned int ticks=(160000000+f/2)/f; // f_clock/0.1f
unsigned int ps=1;
if (ticks> 0xFFFF)ps= 8;
if (ticks> 8*0xFFFF)ps= 64;
if (ticks> 64*0xFFFF)ps= 256;
if (ticks>256*0xFFFF)ps=1024;
unsigned int val_ICR1=ticks/ps-1;
unsigned int val_OCR1B=len*(1024/ps)-1;
unsigned int val_TCCR1B=B00011001;
if (ps== 8) val_TCCR1B=B00011010;
if (ps== 64) val_TCCR1B=B00011011;
if (ps== 256) val_TCCR1B=B00011100;
if (ps==1024) val_TCCR1B=B00011101;
//set the actual values in the timing registers
//noInterrupts();
if (TCNT1>val_ICR1)TCNT1=0; //do not allow timer to exceed 'top'
ICR1=val_ICR1;
OCR1B=val_OCR1B;
TCCR1B=val_TCCR1B;
//interrupts();
}
//set a digit to a certain value
void setdig(byte dig, byte val, bool dot){
//switch off all digits
for (byte idig=0; idig<ndig; idig++){
digitalWrite(digs[idig],DIGOFF);
}
//set the segments
for (byte iseg=0; iseg<nseg; iseg++){
if ((val2seg[val]&(1<<(nseg-1-iseg)))>0){
digitalWrite(segs[iseg], SEGON);
} else {
digitalWrite(segs[iseg], SEGOFF);
}
}
// set the decimal dot if needed
if (dot){
digitalWrite(segs[7], SEGON);
} else{
digitalWrite(segs[7], SEGOFF);
}
//set the digit
digitalWrite(digs[dig],DIGON);
}
byte dispdig=0;
byte prevbutstat=0;
unsigned long millis_butchanged=0;
unsigned long millis_valchanged=0;
void loop() {
//check for buttons
long unsigned millis_current=millis();
bool change=false;
byte butstat=(digitalRead(button_up)==LOW)*1+(digitalRead(button_dw)==LOW)*2;
if (butstat!=prevbutstat)millis_butchanged=millis_current;
int dt=200; int df=1;
if (millis_current-millis_butchanged>1000)dt=100;
if (millis_current-millis_butchanged>2000)dt=50;
if (millis_current-millis_butchanged>3000)dt=20;
if (millis_current-millis_butchanged>4000)dt=10;
if (millis_current-millis_butchanged>5000)dt=5;
if (millis_current-millis_butchanged>6000)dt=2;
if (millis_current-millis_butchanged>7000)dt=1;
if (millis_current-millis_butchanged>8000)df=2;
if (millis_current-millis_butchanged>9000)df=5;
if (millis_current-millis_butchanged>10000)df=10;
if (butstat==3)dt=1000;
if(millis_current-millis_valchanged>dt){
if(butstat==1) freq=freq+df;
if(butstat==2) freq=freq-df;
if(butstat==3) len++;
if(butstat>0){
change=true; millis_valchanged=millis_current;
}
}
prevbutstat=butstat;
//keep frequency and pulselength wihin allowed domain
freq=max(freq,3);
freq=min(freq,9999);
if (len>50)len=1;
if (len*freq>15625)len=1; //corresponds to 0.1 duty cycle
if (change) setfreq(freq,len);
//display a digit
byte val=10; // by default nothing
if (butstat==3){
if (dispdig==0 and len>1)val=((len*64)/100)%10;
if (dispdig==1)val=((len*64)/10)%10;
if (dispdig==2)val=(len*64)%10;
if (dispdig==3)val=11; //the symbol mu
} else {
if (dispdig==0 and freq>999)val=(freq/1000)%10;
if (dispdig==1 and freq>99)val=(freq/100)%10;
if (dispdig==2)val=(freq/10)%10;
if (dispdig==3)val=freq%10;
}
setdig(dispdig,val,(dispdig==2 and butstat!=3));
delayMicroseconds(100);
dispdig=(dispdig+1)%ndig;
}
For reference, here is the project and site it is from: https://www.instructables.com/Portable-Precision-Stroboscope/
I have this built on my workbench and functioning without the 50% duty-cycle that I'm after