This is the project I made in 2010 as a response to the publication about useless machines in Make Magazine1. In overall excellent article there was one statement which looked controversial to me. Author stated that a machine with a microprocessor does not cut itself completely off power and from that point of view cannot be fully qualified as useless machine. This is not true. Sure you can build a machine with microprocessor which at the end of cycle cuts itself off power. And here is its wiring diagram of the machine from the clip above.
As central component this project utilizes Pololu B-168 controller 2 with Atmel ATmega168 as a brain. In addition controller has two H-bridges for bi-polar load. One bridge in this project controls the motor, another controls the reed relay which keep the machine on power disregarding of the control switch state. To eliminate toggle switch (the reason for that you can read here) I designed the push button custom made out of two micro-switches. To justify presence of the controller more complicated task assigned to the machine. This task could be described in in these statements:
- The Machine waits till tester hits the button. With first hit turn itself on.
- Thew Machine waits some time if there is no hits anymore.
- The Machine calculates the number of hits.
- If pause after last hit is big enough working cycle begins and the machine arm hits button as many time as tester did.
- At the end machine cuts itself off power.
// script routine int protothread(struct pt* upt) { // called each timer interrupt static int count=0, ix; static u_time timer; PT_BEGIN(upt); // PT_INIT is called form the main function // just in case to avoid race condition at the end PT_YIELD_UNTIL(upt,isButtonPressed()); turnRelay(DeviceON); // keep device powered turnMotor(DeviceOFF); turnLED(DeviceOFF); do { // counting cycle PT_WAIT_UNTIL(upt,isButtonReleased()); timer = schedule(750); count++; PT_WAIT_UNTIL(upt,isExpired(timer)|| isButtonPressed()); } while(!isExpired(timer)); for(ix = 0; ix != count; ++ix) { // working cycle turnLED(DeviceON); turnMotor(DeviceON); PT_WAIT_UNTIL(upt,isButtonPressed()); turnMotor(DeviceOFF); timer = schedule(20); PT_WAIT_UNTIL(upt,isExpired(timer)); turnMotor(DeviceBACKWARD); turnLED(DeviceOFF); PT_WAIT_UNTIL(upt,isArmDown()); turnMotor(DeviceOFF); timer = schedule(20); PT_WAIT_UNTIL(upt,isExpired(timer)); } turnRelay(DeviceOFF); // kill the machine timer = schedule( 20); PT_WAIT_UNTIL(upt,isExpired(timer)); PT_END(upt); return PT_EXITED; }
See for yourself but to me it looks like good pseudo code which expresses program logic in clear and conscious way.
And at the end some observations from my limited experience with protothreads:
- All yields/resumings of particular protothread have to be in the same protothread routine, in other words you cannot spread switch case statements across more then one function.
- Protothread states must not be stored inside local auto variables, only static or global variables have to be used.
- When working with Microsoft Visual Studio projects you must change default project setting of Debug Information Format field from Program Database For Edit and Continue (/ZI),to Program Database(/Zi). Otherwise your program will not compile.
1 Brett Coulthard. '"The most useless machine" (Issue 23 of Make Magazine). 2010
2 You cannot buy it anymore but there is the substitution with a better functionality in the same package but with slightly different wiring.
3Protothread Home Page.
4 The whole source code is available at this storage.