The following examples are very simple programs which have been heavily commented to illustrate the features of FBasic. More in-depth examples are contained in TICkit application notes, which can be accessed by following the link.
This document has four examples:
; FBasic minimum program - what must be in every FBasic program DEF tic57_e ; You must inform the compiler which ; version of the interpreter you are ; using. LIB fbasic.lib ; You must include the FBasic standard ; library of functions and definitions FUNC none main ; Each program must have a function block ; named "main" which returns no values ; ( function type "none" as shown ). ; This is how FBASIC knows where ; the start of your program is BEGIN ; Every function block must have a BEGIN ; to separate the declarative section of ; the block from the procedural part of ; the block ENDFUN ; Every function block must have an ENDFUN ; to end the procedural part of the block ; as well as to end the entire function ; block. In this case, the end of the ; function named "main"
Example 2: The standard hello world program. This program will display "hello world..." on the console of your display. This program utilizes a library called constrin.lib. This library contains FBasic code to send a string of characters in EEprom to the console.
; Program to display "hello world..." on the console, then wait ; indefinitely. DEF tic57_e ; To informs compiler of TICkit57 ver E LIB fbasic.lib ; includes standard FBasic library LIB constrin.lib ; includes function for string output to ; console FUNC none main ; starting point of program BEGIN ; required for the procedural part of main rs_param_set( debug_pin )
; sets up RS232 for console ; connection (baud & pin info) con_string( "Hello World...." ) ; actually sends string to console ; quoted strings place the chars ; between quotes into EEprom and ; generate a pointer to them REP ; Marks the beginning of a loop block debug_on()
; causes debug program to re-connect after execute LOOP ; Marks the ending of a loop block ; This loop block at the end of main ; is a common way to end the "main" ; function since there is no operating ; system shell on micro-controllers ENDFUN
Example 3: Library listing for
constrin.lib. Shows how library files can be used to keep life
simple for programmers at the same time versatile interfaces for multiple devices can be
; Outputs a string of characters to the console LIB fbasic.lib ; this is a redundant reference to fbasic's ; standard library. The compiler knows not ; to include the library contents twice but ; rather to refer to the first occurrence. FUNCTION none con_string ; this function block is called "con_string" ; which is how it is called by other functions ; in a program PARAM word pointer ; this line defines the symbol pointer as ; a reference to whatever value was passed ; when the function is called by other ; programs LOCAL byte data ; this line creates some local storage ; called "data". This variable data is ; unique to this function block. Even if ; the calling function has a variable named ; "data", con_string will use the variable ; defined here. LOCAL word temp_pntr ; this line creates another local variable ; called "temp_pntr". This is similar to ; "data" in the previous line, but has a ; different name and is a word type (16 bit) ; instead of a byte type (8 bit) BEGIN ; This line tells the compiler we are done defining ; local variables and parameters and are beginning the ; procedural part of this function block. =( temp_pntr, pointer ) ; "temp_pntr" is assigned the value ; of "pointer". This is so the value ; of "pointer" remains unchanged. =( data, ee_read( pointer )) ; here we read the first character ; from eeprom. WHILE <>( data, 0b ) ; This line starts a looping block ; this loop will execute only while ; "data" is not equal to zero. ; If "data" is zero, the program will ; not execute the contents of the ; loop block but will continue executing ; immediately after the end of the ; loop block. FBasic automatically ; ends strings with an extra 0 byte. ; This method of ending strings is ; called null termination. con_out_char( data ) ; This sends the non-zero character ; to the console. ++( temp_pntr ) ; This increments the value of ; "temp_pntr". This means the next ; time through the loop block, we will ; be dealing with the next character ; in the string. =( data, ee_read( temp_pntr )) ; This line reads the next ; character in the string from ; EEprom. LOOP ; this line ends the looping block ; and will cause the program to go ; back and repeat the looping block ; the loop will only stop when the ; test at the top of the looping block ; fails. ENDFUN ; This line ends the function "con_string" and ; causes execution of the program to return ; back to the calling function immediately ; following the reference to "con_string()"
The library above can easily be modified to send string data to a centronix
printer, or to
an LCD, or to a serial device by simply changing the con_out_char line to be some other
function which sends data to the desired device.
Example 4: A more advanced function library which implements a 3-wire driver for a Linear Technology LTC1298 12-bit A/D converter. This library uses DEFINITIONS or GLOBALs as a means for passing data to a function library. This is suitable for situations where the data is not expected to change over the course of execution of a program. This keeps the calling strings of functions shorter and makes the program read a bit more clearly. This function also returns a value, so pay special attention to the use of the variable "exit_value". A sample program is included at the end of this example to show how this library is incorporated into a program.
; Functions to control A/D ; These functions rely on three defines to work properly ; ltc_cs = Chip Select pin 'Must have a separate line ' ; ltc_clk = Clock control pin 'Can share a data line with other device ' ; ltc_data = data pin 'Can share a data line I.E. a LCD' ; Routine to read a data from an LTC1298 or LTC1288 A/D chip FUNC word read_ltc1298 ; function is named "read_ltc1298" ; and will return a word (16-bit) value ; to the calling function when referenced PARAM byte config ; This value indicates mode and channel ; for the A/D chip. ; bit 7 = mode ( 0=single end, 1=differential) ; bit 1-6 = channel select ; bit 0 = polarity for differential or lsb ; channel select for single ended LOCAL byte count 0b ; local data storage called "count" BEGIN ; begins procedural part of this function pin_low( ltc_clk ) ; makes the pin "ltc_clk" a low output pin_low( ltc_cs ) ; makes the pin "ltc_cs" a low output pin_high( ltc_data ) ; makes the pin "ltc_data" a high output ; which is the start bit for the ltc1298 pulse_out_high( ltc_clk, 10w ) ; pulses the pin "ltc_clk" for 100 us IF and( config, 0y10000000b ) ; do we want a differential conversion pin_low( ltc_data ) ; makes the next bit low ELSE pin_high( ltc_data ) ; makes the next bit high ENDIF ; this IF block is used to program ; the ltc1298 in the way specified ; by the calling parameter pulse_out_high( ltc_clk, 10w ) ; pulses "ltc_clk" again IF and( config, 1b ) ; select channel or polarity pin_high( ltc_data ) ELSE pin_low( ltc_data ) ENDIF pulse_out_high( ltc_clk, 10w ) pin_high( ltc_data ) ; use msb first format pin_high( ltc_clk ) ; clock in the msbf bit =( count, pin_in( ltc_data )) ; make data line an input pin_low( ltc_clk ) ; return clock to low state =( count, 0b ) =( exit_value, 0w ) ; get data loop ready ; exit_value is the variable ; automatically assigned when ; a function has a return value ; the value of "exit_value" ; immediately before EXIT or ; ENDFUN is executed is the ; value returned by the function ; call. REP pulse_out_high( ltc_clk, 10w ) ; clock for next data bit =( exit_value, <<( exit_value )); shift exit word to the left IF pin_in( ltc_data ) ++( exit_value ) ENDIF ++( count ) UNTIL ==( count, 12b ) pin_high( ltc_cs ) ENDFUN
The program which uses the library above is as follows. This program is relatively complex in that it has a method for keeping track of time and also sends data back to a PC. This program is designed to work with the AQUIRE.EXE program included in the TIC57 development kit. Using this program and a PC running ACQUIRE, a small network of TICkits can all contribute data to the PC. If you find this program a little overwhelming, do not worry. It is included here just to provide a flavor of what FBasic can do. You can digest it after you have more experience with FBasic.
; This program uses an LTC1298 or LTC1288 (3v version) to take 12bit analog ; voltage readings once a second and sends these readings to a PC console ; running the ACQUIRE program. This program is designed so that multiple ; TICkits can be connected to this wire in a multi-drop configuration. ; Thanks to Scott Edwards for his Jan 1, 1996 "Nuts and Volts" article ; highlighting the use of the LTC1298 with the TICkit. ; Written by: Glenn Clark DEF tickit_d LIB fbasic.lib DEF ltc_cs pin_D0 ; pin D0 connects to ltc chip select DEF ltc_clk pin_D1 ; pin D1 connects to ltc clk line DEF ltc_data pin_D2 ; pin D2 connects to ltc data line LIB ltc1298.lib ; contains routine to drive LTC1298 DEF designation 'a' ; this is the polling code from the PC ; for multiple TICkits connected to ; the serial wire DEF net_pin pin_A7 ; this is the pin to do network acquisition on FUNC none line_sync LOCAL byte match_count 0b LOCAL byte rs_errors BEGIN REP IF ==( rs_receive( 0, rs_errors ), designation ) IF ==( rs_errors, 0b ) ++( match_count ) ELSE =( match_count, 0b ) ENDIF ELSE =( match_count, 0b ) ENDIF UNTIL >=( match_count, 2b ) delay(1) rs_send( designation, 0b ) ENDFUN FUNC none rs_out ; convert word to serial string PARAM word in_val ; parameter is destroyed BEGIN rs_send( +( 48b, trunc_byte( /( in_val, 1000w ))), 0b ) =( in_val, %( in_val, 1000w )) rs_send( +( 48b, trunc_byte( /( in_val, 100w ))), 0b ) =( in_val, %( in_val, 100w )) rs_send( +( 48b, trunc_byte( /( in_val, 10w ))), 0b ) =( in_val, %( in_val, 10w )) rs_send( +( 48b, trunc_byte( in_val )), 0b ) ENDFUN FUNC none main LOCAL byte tic_count BEGIN pin_high( ltc_cs ) pin_low( ltc_clk ) rs_param_set( or( or( rs_invert, rs_9600 ), net_pin )) rs_stop_chek() rtcc_int_256() REP =( tic_count, 150b ) ; used 150 instead of 156 to fudge ; probable xmit delays WHILE tic_count rtcc_wait() rtcc_set( 6b ) ; divide by 250 ( 256 - 250 = 6 ) ; enough time for approx 128 tokens ; results in 78.25 readings per second --( tic_count ) LOOP ; this loop should exit every 2 secs line_sync() rs_send( ':', 0b ) rs_out( read_ltc1298( 0b )) rs_send( ' ', 0b ) rs_out( read_ltc1298( 1b )) rs_send( 13b, 0b ) LOOP ENDFUN
The program above shows how multiple function blocks can be used to keep the program "compartmentalized" for easy comprehension and incremental debugging. I hope this small introduction to FBasic has proven useful to you. As you can probably tell by now, FBasic has the power to be very effective on much larger processors than the TICkit 57. Versions of FBasic are being developed for much larger and more powerful platforms. If you would like to see more code using FBasic, you will find more in each of the application notes contained at this web site.
Protean Logic Inc. Copyright 02/07/04 Top of Page