CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

How to work with low/high bytes of 16bit variable.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

How to work with low/high bytes of 16bit variable.
PostPosted: Sun Oct 26, 2014 9:03 pm     Reply with quote

Hello.
I want to set and/or read just the lower/higher byte of an 16bit variable.
How can I achieve this?

I know it is possible using bit shifts and some mathematics...
Which is the faster way?

Thank you.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Sun Oct 26, 2014 10:08 pm     Reply with quote

this is a basic C question.
read about
STRUCT
in the manual for your answer
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Sun Oct 26, 2014 10:34 pm     Reply with quote

asmboy wrote:
this is a basic C question.
read about
STRUCT
in the manual for your answer


asmboy, it is this one?
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
I found something in page 31 (43 in pdf) but still not understood, it is very vague (or my knowledge too low).
I need, lets say, read or set low byte of 16bit timer counter, or same for a declared variable.
rikotech8



Joined: 10 Dec 2011
Posts: 376
Location: Sofiq,Bulgariq

View user's profile Send private message

PostPosted: Mon Oct 27, 2014 12:34 am     Reply with quote

Code:
int low_byte, high_byte;
int16 word;

low_byte = (int8)(word & 0xFF);
high_byte = (int8)(word >> 8);


As asmboy said,
CCS provides function that handle byte extraction of 16bit and 32bit word.
Look at page 226.
I think the best way is using UNION. Read about it on page 39 into the manual you pointed.
_________________
A person who never made a mistake never tried anything new.
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Mon Oct 27, 2014 3:43 am     Reply with quote

This has been answered many times.

There are many different ways to do this.
The problem with shifts, is that they require the variable involved to be large enough to hold the shifted result (so you can't shift an int8 left or right 8 bits), and they can be inefficient.

Rilotech's answer is right. The key point about 'union', is that it is present in other C's, and with a bit of care (remember that a processor could store data LSB first, or MSB first), can therefore be used in code to run on other chips.
CCS also provide their own functions (downside is that these are non-portable to other compilers).

Have a look at this thread, which shows the methods:

<http://www.ccsinfo.com/forum/viewtopic.php?t=43975>
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Mon Oct 27, 2014 2:43 pm     Reply with quote

Shifts and other mathematics will take processor time.

I have found a joint betwen struct and union, I need to study it a little better, but looks it will fit for variable one, I dont understand why need both but I will try learn.

But I come back with the timer counter.
I was used to program AT89S52 in ASM, timer 16bit counter was just 2 separated bytes, was easy to read and write it separated.
Why this looks so hard in CCS C?
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Mon Oct 27, 2014 3:25 pm     Reply with quote

It's not.

Have a look at the thread example I posted, which shows how to do this with a #BYTE. However, remember that for things like the timers, you want to access them in a single I/O operation if possible, or in a specific order, if you are not to have the danger that one half could update while you access the other. How this is protected in the hardware, affects how you need to handle the read/write. This is why CCS has the 'get_timer' and 'set_timer' functions, which handle this automatically for each different processor type.
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Mon Oct 27, 2014 9:46 pm     Reply with quote

Ttelmah wrote:
It's not.

Have a look at the thread example I posted, which shows how to do this with a #BYTE. However, remember that for things like the timers, you want to access them in a single I/O operation if possible, or in a specific order, if you are not to have the danger that one half could update while you access the other. How this is protected in the hardware, affects how you need to handle the read/write. This is why CCS has the 'get_timer' and 'set_timer' functions, which handle this automatically for each different processor type.


Ttelmah, I think I got it friend.
I seen John P reply which shows #byte method.
Then I would make:
myvariable = get_timer;
Then use value in myv_low or myv_high, right?

But I want to go further, how can I just have access to counter bytes?
The only way is with #BYTE and direct memory address? (completely non portable)

Thanks.
rikotech8



Joined: 10 Dec 2011
Posts: 376
Location: Sofiq,Bulgariq

View user's profile Send private message

PostPosted: Tue Oct 28, 2014 12:30 am     Reply with quote

The standard way of accessing memory locations in C is using pointers.

Code:
volatile unsigned int* const my_pointer = REGISTER_ADDRESS

It works in CCS either, and portable as well. Thus you can read/write bunch of memory with length specified by you (pointer to an int8, int16, int32 or pointer to a structure).
_________________
A person who never made a mistake never tried anything new.
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Tue Oct 28, 2014 9:45 am     Reply with quote

You started by talking about a 16bit variable. Now we are talking about a register.
There is a big difference (though not necessarily in how you do it). A register access is _always_ going to be processor specific, so 'non portable'....

The point about #word, and 'byte, is they allow you to directly map a variable 'to' a physical register location. So for registers, by far the best way to go:
Code:

#byte TMR1L = getenv("SFR:TMR1L")
#byte TMR1H = getenv("SFR:TMR1H")
#word TMR1 = TMR1L

   //then TMR1L is the low byte of the timer, TMR1H the high byte
   //and TMR1 the whole 16bit register

_However_. The problem of access order, and the hardware, then rears it's head. If you look at (for instance), one of the PIC18xxxx chips, these are normally configured, so when you read the low byte, the high byte is _latched_ at the same time, into the high register, which does not then change, until this register is read. So you must always read TMR1L, before TMR1H. When writing, it has to be done the opposite way round, with you writing to the latch on TMR1H, and then writing to TMR1L, writes the entire 16bit register. This is alll done, so you can't accidentally get the timer/counter updating between the two accesses. The get_timer1, and set_timer1 functions 'know' about this, and automatically do the operations in the correct order. This is why 'DIY' access is better avoided. However there are then reasons to do this. For instance, if you are using a timer, and want it to count 32768 cycles, rather than 65536, then the best way to do this, is just to set the top bit of TMR1H, in the interrupt (effectively advancing the timer by 32768 counts). The code becomes:
Code:

#byte TMR1H = getenv("SFR:TMR1H")
#bit RD16 = getenv("BIT:RD16")
#bit TMR1MSb = TMR1H.7

    //then to just set the top bit becomes:
    RD16=FALSE; //allow 8bit access
    TMR1MSb=1; //set the most significant bit
    RD16=TRUE; //and return register access to normal


You can equally well do the accesses with a union, a pointer, or with a structure, and even locate this directly at the register addresses, but it is going to be 'processor specific' code however you do it, so use the CCS tools.
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Fri Nov 14, 2014 7:50 pm     Reply with quote

Sorry for that.

I think I understood it, thank you.

Ttelmah, I still have a doubt...
Using this kind: #byte TMR1L = getenv("SFR:TMR1L")
Can I port it to another uC which have a TMR1L?

Thank you. again.
dyeatman



Joined: 06 Sep 2003
Posts: 1934
Location: Norman, OK

View user's profile Send private message

PostPosted: Fri Nov 14, 2014 7:58 pm     Reply with quote

Quote:
#byte TMR1L = getenv("SFR:TMR1L")

That line will work using the CCS compiler with any PIC processor
having a register with that name.
_________________
Google and Forum Search are some of your best tools!!!!
FJMSoft



Joined: 20 Oct 2013
Posts: 36

View user's profile Send private message

PostPosted: Sat Nov 15, 2014 11:00 am     Reply with quote

Thank you very much!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group