Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

bsf assembler command works different between PIC16F887 and PIC16F84

Status
Not open for further replies.

zobbo

New Member
I'm a newb learning about PIC and Assembler at the same time. I have the PIC Simulator IDE and also a mikroElectronika EasyPIC6 to play with. I'm reading the book by John Morton. "The PIC Microcontroller, your personal introductory course"

If I run the following code on the Pic Simulator IDE (and I assume on the real chips) it behaves differently depending on which chip I am using. The PIC16F84 will leave bits 0,1 and 2 on PORTA set. The PIC16F887 will leave only bit 2 set. So the command bcf on the later chip seems to set the bit specified and clear all the others. Could somebody explain this behaviour to me or point me to. I'm really sorry if this is very elementary.

Code:
    org 0
Start:

	bsf            STATUS, 5
	movlw       b'00000000'	
	movwf       TRISA
	bcf            STATUS, 5
	
	movlw       b'00000011'
	movwf       PORTA
    	bsf            PORTA,2      
	goto 	$

    end
 
Last edited:
I would suggest your 'problem' is far more likely with the simulator than the PIC, or that you haven't set the port correctly (are pins RA0 and RA1 used for another purpose on a 16F887, and you're not setting then as digital I/O).

I would also suggest you don't use 'STATUS, 5' - I've no idea what that means? - use the supplied MicroChip mnemonics like everyone else.
 
Nigel I think STATUS,5 is page 0 / 1 on the pic16f84, this is why he should use banksel..

I presumed it was - but I wasn't going to download the datasheet and check it - when writing it correctly would obviate the need.

Banksel is fine (and I often use it) but it does tend to add multiple lines.
 
Yeah but so does bcf STATUS,6 : bsf STATUS,5... Plus with the banksel makro he doesn't need to worry which bank (It would be porta / trisa ) they used to be doubled up so 0x106 was the same as 0x06....but new peripherals an all...
 
I also notice that if I use PORTB instead of PORTA, it works as I expect it to (i.e. not clearing the other bits).
 
The PIC 16F887 also has an on chip comparator that resides on Port A, which the F84 DOESN'T have. By default the comparators should come up disabled but I would put in the extra instructions to ensure that it does. Modify your code in this fashion to accomplish this -

Code:
		org		0x000			;reset vector

Start		
		banksel		TRISA			;bank 1		
		movlw		b'00000000'		;RA0 - RA7 outputs
		movwf		TRISA
		banksel		CM1CON0			;bank 2
		bcf		CM1CON0,C1ON		;comparator 1 off
		bcf		CM2CON0,C2ON		;comparator 2 off
		banksel		PORTA			;bank 0	

		movlw		b'00000011'		;RA0 & RA1 high
		movwf		PORTA
		bsf		PORTA,2			;RA2 high      
		goto	 	$			;done

		end

When learning PICs and ASM programming you will find that while the instruction set for a given family remains pretty much the same, there are features which differ from PIC to PIC. For this reason, consulting the data sheet to get familiar with each PIC you use is a must.
 
Last edited:
OK, firstly apologies for not using BANKSEL or the Microchip Mnemonics. I have two PIC Assembler books which I am taking my code from. Neither of them even mention BANKSEL. Is there a more recent book which is recommended?

Code:
__CONFIG _HS_OSC

LEDS		EQU	b'00000011' ; Initial LEDS
EXTRA_LED	EQU	0x05 ; Extra led to switch on
    org 0
Start:
        ; banka
	banksel	TRISA
	movlw	b'00000000'	
	movwf	TRISA
	
	banksel PORTA
	movlw	LEDS
	movwf	PORTA
        bsf     PORTA,EXTRA_LED      

	;; bankb 	
	banksel	TRISB
	movlw	b'00000000'	
	movwf	TRISB
	
	banksel PORTB
	movlw	LEDS
	movwf	PORTB
        bsf     PORTB,EXTRA_LED      

	goto 	$

    end

Secondly I can confirm that the code above (I have made some modifications as you see), when run on a real PIC16F887 does vary from when running under the PIC simulator. On the real PIC I am left with only the EXTRA_LED bit set for both BANKA and BANKB. On the simulator, it's the same for BANKA but BANKB has the LEDS and EXTRA_LED bits set.

To ask a really basic question ... is the behaviour I am seeing on the real chip to be expected. bsf will set a bit on a register and clear the others. If these questions are too basic here are there any other forums better suited for newbies?

Many thanks for the responses so far

Ian
 
bsf should only set the desired bit while leaving the other bits in the register unaltered. bsf is a two operand instruction, with the second operand being the physical bit number. Yet you are using the label "EXTRA_LED", which is assigned to a hex value (you can only use decimal values to specify a bit number, not hex values).

Change it to -

Code:
EXTRA_LED	EQU		5

and all should be good.

Now another question...what external crystal are you using (speed-wise)?
 
Last edited:
bsf should only set the desired bit while leaving the other bits in the register unaltered. bsf is a two operand instruction, with the second operand being the physical bit number. Yet you are using the label "EXTRA_LED", which is assigned to a hex value (you can only use decimal values to specify a bit number, not hex values).

