View previous topic :: View next topic |
Author |
Message |
kmp84
Joined: 02 Feb 2010 Posts: 360
|
shift left right |
Posted: Wed Aug 01, 2018 6:11 am |
|
|
Hello All,
I want to implement ccs shift_left( ), shift_right( ) functions in standard "C" language. Can you help me with some efficient C code?
Best Regards! |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9253 Location: Greensville,Ontario
|
|
Posted: Wed Aug 01, 2018 7:25 am |
|
|
Have to ask WHY don't you use the CCS functions ??
As for converting to 'C'...well which 'C', which PIC ?? It's questionable that you can get better than what CCS has done and it brings up the next question
What do you term 'efficient' ? You have to decide on either speed, code space or compromise on a bit of both.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Wed Aug 01, 2018 7:40 am |
|
|
The C equivalent is to shift left one bit with <<, and then OR with the input value. You can though only do this with standard sized variables (so typically one byte, two bytes and four bytes). Shift right you do similarly with >> and then OR in the top bit (make sure the declared value is unsigned).
Many C's will have a similar shift right or shift left in their library. Efficiency depends totally on the capabilities of the processor involved. |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 360
|
|
Posted: Wed Aug 01, 2018 8:27 am |
|
|
Okay, for now let's forget "efficient" code. I have working code that want to be portable to other compilers. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Wed Aug 01, 2018 8:47 am |
|
|
As I said, standard shift and OR. This is how shifting a bit in from a pin for example is done in most C's. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 01, 2018 8:59 am |
|
|
Quote: | I have working code that want to be portable to other compilers. |
Post a few of your shift_left() lines from your program.
Post the variable declarations too. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9253 Location: Greensville,Ontario
|
|
Posted: Wed Aug 01, 2018 9:12 am |
|
|
re:
I have working code that want to be portable to other compilers.
It's highly unlikely that your CCS program can be 'ported' to other compilers , unlike COBOL, C doesn't have a 'setup section' for various processors and environments. At least not that I've seen. COBOL was great that way, just change ONE small section of code and your program would compile and execute on any machine running COBOL.
Those that grew up with 'C' should know, but I rather doubt it can be made 'portable'.
Jay |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 360
|
|
Posted: Wed Aug 01, 2018 9:20 am |
|
|
PCM programmer wrote: | Quote: | I have working code that want to be portable to other compilers. |
Post a few of your shift_left() lines from your program.
Post the variable declarations too. |
Code: |
void BinToBCD(unsigned int32 val, int8 *OutBcdBuff){
//converts U32bit value, to BCD digits.
int1 temp_bit;
int8 size = 32;
int8 i;
int8 buff[] = {0,0,0,0,0}; // For optimization. The PIC processor can address a local array much more efficient than a parameterized address.
do {
if ((buff[0] & 0xF)>=5) buff[0]+=3;
if ((buff[0] & 0xF0)>=0x50) buff[0]+=0x30;
if ((buff[1] & 0xF)>=5) buff[1]+=3;
if ((buff[1] & 0xF0)>=0x50) buff[1]+=0x30;
if ((buff[2] & 0xF)>=5) buff[2]+=3;
if ((buff[2] & 0xF0)>=0x50) buff[2]+=0x30;
if ((buff[3] & 0xF)>=5) buff[3]+=3;
if ((buff[3] & 0xF0)>=0x50) buff[3]+=0x30;
temp_bit=shift_left(&val,4,0);
shift_left(buff,4,temp_bit);
} while (--size);
memcpy(OutBcdBuff, buff, 4);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Wed Aug 01, 2018 12:39 pm |
|
|
Don't get me wrong, but on 90%+ of processors you will have hardware division available. On these just use %, and then divide the number by ten. Don't waste time performing the rotations.
There is also severe problem. A 32bit binary value, can generate a BCD number involving over 9 digits. Your code is only able to code with just over a 16bit value, not 32bit.
Generically the most portable way to code it is to simply sprintf to a string and subtract '0' from each digit. |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 360
|
|
Posted: Thu Aug 02, 2018 2:12 am |
|
|
I changed "BinToBCD()" function with Ttelmah's suggestion.
Code: | void BinToBCD(unsigned int32 val, unsigned int8 *OutBcdBuff){
//converts 32bit value, to ten BCD digits.
U8 i,k;
U8 buff[] = {0,0,0,0,0,0,0,0,0,0};
k = sprintf(buff,"%Lu", val);
for(i=0; i<k; i++){
buff[i] -='0';
}
for(i=0; i<5; i++){
buff[i] = (buff[i*2]<<4) | (buff[i*2+1]);
}
memcpy(OutBcdBuff, buff, 5);
}
|
But I'm not ready yet with shifting bits in array of bytes!
Best Regards, |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Thu Aug 02, 2018 2:19 am |
|
|
There is a problem with the version you have generated. Think about it the number contains (say) 100, so you get a string "100". Only three digits. You need to be justifying the number to a fixed length output. Remember also strings need one extra character for the terminator. |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 360
|
|
Posted: Thu Aug 02, 2018 3:38 am |
|
|
Ttelmah wrote: | There is a problem with the version you have generated. Think about it the number contains (say) 100, so you get a string "100". Only three digits. You need to be justifying the number to a fixed length output. Remember also strings need one extra character for the terminator. |
Yes , just add one more 0\ to U8 buff[] for null terminate string, but there is no problem with 100. I have tested it. Calculation "-=0x30" applies only to ascii data! |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 360
|
|
Posted: Thu Aug 02, 2018 6:03 am |
|
|
Hi mr.TT,
Sorry, I saw the problem!
|
|
|
kmp84
Joined: 02 Feb 2010 Posts: 360
|
|
Posted: Thu Aug 02, 2018 6:40 am |
|
|
This is working code for 32bit bin to bcd: Code: |
void BinToBCD(unsigned int32 val, int8 *OutBcdBuff){
//converts U32bit value, to BCD digits.
int1 temp_bit;
int8 size = 32;
int8 buff[] = {0,0,0,0,0};
do {
if ((buff[0] & 0xF)>=5) buff[0]+=3;
if ((buff[0] & 0xF0)>=0x50) buff[0]+=0x30;
if ((buff[1] & 0xF)>=5) buff[1]+=3;
if ((buff[1] & 0xF0)>=0x50) buff[1]+=0x30;
if ((buff[2] & 0xF)>=5) buff[2]+=3;
if ((buff[2] & 0xF0)>=0x50) buff[2]+=0x30;
if ((buff[3] & 0xF)>=5) buff[3]+=3;
if ((buff[3] & 0xF0)>=0x50) buff[3]+=0x30;
if ((buff[4] & 0xF)>=5) buff[4]+=3;
if ((buff[4] & 0xF0)>=0x50) buff[4]+=0x30;
temp_bit=shift_left(&val,4,0);
shift_left(buff,5,temp_bit);
} while (--size);
memcpy(OutBcdBuff, buff, 5);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Thu Aug 02, 2018 6:54 am |
|
|
You had that code at the start. It has one fault, it wastes time doing all the tests before the rotation. If you read the algorithm for the shift and test conversion it does not do this.
However I don't see where you are going. You asked about doing the conversion in 'standard C'. The ASCII and subtract solution is one to do this. Or divison and remainder. Or just implement the shift by repetitive standard word << shifts ang generating the shifted bit yourself. Funnily one of the old standard methods is just to do subtractions. Have a table of all the values corresponding to BCD digits 1000, 100, 10, and starting with the largest just perform repeated subtractions, if the value tests as bigger than the digiit. This can actually be suprisingly small and quick.
These are the 'generic' solutions, but none are going to be particularly efficient.
So where are you 'going'?. You have a CCS solution. If you want an efficient solution on any other compiler it is going to need to be coded for that compiler. There are inefficient generic solutions. |
|
|
|