'********** WARNING WARNING WARNING ****************
' This project may damage your scope. Don't try this
' on an oscilloscope that you care about.
' It will burn your crt causing permanent damage.
'******************************************************
'--- Scope Clock ver 1.5 ---
'Nov. 30, 2012
'By:David Carr
'dave@technofun.org
'
'Compiled with:
'BASCOM 2.0.7.5.003
'http://mcselec.com/
'
const Vers="Scope_Clk1.5"
const rfm_Addr=&h0C
$regfile = "m328pdef.dat"
$crystal = 20000000
$hwstack = 100
$swstack = 100
$framesize = 100
'Length of the hour, minute and second hands.
const MinLen = 115
const HrLen = 85
'The second hand is a specal case because it has a tail.
'The sum of SecLen+SecYstrt must not be greater then 128.
const SecLen = 154 'Total drawn length of second hand.
const SecYstrt = -30 'Second hand tail length.
const SecYend = SecLen+SecYstrt
const SecIoffst = SecLen-SecYend+1 'Offset for SecHand xy array indexes.
const SecArrayLen = SecLen+1
dim SecDeg as word
dim Tdeg as word
dim i as integer
dim i2 as integer
dim n as byte
dim X as byte
dim Y as byte
dim l as byte
dim w1 as word 'reserved for isr routines
dim w2 as word 'reserved for isr routines
dim Hour as word
dim Minute as word
dim Second as word
dim MinDeg as word
dim Mdeg as word
dim HrDeg as word
dim Hdeg as word
dim SecDecay as word
dim HourFlg as bit
dim MinHandX(MinLen) as byte
dim MinHandY(MinLen) as byte
dim HrHandX(HrLen) as byte
dim HrHandY(HrLen) as byte
dim SecHandX(SecArrayLen) as byte
dim SecHandY(SecArrayLen) as byte
dim sine as single
dim cosine as single
dim s1 as single
dim s2 as single
dim strCmnd as string*1
dim strArg as string*8
dim secFlg as byte
secFlg=3 'show second hand and dot enhancement by default.
HourFlg=1 'show hour dot enhancement by default.
Mdeg=1
Hdeg=1
Hour=12
declare sub SetTime(t as string*8)
'-------- AD7302 is a dual 8 bit DAC. -------
'port configs for DAC.
'Control lines.
DAC_WR alias portd.4
DAC_AB alias portd.3
LDAC alias portb.1
config DAC_WR = output
config DAC_AB = output
config LDAC = output
'DAC data lines map.
'DAC - DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
'AVR - PD.7 PD.6 PC.5 PC.4 PC.3 PC.2 PC.1 PC.0
DB0to5 alias Portc
DB6 alias PORTD.6
DB7 alias PORTD.7
config DB0to5 = output
config DB6 = output
config DB7 = output
'--------------------------------------------
'Test point and z (crt brightness) ports.
TP alias portd.0
config TP = output 'don't use TP if you use the serial port.
z alias portd.5
config z = output:reset z
'NOTE:
'To replace the wireless features with normal serial I/O remove
'the next section of code and rewrite the subroutine UserInput:
'****** INCLUDE THIS FOR RFM12B BOOTLOADER SUPORT ********
'Include this in projects that need a serial link
'over the RFM12B wireless connection.
'Also this include will cause an automatic jump to the bootloader
'if the uploader is trying to connect.
'
'rfm12b hardware config. See include file.
const rfm_DeviceCode = 3
'Packet lenth is rfm_MaxMsgLen+8 so Msg length must be less then 247.
'128 or less is recomended.
const rfm_MaxMsgLen = 15
$include "C:\Documents and Settings\Edev\Desktop\My Projects\rfm_Include\Inc_RFM12B_Generic_2.8.bas"
rfm_Myaddr=rfm_Addr 'set at the beginning of this file.
'Enable Interrupts
goto PastRfmEvents
rfm_ExitMain:
'disable anything that needs do be disabled
'before jumping to the bootloader.
disable interrupts
reset z
stop timer1
stop TIMER0
goto rfm_BootLoaderAddr
return
'When a rfm message is ready.
'Normaly this sub should be left empty.
'It's called from an interrupt routine
'so interrupts are disabled while here.
rfm_MsgEvent:
'reset Rx Message Flag.
rfm_RxMsgFlg=0
gosub User_Input
return
'These two routines are called just before and just
'after rfm tx a packet. Normally these will be left
'empty. But if interrupts are using much of the cpu
'cycles they should be disabled/enabled here.
rfm_PreTx:
disable OC0A
disable OC1A
return
rfm_PostTx:
enable OC0A
enable OC1A
return
PastRfmEvents:
rfm_Tx vers
'***********************************************************
'Clock tick rate.
'Setup timer1 to fire an interrupt 6 times a second.
'Mode 4
'Clk/256
Tccr1a=0
tccr1b=&b0000_1100
ocr1a=13020 '~6 Hz -0.001% error.
on OC1A isr_Tick
enable OC1A
'Screen refresh rate.
'setup timer0 for 77 interrupts per second.
'Mode 2
'Clk/1024
tccr0a=&b0000_0010
tccr0b=&b0000_0101
ocr0a=255
on OC0A isr_DrawScreen
enable OC0A
Enable Interrupts
do
'These three routines calculate the new
'hour, minute & second hand positions.
gosub SecXY
gosub MinXY
gosub HourXY
loop
User_Input:
strCmnd=left(rfm_Msg,1)
strArg=mid(rfm_Msg,2)
Select case strCmnd
case "S"
'Command to set the time.
'Command format is: Shh:mm:ss
'make sure strArg is no more then 8 chars long.
strArg=left(strArg,8)
SetTime strArg
case "s"
'Command to change the way seconds are displayed.
'Format is:
's0 - No seconds are displayed.
's1 - Second hand only.
's2 - Dial enhancement only.
's3 - Second hand & Dial enhancement.
secFlg=val(strArg)
case "h"
'Command to toggle hour dial enhancements.
'Format is: h
toggle HourFlg
case else
'Any other user input returns program version
'and clock time hh:mm:ss.
rfm_Tx vers
waitms 10
rfm_Msg=str(hour)+":"+str(Minute)+":"+str(Second)
rfm_Tx rfm_Msg
end select
return
'draw screen about 77 times a second.
isr_DrawScreen:
'set TP
set z 'brighten the crt.
'Draw the dial from data points in flash.
'pause at ever fifth point and the current Seconds point.
'making those points brighter.
restore Dial
read l
decr l
for n=0 to l
read X
read Y
gosub Write_DAC_XY
if HourFlg=1 then
w1=n mod 5
if w1=0 then waitus 250
endif
if secFlg.1=1 then
'This line make the dial points flash as the second hand sweeps past.
'if n=second then waitus 400
'This version make the points flash with a slow decay.
'But on my scope it also causes the dial to distort slightly.
if n=second then
w2=SecDeg mod 6
if w2=0 then
SecDecay=350
else
if SecDecay>8 then SecDecay=SecDecay-8
endif
waitus SecDecay
endif
endif
next
'draw 1
restore One
read l
for n=1 to l
read X
read Y
x=x+123
y=y+236
gosub Write_DAC_XY
next
'draw 2
restore Two
read l
for n=1 to l
read X
read Y
x=x+128
y=y+236
gosub Write_DAC_XY
next
'draw 3
restore Three
read l
for n=1 to l
read X
read Y
x=x+243
y=y+122
gosub Write_DAC_XY
next
'draw 6
restore Six
read l
for n=1 to l
read X
read Y
x=x+126
y=y+6
gosub Write_DAC_XY
next
'draw 9
restore Nine
read l
for n=1 to l
read X
read Y
x=x+8
y=y+122
gosub Write_DAC_XY
next
'draw the center circle.
restore Center
read l
for n=1 to l
read X
read Y
gosub Write_DAC_XY
next
set TP
'drawing the seond hand can be turned off.
if secFlg.0=1 then
'draw the second hand.
for n=1 to SecLen
x=SecHandX(n)
y=SecHandY(n)
gosub Write_DAC_XY
next
endif
'Draw the minute hand.
for n=1 to MinLen
x=MinHandX(n)
y=MinHandY(n)
gosub Write_DAC_XY
next
'Draw the hour hand.
for n=1 to HrLen
x=HrHandX(n)
y=HrHandY(n)
gosub Write_DAC_XY
next
'dim the crt.
reset z
'stop at the center.
X=128
Y=128
gosub Write_DAC_XY
reset TP
return
'6 ticks/second
'360 ticks/minute
isr_Tick:
incr SecDeg
if SecDeg=360 then SecDeg=0
second=SecDeg/6
'Advance the minute hand one degree
'for every 60 degrees of the second hand.
w1=SecDeg mod 60
if w1=0 then
incr MinDeg
if MinDeg=360 then MinDeg=0
'calculate the minute from the hand postion.
Minute=MinDeg/6
'Advance the hour hand one degree
'for every 12 degrees of the minute hand.
w2=MinDeg mod 12
if w2=0 then
incr HrDeg
if HrDeg=360 then HrDeg=0
'calculate the hour from the hand postion.
Hour=HrDeg/30
if Hour=0 then Hour=12
endif
endif
return
Write_DAC_XY:
'write X to DAC
set DAC_AB
DB0to5 = x and &b0011_1111
DB6 = x.6
DB7 = x.7
reset DAC_WR
set DAC_WR
'write Y to DAC
reset DAC_AB
DB0to5 = y and &b0011_1111
DB6 = y.6
DB7 = y.7
reset DAC_WR
set DAC_WR
reset LDAC
set LDAC
return
dim hms(3) as string*4
sub SetTime(t as string*8)
local H as word
local M as word
local S as word
local b as word
'local hms(3) as string*2
local p as byte
hms(1)="":hms(2)="":hms(3)=""
p=split(t,hms(1),":")
H=val(hms(1))
if H>=1 and H<=12 then
else
exit sub
endif
M=val(hms(2))
if M>=0 and M<=59 then
else
exit sub
endif
S=val(hms(3))
if S>=0 and S<=59 then
else
exit sub
endif
'set hour, minute & second.
Hour=H
Minute=M
Second=S
'calculate new hand positions.
SecDeg=S*6
MinDeg=M*6
b=SecDeg / 60
MinDeg=MinDeg+b
HrDeg=H*30
b=MinDeg /12
HrDeg=HrDeg+b
end sub
SecXY:
'equations to rotate an xy point around some xy_origin:
'x = (((x - x_origin) * cos(angle)) + ((y - y_origin) * sin(angle))) + x_origin
'y = (((y - y_origin) * cos(angle)) - ((x - x_origin) * sin(angle))) + y_origin
'--------------------- Second hand calculations ---------------------------------------------
'SecDeg increments from 0 to 359 deg. in isr_Tick.
'SecDeg updates at a rate of 6Hz (one minute = 365 degree's)
'Each time there is a new tick calculate the new xy points for the second hand.
if Tdeg<>SecDeg then
Tdeg=SecDeg
'Calculate then sin and cos for the new Angle.
s1=Tdeg 'convert Angle to a single.
s1=deg2rad(s1) 'convert degree's to radians.
Sine=sin(s1)
Cosine=cos(s1)
'The second hand is just a line of dots on the y axis. Starting at x=0,y=SecYstrt
'It is created here then rotated to the angle SecDeg.
'i represents --> (y - y_orgin)
for i= SecYstrt to SecYend
i2=i+SecIoffst
'-------------------- New X values for angle SecDeg -------------------------------
'x = (((x - x_origin) * cos(angle)) + ((y - y_origin) * sin(angle))) + x_origin
'x = ( 0 * Cosine(A) ) + ( s2 * Sine(A) ) + 128
'subtract the x origin(128) from x also 128.
's1=128-128 's1 = zero , So comment out.
'cos of x.
's1=s1*Cosine 's1 = zero , So comment out.
'i is the y coordinate of the second hand.
'convert to single and multiply by the sin SecDeg.
s2=i
s2=s2*sine
's2=s2+s1 's1 = 0 , So comment out.
'add offset bak to x=128
s2=s2+128
'store it as a byte.
SecHandX(i2)=round(s2)
'------------------------------------------------------------------------------------
'---------- New Y values. See comments above for new x value. ----------------------
'y = (((y - y_origin) * cos(angle)) - ((x - x_origin) * sin(angle))) + y_origin
'y = ( s1 * Cosine(A) ) - ( 0 * Sine(A) ) + 128
s1=i
s1=s1*cosine
's2=0
's2=s2*sine
's1=s1-s2
s1=s1+128
SecHandY(i2)=round(s1)
'-------------------------------------------------------------------------------------
next
endif
return
MinXY:
'Minute hand calculation.
'See second hand code for comments.
if Mdeg<>MinDeg then
Mdeg=MinDeg
s1=Mdeg
s1=deg2rad(s1)
Sine=sin(s1)
Cosine=cos(s1)
for i= 1 to MinLen
'X
s2=i
s2=s2*sine
s2=s2+128
MinHandX(i)=round(s2)
'Y
s1=i
s1=s1*cosine
s1=s1+128
MinHandY(i)=round(s1)
next
endif
return
HourXY:
'Hour hand calculation.
'See second hand code for comments.
if Hdeg<>HrDeg then
Hdeg=HrDeg
s1=Hdeg
s1=deg2rad(s1)
Sine=sin(s1)
Cosine=cos(s1)
for i= 1 to HrLen
'X
s2=i
s2=s2*sine
s2=s2+128
HrHandX(i)=round(s2)
'Y
s1=i
s1=s1*cosine
s1=s1+128
HrHandY(i)=round(s1)
next
endif
return
'The first byte of each set of data is the number of xy pairs.
'Data is aranged in x,y,x,y,x,y... pairs.
Dial:
data 60 '60 x,y pairs.
data 128,253,141,252,154,250,167,247,179,242
data 191,236,201,229,212,221,221,212,229,202
data 236,191,242,179,247,167,250,154,252,141
data 253,128,252,115,250,102,247,089,242,077
data 236,066,229,055,221,044,212,035,202,028
data 191,020,179,014,167,009,154,006,141,004
data 128,003,115,004,102,006,089,009,077,014
data 066,020,055,027,044,035,035,044,027,055
data 020,066,014,077,009,089,006,102,004,115
data 003,128,004,141,006,154,009,167,014,179
data 020,191,027,202,035,212,044,221,055,229
data 066,236,077,242,089,247,102,250,115,252
One:
data 7
data 0,0,0,2,0,4,0,6,0,8,0,10,0,12
Two:
data 16
data 0,9,1,11,3,12,5,12,7,11,8,9,8,7,6,5
data 4,4,2,3,0,2,0,0,2,0,4,0,6,0,8,0
Three:
data 12
data 0,1,2,0,4,0,6,2,6,4,5,6,3,6,6,8,6,10,4,11,2,11,0,10
Six:
data 16
data 0,3,1,1,3,0,5,0,7,1,8,3,8,5,6,6,4,7,2,6,0,5,0,8,1,10,3,12,5,12,7,11
Nine:
data 17
data 0,1,2,0,4,0,6,0,8,2,8,4,8,6,8,8,7,10,5,11,3,11,1,10,0,8,1,6,3,5,5,5,7,6
Center:
data 16 '16=circle 36=filled circle.
data 125,128,125,129,126,130,127,131,128,131,129,131,130,130,131,129
data 131,128,131,127,130,126,129,125,128,125,127,125,126,126,125,127
data 126,127,126,128,126,129,127,130,128,130,129,130,130,129,130,128
data 130,127,127,126,128,126,127,126,128,127,127,127,127,128,127,129
data 128,129,129,129,129,128,129,127
|