Yes, it is actually calling the routine specified by the first case it sees! I have just arrived at home and looked at your replies. Thanks for the input. I'm going to compare my listing to yours and correct the problem areas. In all honesty, I think I'm attempting to use the macros as a crutch...I should be learning how to write this code first and then use the macros as a convenience. My PIC projects are not work related so I've got the time to learn. I will use the info you have given me to test my project ideas on the PIC to see if they work. Then I'm going to continue with the learning curve! Thanks for the help and I'll post what I've done for all to see. Regards, Steve --- In , "rtstofer" <rstofer@p...> wrote: > > Just a thought - is the code actually calling your subroutines or > just messing about with the xor beq stuff? There is a bunch of code > being executed in sequence - there is certainly no magic that makes > the select statement jump to the proper case right off the bat. > > First the code evaluates whether W is 3, if not it evaluates whether > W is 2, if not it evaluates whether W is 1, if not it loops back and > gets a new value for W and does the process again. > > If any test is true, the appropriate subroutine is called and the > code loops back for a new value of W. > > And yes, using a computed goto table is probably faster but the table > gets ugly if there are unused values of W: 1, 3, 19, 22, 29, 234 for > example. You would need a table with 235 entries (0..234) most of > which would branch to an error subroutine for invalid values. > > Where the values can be limited to something like [0..3] then a > computed goto table can be faster. Just be sure to forcibly limit > them with something like ANDLW B'00000011' after the value is placed > in W. > > Something to think about later. > > --- In , "stephendbarnes" > <stephendbarnes@h...> wrote: > > The code wants to execute the first case argument it sees. I have > > followed it in step mode but I don't yet understand what the macro > is > > doing. I can comment out the first case (case 3) and it executes > the > > the first case it sees regardless of the W reg value! I'm stumped > and > > drowning!! > > > > Regards, > > Steve |
|
Need help with PIC Macros
Started by ●April 16, 2003
Reply by ●April 18, 20032003-04-18
Reply by ●April 19, 20032003-04-19
I never think of macros as a crutch - they are a readability aid and, in some cases, an application specific instruction. If you use them, you can learn from the emitted code and anytime you can see good code and good coding it is worthwhile. That macro library is excellent code. I have two Mark III Minisumo Robots - one uses modified servo motors where a bit is pulsed about 50 times per second. The width of the pulse causes the servo to move at a speed either forward or reverse. The other has an H bridge control and it uses the PWM output of the 16F877. So I have a macro that takes a motor, direction and speed and does conditional assembly depending on the robot I am coding for. The advantage is that the strategy of moving the robot is independent of the hardware. Just call a macro: Motor Left, Foward, Fast Motor Right, Forward, Fast Once I know the macros work correctly I can use them as application specific instructions and not have to worry about the details. No excess code is generated - the instructions are exactly what I would have written in either case. But I only have to do it once. If you write code once, fine. If you write it twice it should be a macro or a subroutine in a library. In my opinion only. Let me know how it works out - the listing I posted does work correctly. None of the subroutines are actually called unless I insert a statement like: MOVLW 3 ; insert before 'select' Good luck! --- In , "stephendbarnes" <stephendbarnes@h...> wrote: > Yes, it is actually calling the routine specified by the first case > it sees! I have just arrived at home and looked at your replies. > Thanks for the input. I'm going to compare my listing to yours and > correct the problem areas. In all honesty, I think I'm attempting to > use the macros as a crutch...I should be learning how to write this > code first and then use the macros as a convenience. My PIC projects > are not work related so I've got the time to learn. I will use the > info you have given me to test my project ideas on the PIC to see if > they work. Then I'm going to continue with the learning curve! > Thanks for the help and I'll post what I've done for all to see. > > Regards, > Steve > --- In , "rtstofer" <rstofer@p...> wrote: > > > > Just a thought - is the code actually calling your subroutines or > > just messing about with the xor beq stuff? There is a bunch of > code > > being executed in sequence - there is certainly no magic that makes > > the select statement jump to the proper case right off the bat. > > > > First the code evaluates whether W is 3, if not it evaluates > whether > > W is 2, if not it evaluates whether W is 1, if not it loops back > and > > gets a new value for W and does the process again. > > > > If any test is true, the appropriate subroutine is called and the > > code loops back for a new value of W. > > > > And yes, using a computed goto table is probably faster but the > table > > gets ugly if there are unused values of W: 1, 3, 19, 22, 29, 234 > for > > example. You would need a table with 235 entries (0..234) most of > > which would branch to an error subroutine for invalid values. > > > > Where the values can be limited to something like [0..3] then a > > computed goto table can be faster. Just be sure to forcibly limit > > them with something like ANDLW B'00000011' after the value is > placed > > in W. > > > > Something to think about later. > > > > > > > > --- In , "stephendbarnes" > > <stephendbarnes@h...> wrote: > > > The code wants to execute the first case argument it sees. I have > > > followed it in step mode but I don't yet understand what the > macro > > is > > > doing. I can comment out the first case (case 3) and it executes > > the > > > the first case it sees regardless of the W reg value! I'm stumped > > and > > > drowning!! > > > > > > Regards, > > > Steve |
Reply by ●April 19, 20032003-04-19
I agree with you. My point was that as a raw
beginner in assembly language, the easy way out has a way of making one loose
sight of the objective (learning how to code). At times, one is so focused on
the project at hand that looking at the results of the macro plays second fiddle
to enjoying the end product! What is the saying...."Know thy self"?
;-)
Back to the subject...I have not tried the
macro example listing you posted yet (but I will soon) because I solve this
particular problem with inline code! I have always used high level languages
when writing software for PC's, PLC's, etc., so assembly has really
made me think about new ways (to me) to solve old problems. If you have the
time, take a look at the attached file to see what I have done. It is well
commented and is a work in progress so please excuse the time delay stuff which
came from the MIT piclist examples page (any suggestions would be
welcome).
Regards,
Steve
| |||
| |||
|
Reply by ●April 19, 20032003-04-19
Wonder why my email post never made it. Strange. OK, the only thing I would reconsider is using self-relative jumps as in 'goto $ - 3'. If you ever add a little debug code in the middle of the loop that instruction will come back to bite you. In fact, any change in the loop is a problem. I would consider adding 3 labels (Reverse1, Left1, Right1) as the targets for the 3 self-relative jumps. I like the idea of assigning names to port bits with #define. I have been trying to use that at every opportunity. Looking good! --- In , "Stephen D. Barnes" <stephendbarnes@h...> wrote: > I agree with you. My point was that as a raw beginner in assembly language, the easy way out has a way of making one loose sight of the objective (learning how to code). At times, one is so focused on the project at hand that looking at the results of the macro plays second fiddle to enjoying the end product! What is the saying...."Know thy self"? ;-) > Back to the subject...I have not tried the macro example listing you posted yet (but I will soon) because I solve this particular problem with inline code! I have always used high level languages when writing software for PC's, PLC's, etc., so assembly has really made me think about new ways (to me) to solve old problems. If you have the time, take a look at the attached file to see what I have done. It is well commented and is a work in progress so please excuse the time delay stuff which came from the MIT piclist examples page (any suggestions would be welcome). > > Regards, > Steve > ----- Original Message ----- > From: rtstofer > To: > Sent: Saturday, April 19, 2003 1:38 AM > Subject: [piclist] Re: Need help with PIC Macros > > I never think of macros as a crutch - they are a readability aid and, > in some cases, an application specific instruction. If you use them, > you can learn from the emitted code and anytime you can see good code > and good coding it is worthwhile. That macro library is excellent > code. > > I have two Mark III Minisumo Robots - one uses modified servo motors > where a bit is pulsed about 50 times per second. The width of the > pulse causes the servo to move at a speed either forward or reverse. > The other has an H bridge control and it uses the PWM output of the > 16F877. So I have a macro that takes a motor, direction and speed > and does conditional assembly depending on the robot I am coding > for. The advantage is that the strategy of moving the robot is > independent of the hardware. Just call a macro: > > Motor Left, Foward, Fast > Motor Right, Forward, Fast > > Once I know the macros work correctly I can use them as application > specific instructions and not have to worry about the details. No > excess code is generated - the instructions are exactly what I would > have written in either case. But I only have to do it once. > > If you write code once, fine. If you write it twice it should be a > macro or a subroutine in a library. In my opinion only. > > Let me know how it works out - the listing I posted does work > correctly. None of the subroutines are actually called unless I > insert a statement like: > > MOVLW 3 ; insert before 'select' > > Good luck! > > --- In , "stephendbarnes" > <stephendbarnes@h...> wrote: > > Yes, it is actually calling the routine specified by the first case > > it sees! I have just arrived at home and looked at your replies. > > Thanks for the input. I'm going to compare my listing to yours and > > correct the problem areas. In all honesty, I think I'm attempting > to > > use the macros as a crutch...I should be learning how to write this > > code first and then use the macros as a convenience. My PIC > projects > > are not work related so I've got the time to learn. I will use the > > info you have given me to test my project ideas on the PIC to see > if > > they work. Then I'm going to continue with the learning curve! > > Thanks for the help and I'll post what I've done for all to see. > > > > Regards, > > Steve > > > > > > --- In , "rtstofer" <rstofer@p...> wrote: > > > > > > Just a thought - is the code actually calling your subroutines or > > > just messing about with the xor beq stuff? There is a bunch of > > code > > > being executed in sequence - there is certainly no magic that > makes > > > the select statement jump to the proper case right off the bat. > > > > > > First the code evaluates whether W is 3, if not it evaluates > > whether > > > W is 2, if not it evaluates whether W is 1, if not it loops back > > and > > > gets a new value for W and does the process again. > > > > > > If any test is true, the appropriate subroutine is called and the > > > code loops back for a new value of W. > > > > > > And yes, using a computed goto table is probably faster but the > > table > > > gets ugly if there are unused values of W: 1, 3, 19, 22, 29, 234 > > for > > > example. You would need a table with 235 entries (0..234) most > of > > > which would branch to an error subroutine for invalid values. > > > > > > Where the values can be limited to something like [0..3] then a > > > computed goto table can be faster. Just be sure to forcibly > limit > > > them with something like ANDLW B'00000011' after the value is > > placed > > > in W. > > > > > > Something to think about later. > > > > > > > > > > > > --- In , "stephendbarnes" > > > <stephendbarnes@h...> wrote: > > > > The code wants to execute the first case argument it sees. I > have > > > > followed it in step mode but I don't yet understand what the > > macro > > > is > > > > doing. I can comment out the first case (case 3) and it > executes > > > the > > > > the first case it sees regardless of the W reg value! I'm > stumped > > > and > > > > drowning!! > > > > > > > > Regards, > > > > Steve > Yahoo! Groups Sponsor > > to unsubscribe, go to http://www.yahoogroups.com and follow the instructions > > Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service. |
Reply by ●April 19, 20032003-04-19
I'm not sure why the group doesn't accept your
email posts. It took about eight tries before it finally posted from my email
client!
Good suggestion concerning the self relative
jumps...I've implemented that. What are your thoughts about the timing
loops?
Regards,
Steve
|
|
Reply by ●April 20, 20032003-04-20
Well, as you have no doubt discovered, timing loops consume 100% of the CPU cycles. Maybe that is ok, maybe not. I have been using a cooperative multi-task scheduler which doesn't take a lot of code. Not coincidentally it uses a few macros to generate the code and tables. Basically, tasks are statically created at assembly time and an interrupt routine schedules them for execution on a periodic basis. One of the neat things is that not only do the tasks repeat every so many clock ticks but they can be delayed an initial amount of time and this achieves an interleave effect. Take something as simple as flashing an LED. What happens is that every 250 mS the flash task is scheduled by the interrupt routine and subsequently executed by the dispatch loop. The routine itself just alternates the state of the LED. Very fast task, just invert the output bit and return. A couple of other thoughts: infrared proximity sensors (Sharp GP2D12, etc) only update every 28.7 to 37.9 mS. Then a handfull of microseconds for the A/D conversion and the data is ready. At most these devices need to be sampled every 14 mS. So, if there are 8 A/D channels why not schedule it such that at every 1 mS tick a channel is read and the value placed in an A/D array. This implies that the latest A/D conversion of any sensor is immediately available for the code - no time lost selecting a channel, starting a conversion and fetching the result. Just get the value from the array! Overlap and pipeline - these are the keys to getting a lot of processing out of a small processor. My interrupt routine does two things: it grabs an A/D conversion, sticks it in an array, updates the channel selection and ultimately starts the conversion. Second, it looks through an array of task schedule information for a task to initiate and sets a flag for those that are ready. One assumption is that any given task will be complete before the next mS tick. This is pretty easy to do since the processor can execute about 5000 instructions in a mS (generally I am using a 20 MHz 16F87x). Now, there is the fixed overhead of the interrupt handler and the dispatch loop that takes a certain amount of time out of every mS tick but there is still a lot of time for each task. This is where staggering the tasks really pays off - assuming that every task doesn't have to be scheduled every mS. Outside the interrupt routine is a round robin task dispatcher as the main code for the program. It simply looks through the ready flags and calls the various routines. No real processing being done in the main loop - just test and call. By creating tasks the larger problem has been partitioned into smaller pieces that can be developed separately. Intellectually the progam is easier to comprehend because a certain structure has been forced on a complex problem. So, my thoughts on delay loops are that they waste resources that could better be used for other things like strategy and tactics and that, in most cases, they are unnecessary. Further, eliminating them actually simplifies the program while adding structure and clarity. When I get home I will try to polish up what I have and see if I can post it using MS Outlook instead of Linux sendmail. --- In , "Stephen D. Barnes" <stephendbarnes@h...> wrote: > I'm not sure why the group doesn't accept your email posts. It took about eight tries before it finally posted from my email client! > > Good suggestion concerning the self relative jumps...I've implemented that. What are your thoughts about the timing loops? > > Regards, > Steve > ----- Original Message ----- > From: rtstofer > To: > Sent: Saturday, April 19, 2003 10:03 PM > Subject: [piclist] Re: Need help with PIC Macros > > Wonder why my email post never made it. Strange. > > OK, the only thing I would reconsider is using self-relative jumps as > in 'goto $ - 3'. If you ever add a little debug code in the middle > of the loop that instruction will come back to bite you. In fact, > any change in the loop is a problem. > > I would consider adding 3 labels (Reverse1, Left1, Right1) as the > targets for the 3 self-relative jumps. > > I like the idea of assigning names to port bits with #define. I have > been trying to use that at every opportunity. > > Looking good! |
Reply by ●April 20, 20032003-04-20
Thank you. I would really like to see what you have
created!
Regards,
Steve
|
Reply by ●April 21, 20032003-04-21
Attached is the code we discussed. Thinking about it today I have decided that since the A/D values are only used every 20 mS (by throttle and steering code) it would be better to pull that code out of the interrupt routine and use two tasks separated in time by a couple of mS. The first task would grab the previous conversion, update the channel selection and exit. A couple of mS later the second task would start the conversion. This gives plenty of time for settling after channel selection and the actual conversion. It also reduces the amount of overhead in the interrupt routine. Work in progress but maybe there are some tidbits. | |||
|
Reply by ●April 21, 20032003-04-21
Thanks for the attachment. I'll be looking at it
tonight.
Regards,
Steve
|
|
Reply by ●April 22, 20032003-04-22
During the 'clean-up' process at least one problem crept in. The definition of Delay in CBLOCK has a semicolon where a colon is required. I started playing with the cleaned up version plus the task changes and noted the problem. --- In , "Stephen D. Barnes" <stephendbarnes@h...> wrote: > Thanks for the attachment. I'll be looking at it tonight. > > Regards, > Steve > ----- Original Message ----- > From: rstofer > To: > Sent: Monday, April 21, 2003 9:07 PM > Subject: [piclist] Re: Need help with PIC Macros > > Attached is the code we discussed. Thinking about it today I have decided > that since the A/D values are only used every 20 mS (by throttle and > steering code) it would be better to pull that code out of the interrupt > routine and use two tasks separated in time by a couple of mS. > > The first task would grab the previous conversion, update the channel > selection and exit. A couple of mS later the second task would start the > conversion. This gives plenty of time for settling after channel selection > and the actual conversion. It also reduces the amount of overhead in the > interrupt routine. > > Work in progress but maybe there are some tidbits. > > Yahoo! Groups Sponsor > to unsubscribe, go to http://www.yahoogroups.com and follow the instructions > > Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service. |