### Welcome to EDAboard.com

#### Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Status
Not open for further replies.

#### Noman Yousaf

##### Full Member level 4
hi all

i am not very new in assembly. but i am wondering that why i cant solve this very very simple I/O problem.

i want to use portc,2 and portc,3 as input an portc,4 and portc,5 as output and a simple delay.
(other all ports are set for their jobs)

when portc2 will hi, portc4 will lo and when portc2 will lo, portc4 will ho.

and same will be done with portc3 to portc5.

problem is, when only "chk_sw" routine is run, it works good and if i add a "delay", only portc,3 and portc,5 work, not portc2 and portc4.

I am getting mad that why delay is turning off the working of first portion of chk_sw routine.

can anybody help me.

i am stuck.

code is
Code:
LIST   P=PIC16F887
PROCESSOR  16F887
#include "P16F887.INC"

BANKSEL        TRISC

MOVLW        03FH
MOVWF        TRISA
MOVLW        0FH
MOVWF        TRISB
MOVLW        0CFH
MOVWF        TRISC
MOVLW        00H
MOVWF        TRISD
BANKSEL        ANSEL
CLRF        ANSEL
BANKSEL        ANSELH
CLRF        ANSELH

BANKSEL        PORTA
MOVLW        0FFH
MOVWF        PORTA
MOVWF        PORTB
MOVWF        PORTD
MOVLW        0CFH
MOVWF        PORTC

MAIN:
CALL        CHK_SW

CALL        DELAY        ;MAKE A DELAY
GOTO        MAIN

DELAY:

MOVLW        08H
MOVWF        30H

MOVLW        0FFH

MOVWF        31H
MOVWF        32H

DECFSZ        32H,F
GOTO        $-1 DECFSZ 31H,F GOTO$-4

DECFSZ        30H,F
GOTO        $-6 RETURN CHK_SW: BANKSEL PORTC BTFSC PORTC,2 GOTO SW1_1 BSF PORTC,4 GOTO SW2_1 SW1_1: BCF PORTC,4 SW2_1: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BTFSC PORTC,3 GOTO SW1_2 BSF PORTC,5 GOTO SW2_2 SW1_2: BCF PORTC,5 SW2_2: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RETURN END Last edited by a moderator: #### betwixt ##### Super Moderator Staff member A few more comments would be helpful. I suspect your problem is the watchdog timer though, if you have it enabled, add "clrwdt" to the delay routine so the WDT can't time out inside it. Incidentally, there is no point in clearing the ANSEL registers because their values will be overwritten when you use them and they are both in the same bank so you can remove the second 'banksel' instuction. Although what you have done isn't wrong, I would strongly advise you to use labels instead of '$-x' addresses. It will work as it is but isn't portable. For example:
Code:
DELAY:

MOVLW        08H
MOVWF        30H

MOVLW        0FFH

MOVWF        31H
MOVWF        32H
DelayLoop
clrwdt
DECFSZ        32H,F
GOTO        DelayLoop

DECFSZ        31H,F
GOTO        DelayLoop

DECFSZ        30H,F
GOTO        DelayLoop

RETURN

Brian.

#### Noman Yousaf

##### Full Member level 4
i changed the delay routine by copying and pasting your sent one in my code but nothing changed. problem is still there.

- - - Updated - - -

and very interesting thing is if i change 2nd portion (portc3) to first potion (portc2), even then only upper portion disables.
in both cases only lower portion works and upper disables.

#### betwixt

##### Super Moderator
Staff member
I can't see any obvious reason why it wont work. If you are using real hardware to test it, make sure you have pull-up or pull-down resistors on the input pins so you can be sure the logic level requirements are being met. A switch from an input pin to CSS or VDD alone wont work, you need the resistor to ensure the level reverses whn the switch is opened.

There is a remote chance you are seeing an RMW effect because you write to and then immediately read PORTC. I doubt thats the problem but you an easily fix it by adding a 'nop' instruction after the line 'BCF PORTC,4'.

Hint: a better way of assigning addresses to variables (as opposed to you explicitly using 30H, 31H and 32H) is to use the 'cblock' directive. It will ensure you don't accidentally use the same address for something else. For example:
Code:
   cblock 30H
delay1
delay2
delay3
endc
then use the names delay1, delay2 and delay3 instead of the numbers. It will work exactly the same, but if you later want to add more variables you just insert them in the cblock list and the assembler will take care of working out a suitable address for them.

Another hint:
your code will not work if you add interrupts because you are putting other instructions where the interrupt vector will be. If you start your program by copying the template provided with the assembler then add your own code to it, the interrupt vector will be dealt with automatically. Look for the file called '16F887TEMP.ASM' and add your code to it.

Brian.

Points: 2

### Noman Yousaf

Points: 2

#### PA3040

As explained by betwixt in his post #2 and #4 please check the switch pull_up in the picture

#### pjmelect

Use

Code:
	bsf	STATUS,RP0   ;Switch to Bank 1
bcf	STATUS,RP0   ;Switch to Bank0

Last edited:

#### betwixt

##### Super Moderator
Staff member
NO NO NO - that is both dangerous and counter intuitive. Use 'banksel' instead.

The difference is 'banksel' controls ALL the bank selection bits, not just RP0. Different PICs with different register banking schemes use different bank selecting bits. Specifying STATUS,RP0 is only valid for some devices but 'banksel' will be adapted by the assembler so it is always correct for the target device. You can use 'banksel x' where 'x' is the bank number you desire but using a register name is easier to read and always uses the bank for the named register, even if it maps to a different address in another device.

Brian.

#### Noman Yousaf

