This is a sub post of the larger XYZ machine post project. This piece is about an Arduino based module that reads rotary encoders and displays on an LCD the current machine position;
A couple photos of the breadboard version. Note the three encoders are under the display, this prototype wasn't really meant to be used for anything. Of course the permanent version will have the encoders attached to the XYZ machine and not on a breadboard.
This picture (pardon the rotation) shows the display, you can just see one of the encoders on the breadboard below the display. This picture was taken before I added the math to print out converted inches, it just shows the raw encoder count.
I might also later have at least one button to set the home position, or I may just rely on the Arduino reset button to set 0,0,0. Some sort of home/limit switch setup might be nice too.
The encoders are attached to the ends of the drive screws for the platform. I used a short piece of flexible plastic tubing from the hardware store, because I couldn't find set screw shaft couplers the right size for any reasonable price. The hose gives me a little flex, so it should be OK. It stretches over the encoder shaft and the drive shaft.
Using rotary encoders from sparkfun. They are inexpensive, I hope they hold up to the job over time. They are really for human input knobs. http://www.sparkfun.com/products/9117
Datasheet: http://www.sparkfun.com/datasheets/Components/TW-700198.pdf
Later I swapped with some slightly different encoders from Digikey
http://search.digikey.com/scripts/DkSearch/dksus.dll?WT.z_header=search_go&lang=en&site=us&keywords=987-1199-ND&x=20&y=18
http://www.bitechnologies.com/pdfs/en16.pdf
I changed because these didn't have detents, which tended to snap the encoders to certain values. Also these had threaded shafts and were easier to mount. For $1.18 why not get the best?
Some example rotary encoder code that I started with is here:
http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino
The example code worked out of the box, I modified it to read three encoders at the same time.
It makes use of port manipulation to read all the input simultaneously. This page helped http://www.arduino.cc/en/Reference/PortManipulation
However, this guy must have been a programmer for a living, the program was basically 2 lines and very hard to understand. I wrote my version with more comments and a little less pizazz. Hopefully more understandable.
Got the three encoder code working, included it below, it was a bit tricky.
I added the LCD readout, attempting to keep the code delays as small as possible so we don't skip and encoder positions. The LCD is hooked up pretty much like all the Arduino examples, using 4 bit wide parallel mode. I like to use pins 7 6 5 4 3 2 because it keeps all the LCD pins on the same Arduino connector. You might note in the photo there is a adafruit arduino prototype board and some headers that I use to stack the LCD on top of the Arduino and map the pins. I'm not going to repeat the LCD interfacing stuff in this post. The Optrex display i used is cost effective but a bit quirky, it has the tendency to print garbage if you give it commands too fast.
The code is after the break:
Hobby blog about tech tips I've picked up, projects I'm working on, or links to useful information and cool stuff. I'm an Electrical Engineer and professional Analog IC designer for 25 years playing in my spare time. Arduino, hacking consumer electronics, video game hardware, satellite TV, PC building, Android apps, appliance repairs and whatever else that interests me.
Search This Blog
Saturday, February 26, 2011
Monday, February 21, 2011
Arduino based "crazy clock" idea
I thought of something fun to do with them, to make an analog crazy clock or backwards clock.
I have some small stepper motors from adafruit.
The arduino could keep time, and drive the steppers to move the hands in any pattern you want.
This could mimic a watch I've seen where the hours are out of order.
http://www.blogcdn.com/www.luxist.com/media/2009/05/franck-muller-crazy-hours-watch-blue.jpg
Just writing it down to come back to it later if I get bored
I have some small stepper motors from adafruit.
The arduino could keep time, and drive the steppers to move the hands in any pattern you want.
This could mimic a watch I've seen where the hours are out of order.
http://www.blogcdn.com/www.luxist.com/media/2009/05/franck-muller-crazy-hours-watch-blue.jpg
Just writing it down to come back to it later if I get bored
Sunday, February 20, 2011
Replaced the windshield washer nozzle in a 04 Sienna minivan
Ice and snow broke off the black plastic washer nozzle on the hood of my minivan. Activating the windshield washer resulted in a fountain of spray straight up, no where near the window. Here on the east coast, you lose your windshield washer, it is pretty much not safe to drive your car in the winter.
Looked all over the internet, and found it is really hard to buy a replacement. None of the online auto part stores, ebay or amazon had it. Some cars are there, but not mine. Had to resort to going physically to the dealer and buying it. Yuck. But the Toyota dealer had it.
Fun part is, you open the hood and it is very tough to access the nozzle. They have press in ears that clip them in place. Under the hood is an insulation layer of fabric that has press in clips. Removing it looked like a very bad idea, the clips were going to break and the fabric tear. I pried up one edge and could sneak my hand under. Felt around and couldn't access the back of the washer still to free it up because of the metal.
Found an easy way to do it from outside the car, that worked great. Grabbed what remained of the nozzle with some pliers and crushed it. That left the base in the hole, and I was able to use a small screw driver to release the clips from the top of the hood and pull it up out of the top of the hood with the hose still attached. Pulled off the hose from the old nozzle, and put the new one on the hose. Snapped the new nozzle into the hole and Voila!. Took less than 5 minutes this way!
Looked all over the internet, and found it is really hard to buy a replacement. None of the online auto part stores, ebay or amazon had it. Some cars are there, but not mine. Had to resort to going physically to the dealer and buying it. Yuck. But the Toyota dealer had it.
Fun part is, you open the hood and it is very tough to access the nozzle. They have press in ears that clip them in place. Under the hood is an insulation layer of fabric that has press in clips. Removing it looked like a very bad idea, the clips were going to break and the fabric tear. I pried up one edge and could sneak my hand under. Felt around and couldn't access the back of the washer still to free it up because of the metal.
Found an easy way to do it from outside the car, that worked great. Grabbed what remained of the nozzle with some pliers and crushed it. That left the base in the hole, and I was able to use a small screw driver to release the clips from the top of the hood and pull it up out of the top of the hood with the hose still attached. Pulled off the hose from the old nozzle, and put the new one on the hose. Snapped the new nozzle into the hole and Voila!. Took less than 5 minutes this way!
Monday, February 14, 2011
Arduino LCD Countdown Clock
Quickie project for a desktop clock that counts down to when my work project has to be done, then counts how many weeks it is late.
The design is the "raw electronics" look. The arduino is mounted on the back of the large LCD display by nothing more than a stacked header, and hot glued to a small piece of wood for a base.
The code is built on top of the basic example for a clock that syncs from the PC, found here:
The Arduino Time Library on the Arduino Playground
http://www.arduino.cc/playground/Code/Time
When plugged into the PC and using the Arduino serial monitor, it waits for you to enter a unix timestamp.
You can generate these from web sites like these ones:
http://www.timestampgenerator.com/
http://www.unixtimestamp.com/index.php
They have the form of seconds since Jan 01 1970, type in T1297687386
Type that in the start the clock. There are PC programs out there that run a host to send that string, like gobetwino if you want to do that to, you don't need to. This is just a manual start.
Change this variable in the code to the unix timestamp of the event you want to count down to
signed long tapeout = 1309539600;
The hardware is nothing more than an arduino interfaced to a huge 20x4 backlit LCD module, using the 4 bit wide parallel communication mode. The pinout is a very slight mod to the descriptions in the Arduino examples, because I like to group the pins all on one header. This is exactly like the setup in the Arduino examples.
I use an external wall wart as power, so it doesn't have to be plugged into the PC all the time.
Here is the code
* Sketch for 4x20 LCD to display current time and date, and countdown of weeks, days, hours, min to an event
*
*/
#include <Time.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6 , 5, 4, 3, 2);
#define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER 'T' // Header tag for serial time sync message
#define TIME_REQUEST 7 // ASCII bell character requests a time sync message
signed long tapeout = 1309539600;
// to make sure the display is cleared once a day
int yesterday = 0;
int weeksleft = 0;
int daysleft = 0;
int hoursleft = 0;
int minleft = 0;
void setup() {
lcd.begin(20, 4);
lcd.clear();
//backlight on pin 8
pinMode(8, OUTPUT);
digitalWrite(8, LOW);
Serial.begin(9600);
setSyncProvider( requestSync); //set function to call when sync required
Serial.println("Waiting for sync message");
Serial.println("Unix Timestamp");
Serial.println("Example T1297674000");
lcd.setCursor(0,0);
lcd.print("Waiting for PC time sync...");
}
void loop(){
if(Serial.available() )
{
processSyncMessage();
digitalWrite(8, HIGH);
}
if(timeStatus()!= timeNotSet)
{
digitalClockDisplay();
// clear the display if the day changes to clear glitches
if (day() != yesterday) {
//lcd.clear();
yesterday = day();
}
}
delay(20000); //can be set to 1000, this makes the display more stable
}
void digitalClockDisplay(){
//turn on backlight only during workday
if((hour() >= 8) & (hour() < 19)) digitalWrite(8, HIGH);
else digitalWrite(8, LOW);
// digital clock display of the time
lcd.setCursor(0,0);
Serial.print(hour());
lcd.print(hourFormat12());
printDigits(minute());
//printDigits(second());
Serial.print(" ");
if (isAM()) lcd.print(" AM ");
if (isPM()) lcd.print(" PM ");
Serial.print(dayStr(weekday()));
lcd.print(dayStr(weekday()));
Serial.print(" ");
lcd.print(" ");
lcd.setCursor(0,1);
Serial.print(day());
lcd.print(day());
Serial.print(" ");
lcd.print(" ");
Serial.print(monthShortStr(month()));
lcd.print(monthShortStr(month()));
Serial.print(" ");
lcd.print(" ");
Serial.print(year());
lcd.print(year());
Serial.println();
lcd.setCursor(0,2);
if (tapeout < now()) {
weeksleft = (now() - tapeout)/60/60/24/7;
daysleft = (now() - tapeout)/60/60/24 - weeksleft*7;
hoursleft = (now() - tapeout)/60/60 - daysleft*24 - weeksleft*7*24;
minleft = (now() - tapeout)/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
lcd.print( weeksleft );
lcd.print("wk ");
lcd.print( daysleft );
lcd.print("d ");
lcd.print( hoursleft );
lcd.print("h ");
lcd.print( minleft );
lcd.print("m ");
lcd.setCursor(0,3);
lcd.print("Late! OMG! Ship It! ");
} else {
weeksleft = (tapeout - now())/60/60/24/7;
daysleft = (tapeout - now())/60/60/24 - weeksleft*7 ;
hoursleft = (tapeout - now())/60/60 - daysleft*24 - weeksleft*7*24;
minleft = (tapeout - now())/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
lcd.print( weeksleft );
lcd.print("wk ");
lcd.print( daysleft );
lcd.print("d ");
lcd.print( hoursleft );
lcd.print("h ");
lcd.print( minleft );
lcd.print("m ");
lcd.setCursor(0,3);
lcd.print("To Santan Tapeout! ");
}
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
lcd.print(":");
if(digits < 10){
Serial.print('0');
lcd.print('0');
}
Serial.print(digits);
lcd.print(digits);
}
void processSyncMessage() {
lcd.clear();
// if time sync available from serial port, update time and return true
while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits
char c = Serial.read() ;
Serial.print(c);
if( c == TIME_HEADER ) {
time_t pctime = 0;
for(int i=0; i < TIME_MSG_LEN -1; i++){
c = Serial.read();
if( c >= '0' && c <= '9'){
pctime = (10 * pctime) + (c - '0') ; // convert digits to a number
}
}
setTime(pctime); // Sync Arduino clock to the time received on the serial port
}
}
}
time_t requestSync()
{
Serial.print(TIME_REQUEST,BYTE);
return 0; // the time will be sent later in response to serial mesg
}
The design is the "raw electronics" look. The arduino is mounted on the back of the large LCD display by nothing more than a stacked header, and hot glued to a small piece of wood for a base.
The code is built on top of the basic example for a clock that syncs from the PC, found here:
The Arduino Time Library on the Arduino Playground
http://www.arduino.cc/playground/Code/Time
When plugged into the PC and using the Arduino serial monitor, it waits for you to enter a unix timestamp.
You can generate these from web sites like these ones:
http://www.timestampgenerator.com/
http://www.unixtimestamp.com/index.php
They have the form of seconds since Jan 01 1970, type in T1297687386
Type that in the start the clock. There are PC programs out there that run a host to send that string, like gobetwino if you want to do that to, you don't need to. This is just a manual start.
Change this variable in the code to the unix timestamp of the event you want to count down to
signed long tapeout = 1309539600;
The hardware is nothing more than an arduino interfaced to a huge 20x4 backlit LCD module, using the 4 bit wide parallel communication mode. The pinout is a very slight mod to the descriptions in the Arduino examples, because I like to group the pins all on one header. This is exactly like the setup in the Arduino examples.
I use an external wall wart as power, so it doesn't have to be plugged into the PC all the time.
Here is the code
* Sketch for 4x20 LCD to display current time and date, and countdown of weeks, days, hours, min to an event
*
*/
#include <Time.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6 , 5, 4, 3, 2);
#define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER 'T' // Header tag for serial time sync message
#define TIME_REQUEST 7 // ASCII bell character requests a time sync message
signed long tapeout = 1309539600;
// to make sure the display is cleared once a day
int yesterday = 0;
int weeksleft = 0;
int daysleft = 0;
int hoursleft = 0;
int minleft = 0;
void setup() {
lcd.begin(20, 4);
lcd.clear();
//backlight on pin 8
pinMode(8, OUTPUT);
digitalWrite(8, LOW);
Serial.begin(9600);
setSyncProvider( requestSync); //set function to call when sync required
Serial.println("Waiting for sync message");
Serial.println("Unix Timestamp");
Serial.println("Example T1297674000");
lcd.setCursor(0,0);
lcd.print("Waiting for PC time sync...");
}
void loop(){
if(Serial.available() )
{
processSyncMessage();
digitalWrite(8, HIGH);
}
if(timeStatus()!= timeNotSet)
{
digitalClockDisplay();
// clear the display if the day changes to clear glitches
if (day() != yesterday) {
//lcd.clear();
yesterday = day();
}
}
delay(20000); //can be set to 1000, this makes the display more stable
}
void digitalClockDisplay(){
//turn on backlight only during workday
if((hour() >= 8) & (hour() < 19)) digitalWrite(8, HIGH);
else digitalWrite(8, LOW);
// digital clock display of the time
lcd.setCursor(0,0);
Serial.print(hour());
lcd.print(hourFormat12());
printDigits(minute());
//printDigits(second());
Serial.print(" ");
if (isAM()) lcd.print(" AM ");
if (isPM()) lcd.print(" PM ");
Serial.print(dayStr(weekday()));
lcd.print(dayStr(weekday()));
Serial.print(" ");
lcd.print(" ");
lcd.setCursor(0,1);
Serial.print(day());
lcd.print(day());
Serial.print(" ");
lcd.print(" ");
Serial.print(monthShortStr(month()));
lcd.print(monthShortStr(month()));
Serial.print(" ");
lcd.print(" ");
Serial.print(year());
lcd.print(year());
Serial.println();
lcd.setCursor(0,2);
if (tapeout < now()) {
weeksleft = (now() - tapeout)/60/60/24/7;
daysleft = (now() - tapeout)/60/60/24 - weeksleft*7;
hoursleft = (now() - tapeout)/60/60 - daysleft*24 - weeksleft*7*24;
minleft = (now() - tapeout)/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
lcd.print( weeksleft );
lcd.print("wk ");
lcd.print( daysleft );
lcd.print("d ");
lcd.print( hoursleft );
lcd.print("h ");
lcd.print( minleft );
lcd.print("m ");
lcd.setCursor(0,3);
lcd.print("Late! OMG! Ship It! ");
} else {
weeksleft = (tapeout - now())/60/60/24/7;
daysleft = (tapeout - now())/60/60/24 - weeksleft*7 ;
hoursleft = (tapeout - now())/60/60 - daysleft*24 - weeksleft*7*24;
minleft = (tapeout - now())/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
lcd.print( weeksleft );
lcd.print("wk ");
lcd.print( daysleft );
lcd.print("d ");
lcd.print( hoursleft );
lcd.print("h ");
lcd.print( minleft );
lcd.print("m ");
lcd.setCursor(0,3);
lcd.print("To Santan Tapeout! ");
}
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
lcd.print(":");
if(digits < 10){
Serial.print('0');
lcd.print('0');
}
Serial.print(digits);
lcd.print(digits);
}
void processSyncMessage() {
lcd.clear();
// if time sync available from serial port, update time and return true
while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits
char c = Serial.read() ;
Serial.print(c);
if( c == TIME_HEADER ) {
time_t pctime = 0;
for(int i=0; i < TIME_MSG_LEN -1; i++){
c = Serial.read();
if( c >= '0' && c <= '9'){
pctime = (10 * pctime) + (c - '0') ; // convert digits to a number
}
}
setTime(pctime); // Sync Arduino clock to the time received on the serial port
}
}
}
time_t requestSync()
{
Serial.print(TIME_REQUEST,BYTE);
return 0; // the time will be sent later in response to serial mesg
}
Subscribe to:
Posts (Atom)