The next program blinks a LED which is connected to pin A0 and (via a suitable resistor) to either Gnd or Vcc.
example 1
[1] -- flash a LED on pin A0
[2] include 16f84_10
[3] include jlib
[4] pin_a0_direction = output
[5] forever loop
[6] pin_a0 = on
[7] delay_1s
[8] pin_a0 = off
[9] delay_1s
[10] end loop
[1] Jal is a free format language. The end of a line has no special meaning, except that it terminates a comment. A comment starts with two dashes. The numbers [1] etc. are for reference only and are not part of the program!
[2] The target is a 16f84 with a 10MHz crystal.
[3] The jlib standard library is included.
[4] On power-up all pins are in the input (high impedance) state. This statement makes pin A0 an output.
[5] The main part of the program is an endless loop.
[6] Pin A0 is set high. High and on are synonyms for true. likewise low and off are synonyms for false. Output and input are declared in jlib. The jlib output routines use a port buffer to avoid the read-modify-write problem inherent to the PIC architecture.
[7] This call causes a busy delay of 1 second. Related calls exist for delays of (multiples of) 100mS, 10mS, 1mS and 100uS. The argument to the delay calls is a byte, so the range is 0..255. All calculations in jal are modulo calculations. For a byte this means that a specified value will silently be interpreted modulo 256. The default argument is 1, so the statement causes a delay of 1 second.
The various delay routines are the main reason that the target's clock frequency must be specified. If we had included 16f84_4 while using a 10MHz clock the actual delay would have been 2.5 seconds.
[8] Pin A0 is set low.
[9] Same call as in line [7]: a one second delay.
[10] This line indicates the end of the loop which was started in line [5].
The next program shows night-rider style LED display on port B.
example 2
[ 1] include 16f84_10
[ 2] include jlib
[ 3]
[ 4] -- night-rider LED display on port B
[ 5] const bit to_right = 1
[ 6] const bit to_left = 0
[ 7]
[ 8] procedure night( byte in out x, bit in out direction ) is
[ 9] if ( x & 0b_1000_0000 ) != 0 then
[10] direction = to_right
[11] end if
[12] if ( x & 0b_0000_0001 ) != 0 then
[13] direction = to_left
[14] end if
[15]
[16] if direction == to_right then
[17] x = x >> 1
[18] else
[19] x = x << 1
[10] end if
[21] end procedure
[22]
[23] b_direction = all_output
[24] var byte x = 0b_0000_0001
[25] var bit d = to_left
[26]
[27] forever loop
[28] port_b = x
[29] delay_100ms( 2 )
[30] night( x, d )
[31] end loop
[5] Jal does not support enumerates, so two constants of type bit are used to identify the current direction in which the LED pattern moves.
[8] The procedure night is declared which has two input-output parameters: the display and the current shift direction. Input-output parameters are copied to and from the actuals both before and after the procedure is executed. Input-only parameters are copied only before, and output-only parameters are copied only after the execution of the procedure.
[9,16] If the current display value has hit the left or right border the current shift direction is updated. The display value is AND-ed with 0b_000_0001 to detect a collision with the right border and with 0b_1000_0000 to detect a collision with the left border. The prefix 0b indicates a base-2 (binary) value. Other prefixes are 0h or 0x for hexadecimal and 0d (which is the default) for decimal. Underscores within a literal are ignored by the compiler but can be used to improve the readability.
[16] Depending on the current direction the display value is shifted one position to the right or to the left.
[23] This statement switches all pins of port B to output. All_output is decleared in jlib.
[24] The initial value of the display is 0b_0000_0001. A value of 0b_0000_0101 or 0b_0000_1111 would also produce a nice display.
[25] The initial direction is set to to_left. This could be omitted because the initial value of x cause the direction to be set immediatley.
[27] The infinite loop updates the PORT B value, waits 200 mS and calls the procedure night to calculate the next display value and possibly update the direction.
[28] For active-low LEDs this line could be changed to invert the x value before assigning it to port_b:
[27] port_b = x ^ 0x0FF
The next program controls a simple line-following robot which consists of two four-phase stepper motors and two reflective IR sensors. The robot follows a black line on a white background by stepping each motor only when the associated sensor sees white.
example 3
[ 1] -- A line following robot:
[ 2] -- port B drives two 4-phase stepper motors via an ULN2803.
[ 3] -- a0 and a1 are connected to 2 white-is-low reflective sensors.
[ 4] -- a2 and a3 drive 2 LEDs which show the state of the sensor inputs.
[ 5]
[ 6] include 16f84_10
[ 7] include jlib
[ 8]
[ 9] port_b_direction = all_output
[10] pin_a0_direction = input
[11] pin_a1_direction = input
[12] pin_a2_direction = output
[13] pin_a3_direction = output
[14]
[15] procedure steppers( byte in a, b ) is
[16] port_b = a + ( b < < 4 )
[17] delay_1mS( 10 )
[18] end procedure
[19]
[20] var byte left_stepper = 0b_0001
[21] var byte right_stepper = 0b_0001
[22]
[23] forever loop
[24] pin_a2 = pin_a0
[25] pin_a3 = pin_a1
[26]
[27] if ! pin_a0 then
[28] stepper_motor_half_forward( right_stepper )
[29] end if
[30] if ! pin_a1 then
[31] stepper_motor_half_forward( left_stepper )
[32] end if
[33]
[34] steppers( left_stepper, right_stepper )
[35] end loop
[15] The procedure Steppers is declared which has two input-only parameters.
[16] Port B is set to the appropriate value for driving the one stepper motor from pins B0 .. B3 and the other one from pins B4 .. B7.
[17] This delay between each step is appropriate for the stepper motors used in older 5-1/4 inch diskdrives. The argument to the delay is a byte, so it must be in the range 0 .. 255.
[18] Two variables are declared to hold the current steering value for each stepper motor. The initial values for both motors is 0b_0001.
[24] The indicator LEDs are set according to the values of the sensor inputs.
[27] Each stepper motor value is advanced one (half) step only when the associated sensor input is low. The procedure Stepper_Motor_Half_Forward is declared in jlib. Alterantively Stepper_Motor_Full_Forward could be used. Note that jal is not case sensitive.
[34] The Steppers procedure is called to provide the new steering to the motors and wait the appropriate time before the next step.
The next program reads the temperature from an LM75 using the i2c protocol, and writes the result to an LCD controlled by a Hitachi HD44780.
example 4
[ 1] -- a temperature display using
[ 2] -- an LM75 and a HD44780 LCD controller
[ 3]
[ 4] include 16c84_10
[ 5] include jlib
[ 6] include lm75
[ 7] include hd447804
[ 8]
[ 9] const lm75_address = 0
[10]
[11] hd44780_clear
[12]
[13] forever loop
[14]
[15] var byte t, d
[16] var bit f
[17]
[18] lm75_read_fdt( lm75_address, f, d, t )
[19]
[20] hd44780_line1
[21] if f then
[22] hd44780 = "-"
[23] else
[24] hd44780 = "+"
[25] end if
[26] print_decimal_2( hd44780, d, " " )
[27] hd44780 = "."
[28] print_decimal_1( hd44780, t, "0" )
[29]
[30] delay_200mS
[31]
[32] end loop
[6,7] The i2c and hd447804 libraries must be included explicitly because they are not part of jlib. Refer to the i2cp and hd44780p library files for the IO pin assignments used. When your target circuit uses different IO pins you should make a local copy of these files and edit that copy.
[9] This constant defines the 3-bit i2c address of the LM75 as configured by the LM75's A0 A1 and A2 pins. The LM75 routines will set the higher bits of the address (0b_1001 for an LM75).
[11] The LCD display is cleared.
[15,16] The variables for reading the LM75 are declared. It is a good idea to declare variables within smallest possible scope.
[18] The LM75 is read.
[20] The cursor in the HD44780 is put back to the first position. Using HD44780_clear at this point would cause some flickering of the display.
[21] First the sign is written. HD44780 is a pseudo-variable: each assignment to this variable invokes a procedure which writes the value to the display and advances the cursor.
[26] The temperature is written using the print_decimal_2 procedure. The HD44780 pseudo-variable is passed as destination of the formatted string. The second argument is the value to be written. The last argument is the ASCII value to use for leading zero's. Here we supply a space.
[27,28] After the decimal point the tenth degree value is printed. Print_decimal_1 is used which prints only one digit. A "0" is supplied for leading zero's, so either "0" or "5" is printed.
[30] A little delay is inserted to limit the update speed.