Square wave generation using nano

Hi all,
I am recently working on an approach to generate a square wave from 0 - 5KHZ using arduino nano. After some searching, I came across a program to use tone() to create square wave. But the lower limit is 50hz.

Now I am thinking of using timer1 to create an accurate delay in order to create the square wave. Will this approach create my desired output?. Also, I am having trouble doing calculations using float and double in arduino. Can someone help me out on this. End goal is to get an user input (frequency) and have the nano output the desired square wave.

Thank you,
aaron

Hello
Take a view into the BLINKWITHOUTDELAY example IDE.
Have a nice day and enjoy coding in C++.

You need to post code of up to
where you have got .

This type of project has been done before For example

Since that's not a square wave, wat is your actual lower limit?

Just incidentally, what is "5 KHz"? :face_with_raised_eyebrow:

"Kelvin Hertz?"

"As an SI unit, Hz can be prefixed; commonly used multiples are kHz (kilohertz, 10^3 Hz), MHz (megahertz, 10^6 Hz), GHz (gigahertz, 10^9 Hz) and THz (terahertz, 10^12 Hz)."

But no such thing as "KHz". :rofl:

1 Like

1K==1024 :nerd:

And k is not the same as K. k-kilo, K-not kilo.

Steve

In Computer Science, K is 1024. For example: 1 Kbyte memory means 1024 bytes.

Which, correctly spelled, would still be 'kByte'.

Quote from net:
"A kilobyte (KB or Kbyte) is a unit of measurement for computer memory or data storage used by mathematics and computer science professionals, along with the general public, when referring to amounts of computer data using the metric system."

"KB, MB, GB - A kilobyte (KB) is 1,024 bytes. A megabyte (MB) is 1,024 kilobytes ."

Check Wikipedia; it adheres to SI standards. Your source, apparently TechTarget.com, is not what I would call 'reputable'.

Anyway, shall we forget about semantics for a bit and go back to waiting for OP to provide additional details on their question so they can get help with that?

1 Like

@aaronrenny

Some Hints:

1. To generate squave wave signal, we can operate TC1 in CTC Mode (Mode 4).
pwmAppOscTc1

2. The frequencey can be varied from ~2 Hz to 5 kHz by changing the value of OCR1A register from 65535 to 24. The TC1 clock prescaler is 64.
fpwm = 16^6/(2N(1+OCR1A)) Hz
3. Explore the data sheets and try to compute the values for TCCR1A, TCCR1B, and TCNT1 Registers.

2 Likes

Additionally, to cover the frequencies below 2Hz, a millis()-based approach might be used as suggested by @paulpaulson.

Timer1 can go down to about 0.12 Hz and up to about 8 MHz on a 16 MHz system clock. Is that range good enough? You can also go to 0 Hz by stopping the clock but there are no values between 0 and 0.12.

TCCR1B = (0b101<<CS10); can set the prescaler to /1024 for lower than 2 Hz.

@aaronrenny
Configuring TC1 in CTC Mode-4 to genertae ~2 Hz to 5 kHz square wave signal at OC1A-pin (DPin-9) of Fig-1, 2.
pwmAppOscTc1
Figure-1:
ctcMode4
Figure-2:

1. Clear TCCR1A Register as they are initialized to some values by init() function.
TCCR1Ax
COMbits
Figure-3:

TCCR1A = 0x00;

2. Clear TCCR1B Register for above reason and also to keep TC1 at OFF state.


Figure-4:

TCCR1B = 0x00;

3. Place appropriate values to WGM13 - WGM10 bits of TCCR1A and TCCR1A Registers to set Mode-4 (0100) operation (the CTC Waveform Generation Mode).

bitClear(TCCR1B, WGM13);
bitSet(TCCR1B, WGM12);     //equivalent code is: 1<<WGM12
bitClear(TCCR1A, WGM11);
bitClear(TCCR1A, WGM10);

4. Place appropriate values to COM1A1 and COM1A0 bits of TCCR1A Register so that the signal at DPin-9 (OC1A, Fig-1) toggles at each compare match (point-M, N in Fig-2) to deliver square wave signal. Note that the direction of DPin-9 must be set as OUTPUT.

bitClear(TCCR1A, COM1A1);
bitSet(TCCR1A, COM1A0);       
pinMode(9, OUTPUT);