You can specify bit-values in any base you want, it makes no difference - it's all binary in the end anyway.

Certainly as far as bit values are concerned (0-7) HEX and Decimal are exactly the same.
 
Code:
	list	p=16F887		
	include "P16F887.inc"		
	

LEDS		EQU	b'00000011' ; Initial LEDS
EXTRA_LED	EQU	0x05 ; Extra led to switch on
    org 0
Start:
        ; banka
	banksel	TRISA
	movlw	b'00000000'	
	movwf	TRISA
	banksel	ANSEL
	clrf	ANSEL
	banksel	ANSELH
	clrf	ANSELH
	
	banksel PORTA
	movlw	LEDS
	movwf	PORTA
        bsf     PORTA,EXTRA_LED      

	; bankb 	
	banksel	TRISB
	movlw	b'00000000'	
	movwf	TRISB
	
	banksel PORTB
	movlw	LEDS
	movwf	PORTB
        bsf     PORTB,EXTRA_LED      

	goto 	$

end

Setting the ansel registers cures that..
 
Last edited:
Solved

Ian

Many thanks - I had to do two things in the end to solve this. One of them was to add your suggestion. The other was to disable low voltage program in the configuration bits. The following assembler will light up all LEDS on an EasyPIC6 with PIC16F887 processor - banks A to D, excluding the 7th bit on each bank.

Now I need to learn about the low voltage program and ANSEL/ANSELH. Many thanks to everybody for their help and advice!

Code:
list p=16f887
#include <p16f887.inc>
errorlevel -302 ; Disables warning about bank bits

__CONFIG	_CONFIG1,_INTOSCIO    & _WDT_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _DEBUG_OFF & _LVP_OFF   
__CONFIG	_CONFIG2, _BOR40V & _WRT_OFF 

LEDS		EQU	b'00111111' ; Initial LEDS
EXTRA_LED	EQU	0x07 ; Extra led to switch on
ALL_OUTPUT  EQU b'00000000' ; All pins outputmode

org 0

Start:

	banksel TRISA
	movlw	ALL_OUTPUT
	movwf	TRISA

	banksel	ANSEL
	clrf	ANSEL
	banksel	ANSELH
	clrf	ANSELH

	banksel PORTA
	movlw	LEDS
	movwf	PORTA
	bsf	PORTA,EXTRA_LED


	banksel	TRISB
	movlw	ALL_OUTPUT	
	movwf	TRISB
	
	banksel PORTB
	movlw	LEDS
	movwf	PORTB
	bsf	PORTB,EXTRA_LED	
	
	banksel	TRISC
	movlw	ALL_OUTPUT	
	movwf	TRISC
	
	banksel PORTC
	movlw	LEDS
	movwf	PORTC
	bsf	PORTC,EXTRA_LED
	
	banksel	TRISD
	movlw	ALL_OUTPUT	
	movwf	TRISD
	
	banksel PORTD
	movlw	LEDS
	movwf 	PORTD
	bsf	PORTD,EXTRA_LED
	
	goto 	$

    end

Ian
 
In PICs such as the 16F84 and the 16F877A, the BSF instruction is executed like all 8 bit instructions:-
1) Collect 8 bit word from memory into ALU
2) perform operation in ALU
3) Store 8 bit word from ALU back into memory

The internal architecture on the PIC has to be able to do those operations so that it can perform all the usual instructions like add, rotate, xor etc etc. Microchip have used the same addressing structures to do BSF. The only alternative would have been to build register addressing that was able to write to an individual bit rather than a whole byte, which would have made the whole addressing system far more complicated.

So the BSF instruction does this:-
1) Collect 8 bit work from memory into ALU
2) Set just one of the bits and leave all the other bits unchanged
3) Store 8 bit word from ALU back into memory

That's fine for registers, but when the bit is in PORTA, the same thing happens. All the bits that are not supposed to change are read, and then written back to PORTA. If something stops them being read correctly, they will be overwritten with an incorrect value.

Two things can stop them being read correctly. One is that the pins are configured as analogue or comparator inputs, which disables the digital reading. The other thing is that the voltage on the pin has not had enough time to get to the correct value.

Where you have got:-
Code:
	movlw		b'00000011'		;RA0 & RA1 high
		movwf		PORTA
		bsf		PORTA,2			;RA2 high

the movwf line will write to PORTA at the end of the second instruction. Very shortly after that, at the beginning of the third instruction, PORTA voltages are read. If the voltages on PORTA, 0 and PORTA, 1 have not got high enough in that very short time interval, then the BSF instruction will read them as low, so the pins will drive low as soon as the BSF instruction finishes.
 
Diver300, that is extremely helpful - thank you very much. You may have explained the next query I had regarding some strange behaviour I was seeing. I'm away from home for the next couple of days but will take a look when I return. Is the fix just to insert a delay before setting anything? What's a safe delay to have?
 
I usually allow one clear instruction after any operation that writes to a port before a BCF or BSF on another bit for that same port.

However, a large load on the pin can cause incorrect operation no matter how big the delay.

Some people use a shaddow register for the port, and only ever write to the whole port with the contents of the shadow register. Some newer PICs have a port latch register that does just about the same in hardware.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top