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.

Defining Constants & Variables

Status
Not open for further replies.

Electrix

Member
I have a question about the foll:

Code:
 DataByte equ 0x20; DataByte is at location 0x20 in RAM--VARIABLE---
 Freq equ 4; Freq is same as 4--CONSTANT-------

Now my question is that if I want to declare a constant that holds a hex value how should i define it.
Lets say i want DataByte should hold a constant of Hex 41. So if I write
Code:
 DataByte equ 0x41
it will not mean that DataByte is a constant holding value Hex 41. So how do I define it ?
 
Code:
 DataByte equ 0x20; DataByte is at location 0x20 in RAM--VARIABLE---
 Freq equ 4       ; Freq is same as 4--CONSTANT-------

The description of the above code is not correct. DataByte means 0x20. If you use it as the target of an address, then it would means RAM location 0x20. If you use it as data, then it has a value of 0x20. See the following example for codes on PIC.

Code:
movlw    DataByte    ;this would give W a value of 0x20, not the RAM content of 0x20
movwf    DataByte    ;this would move the value in W to RAM location 0x20
movf     DataByte,W  ;this would move the RAM content of location 0x20 into W
 
2 alternatives to equ that I know of :

1st, use the assembler directive #define. What you get is not really a constant variable, but actually a literal copied at every places you used the #defined name.

Code:
#define    DataByte  0x41

2nd, the "constant" keyword defines constant variables

Code:
    constant    DataByte = 0x41

Note however that

Code:
DataByte    equ    0x41

movf    DataByte, w    ; Puts data contained at address 0x41 in W
movlw    DataByte    ; Puts literal 0x41 in W

So equ works too.
 
BTW, note the blank space before the keyword "constant". It is needed, although MPASM will only issue a warning if you forget it. At least, the latest version of MPASM will treat is as non-critical. I don't know about earlier versions.

Also note that the #define method has the advantage of not using up any RAM space. Could be useful in smaller PICs.
 
Joel Rainville said:
BTW, note the blank space before the keyword "constant". It is needed, although MPASM will only issue a warning if you forget it. At least, the latest version of MPASM will treat is as non-critical. I don't know about earlier versions.

Also note that the #define method has the advantage of not using up any RAM space. Could be useful in smaller PICs.

I did not understand that. Why should the 'equ' directive use up the RAM space. Like the #define. equ should not, right ??
 
#define defines a text substitution string. Instead of defining a variable that your code will access during execution, MPASM just replaces every occurence of the #defined value in your code with a literal.

equ on the other hand, tells the assembler to reserve 8 bits of RAM to eventually store data at the address location used as a constant. So while the address is constant and can be used as a literal, the data pointed to is not, so it needs RAM allocated to be modified.

As far as I know, there is no real constant in PIC assembly, where both the address and the memory content are constant and not writable. Someone please correct me if I'm wrong, but I really doubt it.
 
Joel Rainville said:
#define defines a text substitution string. Instead of defining a variable that your code will access during execution, MPASM just replaces every occurence of the #defined value in your code with a literal.

equ on the other hand, tells the assembler to reserve 8 bits of RAM to eventually store data at the address location used as a constant. So while the address is constant and can be used as a literal, the data pointed to is not, so it needs RAM allocated to be modified.

As far as I know, there is no real constant in PIC assembly, where both the address and the memory content are constant and not writable. Someone please correct me if I'm wrong, but I really doubt it.

Sorry but I still do not understand..

Code:
 Freq equ 4

Isn't this also a plain text(string) substitution method.
If equ does occupy RAM, which(Address) RAM does it use
Besides, I thought all assembler directives do not occupy any memory.

PS: Thanks for all your patience... :D
 
Electrix said:
Joel Rainville said:
#define defines a text substitution string. Instead of defining a variable that your code will access during execution, MPASM just replaces every occurence of the #defined value in your code with a literal.

equ on the other hand, tells the assembler to reserve 8 bits of RAM to eventually store data at the address location used as a constant. So while the address is constant and can be used as a literal, the data pointed to is not, so it needs RAM allocated to be modified.

As far as I know, there is no real constant in PIC assembly, where both the address and the memory content are constant and not writable. Someone please correct me if I'm wrong, but I really doubt it.

Sorry but I still do not understand..

Code:
 Freq equ 4

