Frequency
Prerequisite
This page assumes you have completed the analog, sound, and servo lessons.
Frequency.Write()
This feature allows for accurate control of specially dedicated pins using internal special hardware. For example, the BrainPad Pulse has this feature available on either pin 0 or ‘p’. Note that the ‘p’ pin is the on-board piezo buzzer, see specific hardware pin-out for details on supported pin(s).
Frequency.Write() functions take 4 arguments: pin, frequency, duration, and dutyCycle. Frequency is how many times the pin will cycle per second. The duty cycle is the percentage of the pin’s high to low state. A duty cycle of 0 will leave the pin inactive, 10 will make the pin active (high) 10% of the time, 90 will make the pin active 90% of the time, and so on. Duration is used to set a period for the pin to be active. A duration of 1000 will output the specified PWM signal on the pin for 1 second. Setting duration to 0 is a special case and will make the pin active forever.
There are many ways to use PWM. One of the uses is to generate sounds by connecting the pin to a piezo. Connecting a speaker is also possible if using an amplifier circuit.
This example uses frequency to control the on-board buzzer of the BrainPad Pulse. Note that the duty cycle is always 50 when generating sounds. Changing the duty cycle will reduce the “volume” of the sound but this is not typically a standard use. It is best to keep the duty cycle at 50 and use the frequency to generate sounds.
Python
while True:
for x in range(16,1000):
BrainPad.Frequency.Write('p', x, 200, 50)
BrainPad.System.Wait(200)
for x in range(1000,16,-1):
BrainPad.Frequency.Write('p', x, 200, 50)
time.sleep(.2)
C#
while (true){
for (var x = 16; x < 1000; x++){
BrainPad.Frequency.Write('p', x, 200, 50);
BrainPad.System.Wait(200);
}
for (var x = 1000; x > 16; x--){
BrainPad.Frequency.Write('p', x, 200, 50);
BrainPad.System.Wait(200);
}
}
JS
while (true) {
for (let x = 16; x < 1000; x++) {
await BrainPad.Frequency.Write('p', x, 200, 50);
await BrainPad.System.Wait(200);
}
for (let x = 1000; x > 16; x--) {
await BrainPad.Frequency.Write('p', x, 200, 50);
await BrainPad.System.Wait(200);
}
}
Since Frequency.Write() is a non-blocking function, it will return immediately even if the duration is set to a future time. Making a second call to Frequency.Write() will terminate any existing active frequency, despite the duration of previous calls argument.
In this example, 1Khz will be generated for only 2 seconds and not 5 seconds, because of the second Frequency.Write() called cancels out the first one.
Python
BrainPad.Frequency.Write('p',1000,5000,50)
BrainPad.System.Wait(2000)
BrainPad.Frequency.Write('p',16,0,0)
C#
BrainPad.Frequency.Write('p',1000,5000,50)
BrainPad.System.Wait(2000);
BrainPad.Frequency.Write('p',16,0,0);
JS
await BrainPad.Frequency.Write('p', 1000, 5000, 50);
await BrainPad.System.Wait(2000);
await BrainPad.Frequency.Write('p', 16, 0, 0);
Another use of the buzzer is through fixing the frequency and changing the duty cycle. This is used to control energy levels, for example, dimming lights and motor speed control. Note that motors and large lights draw a lot of current and need to be wired to the BrainPad through a special circuit. This will be detailed in other lessons. However, a small LED can be connected directly. This is an example that will activate the pin at a 10% energy level.
Python
BrainPad.Frequency.Write(0,1000,0,10)
C#
BrainPad.Frequency.Write(0,1000,0,10);
JS
await BrainPad.Frequency.Write(0, 1000, 0, 10);
Hardware vs Software Pin Control
Another use of PWM is to control servo motors. Servo motors need a pulse every 20ms (50Hz) and then the pulse width is used to determine the servo position where typically a 1ms pulse sets the servo at about 0 degrees and 2ms sets it at about 180 degrees. Can you guess what pulse width we need for 90 degrees? It is 1.5ms.
If a PWM-capable pin is needed to generate a signal to control a servo then how come BrainPad boards can control servos on any pin? There are two ways to generate PWM (frequencies) on a pin. Some special pins can be controlled using hardware control through special hardware that is built inside the chip. This is what Freq() uses. This is very accurate but is only available on special pins. Another way to control the pin is through Software control, which is not very accurate but can be done on any pin. AnalogOut(), Sound(), and Servo() are examples of functions/features that use software control. They are available on all pins but they are not very accurate. In contrast, Freq() offers much higher accuracy but it only works on specific pins.
The accuracy difference is invisible in most cases but can be slightly noticed in the case of servo control. The Servo() feature works on any pin as it is handled by software control but it only offers 20 steps though the whole 180-degree range. In this animated gif, the software-controlled servo will jump into position, where the hardware-controlled one moves more smoothly. As you can tell, it is not too bad and works in most cases.
The needed 1ms to 2ms pulse can be generated by setting the duty cycle. We know the servo needs a pulse every 20ms (50Hz). Setting the duty cycle to 50% will get us a signal that is 10ms high and 10ms low. A 10% duty cycle will set the pin to be 2ms high and the rest is low. We know 2ms is what we need for the servo to go to 180. For the 1ms needed to set the servo at 0 degree, we need a duty cycle of 5. But why 5? 5% of 20ms is 1ms!
Ok great! We now know we need a duty cycle set between 5 and 10 (range 5) and this needs to be scaled from 0 to 180. The formula needed is duty=(5/180*deg)+5.
the d variable is used to hold the servo position and then Freq() is then set with the scaled value.
Python
d=90
BrainPad.Frequency.Write(0,50,0,(5/180*d)+5)
C#
var d=90;
BrainPad.Frequency.Write(0,50,0,(5/180*d)+5);
JS
const d=90;
BrainPad.Frequency.Write(0,50,0,(5/180*d)+5);
While 1ms to 2ms is the standard, many hobby servos can have different ranges. Some are 0.5ms to 2.5ms, which is a ratio of 2.5% to 12.5% off 20ms (range is 10ms).
Python
d=90
BrainPad.Frequency.Write(0,50,0,(10/180*d)+2.5)
C#
var d=90;
BrainPad.Frequency.Write(0,50,0,(10/180*d)+2.5);
JS
const d=90;
BrainPad.Frequency.Write(0,50,0,(10/180*d)+2.5);
If not sure about your servo’s range, use the second formula and then try different values to determine the min and max possible degree.
BrainStorm
Compromises are made everywhere in computer systems. Speed vs accuracy, color depth vs memory utilization. In this case, making a feature available on all pins with less accuracy vs being very accurate on a specific pin. Can you think of other similar cases? What about slow diesel trucks that can move very heavy weights vs a sports car that can accelerate from 0 to 100 in 3 seconds?