I use KeilC uVision4 for 89C51 MCU. By "Inline ASM", i can easily direct write value to R7 register, like this :
#pragma ASM MOV R7, #10 #pragma ENDASM
But now, there are some reason that i have to write to R7 register direct from C (not from inline ASM), eg:
R7 = 10;
Of course, the C compiler does not understand R7 as MCU Register (not Inline ASM).
-> Is there anyway to solve this problem. Please help me if anyone know, thanks a lot !
If you really want to access R7 in this way then one method would be to access it as a direct memory location. Knowing the register bank number you want the location would be one of 0x07, 0x0F, 0x17, 0x1F.
That really does not sound like a good idea!
It would probably be better if you would explain what you're actually trying to achieve - then people may be able to make appropriate suggestions.
Note that the Keil C51 Compiler uses R7 internally - so messing with it directly is almost certainly a Really Bad Idea: http://www.keil.com/support/man/docs/c51/c51_ap_parampassreg.htm
Well, I intend to write an Accurate "ASM Delay Routine" by "Inline ASM".
Let take the simplest delay code:
#pragma ASM MOV R1, #vR1 // Calculate Time spent From Here DJNZ R1, $ //2 Machine cycle (MCs) #pragma ENDASM
With 8051MCU, it spent : t1 = vR1 x 2 machine cycles (MCs)
Now, with 2 registers used:
#pragma ASM MOV R1, #vR1 MOV R2, #vR2 // Calculate Time spent From Here DJNZ R1, $ DJNZ R2, $-2 #pragma ENDASM
time spent : t2 = (t1 + 257vR2 - 256) x 2 MCs
Finally, with 3 registers used:
#pragma ASM MOV R1, #vR1 MOV R2, #vR2 MOV R3, #vR3 DJNZ R1, $ DJNZ R2, $-2 DJNZ R3, $-4 #pragma ENDASM
time spent : t3 = (t2 + 65793vR3 - 65792) x 2 MCs
Generraly, with n Register used, we can delay :
tn = (tn-1 + (Cn-1 + 1)vRn - Cn-1) x 2 MCs where :
Cn = 256^n + 256^(n-1) + ... + 256 + 0
Now i write a delay 3000MCs routine :
//8051 MCU #define Interval 3000 // Change here to change delay in MCs) #define C0 0 // Constant in formula above #define C1 256 // Constant #define C2 65792 // Constant #define t3 Interval/2 // DJNZ take 2 MCs, so divide by 2 for easier calculation #define vR3 ((t3+C2-2)/(C2+1)) // Calculate R3 value #define t2 (t3+C2-(C2+1)*vR3) #define vR2 ((t2+C1-1)/(C1+1)) // Calculate R2 value #define t1 (t2+C1-(C2+1)*vR2) #define vR1 ((t1+C0-0)/(C0+1)) // Calculate R1 value void Delay() { #pragma ASM MOV R1, #vR1 MOV R2, #vR2 MOV R3, #vR3 DJNZ R1, $ DJNZ R2, $-2 DJNZ R3, $-4 #pragma ENDASM }
Use in main routine :
void main() { Delay(); // Delay 3000 Machine Cycles }
=> For easier use, i should write a DelayMCs() Macro, eg :
#define DelayMCs(Interval) //Code Here???
Then, use this Macro like this :
void main() { DelayMCs(7000); }
=> That's my idea. But i don't know how to write this Macro. Can anyone help me build "Code Here" above. Thanks !
See: http://www.keil.com/forum/docs/thread16420.asp
It is very simple to do this as a separate assembly module - and, in my opinion, much to be preferred. See the above link.
By "Inline ASM", i can easily direct write value to R7 register, like this :
By "having a gun", i can easily shoot myself in the foot, like this
that something can be done, does not mean it is right to do it.
Erik
Thanks a lot for your helps. In a couple of days, I found the Macro should be as following :
// Delay Routine void RoutineDelayMCs(unsigned int interval) { #pragma ASM DJNZ R7, $ DJNZ R6, $-2 #pragma ENDASM } // Delay Macro -> Calculate interval to pass into Delay Routine #define MacroDelayMCs(interval) \ ((!(((interval)/2) - 257*((((interval)/2)+256-1)/257))) ? \ RoutineDelayMCs(257*((((interval)/2)+256-1)/257)) : RoutineDelayMCs(((interval)/2)+256-(((interval)/2)+256-1)/257)) // Offset Macro -> Calculate offset MCs of MOV, LCALL, RET ... command -> for better accuracy // Accuracy (if interval even, error = 0; if interval odd, error = -1 MCs // interval apply Range : 14 -> 131592 #define DelayMCs(interval) \ MacroDelayMCs(interval-10) void main() { DelayMCs(14); // This call delay 14 Machine Cycles DelayMCs(512); // This call delay 512 MCs DelayMCs(131592); // This call delay 131592 MCs }
It works fine ! Of course, manually hacking the registers is really Bad. I will put the RoutineDelayMCs in an ASM Module later.
Thanks again, friends !
... to make something simple & safe into something over-complicated and dangerous!
Yes.
For me, it would definitely take less time and effort to write a routine in assembler than to understand those macros!
... that an Engineer is someone who can make for a pound what any fool can make for a tenner.
I think we have just seen a proof by counter-example...
;-)
Maybe you understand my idea incorrectly. I've used MikroC for 8051. That compiler has a built-in Delay_ms() routines. When I want to delay 10ms, just code
Delay_ms(10);
The compiler will auto generate source code (to delay 10ms) :
_Delay_10ms : MOV R5, #8 MOV R6, #1 MOV R7, #247 DJNZ R7, PC-2 DJNZ R6, PC-4 DJNZ R5, PC-6 RET
Then, I wonder if I can write a Macro like that in KeilC. Just code "Delay_ms(x);" with x is any number you want. Anything wrong in my idea ?
Yes - trying to mess about with macros in 'C'!
if at least 2 experienced people are telling you DON'T DO IT! and you refuse and insist on doing it your way, when it is clear even to a non-C51 guy like me that what you are doing is plain wrong, then you are no less than a ticking bomb. have you even considered that your "time gain" will be nullified by the hoops the processor will have to jump through in order to compensate for your macroed assembly...?
.. I will repeat
DO NOT MESS WITH REGISTERS IN INLINE ASM
you are hellbent on doing it this way and in a while you will come crying here "why does this not work" when you run into a conflict between your inline and the compilers register usage which legally can be any which way and be changed at any time.
Actually, that's about the one thing that's not at issue!
We're talking about software delays - so wasting processor cycles is the object of the exercise!
The problem is that the proposed macro approach is so horribly cumbersome and error-prone - especially when doing it as an assembler module is so clean, simple, and easy!
to compensate for his register usage in the middle of it