##### Full Member level 4
thanks sir you helped me. actually the problem was RMW.
i added little delays somewhere and it started working.

what is meant by the ORG set in any ISR? and how to calculate the org #?

i am using timer1 interrupt and my code is long.

when i build it,
CORE-E0001: Stack over flow error occurred from instruction at 0x0008ed
CORE-E0001: Stack over flow error occurred from instruction at 0x000102

which org is to be set? guide please

code is here
Code:
org    0
goto   start

org   04h

BTFSS    PIR1,TMR1IF
RETFIE

LCALL        SECONDS

org        100h

start:
...........main code

.
.
.
.
.
.
SECONDS
ORG     1000H
;;;;saving wreg values
BCF        INTCON,GIE
MOVWF    WHAT
SWAPF    STATUS,0
MOVWF    QSTAT
;;;;end saving wreg values

BCF        PIR1,TMR1IF
BCF        T1CON,TMR1ON

DECFSZ    SECOND_REG
GOTO    SCND
MOVLW    DIVS
MOVWF    SECOND_REG
BSF        50H,0        ;goes hi after 1 sec
SCND

MOVLW    TMRH
MOVWF    TMR1H
MOVLW    TMRL
MOVWF    TMR1L
BSF            56H,1
BSF        T1CON,TMR1ON

;;;;retrieving wreg values
SWAPF    QSTAT,0
MOVWF    STATUS
SWAPF    WHAT,1
SWAPF    WHAT,0
BSF        INTCON,GIE
;;;;end retrieving wreg values

RETURN

Last edited by a moderator:

#### pjmelect

NO NO NO - that is both dangerous and counter intuitive. Use 'banksel' instead.

The difference is 'banksel' controls ALL the bank selection bits, not just RP0. Different PICs with different register banking schemes use different bank selecting bits. Specifying STATUS,RP0 is only valid for some devices but 'banksel' will be adapted by the assembler so it is always correct for the target device. You can use 'banksel x' where 'x' is the bank number you desire but using a register name is easier to read and always uses the bank for the named register, even if it maps to a different address in another device.

Brian.

The problem with using banksel x is that it uses an extra byte and if you are like me I am always running out of memory, and as you change the bank often in a typical program the savings can mount up.

#### betwixt

##### Super Moderator
Staff member
If you post a section of code, please enclose it in "code tags" so the forum doesn't remove formatting. Paste it in the message window, highlight it with your mouse then click on the # symbol in the window header. I will add the code tags to your code for you this time.

When the assembler converts your instructions into a binary image so it will run in the PIC, it normally works from the first address (normally 0000H), stores the first instruction there and moves to the next address to store the next instruction and so on. The 'ORG' directive (its an instruction to the assembler, not a PIC instruction) makes the next instruction start at a different address. It gives you the ability to jump over some addresses which sometimes you have to do. What your code:
Code:
code is here
org 0
goto start

org 04h

BTFSS PIR1,TMR1IF
RETFIE

LCALL SECONDS

org 100h

start:
does is this:
'org 0' tells the assembler the following instruction is to be stored at address zero,
'org 04h' tells the assemble the next instruction is to be placed at address 4, so you skipped over addresses 1 ,2 and 3. I'll explain why this is done later.
the next two instructions are placed starting at address 4.
The 'LCALL' isn't quite right, it should just be 'call' in this case although it will still work in most cases.
'org 100h' moves the address for the next instruction to address 100h, so you left nearly 250 addresses unused!

In that PIC there are two special addresses, the reset vector (0000h) and the interrupt vector (0004h). They are both 'hard coded' inside the PIC and can never be changed. The reset vector is where the program counter picks up the first instruction after the power is turned on, the MCLR pin goes from low to high or a watchdog timeout occurs. So that's where your program is normally located so it runs straight away. The interrupt vector is the address the PIC automatically jumps to when an interrupt occurs, that's why you will find the interrupt service routine (ISR) is always located at address 0004h. Now you can see why the 'org 04h' is important, if you didn't use it the assembler might put instructions at address 04h that were nothing to do with the interrupt and cause chaos if an interrupt happened.

Instead of 'org 04h' you could have used other instructions to fill in the gap so the first ISR instruction was still at address 04 but that would mean if you changed those instructions the gap they filled may change size and the ISR be placed wrongly. Using the 'org' makes sure the address is always correct.

The normal way we start an assembly program is to put a jump instruction to the real starting address at 0000h, then move the address to 0004h and place the ISR there. After the end of the ISR code, we place the 'real' program to be run. That explains why we use labels in jump instructions rather than a numeric address. When the assembler runs, it goes through the code twice (that's why we call them two-pass assemblers!), the first pass ignores what the instructions actually do, it just looks to see if they are one byte or two bytes long and whether there are any 'org' lines that change the addresses. From this it can work out what addresses each of the labels will be at in the final binary image. It builds a list of labels and their addresses called a 'symbol table'. Then it makes the second pass, this time converting the assembler instructons to their binary equivalents and wherever a label is found it substitutes the value from the symbol table. It make the program very flexible because if you add or remove lines of code, the assembler will re-calculate all the label addresses for you.

Don't worry about it too much for now but there is an alternative way of writing your program in 'relocatable' code where the benefits of labels really show because you can write the code in modules are use them in other programs. Thats really useful if you write library routines.

Back to your program. If you remove the 'org 100h' altogether it will move the 'start' label from address 100h to the next address after "LCALL SECONDS" and save you lots of memory space. Also make the 'LCALL' a normal 'call' and it should assemble with no errors.

It still wont work though! You have a serious error in the ISR. See if you can get it to assemble using the suggestions I gave first.

Brian.

Noman Yousaf

Points: 2