5. Accepting this equation for the frequency of the signal at DPin-9: f = 16x10^6/(2N(1+OCR1A)), let us choose 64 for N (TC1 clock prescaler) and calculate the value that is to be loaded into OCR1A Register for an initial f = 10 Hz. It is 12499.

OCR1A = 12499;

Given: //Edit

f = 16x10^6/(2N(1+OCR1A))
==> OCR1A + 1 = 16x10^6/(2Nf)
==> OCR1A + 1 = 16000000/(2x64x5000)   //
==> OCR1A + 1 = 12500                                //N = 64, f = 5 kHz
==> OCR1A = 12500 - 1
==> OCR1A = 12499

6. Load initial value of 0x0000 into CTCNT1 Register (software namw for TC1).

TCNT1 = 0x0000;

7. Strat TC1 with clocking frequency of 250 kHz (16^6/N = 16^6/64) by placing appropriate values for the CS12 - CS10 bits of TCCR1B Register.

bitClear(TCCR1B, CS12);
bitSet(TCCR1B, CS11);
bitSet(TCCR1B, CS10);

8. Let us put all the above information in the Arduino sketch as follows:

void setup()
{
  Serial.begin(9600);

  //---- registers are cleared for safety---
  TCCR1A = 0x00;
  TCCR1B = 0x00;

  //----- CTC Mode-4 setting-----
  bitClear(TCCR1B, WGM13);
  bitSet(TCCR1B, WGM12);
  bitClear(TCCR1A, WGM11);
  bitClear(TCCR1A, WGM10);

  //------ signal at DPin-9 will toggle---
  bitClear(TCCR1A, COM1A1);
  bitSet(TCCR1A, COM1A0);
  pinMode(9, OUTPUT);

  //---inital value to set frequency at 10 Hz------
  OCR1A = 12499;  //12499 for 10 Hz; 62499 for 2 Hz
  TCNT1 = 0x0000;

  //---- set Tc1 clock prescaler at /64 and start TC1------
  bitClear(TCCR1B, CS12);
  bitSet(TCCR1B, CS11);
  bitSet(TCCR1B, CS10);
}

void loop() 
{
  
}

9. Connect R1-LED1 with DPin-9 of UNO as per Fig-1.
10. Upload the sketch of Step-7.
11. Check that LED1 is running at 10 Hz speed.
12. Connect the wiper-point of a 5k Pot with UNO as per Fig-1.
13. Include the following codes in the loop() function of the sketch of Step-7. The map() function transforms input value (y) from this range: 0 to 1023 into this range: 65535 to 24.

  unsigned int y = analogRead(A0);
  OCR1A = map(y, 0, 1023, 65535, 24); //value of OCR1A chnages frequency
  delay(1000); //test interval

14. Upload the new sketch in the UNO.
15. Slowly vary the Pot and observe that the blink rate of LED1 changes indicating that the frequency is chnaging.

16. To check the symmetry of the ON and OFF period of the signal at DPin-9, connect an scope at DPin-9. You will observe a good square wave signal.

17. Exercises
(1) Pick up all the codes that manipulate the bits of TCCR1A Register and then combine them using | (or) operator and then assign the whole expression to TCCR1A Register.

(2) Repeat Step-17(1) for TCCR1B register.
(3) In Fig-2, the OCF1A (Output Compare Match Flag A of TC1) of TIFR1 Register assumes HIGH when the value of TCNT1 becomes equal to the value of OCR1A Register at M-point.

The above flag can be used to interrupt the MCU by prior activation (enabled) of OCIE1A-bit of TIMSK1 Register and I-Bit of SREG Register.

bistSet(TIMSK1, OCIE1A);
bitSet(SREG, 7);    //equivalent code is: sei(); or interrupts();

As a resut, the MCU will enetr into the following ISR Routine where a flag can be set bassed on which the MCU will carry out necessary acctions in the loop() function.

 ISR(TIMER1_COMPA_vect)
{
     flag = true;
}

Add codes with the sketch of Step-8 so that the oscillator runs at 2 Hz, interrupt logic comes into picture and the message "Match Occurred" appears on Serial Monitor.

1 Like

No, notwithstanding the falsity of that comparison statement, 1K is actually very, very cold indeed :cold_face:

Enough for now, :grin:

Then use the toneAC library (from the library manager).
Leo..