| CODE |
' ' Function declarations for LEGOLIB.BAS ' ' Include this near the top of your source file. ' Declare Sub Initlego Declare Sub Dolegoencoder(byval Port As Byte , State As Byte , Encoder As Integer) Declare Function Light(byval Port As Byte) As Byte Declare Function Switch(byval Port As Byte) As Byte |
| CODE |
' ' LEGO Rotation Sensor test code ' ' Encoder on PA1 and switch/light sensor on PA2 and Switch on PA3 ' ' The lego rotation sensor is queried roughly 122hz ' ' NOTE WELL! You need to configure BASCOM for a larger hw stack than ' the default 32 bytes. Go to Options->Compiler->Chip and enter in at ' least 48 for the stack size. Real applications might need more. ' $regfile = "m16def.dat" $crystal = 8000000 $baud = 19200 $include "legolibdefine.bas" ' ' Configure AVR Timer for 122 hz interrupt rate: 8mhz / 256 / 256 ' The second 256 is due to the 8 bit counter simply rolling over. ' Config Timer0 = Timer , Prescale = 256 On Timer0 Timer0_isr ' Our timer interrupt hanlder Enable Timer0 Enable Interrupts ' ' Configure "Program" led on ARC board as an output ' Config Pinb.4 = Output Prog_led Alias Portb.4 ' ' Define ports which we will connect the sensors. ' Const Encoderport = 1 Const Lightport = 2 Const Switchport = 3 Call Initlego() ' ' My_encoder and Encoder state are needed to track an encoder. ' If a second encoder is being used, declare a second set of values. ' Dim My_encoder As Integer , My_encoderstate As Byte ' ' Do loop prints out only when Encoder changes value. Note, Encoder ' is only modified in the interrupt handler, below. Also note the ' enabling and disabling of interrupts to protect access to "my_encoder" ' Dim Temp As Integer , Sys_timer As Byte Print "LEGO Sensor test application" ' Uncomment "If" and "End if" if you don't want continuous output Do Disable Interrupts ' If My_encoder <> Temp Then Temp = My_encoder Enable Interrupts ' Enable interrupts before printing Print " Encoder="; Temp; Print " Switch="; Switch(switchport); Print " Light="; Light(lightport); ' End If Enable Interrupts Idle ' Sleep until next interrupt. Loop End ' ' Interrupt handler for timer. This is called at roughly 122hz, based upon ' the timer0 setup. ' Timer0_isr: ' ' State machine to flash LED at 1 hz. ' Incr Sys_timer If Sys_timer = 25 Then Prog_led = 0 'enable low output (ON) Elseif Sys_timer = 122 Then Prog_led = 1 'disable output (OFF) Sys_timer = 0 'reset timer End If ' Call Dolegoencoder(encoderport , My_encoderstate , My_encoder) ' Return ' $include "legolib.bas" 'end program |
| CODE |
' ' LEGO Interface library ' ' All lego sesors connected to PORTA, which is the ' ADC input port. ' ' Declare Function Readport(port As Byte) As Integer Declare Sub Powerport(port As Byte) ' Dim Enc_tmp As Byte , Light_tmp As Integer ' ' Initialize the ADC for fast conversion. If accuracy is important in your application ' don't call this routine and set up the ADC per Atmel specifications. Each ' LEGO sensor function will take a little longer. ' Sub Initlego() ' Note: atmel doesn't recommend running the ADC this fast ' but as far as I can tell it works fine. The results will be noiser ' but only by 2-4 counts. Config Adc = Single , Prescaler = 8 Start Adc End Sub ' ' Read and decode the LEGO rotation sensor. ' ' The speed at which the encoder can be read is determined ' by the call rate. LEGO specifies the encoder as capable of ' 300 rpm (4800 transitions/min or 80/sec) so call this routine ' at least 100 times/second. ' ' Parameters: Port bit #, Previous state, Encoder value ' Returns: Nothing ' Modifies: Previous state and Encoder Value ' Sub Dolegoencoder(byval Port As Byte , State As Byte , Encoder As Integer) Light_tmp = Readport(port) Select Case Light_tmp Case Is > 850 : Enc_tmp = 2 If State = 1 Then Goto Inc_encoder If State = 3 Then Goto Dec_encoder Case Is > 700 : Enc_tmp = 1 If State = 0 Then Goto Inc_encoder If State = 2 Then Goto Dec_encoder Case Is > 450 : Enc_tmp = 3 If State = 2 Then Goto Inc_encoder If State = 0 Then Goto Dec_encoder Case Else : Enc_tmp = 0 If State = 3 Then Goto Inc_encoder If State = 1 Then Goto Dec_encoder End Select Goto No_encoder Inc_encoder: Encoder = Encoder + 2 Dec_encoder: Encoder = Encoder - 1 No_encoder: State = Enc_tmp Call Powerport(port) End Sub ' ' Read a LEGO light sensor. ' ' The raw output varies from ~600 to ~900, depending. I clip the ' output and shift it & invert so low numbers == dark and high numbers ' equal light. If you parallel a switch on this port a switch closure ' will read as 0. If only a switch is on this port, it will read 20 (open) ' and 0 (closed) ' ' Parameters: Port Bit Value ' Returns: Cooked Sensor Reading ' Modifies: nothing (but port i/o values) ' Function Light(byval Port As Byte) As Byte Light_tmp = Readport(port) If Light_tmp < 200 Then Light = 0 Elseif Light_tmp < 620 Then Light = 255 Elseif Light_tmp > 855 Then Light = 20 Else Light = 875 - Light_tmp End If Call Powerport(port) End Function ' ' Read LEGO switch ' ' functionally redundant with Light(), but ' consumes less power as the outputs are not driven. ' NB - calling this will mess up logic for Light(). Use ' one or the other but not both. This routine returns ' either a 0 or a 1 (closed, open, respectively) ' Function Switch(byval Port As Byte) As Byte Light_tmp = Readport(port) Switch = Pina.port End Function ' ' Restore power to a port after reading it. ' Sub Powerport(port As Byte) Porta.port = 1 Ddra.port = 1 End Sub ' ' In order to keep code size to a minimum I put all common ' functions into this routine as I could. ' Function Readport(port As Byte) As Integer Ddra.port = 0 Porta.port = 0 Waitus 10 Readport = Getadc(port) End Function 'end program |