Discussion forum for the BasicX family of microcontroller chips.
Is there a way to produce a 20Hz squarewave on one of the pins on the BX-24? I would like this to run all the time and affect my normal program as little as possible. Right now my main program is the only task running on it. I am using com1 for serial data in and out. The 20Hz doesn't have to be very accurate (within 5%) and can vary a bit if it has to. Of course a perfect signal is best. Any ideas? Tom [Non-text portions of this message have been removed]
> ... to produce a 20Hz squarewave... I can suggest two methods. You can run another task that sleeps for half of the 20Hz period, toggles (inverts) any pin, and sleeps again, repeating endlessly. Task switching will result in some irregularity with this method. sub TaskB() Do call sleep(0.5/20.0) register.PortD = register.PortD xor bx1000_0000 'Red, pin 25 Loop end sub You can program Timer1 or Timer2 to produce 20Hz, exactly, independent of firmware, on pins 26 or 27 (Timer1) or 25 (Timer2). You'll need to set the timer's mode registers for Ck/1024 prescaling, the compare match mode (to toggle the pin), and an appropriate output compare value for half of the period. If the timer counts at Ck/1024, half of a 20Hz period would be represented by a compare count of (7372800/1024/20/2)=180; if the output pin is toggled accordingly, the result is 20Hz. Here is a Timer2 implementation: Sub Put20HzOnPin25() Const T2mode As Byte = bx0001_1111 'flip 25, clear, 7200Hz Register.TCCR2 = 0 'stop Timer2 Register.TCNT2 = 0 Register.OCR2 = 180 '20Hz=(7372800/1024/20/2)=180 Register.TCCR2 = T2mode End Sub Tom
Thanks Tom, that was exactly what I was looking for! Tom -----Original Message----- From: Tom Becker [mailto:gtbecker@gtbe...] Sent: Wed 3/8/2006 12:42 PM To: basicx@basi... Cc: Subject: Re: [BasicX] 20 Hz squarewave > ... to produce a 20Hz squarewave... I can suggest two methods. You can run another task that sleeps for half of the 20Hz period, toggles (inverts) any pin, and sleeps again, repeating endlessly. Task switching will result in some irregularity with this method. sub TaskB() Do call sleep(0.5/20.0) register.PortD = register.PortD xor bx1000_0000 'Red, pin 25 Loop end sub You can program Timer1 or Timer2 to produce 20Hz, exactly, independent of firmware, on pins 26 or 27 (Timer1) or 25 (Timer2). You'll need to set the timer's mode registers for Ck/1024 prescaling, the compare match mode (to toggle the pin), and an appropriate output compare value for half of the period. If the timer counts at Ck/1024, half of a 20Hz period would be represented by a compare count of (7372800/1024/20/2)=180; if the output pin is toggled accordingly, the result is 20Hz. Here is a Timer2 implementation: Sub Put20HzOnPin25() Const T2mode As Byte = bx0001_1111 'flip 25, clear, 7200Hz Register.TCCR2 = 0 'stop Timer2 Register.TCNT2 = 0 Register.OCR2 = 180 '20Hz=(7372800/1024/20/2)=180 Register.TCCR2 = T2mode End Sub Tom SPONSORED LINKS Microcontrollers <http://groups.yahoo.com/gads?t=ms&k=Microcontrollers&w1=Microcontrollers&w2=Microprocessor&w3=Intel+microprocessors&w4=Pic+microcontrollers&c=4&s=95&.sig=mfaAujKZXA2Z_vxre9sGnQ> Microprocessor <http://groups.yahoo.com/gads?t=ms&k=Microprocessor&w1=Microcontrollers&w2=Microprocessor&w3=Intel+microprocessors&w4=Pic+microcontrollers&c=4&s=95&.sig=9jjd2D3GOLIESVQssLmLsA> Intel microprocessors <http://groups.yahoo.com/gads?t=ms&k=Intel+microprocessors&w1=Microcontrollers&w2=Microprocessor&w3=Intel+microprocessors&w4=Pic+microcontrollers&c=4&s=95&.sig=OMnZuqMZX95mgutt4B-tDw> Pic microcontrollers <http://groups.yahoo.com/gads?t=ms&k=Pic+microcontrollers&w1=Microcontrollers&w2=Microprocessor&w3=Intel+microprocessors&w4=Pic+microcontrollers&c=4&s=95&.sig=Malspbd0T4Rq3M4Q0nHrfw> _____ > . _____ [Non-text portions of this message have been removed]
> > ... to produce a 20Hz squarewave...
> ... Task switching will result in some irregularity with this method.
I spent some time looking at a couple of techniques to generate a 20Hz
squarewave in software. The simplest, looping around a Sleep(0.025),
produces a small rate error because 0.025 second isn't an integral
tick count; the resulting rate is pretty stable, but wrong. Another
method slaves the rate to the RTC; that results in an exact short-term
_average_ rate; the resulting rate is jittery, but correct.
I ran both techniques, each in a task, and drove the same LED with
them, simultaneously. Since each task XORs the LED bit, the LED
displays the beat frequency, the difference between the two
techniques. The difference appears as a slow intensity change of the
LED, actually 20Hz PWM. The intensity cycles in about three seconds,
implying that the rate difference is about 0.3Hz, or about 2% error,
if my math is right.
Tom
dim TaskAStack(1 to 31) as byte
dim TaskBStack(1 to 31) as byte
sub Main()
register.DDRD = register.DDRD or bx1010_0000 'LEDs out
register.PortD = register.PortD or bx1010_0000 'LEDs off
CallTask "TaskA", TaskAStack
CallTask "TaskB", TaskBStack
Do
call Sleep(-1)
Loop
end sub
sub TaskA()
const iFreq as integer = 20
dim iThen as integer, iNow as integer
Do
do
iNow = (cint(register.RTCTick mod 512) * 2 * iFreq) \ 512
loop until iNow <> iThen 'average rate is exactly 40Hz
iThen = iNow
register.PortD = register.PortD xor bx1000_0000 'flip LED
Loop
end sub
sub TaskB()
Do
call sleep(0.025) 'rate is approximately 40Hz
register.PortD = register.PortD xor bx1000_0000 'flip LED
Loop
end sub
Another academically interesting exercize, I think:
The code below runs two instances of the same task, each producing a
slightly different rate, set by Main before each task is launched. If
you play with the SPeriod values, you'll find the effect of the tick
increment.
dim TaskStack1(1 to 31) as byte
dim TaskStack2(1 to 31) as byte
dim sPeriod as single
sub Main()
register.DDRD = register.DDRD or bx1010_0000 'LEDs out
register.PortD = register.PortD or bx1010_0000 'LEDs off
sPeriod = 0.025 'rate is approximately 40Hz
CallTask "TaskB", TaskStack1
sPeriod = 0.024 'rate is quicker
CallTask "TaskB", TaskStack2
Do
call Sleep(-1)
Loop
end sub
sub TaskB()
dim sP as single
sP = sPeriod
Do
call sleep(sP)
register.PortD = register.PortD xor bx1000_0000 'flip LED
Loop
end sub
Even simpler. Main becomes the second instance by a Call, instead of a
second CallTask, so TaskB is run as both a task and as a endless sub of
Main. Nothing practical here, just amusing code.
dim TaskStack1(30) as byte
dim sPeriod as single
sub Main()
register.DDRD = register.DDRD or bx1010_0000 'LEDs out
register.PortD = register.PortD or bx1010_0000 'LEDs off
sPeriod = 0.025 'rate is approximately 40Hz
CallTask "TaskB", TaskStack1
sPeriod = 0.024 'rate is quicker
Call TaskB
end sub
sub TaskB()
dim sP as single
sP = sPeriod
Do
call sleep(sP)
register.PortD = register.PortD xor bx1000_0000 'flip LED
Loop
end sub