I am facing a problem in using the right shift operator in C with keil. The instruction is:for(i=0;i<=8;i++) { j=sum>>i; } where sum= 32 bit no. the instruction is not executed if the syntax is as shown above. but if i write a numerical value instead of using the variable name 'sum' then the instruction is easily executed. i need to use the variable name only. how do i fix this problem?
Try this
sum >>= 8; // right justify by 8 bit positions
or create a union
My interpretation of the original post is that he wants to do something to each of the least significant 8 bits one at a time.
for (i = 0; i < 8; ++i) { bit = (sum >> i) & 1; DoSomething(bit); // called for bit 0, bit 1... bit 7 }
This should work, though it's a little inefficient because it shifts too much. It also shifts a U32 unnecessarily, which will take time on an 8051. I'd probably write code more like:
U8 temp = (U8)sum; for (i = 0; i < 8; ++i) { DoSomething (temp & 1); temp >>= 1; }
so that you only have to shift an 8-bit quantity, and you only do 8 1-bit shifts.
So, if my interpretation of the OP is correct, the question is why (sum >> i) doesn't work in the posted code, though (sum >> 1) does.
How about posting the assembly code output from the .cod file in both cases?
i tried doing this but it doesnt work.
"it doesnt work"
You haven't actually stated what it is supposed to do yet! What is it, exactly, that you are trying to achieve?
"How about posting the assembly code output from the .cod file in both cases?"
Before posting any more code, please take care to read the Notes immediately above the 'Message' window when you post - they tell you what to do to have your code appear properly formatted (as in Drew's post).
Note that the .cod file is generated by the LX51 Linker, and shows the result of Linker optimisations; you also need to show the Compiler listing (.lst) to see what the compiler actually generated...
this is the actual code i am referring to:
#include<stdio.h> #include<intrins.h> #include<absacc.h> #include<math.h> #include<reg51.h> int count; /* holds counter value*/ int arr[15]; /* array to store 15 nos.*/ int avg; /* average of 15 nos. */ long int sum; /* sum of 15 nos. (16 bit)*/ void main() { int i,j; /* variable initialization */ sum=0x00; /* initial value*/ count=0x00; /* initial value*/ #pragma asm /* entering 15 nos into memory locations*/ mov r2, #0fh mov dptr, #3000h mov a, #21h up1:movx @dptr, a inc dptr inc a djnz r2,up1 mov r3, #0fh /* retreiving data from memory and storing 15 nos in array*/ mov dptr, #3000h up2: movx a, @dptr mov b, a #pragma endasm arr[count]=ACC; count++; #pragma asm inc dptr djnz r3,up2 #pragma endasm for(count=0;count<=15;count++) /* adding 15 nos. */ { sum=sum+arr[count]; /* sum */ } avg=sum / 0x0f; /* average of 15 nos. */ P2=avg; ACC=sum; /*moving lsb 8 bits of 16 bit sum on port 0 */ P0=ACC; for(i=0;i<=8;i++) { j=sum>>i; /*moving msb 8 bits of 16 bit sum on port 1*/ } B=j; P1=B; }
here i am not able to divide neither am i able to right shift the data when i use the variable name sum
Good. However, you still have not explained what the code is supposed to do, what it is doing, and why you think it does not work properly.
for(count=0;count<=15;count++) /* adding 15 nos. */
If that means that the loop should add 15 numbers, then you've got a bug - this loop will add 16 numbers. Could this be why you are not getting the result you expect ?
for(i=0;i<=8;i++) { j=sum>>i; /*moving msb 8 bits of 16 bit sum on port 1*/ }
This code snippet does not move anything to P1. In fact, what it does is equivalent to
j = sum >> 8;
, but wastes a lot more cpu cycles.
the code is for adding 15 nos and then finding the average. the problem i am facing is: if the synax is as follows:
j=sum>>8;
the instruction is not executed. but if i put a numerical value instead of the variable name sum then the instruction is easily executed. Similarly if the syntax is as follows:
avg=sum / 0x0f;
the above instruction is not executed using the variable name 'sum'. Since i need to use only variable names in the code what can i do about the above mentioned problems.
"Since i need to use only variable names in the code"
Why is that?
Despite many requests, you still have not explained why you need to do this shift in a loop, rather than simply
"the above instruction is not executed"
How have you confirmed that it is actually "not executed"?
Have you examined the generated code?
Have you stepped through it in the simulator?
"the above instruction is not executed using the variable name 'sum'"
Just a thought: have you checked that 'sum' hasn't been defined with some special meaning, etc...
What if you call it 'my_sum' or something?
yes i have confirmed that it is not executed. yes i have examined the generated code. i did single stepping and found that these instructions are not executed.
and i have done away with the for loop and instead just used:
yeah i have checked that too. even if i replace 'sum' by any other varible name say 's' or 'x' or whatever, it is still not executed
"yes i have examined the generated code."
And what did you observe?
"i did single stepping and found that these instructions are not executed."
Again, what did you observe?
This should tell you why they weren't executed!
"i have done away with the for loop and instead just used..."
Again, you still haven't explained why you wanted the for loop in the first place!
"this is the actual code i am referring to:"
The code will only work with the small memory model. What model are you using?
What do you expect to happen when main() returns (aka, running off the end of main)?
If the optimizer is smart enough, it could eliminate the loop entirely, and just replace it with "j = sum >> 8;" as that's the net effect of the loop. Have you checked the .lst and .cod files to see what the code generator generates? Alternatively, you could temporarily declare j and sum "volatile" to force the optimizer to read/write them on every pass. Or disable the optimizer.
ACC=sum; P0=ACC; B=j; P1=B;
More simply, just
P0=sum; P1=j;
In general, it's not safe to directly manipulate the 8051 registers from C code. You don't know exactly what the code generator will be doing with those registers to implement all the other C statements. For any given release of a particular compiler, you can inspect the assembly output and decide that in this particular case you can get away with it -- but things can change on the next compiler upgrade or even if you rearrange your code. The point of using a high-level language is to leave details like register management up to the compiler. It's tricky to mix the two.
The 'for' loop is to right shift the contents of the variable 'sum'. 'sum' holds my 16 bit result. now i want to move this result in two 8 bits registers of the microcontroller. for that moving the lsb 8 bits of the result is simple. but the msb 8 bits have to be brought to the lsb position first to move it into an 8 bit reg. hence i used the for loop. but now as per your advice i have done away with the for loop and simply used:
But still the instruction is not executed. is there any other alternate way of moving the 16 bit result in 'sum' to the registers of the microcontroller?