PICNIC

Tutorial (Exercise 0)

Tutorial (Exercise 0)

1. Tutorial Objective

2. Memory Use Status and Jumps between Pages

3. On Firmware ver1.2.0.4

4. call/return with a dummy module

5. Door sensor -> LED relay outputs

6. Introduction of In/Out mode

7. Submission of Exercise 0

Report Submission System

 

→Click here if you have some questions and comments.

←Back to the table of contents

Updated May 4, 2005 20:33

 

Tutorial Objective

Now we will begin the tutorial using the PICNIC+peripheral extension option kit.

In this tutorial, we will show the programming for the following implementation examples:

*call/return with a dummy module (Experiments 1, 2)
*Door sensor -> LED relay output (Experiments 3-7)

Finally, for Exercise 0 (Experiment 8), we will implement
a "Door open/close alarm for in/out home modes"
and submit the exercise.

* Memory Use Status and Jumps between Pages

Now, I can understand wanting to take the code up to Exercise 0 and placing it directly in the main loop main0-main99, but let's not rush and wait a minute here.

If you think OK and merrily go about adding code right after main0, after a while, you will start noticing things like lack of response from the web control screen, partial displays of the HTML control screen, the browser receiving icon never moving on from "receiving" mode, etc. and from the symptoms it would appear that the system is "unstable".

< Cause of Problems >

With the current implementation of firmware, PAGE#0 of program memory is used right up to the limit.

Memory Use Status

PAGE#0 : 0x0000-0x07FF : 0x0000--0x07EA Used
PAGE#1 : 0x0800-0x0FFF : 0x0820--0x0FED Used
PAGE#2 : 0x1000-0x17FF : 0x1000--0x1240, 0x1300--0x13FB, 0x1400--0x14EB
0x1700--0x17FF Used
PAGE#3 : 0x1800-0x1FFF : 0x1800--0x185A, 0x1A00--0x1B19, 0x1D00--0x1DA5
0x1F00--0x1FC1 Used

For example, on PAGE#1, the put_socket_stat module (for sending socket status to the Web browser (i.e., netstat -n)) is commented out because PAGE#1 is already full and unless we delete this portion, the other modules will not fit in the memory. In firmware development, we need to treat one word of memory like a single drop of blood and use the limited memory space to the fullest.

< How to solve the problem >

About the only other place to put additional modules while preserving the current functions is in:
   PAGE#3 1E00h--1EFFh 256 words

This is right after Bank#4 for web messages, so here also we need to be careful not to let the Bank#4 messages exceed 256 words.

In the remainder of the tutorial, we will implement the experimental module from 1E00h and to check its operation we will write code for calling "across pages" to call the experimental module right after the main0 label.

(PIC16F87x CPUs have four pages of program memory. If you do not understand what that means, go back and review (refer to page 11))

OK, let us proceed with the actual implementation.

* On Firmware ver1.2.0.4(b) (updated 2004/10/30)

In Section 4. Firmware Updating Procedure, we started with the original ver1.2.0.0 (v12.asm) and made the following changes:

Update of the firmware version number
Addition of a line to the web control screen footer (end of web messages Bank#4)

to update the firmware to ver1.2.0.1.

ver1.2.0.0 * original distribution
ver1.2.0.1  update history 0.0->0.1

After that, a number of small modifications were made to update the firmware to Version ver1.2.0.4(b), the "starting point" for this tutorial.

ver1.2.0.2  update history 0.1->0.2
ver1.2.0.3  update history 0.2->0.3
ver1.2.0.4・ update history 0.3->0.4
ver1.2.0.4(a)  update history 0.4->0.4(a)
ver1.2.0.4(b)  update history 0.4(a)->0.4(b)

View the web control screen for the latest version
* taken for http://192.168.1.200:8080/

The remainder of the tutorial makes changes to this latest version of the firmware ver1.2.0.4(b). Of course, you can make the changes to the original firmware (v12.asm) and still get it to work in the same way.

Click here to download the latest version of the firmware (v1204org.asm, modified Oct. 30, 2004)

* Notes of Caution
We have changed the default IP address:http port number to the following:

* IP address: 192.168.1.200 (not 0.200)
* http port: 8080 (not 80)

To use this form of the firmware, set the network segment of the operation PC to:

* IP address: 192.168.1.10
* network mask: 255.255.255.0

(If you don't understand what this means, go back and review)


* Oct. 12, 2003 modification(a):
In v1204org.asm created Sep. 8, 2003, the HTML response section was made to output junk 0x00 after \r\n and as a result, there were reports that a number of browsers (such as Netscape7.1) could not understand that it was a text/html message type and functioned incorrectly. For this reason, we changed the HTML response section to output in one DA line. We apologize to our students for the trouble.

* Oct. 30, 2004 modification(b):
In v1204org(a).asm, line 556 contained an MPASM quasi-command and this generated an error in the GNUPIC (gpasm) assembler for MacOSX, so we deleted it.

* call/return using a dummy module

[Experiment 1] Construction of a dummy module
[Experiment 2] Construction of a dummy2 module for saving the status register values


e0.4.1 [Experiment 1] Construction of a dummy module

Let us construct and experiment with a dummy module.

< Specification >
This module will be designed as a dummy module on a separate page (PAGE#3, 1E00h-?) which will be called after a page change (PCLATH setting) and return to label main1.

< Operation >
No changes in particular.

< Outline of Processing >
The basic procedure for processing a call across program memory pages is as follows:

* figure out the page position (#0-#3) of the module to be called
* set the page control register
* call the module (call)
* reset the page control register (dependent on the current page position)

< Implementation >
The actual implementation is as follows.

+++++++++++++++++++++++++++++
PAGE#0
+++++++++++++++++++++++++++++
main0
movlw HIGH (dummy) ; dummy >> 8 obtain PAGE position
movwf PCLATH ; set PAGE control register
call dummy ; call dummy module
clrf PCLATH ; reset PAGE control register
main1
......
+++++++++++++++++++++++++++++
PAGE#3
+++++++++++++++++++++++++++++
org 1E00h
dummy
nop
return
+++++++++++++++++++++++++++++

[ Calling side of dummy call ]
The main0 label can be found near line 860 (memory bank #0). The main loop (portion which is executed periodically) consists of the area from the main0 label to the jump to the get_packet module just before the main99 label. We will add the four steps of the calling procedure shown above just after the main0 label.

Note of caution:Be sure the four lines to be added for calling the dummy module are positioned just after the existing main0 label. In this position, the calls will be sure to be made periodically from the main loop. (Added May 3, 2005)

 

[ Placement of the dummy module ]
We will place the dummy module near line 7243 of memory bank #3 between

Web browser messages up to here [ver0.4]
and
EEPROM data initialization

because it will be a suitable place to do an org 1E00h. The processing of the dummy module will be to perform only a nop command (do nothing) and then return.

 

[ Experiment 1 ]
Implement the dummy module and its call from main0 and verify that it works correctly. Since the dummy module does nothing and only returns after being called, the operation should be no different from the previous version ver1.2.0.4.

 


e0.4.2 [ Experiment 2 ] Construction of dummy2 module version for saving STATUS register values

Once Experiment 1 has been completed correctly, let us next construct a dummy2 module version which saves the values of the STATUS register.

< Specification >
Unlike interrupt routines, there is no problem if the W register, FSR, etc. are changed near main0, so we do not need context save/restore processing inside the dummy module. However, there cases where we do need to be careful with STATUS register changes so we will add processing for this part only, saving after a call and restoring after a return.

< Operation >
No change in particular

< Outline of Processing >
To save the values of the STATUS register, we will use the common variable wk2 (wk2 07FH).

wk2 is convenient because it looks the same from any of the register banks BANK#0-#3.
microchip/30292a-j.pdf#page=13

In interrupt routines where wk2 is used without initialization, processing for first storing the value of wk2 is performed before it is used, creating a vicious cycle of saves in the implementation. However, in the current firmware, wk2 is not used when dummy2 is called so we will use it to store the values of the STATUS register, but not add processing for storing wk2 itself (<- complicated, but be sure you understand what that means).

Of course, since wk2 holds the values of the STATUS register, it cannot be changed until the STATUS register has been restored.

< Implementation >
The actual implementation will be as follows.

+++++++++++++++++++++++++++++
PAGE#0
+++++++++++++++++++++++++++++
main0
movlw HIGH (dummy2) ; dummy2 >> 8 get PAGE position
movwf PCLATH ; set PAGE control register
call dummy2 ; call dummy2 module
clrf PCLATH ; reset PAGE control register
main1
......
+++++++++++++++++++++++++++++
PAGE#3
+++++++++++++++++++++++++++++
org 1E00h
dummy2
; STATUS store processing
swapf STATUS, 0 ; save STATUS register
clrf STATUS ; set STATUS to 0
movwf wk2 ; store in wk2
nop ; do nothing
; STATUS restore processing
swapf wk2,0
movwf STATUS ; restore status
return
+++++++++++++++++++++++++++++

Now, while the STATUS register is being stored (at the point where nop is being executed), we can change the STATUS RP0,RP1 bits as much as we like. With this, the base for the experimental form below is completed. :-)

[ Experiment 2 ]
Implement the dummy2 module version for saving the values of the STATUS register and its call from main0 and verify that it works correctly.
Since dummy2 does nothing and only returns after being called, the operation will be no different from the previous version ver1.2.0.4.

 

Door sensor -> LED relay output

[ Experiment 3 ] Fixed value output ("H") on RB4 (LED#4) Construction of test1 module
[ Experiment 4 ] Output from RB0 (door sensor) -> RB4 (LED#4) Construction of test2 module
[ Experiment 5 ] Reverse logic output RB0 (door sensor) -> RB4 (LED#4) Construction of test2a module
[ Experiment 6 ] Reverse logic output RB0 (door sensor) -> RB7 (Relay#2) Construction of test2b module
[ Experiment 7 ] Normal logic output RB0 (door sensor) -> RB4 and reverse logic output RB0 (door sensor) -> RB7 Construction of test2c module


e0.5.1 [ Experiment 3 ] Fixed value output ("H") on RB4 (LED#4) Construction of test1 module

To practice outputting values on PORTB, let us create a test1 module which will output a fixed value ("H") on RB4 (LED#4).

< Specification >
Fixed value ("H") output to RB4 (LED#4)

< Operation >
The operation will be that following a reset, RB4 will always be High (LED#4 on).

< Outline of Processing >
RB4 is assigned to PORTB[bit4] on register bank BANK#0 or #2.
microchip/30292a-j.pdf#page=13

We can switch to register bank BANK#0 and #2 by clearing the RP0 bit of the STATUS register.

To set PORTB[bit4] high, we can first read PORTB with movf, do an OR operation on bit4 to force it high, and then write the result back to PORTB.

< Implementation >
The actual implementation is as follows.

Below, we will omit changes to the main0 side and the save/restore processing at the beginning and end of the module. The four lines below will replace the nop in dummy2.

Of course, the module entry label should be test1, not dummy2.

         org 1E00h
test1
............ ; save STATUS register
bcf STATUS,RP0 ; register BANK#0/2
movf PORTB,0 ; read PORTB->regW
iorlw B'00010000' ; set RB4 high
movwf PORTB ; output regW->PORTB
............ ; restore STATUS register
return

Now, even if we command RB4=L, it will hold at H.
(If we send the command from the web control screen, it seems that it will change to "L" for an instant).

[ Experiment 3 ]
Implement the test1 module and its call from main0 and verify that it works correctly. Verify that RB4 always stays H. Aside from this, no changes are made and the module only returns so the operation should be no different from the previous version ver1.2.0.4.

 


e0.5.2 [ Experiment 4 ] Output RB0 (door sensor) -> RB4 (LED#4) Construction of test2 module

Next, to review conditional branching commands, let us construct a test2 module for outputting the value of RB0 (door sensor) to RB4 (LED#4).

< Specification >
* Port assignment:
PORTB[0](RB0): Input (door sensor "H" when door is closed)
PORTB[4](RB4): Output (LED#4 door state lamp "ON" when door is closed)

Output RB0・door sensor) -> RB4・LED#4) (normal logic)

< Operation >
The operation should be to always reflect the status of the door as follows:
* Door open (RB0=="L") -> LED#4 OFF (RB4:="L")
* Door closed (RB0=="H") -> LED#4 ON (RB4:="H")

< Outline of Processing >
RB0,4 are assigned to PORTB[bit0] and [bit4], respectively, in register bank BANK#0 or #2.
microchip

To switch to register bank BANK#0 or #2, we can clear RP0 of the STATUS register as in Experiment 3.

Check status of PORTB[0](RB0)
if (PORTB[0](RB0) == H)
PORTB[4](RB4) := "H"
else
PORTB[4](RB4) := "L"
endif

To check the status of PORTB[bit0], we first read PORTB with movf and copy it to working memory wk1. We then check the bit (e.g., using the btfsc command) (since we do not want to destroy the W register).

To save the W register, we use the common variable wk1 (wk1 07EH).
wk1 looks the same from every register bank BANK#0-#3.
microchip/30292a-j.pdf#page=13

* To set PORTB[bit4] H, we do the same as Experiment 3 (force bit4 to H with OR logic).
* To set PORTB[bit4] L, we can use AND logic to force bit4 to L with a bitmask and then write the value back to PORTB.

< Implementation >
The actual implementation is as follows.

         org 1E00h
test2
............ ; save STATUS register
bcf STATUS,RP0 ; register BANK#0/2
movf PORTB,0 ; read PORTB->regW
movwf wk1 ; copy to wk1
btfsc wk1,0 ; RB0 bit check
goto test2_01
andlw B'11101111' ; set RB4 to L
goto test2_02
test2_01
iorlw B'00010000' ; set RB4 to H
test2_02
movwf PORTB ; output regW->PORTB
............ ; restore STATUS register
return

Now the value of RB0 (door sensor) is output as is to RB4 (LED#4). (In other words, LED#4 is on when the door is closed.)

[ Experiment 4 ]
Implement the test2 module and its call from main0 and verify that it works correctly. Verify that the status of RB0 (door sensor) is output as is to RB4 (LED#4) (LED#4 is on when the door is closed).

 


e0.5.3 [ Experiment 5 ] Reverse logic output RB0 (door sensor) -> RB4 (LED#4) Construction of test2a module

Construct a test2a module by modifying the test2 module to output the reverse logic value of RB0 (door sensor) to RB4 (LED#4). In other words, in the security system we want to use the opposite meaning from test2 and assume

the lamp goes on (=door open alarm) when the door has been opened (danger situation)

< Specification >
Output RB0 (door sensor) -> RB4 (LED#4) (reverse logic)

< Operation >
The operation should be as follows
* Door open (RB0=="L") -> LED#4 ON (RB4:="H")
* Door closed (RB0=="H") -> LED#4 OFF (RB4:="L")
The output will serve as "an alarm for informing when the door has been opened".

Check status of PORTB[0](RB0)
if (PORTB[0](RB0) == L)
PORTB[4](RB4) := "H"
else
PORTB[4](RB4) := "L"
endif

 

[ Experiment 5 ]
Implement a test2a module as specified above and test its operation as a "door open alarm".

< Hint >
Just reverse the logic for the conditional jumps based on the door status.

(Before modification)
  btfsc wk1,0 ; RB0 bit check

(After modification)
  btfss wk1,0 ; RB0 bit check

 


e0.5.4 [ Experiment 6 ] Reverse logic output RB0 (door sensor) -> RB7 (Relay#2) Construction of test2b module

< Specification >
When the door is opened (time of danger), turn on the LED#7 lamp and the warning alarm (= door open warning alarm).

< Processing >

Check the status of PORTB[0](RB0)
if (PORTB[0](RB0) == L)
PORTB[7](RB7) := "H"
else
PORTB[7](RB7) := "L"
endif

 

[ Experiment 6 ]
Implement a test2b module according to the specifications above and verify that it works as a "door open warning alarm".

< Hint >
In place of RB4 bit processing, use RB7 bit processing.

Before modification
andlw B'11101111' ; set RB4 to L
iorlw B'00010000' ; set RB4 to H

After modification
andlw B'01111111' ; set RB7 to L
iorlw B'10000000' ; set RB7 to H

 


e0.5.5 [ Experiment 7 ] Normal logic output RB0 (door sensor) -> RB4 and reverse logic output RB0 (door sensor) -> RB7 Construction of test2c module

< Specification >
Monitor the state of RB0・door sensor) and perform the following
Lamp on when door closed <-> Turn on warning alarm when door open

RB0・door sensor)
-> output normal logic to RB4・LED#4) (lamp on when door closed)
-> output reverse logic to RB7・Relay#2) (turn on warning alarm when door open)

< Processing >

Check the status of PORTB[0](RB0)
if (PORTB[0](RB0) == L)
PORTB[7](RB7) := "H"
PORTB[4](RB4) := "L"
else
PORTB[7](RB7) := "L"
PORTB[4](RB4) := "H"
endif

 

[ Experiment 7 ]
Implement a test2c module according to the specifications above and verify its operation by monitoring the state of RB0 (door sensor) and checking that the lamp goes on when the door is closed <-> the warning alarm goes on when the door is opened.

< Hint >
If you are using test2b as a base, perform the RB4 bit operations with the RB7 bit operations.

(Before modification)
andlw B'01111111' ; set RB7 to L
(After modification)
andlw B'01111111' ; set RB7 to L
iorlw B'00010000' ; set RB4 to H

(Before modification)
iorlw B'10000000' ; set RB7 to H
(After modification)
iorlw B'10000000' ; set RB7 to H
andlw B'11101111' ; set RB4 to L

 

* Introduction of the in/out mode

[ Experiment 8 ] (Exercise 0) Alarm operation switching based on in/out mode Construction of test3 module
Considerations for setting "out mode" on reset initialization (RB5==Low)


e0.6.1 [ Experiment 8 ] Alarm operation switching based on in/out mode Construction of test3 module

< Specification >
We will use RB5(Mode#2) for the in/out mode switch.

During Low: out mode (initial value on reset)
During High: in mode

Based on this in/out mode we want to do the following

RB0・door sensor)
-> RB4 (LED#4): Lamp on when door closed (independent of mode)
-> RB7・Relay#2): When RB0==Low && RB5 == Low, turn on warning alarm when door is open (out mode)

< Operation >

Based on the in/out mode, we can do the following

* check the door status from LED#4 during in mode
* sound the warning alarm when the door is opened during out mode

[ Experiment 8 ] (Exercise 0)
Build a test3 module as specified above and verify its operation.

* Note of caution during programming Be sure to always add a short comment describing the action being taken on every line of assembly code. Even the person writing the program can forget the contents after 2-3 days and since the names of many branching commands in particular have confusing names (e.g., btfsc, btfss), be sure to add comments carefully to branching conditions in the code. Writing comments might seem useless at first, but it is an important element in the process of developing programs (->refer to Javadoc samples)


e0.6.2 Considerations for setting "out mode" on reset initialization (RB5==Low)

(A) Case of assuming "in mode" during the initial value (Low)

If a soft reset is done or a power outage occurs while you are out, the initial Low value on restart would be taken as "in mode" and the door open warning function would stop working.

(B) Case of assuming "out mode" during the initial value (Low)

As opposed to case (A), restarting from a soft reset or power outage would set the initial value Low and be taken as "out mode", so the door open alarm function would continue working.

(C)Battery backup during power outages

If you use an AC adapter and provide power to your system from an outlet, the door alarm "will not work" during a power outage. For this reason, you should prepare an uninterruptible power supply (UPS) for your PICNIC+peripheral extension options kit+network connecting environment.

* Submission of Exercise 0

(1) Do * e0.6.1 [ Experiment 8 ] Switching alarm operations based on in/out mode Construction of test3 module

(2) Verify that it works according to the specifications by using the door sensor status and the RB5 state change functions from the web control screen.

(3) Change the assembly source file version number to
 ver1.2.0.4 --> ver1.2.0.5
Also, change the web control screen footer section to include your student ID number, etc. as appropriate.

(4) Save the completed assembly source file as v1205e0.asm (use only one-byte English alphabet characters and numerals, alphabet characters should be lowercase, do not use one-byte katakana or two-byte characters in the file name.)

(5) Using the report submission system below, upload v1205e0.asm. Reports will be scored upon receipt.

< Method of submission >
Submit the assembly source file (file extension *.asm, not *.hex) of the program you created using the report system (with file uploading feature) below.

We will check the submitted programs and post a COMPLETED mark if the operation is OK and a RESUBMIT mark if there are any problems with the program operation.

Submit Report Exercise 0 (Exercise number: picnic-exp00) here

(6) The report status will be WAITING FOR MARK. Please wait while we check your report. If the waiting status does not change for an extended period of time, please send mail here.

(7) If a report has been marked as RESUBMIT, correct the problems indicated and submit under a different name such as v1205e0a.asm.

(8) If (7) does not occur (COMPLETED mark), Report Exercise 0 has been received and marked as completed.

Shinshu University Graduate School on the Internet

wasaki@cs.shinshu-u.ac.jp
Copyright(c) 2005 Katsumi Wasaki. All rights reserved.