Once again I have successfully blundered my way through and got it working!
I also now know about .pre files - very handy for me to see what this these crazy-ass compilers do behind the scenes.
First I had to remove the outermost braces around Macboy's code, then it compiled OK, but didn't work.
Looking at the .pre file, I could see that is was only placing the first "if" statement and subsequent bit assignment. But why?
I then noticed that the last line of the macro that was successfully expanded had a comment in it. A comment using the "//" method. So of course the pre-processor (correct term?) treated EVERYTHING after that as a comment, as the lines were concatenated using "\".
I redid the comments using "/* blah blah /*" and it worked a treat!
I've also optimised my debouncing code, so the #define:
#define read_pb(x) \
if (SW ## x ## _PIN == 0) /* IF pin pulled low */ \
{\
if (!pb ## x) /* IF the button is NOT already set... */ \
{\
if (debounce_timer ## x == DEBOUNCE_TIME)\
{\
pb ## x ## _edge = 1 ; /* set the edge bit */ \
pb ## x = 1 ; /* set the pb bit */ \
}\
debounce_timer ## x ++ ; /* if we reach here, the pin is pulled low, but the timer hasn't reached yet */ \
}\
\
}\
else\
{\
debounce_timer ## x = 0 ;\
pb ## x=0 ;\
}\
now beautifully expands to:
if (PORTAbits.RA7 == 0) { if (!pb1) { if (debounce_timer1 == 250) { pb1_edge = 1 ; pb1 = 1 ; } debounce_timer1 ++ ; } } else { debounce_timer1 = 0 ; pb1=0 ; } ;
if (PORTAbits.RA6 == 0) { if (!pb2) { if (debounce_timer2 == 250) { pb2_edge = 1 ; pb2 = 1 ; } debounce_timer2 ++ ; } } else { debounce_timer2 = 0 ; pb2=0 ; } ;
This seems a very powerful and useful feature, so thanks again Macboy for explaining it to me.