Isn't this also a plain text(string) substitution method.
If equ does occupy RAM, which(Address) RAM does it use
Besides, I thought all assembler directives do not occupy any memory.

PS: Thanks for all your patience... :D

Well, ok, you're right. Freq in that case doesn't reserve any RAM because you're never actually gonna write to address 0x04. And if you plan on doing so, don't! :lol: It's a reserved memory location.

One thing I overlooked is the fact that a memory location is only used up if you actually plan to write to the address pointed to.

However, in that case I would use the constant or #define methods instead of equ, even though they offer basically the same functionality, mainly for the readability factor. But that's a matter of personal preference.
 
Joel Rainville said:
Well, ok, you're right. Freq in that case doesn't reserve any RAM because you're never actually gonna write to address 0x04. And if you plan on doing so, don't! :lol: It's a reserved memory location.
Not so fast!
EQUs and #Defines don't occupy any space!
The only difference is that EQU has to be a numerical value (and can be used in ASSEMBLER scripts, or to use it as a substitution while working with certain memory space - but has to be used first "MOVWF REG1") and #define is a TEXT substitution (or it can span through multiple bytes, such as #define GR_LED PORTA,4).

EQU must resolve to an integer, #define can be any text string.
 
Jay.slovak said:
Joel Rainville said:
Well, ok, you're right. Freq in that case doesn't reserve any RAM because you're never actually gonna write to address 0x04. And if you plan on doing so, don't! :lol: It's a reserved memory location.
Not so fast!
The only difference is that EQU has to be a numerical value (and can be used in ASSEMBLER scripts, or to use it as a substitution while working with certain memory space - but has to be used first "MOVWF REG1") and #define is a TEXT substitution (or it can span through multiple bytes, such as #define GR_LED PORTA,4).

EQU must resolve to an integer, #define can be any text string.

Sure, I was just pointing out how to use #define instead of equ for constant numeric values. I did not imply #define could only be used for this purpose.

EQUs and #Defines don't occupy any space!

In fact, you could say that nothing ever occupies any RAM space, because even when I do this :

Code:
Byte    equ    0x72

while it clearly looks like I am reserving memory location 0x72 for future use, the assembler will be happy to let you write

Code:
Byte    equ    0x72
Byte1   equ    0x72
Byte2   equ    0x72
Byte3   equ    0x72
Byte4   equ    0x72

because the memory isn't reserved at all, and the 0x72 values could very well be used as literals only and the byte at 0x72 never written to.

However, what I'm saying is that when you do want to use 0x72 as a literal constant, it would be better to use constant or #define because it is easier to see, when reading the code, especially someone else's, that a a value declared as a constant or #defined isn't interpreted as a memory location, while one declared with equ is.

But like I said, it's a matter of personal preference, and you're right, equ directives don't litterally use up RAM space... unless you decide so, i.e. when you decide to use memory location 0x72, the net result is that you have one less byte in RAM available to your program...

Sometimes my limited english vocabulary fails to clearly express my thoughts :lol: Sorry about that ;)
 
Joel Rainville said:
Sometimes my limited english vocabulary fails to clearly express my thoughts :lol: Sorry about that ;)
Same here :)

Let's analyse this:
Code:
REG1 equ 0x10
MOVLW REG1
MOVWF REG1
As we can see the number 10h will get written to the RAM byte number 16 (10h) so we can use it this way.

Here is what I do in most of my programs:
Code:
;********** Definovanie uzivatelskych registrov *******************
	Fosc	equ	20	;Frekvencia Oscilatora v Mhz
	#DEFINE	RW	PORTB,1	;Hlavne tlacidlo
	#DEFINE	RS	PORTB,2	;Pomocne tlacidlo
	#DEFINE	E	PORTB,0
	#DEFINE	BCKL	PORTC,1
	#DEFINE	TL	PORTB,3
	#DEFINE	LED	PORTB,4
	#DEFINE	SPI_CSH	PORTB,5
	#DEFINE	SPI_CSL	PORTB,6
