![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
FJMSoft
Joined: 20 Oct 2013 Posts: 36
|
How to work with low/high bytes of 16bit variable. |
Posted: Sun Oct 26, 2014 9:03 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sun Oct 26, 2014 10:08 pm |
|
|
this is a basic C question.
read about
STRUCT
in the manual for your answer |
|
![](templates/subSilver/images/spacer.gif) |
FJMSoft
Joined: 20 Oct 2013 Posts: 36
|
|
Posted: Sun Oct 26, 2014 10:34 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
|
Posted: Mon Oct 27, 2014 12:34 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Mon Oct 27, 2014 3:43 am |
|
|
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> |
|
![](templates/subSilver/images/spacer.gif) |
FJMSoft
Joined: 20 Oct 2013 Posts: 36
|
|
Posted: Mon Oct 27, 2014 2:43 pm |
|
|
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? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Mon Oct 27, 2014 3:25 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
FJMSoft
Joined: 20 Oct 2013 Posts: 36
|
|
Posted: Mon Oct 27, 2014 9:46 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
rikotech8
Joined: 10 Dec 2011 Posts: 376 Location: Sofiq,Bulgariq
|
|
Posted: Tue Oct 28, 2014 12:30 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Tue Oct 28, 2014 9:45 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
FJMSoft
Joined: 20 Oct 2013 Posts: 36
|
|
Posted: Fri Nov 14, 2014 7:50 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
|
Posted: Fri Nov 14, 2014 7:58 pm |
|
|
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!!!! |
|
![](templates/subSilver/images/spacer.gif) |
FJMSoft
Joined: 20 Oct 2013 Posts: 36
|
|
Posted: Sat Nov 15, 2014 11:00 am |
|
|
Thank you very much! |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|