I had searched in the Discussion Forum for the whole moring but I couldn't find the right way to solve the problem I met,so I send this message hoping you guys can help me!Thanks in advance:-)My problem is as follows: 1.I want to define a macro,which is similar like function.It will be used in my communction interrupt service routine(so you can see that why I don't choose to call a function to realize it) 2.here's the definition of this macro: #define Macro_TestRxEnd(sbit Header_flag,uchar Header,uchar Tailer) \ { \ Return_flag = 0; \ if (!Header_flag) \ { \ if (Rxbuf == Header) \ { \ Header_flag = 1; \ ptRxBuf++; \ } \ else \ { ptRxBuf = xBuf; } \ else \ { \ if (Rxbuf == Tailer) \ { Return_flag = 1; } \ } 3.then the compile result is : Error C304: Bad Macro Parameter List so can anyone help me find out the right way to define such a long macro? I'm waiting for your good ideas earnestly!
"Remember that a macro is implemented by text substitution - a macro parameter list doesn't need (or accept) data types." And being a text substitution, one must be aware of the gotcha using brace-enclosed multi-statements macros in if/else clauses that don't use braces. Multi-statement macro definitions should envelope those multiple statements in do{}while(0) See: http://www.eskimo.com/~scs/C-faq/q10.4.html
:-)I'm so happy to see so many engineers take part in the discussion and raise many new ideas,thank you.And apologies for the length of time it has taken me to cknowledge your help.OK,Here's some of my points after reading your respondence: 1.First of all,I'd like to give an example to explain more about: It will be used in my communction interrupt service routine(so you can see that why I don't choose to call a function to realize it) Whether I write program in C or in assemble,I'll always try to avoid calling a function in ISR routine,the main reason is to avoid the overflow of SP(stack).As you know,the resource of microprocessor is limited,especially the ability of multi-level nesting.For example: the main program calls the display function --->the display calls read EEPROM function to read back data to LCD buffer--->the read EEPROM calls the bottom I2C sub-functions to get the data--->imagine the communcion ISR occurs at this time,then if use call other functions in ISR routine, you can see the nesting is so multi-level(of ourse,different microprocessers vary in this property). Now can you understand my point?If still puzzled,respondence is welcomed:-) 2.Secondly,the reason "why a macor" is that: there're 3 kinds of frame mode in the communication protocol.Let me put it like this:frame A/ frame B/frame C each frame has their own frame header and tailer.So in the ISR, void ISR_ROUTINE(void) { ....... switch(framemode) { case A: Macro_TestRxEnd(AHeader_flag, A_Header, A_Tailer); break; case B: Macro_TestRxEnd(BHeader_flag, B_Header, B_Tailer); break; case C: Macro_TestRxEnd(CHeader_flag, C_Header, C_ Tailer); break; default: break; } ...... } So that's why not just write it as straight code!! 3.Remember that a macro is implemented by text substitution - a macro parameter list doesn't need (or accept) data types. Yes, that's true. 4.Thanks Dan Henry for the link :http://www.eskimo.com/~scs/C-faq/q10.4.html .It helps a lot:-)If your guys don't mind,I suggest that let's forget all other things only for 1minute except putting focus on finding the right way to write a multi-statement macro that can be successfully compiled.So I'll try this define way later(because I'm now busy in writing back of your warmhearted respondence:-) 5.Thanks Andy Neil for your advice:-) There is a general rule-of-thumb that one should try to keep Interrupt Service Routines (ISRs) "small" - meaning that the amount of code executed during the interrupt service should be minimised.Putting your code into a Macro will not help in this respect! From the above point 2,you can see that in this case,the macro here not affect much in the ISR "small" rule.Of cource,I'll re-think about the best way to realize it:-) 6.Lastly,thank you again for everyone who take time to reply.The above is my personal points of view,and if any questions,please feel free to respond:-)
I work on 32-bit RISC systems with vast amounts of memory and stack space, but I mostly work on very small 4-bit and 8-bit systems with very limited amounts of memory and stack space. For example some PICs have an 8-level hardware return stack and some have only 2 levels, so I am very familiar with call/interrupt nesting awareness and using memory efficiently. That said, I think you are being a bit too conservative in this regard with respect to an 8051-based system. If you are that tight on memory then you could be destined for trouble despite your efforts to save a call from within an ISR. Give your ISR room to breathe. Don't get me wrong, I eschew unnecessary calls from ISRs too, but I also don't obscure my code by using macros (inappropriately) either. By "obscure", I mean that your protocol frame tests are not that complex and by using macros (at least as you have presented them) you are actually doing yourself and your successors a disservice by obscuring direct data object manipulation and side effects. Let's say you fix the macro parameter typing, you are still using "xBuf", "Rxbuf", "ptRxBuf", and "Return_flag" inside the macro, hiding their use from a reader. In this case you are much better off just laying it all out explicitly in the ISR so that one can see exactly what is being used and affected. Keeping ISRs small refers to keeping the execution paths short and overall time spent in the ISR short. You could have a mile-long switch/case statement in your ISR with each case having a simple body and it would be considered "small". So look again, switch on "framemode", a few conditional statements, and you're done! That's "small".
"each frame has their own frame header and tailer." Yes, but all messages have the same format, I presume: 1. A header; 2. a body; 3. a tail. I would structure the ISR on this basis, rather than try to detect each message type independently... "If you guys don't mind,I suggest that let's forget all other things only for 1minute except putting focus on finding the right way to write a multi-statement macro that can be successfully compiled." I do mind! Dan has said it too: using macros here is unnecessary and too risky - so don't do it I don't want to help you shoot yourself in the foot! Dan has now pointed out another common macro pifall - so, I'll say again: "You have already fallen into two such traps before you've even started - do you really want to dig yourself (and the rest of your team, and their successors) even more traps to fall into...?" Ancient proverb say: Man at bottom of deep hole should stop digging!
"...all messages have the same format, I presume: 1. A header; 2. a body; 3. a tail. I would structure the ISR on this basis..." Something like this:
void isr( void ) { static bit in_message = 0; // Set to 1 after a header has been detected; // Cleared to 0 when a trailer is detected; // Thus it indicates when we are within the body // of a message static unsigned char msg_type; // Records the last-received header; // So, when in_message is set, this indicates the // type of message currently in progress. if( in_message ) { // We're within the body of a message; // ie, a Header has previously been detected. // Check if this is now the end of the message if( Rxbuf == Tailer ) { // It's the end of the message in_message = 0; } else { // It's not the end of the message; // handle a message-body character // (possibly depending on msg_type?) } } else { // Not currently within the body of a message; // Check if this is a header switch( Rxbuf ) { case A_Header: // It's the start of an "A" frame: in_message = 1; msg_type = Rxbuf; break; case B_Header: // It's the start of a "B" frame: in_message = 1; msg_type = Rxbuf; break; case C_Header: // It's the start of an "C" frame: in_message = 1; msg_type = Rxbuf; break; default: // Not the start of a frame - Do nothing! break; } } }
:-)special thanks to Dan and Andy for shareing your experience to me and other friends,you both have a kind heart and a preciseness attitude toward work[from Andy's saying that he do mind even for 1minute,so I guess you are preciseness :-) Just as the Chinese ancient proverb say: Among any three people walking, I will find something to learn for sure.Today I learn a lot from you.And I've accepted Andy's strong advice that not to use macor in this condition.As to the point: but all messages have the same format, I presume: 1. A header; 2. a body; 3. a tail. I would structure the ISR on this basis, rather than try to detect each message type independently... The ISR need to tell the main program which frame is received now,that is to return relative flags, so if not detect each message type independently,how can the ISR translated frame message to main program? By your way,the ISR can only tell the main program that a total frame is received,but the main has to test the rxbuf(header) again to find out the kind of frame. During this weekend I can't come here to read the later responses and write back,so please allow me to reply next Monday:-)Wish you all have a good weekend!
A.W. Neil,thank you the same:-)I'll read your ideas carefully and send back next Monday,see you!Looking forward to more ideas(maybe not only limited to the original message) ^-^
"By your way,the ISR can only tell the main program that a total frame is received" Not true. The code I posted was just an idea of an outline; you need to fill in the details - including how to integrate it with the rest of your system For example, You could make the msg_type variable public...? No doubt you will also need to add other stuff shared between the ISR and the main code... Don't forget that 'volatile' keyword...!!
Today I've re-organized my uart-isr program on the base of the above good advice,and I get many useful ideas from this message,thank you all:-)