;	#DEFINE	Ul	PORTC,0	;!!
;	#DEFINE	Uh	PORTC,1	;!!
	#DEFINE	ON_OUT	PORTB,7
	#DEFINE	ON_AUX	PORTA,4	
	#DEFINE	SWITCH	PORTC,0
	#DEFINE	FAN	PORTC,2
	#DEFINE	lcdBF	PORTD,7
	#DEFINE	BEEP	PORTE,2
	#DEFINE	OverFlow	Flags,0
	#DEFINE	POT	CONTROL,1
	#DEFINE	TLAC	CONTROL,0
	#DEFINE	PC	CONTROL,2


	ZDRZ0	equ	D'000'
	ZDRZ1	equ	D'001'
	ZDRZ2	equ	D'002'
	SPIreg	equ	D'003'
	TAB_CISLO	equ	D'004'
	TAB_MIESTO	equ	D'005'
	DEC_orig	equ	D'006'
	DEC_n	equ	D'007'
	stovky	equ	D'008'
	desiatky	equ	D'009'
	jednotky	equ	D'010'
	DEC_TMP	equ	D'011'
	Count	equ	D'012'
	R0	equ	D'013'
	R1	equ	D'014'
	R2	equ	D'015'
	R3	equ	D'016'
	R4	equ	D'017'
	Uset	equ	D'018'
	ADSEND	equ	D'019'
	LCD	equ	D'020'
	LCDc	equ	D'021'
	Usense	equ	D'022'

	Isense	equ	D'023'
	Temp	equ	D'024'
	Pot1	equ	D'025'
	Pot2	equ	D'026'
	Flags	equ	D'027'
	Acc1L	equ	D'028'
	Acc1H	equ	D'029'
	Acc2L	equ	D'030'
	Acc2H	equ	D'031'
	CONTROL	equ	D'032'
	TLATCH	equ	D'033'
	DEMOcount	equ	D'034'
	DEMOtab	equ	D'035'
	INTcount	equ	D'036'
	
;************** Tabulka pridelenych napeti ku tlacidlam **********
	s0	=	015*factor
	s1	=	030*factor
	s2	=	045*factor
	s3	=	060*factor
	s4	=	075*factor
	s5	=	090*factor
	s6	=	105*factor
	s7	=	120*factor
	factor	equ	2
I am happy with it this way.
 
Yeah, I understand. It's actually what #defines are mostly for.

But one point that I insist on is that it is less readable for someone else than you. When I see an occurence of say "ON_OUT" in your code, I have no clue what it is and have to scroll back to the #define for "ON_OUT" to see that it's actually "PORTB, 7". A more descriptive name would help, though not as clear as "PORTB, 7".

Also in your code

Code:
REG1 equ 0x10
MOVLW REG1
MOVWF REG1 <- I assume EG1 was actually a typo

As a reader of your code, when I see the first use of REG1 as a literal, I make a mental note that REG1 is a literal constant. If I later see that movwf where REG1 is used as a memory location, my first thought is "woops, here's a bug". It is very confusing. So a nice comment to clear things up, or using constant or a #define would make the code much clearer to an outside person, and much easier to maintain even if you're the only one touching that code for the next 10 years, because there's a chance that in a few months, you're gonna forget all about REG1 and what it is used for...
 
Joel Rainville said:
Also in your code

Code:
REG1 equ 0x10
MOVLW REG1
MOVWF REG1 <- I assume EG1 was actually a typo

Yes, a typo :oops:

Well "ON_OUT" is the most important bit (it turn's on/off the power supply output) so I didn't bother making the name more understandable (and therefore longer), and the code itself IS well comented.

As a reader of your code, when I see the first use of REG1 as a literal, I make a mental note that REG1 is a literal constant. If I later see that movwf where REG1 is used as a memory location, my first thought is "woops, here's a bug". It is very confusing
Yes, Commenting is the only way how to prevent such situations...
 
Perhaps an error with MPLAB (IDE v7.30) setup, but I'm entering the torturous compiling of my first "proper" program for the 18f452, and for equ directives such as
Code:
count_mtableequ equ 0x500 ;equates counter1 variable at RAM bank 5 (start position)

I'm getting
Code:
Warning[207] Found label after column 1. (count_mtableequ)

Just trying to place a variable in a RAM location to be serviced later on.
 
That is NOT an Error, it is a Warning (non critical in this case). MPASM requires that all labels to be placed in first column. Again, this is only a warning, to correct this, just delete the leading space or Tab character(s) before the label.
 
When defining ram variables I use the cblock instruction.

Example
Code:
        cblock  20h
Acc:0
AccLo
AccHi
Buffer:10h	
Flags		
Count
Keys
OldKeys
Edge
        endc

        cblock  70h
int_work
int_status
        endc
In the above, Acc is a 16 bit variable that can be refered to as Acc or AccLo for the low byte and AccHi for the high. The variable Buffer is 16 bytes long.

The variable Flags would typically contain bit variable. These would be defined using #define. I start them b_ to indicate that they are bits.
Code:
        #define b_GotByte Flags,7
        #define b_Next Flags,6

When I’m defining the I/O bits I tend to do something like.
Code:
In      equ     1
Out     equ     0     

PA0     = Out  ; description of this bit
PA1     = In    ; ditto
PA2     = Out
PA3     = Out
PA4     = In
PA5     = In
PA6     = In
PA7     = In

TrissA  equ     (PA7<<7)+(PA6<<6)+(PA5<<5)+(PA4<<4)+(PA3<<3)+(PA2<<2)+(PA1<<1)+(PA0<<0)

I also use the shift left function to setup registers.
EG
Code:
        bsf     STATUS,RP0
        movlw   (0<<CSRC|0<<TX9|1<<TXEN|0<<SYNC|1<<BRGH|0<<TRMT|0<<TX9D)
        movwf   TXSTA;		bit 2 = 1 therefore high speed
        bcf     STATUS,RP0
        movlw   (1<<SPEN|0<<RX9|0<<SREN|1<<CREN|0<<ADDEN|0<<FERR|0<<OERR|0<<RX9D)
        movwf   RCSTA
        movlw   (1<<GIE|1<<PEIE|0<<TMR0IE|0<<INTE|0<<RBIE|0<<TMR0IF|0<<INTF|0<<RBIF)
        movwf   INTCON;		enable Peripheral interrupts

Hope someone found that interesting.

Mike.
Edit corrected error found by eblc1388
 
Pommie said:
I also use the shift left function to setup registers.
EG
Code:
                bsf     STATUS,RP0
                movlw   (0<<CSRC|0<<TX9|1<<TXEN|0<SYNC|1<<BRGH|0<<TRMT|0<<TX9D)
                movwf   TXSTA;		bit 2 = 1 therefore high speed
                bcf     STATUS,RP0
                movlw   (1<<SPEN|0<<RX9|0<<SREN|1<<CREN|0<<ADDEN|0<<FERR|0<<OERR|0<<RX9D)
                movwf   RCSTA
                movlw   (1<<GIE|1<<PEIE|0<<TMR0IE|0<<INTE|0<<RBIE|0<<TMR0IF|0<<INTF|0<<RBIF)
                movwf   INTCON;		enable Peripheral interrupts

Hope someone found that interesting.

Mike.

Yes. I do.

Looks closely at the second line in the quote about the setup of the SYNC bit value. Instead of the bit shift operator, it uses a comparison operator. Extremely difficult error to catch visually during source code debugging.
 
Very well spotted, that was a bug waiting to happen and as you say very difficult to spot.

Mike.
 
Pommie said:
I also use the shift left function to setup registers.
EG
Code:
        bsf     STATUS,RP0
        movlw   (0<<CSRC|0<<TX9|1<<TXEN|0<<SYNC|1<<BRGH|0<<TRMT|0<<TX9D)
        movwf   TXSTA;		bit 2 = 1 therefore high speed
        bcf     STATUS,RP0
        movlw   (1<<SPEN|0<<RX9|0<<SREN|1<<CREN|0<<ADDEN|0<<FERR|0<<OERR|0<<RX9D)
        movwf   RCSTA
        movlw   (1<<GIE|1<<PEIE|0<<TMR0IE|0<<INTE|0<<RBIE|0<<TMR0IF|0<<INTF|0<<RBIF)
        movwf   INTCON;		enable Peripheral interrupts

Hope someone found that interesting.

Mike.
Edit corrected error found by eblc1388

Mike,

I like that example... Incredibly creative and intuitive... Are you the one who deserves credit for coming up with that?

Regards, Mike
 
Mike said:
I like that example... Incredibly creative and intuitive... Are you the one who deserves credit for coming up with that?

Regards, Mike

I'm not sure if I deserve credit, I realised it could be done this way after seeing how bits are accessed in C. Quiet often I would see INTCON&=1<<TMR0IF and realised it could be used to good effect as self documenting code in asm.

Mike.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top