SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
By nihil
#20274
Been playing with the MaxSonar-EZ1 module for the past day or so, and figured I'd post my include for it. It's using ADC on an ATMega32 currently, but should work with any AVR that has ADC. It is not the prettiest or most "proper" code, but it works. Here's a shot of it in action:

Image
Code: Select all
// sonar_maxez1.h
//
// Include for MaxSonar-EZ1 sonar ranging module using ADC. Tested on
// ATMega32 under avr-libc/avr-gcc on Linux. Thanks to Paul Daniels 
// for the example I ripped the ADC stuff out of.
//
//                                      nihil[at]nihil.rchomepage.com
//

// ADC input (ADC0 by default)
#define ADC_INPUT	_BV(REFS0)

// 2.048 = inches, 0.806 = cm 
#define SONAR_SCALER	2.048

// Initialize ADC for the module, call once before reading
void sonar_init() {
  ADCSRA = _BV(ADEN)|_BV(ADPS1)|_BV(ADPS0);
  ADMUX = ADC_INPUT;
}

// Read from the module, returns distance scaled by SONAR_SCALER
unsigned int sonardata;
int sonar_read() {
  ADCSRA |= _BV(ADSC);
  while(ADCSRA & _BV(ADSC));
  sonardata = (ADC/SONAR_SCALER);
  return sonardata;
}

// _EOF_
Questions/comments always appreciated.
By nihil
#20355
Just had to "announce" that I now have sonar reporting data over bluetooth via BlueSMiRF. :D

nihil@akui:~$ cu -l /dev/rfcomm0
Connected.
Range(in.): 66

(For non-*ix types, that's a paste from terminal where the 'cu' command opens a serial port. In this case, a virtual serial port bound to a BT channel.)
By transcendentnb2
#20358
It gets pretty computationally expensive when you're dealing with floating points (2.048). For my senior design project that used 2 of these ultrasonic sensors, I simply divided the A/D reading by 2 (which compiles into 2 right shifts in assembly... one for each byte of the 16bit number). But then again, we only needed a rough value... didn't care about the accuracy for long ranges.

Style points I follow and I figure most do:
1) Keep header files for defines and function prototypes, and other includes
2) Put all compile-able code in a .c file.

But, since this code is pretty small, it doesn't really matter :D

Note about my project: I used 2 of these sensors. The A/D interrupt was used and each sensor was converted one at a time (multiplexed, single-ended mode). After each sensor value was calculated, it was stored in a global variable to be read by anything else. The A/D control register was updated to read the next sensor. The caveat to this is that you have to be careful when reading/writing these 16bit global variables now that you have an interrupt accessing them at potentially the same time.

Just a thought.
By nihil
#20417
Thanks, I know about splitting compilable code and includes, but as you mentioned this is small, and doesn't really matter for a quick and dirty 'ok it works'. I'm very new to programming microcontrollers, and am re-learning C in the process (learned the basics of it 10+yrs ago and never used it).

Sounds like you had a fun project. I think for mine I'm going to stick a single sensor on a servo that sweeps back and forth and reads data at predetermined positions in the arc. I dont have any specific goal in mind, just learning the ins and outs.
By vic7767
#20490
nihil
if you don't mind, how did you connect the maxsonar to your bluesmirf. I tried connecting Tx of the sonar to Rx of the bluesmirf ran a discovery using BT connected to comm 9 in my case. just receive garbage characters using procomm or hyterterminal at 9.6, N, 8, 1.
also jumpered CTS to RTS on the bluesmirf.
thanks
vic
By nihil
#20493
Heres a map of the pins I'm using, though it sounds like you have it connected right, and just need to set the baud rate properly. What environment are you using to program? I ran into an issue with an older version (debian stable) of avr-libc where delay.h was timing things wrong. It caused me quite a bit of headache when I started doing UART stuff. I switched to an alternate delay.h, and it's timing fine now.

On the SMiRF:
CTS = jumped to RTS on SMiRF
PWR = +5V
GND = GND
TX = RXD(PD0) of ATMega32
RX = TXD(PD1) of ATMega32
RTS = jumped to CTS on SMiRF

On the MaxEZ1:
GND = GND
+5V = +5V
TX = <not connected>
RX = <not connected>
AN = ADC0(PA0) on ATMega32
PW = <not connected>
BW = <not connected>

Reading from the MaxEZ1 and writing to UART was all done in programming. You dont need anything like a Mega32 though, this can be done on any AVR that has both a UART and ADC.

As an alternate method, you can forego the ADC and write PWM reading/timing routines, and connect PW on the MaxEZ1 to any unused pin on your AVR.

If you can find an AVR with two UARTs, you can use the TX/RX pins on the MaxEZ1, then read from one UART and write to the other.

Hope this helps.
By vic7767
#20496
thanks much for the info, i'm just using WinXP and a BT application right now and wanted to just get something out of the maxsonar via the rs232. I plan on moving to a basic stamp connected to a roomba later on. The only time i get real ascii output is using an older laptop with a 9pin comm port connected to pin 2 and gnd on pin 5.
By nihil
#20498
You should be careful when connecting things directly to computer serial ports. A max232 (or equivalent) level converter should be used to convert TTL levels to the RS232 levels most computers use. Laptops, particularly older ones use a lower voltage RS232 spec if I remember correctly, which would explain why it works on the laptop but not the workstation.

Here's a link that might help:
http://www.kmitl.ac.th/&#126;kswichit/MAX232/MAX232.htm
By vic7767
#20499
again, thanks much, i forgot to mention that i attempted using a rs232 to Uc level shifter. the same one i use on my pic programmer, in fact i got it here at sparkfun. i googled the maxsonar and one of the web pages mentioned that the output of the rs232 port on the maxsonar is inverted. just ordered a 74LS05 hex level shifter. when it gets here i'll hook it up and see what happens.
User avatar
By jessewelling
#21533
I am also having problems hooking up the Max to my ATmega128 uart.
I keep getting junk out of the serial port even though the Analog out seems to be working. I say I'm getting junk but I do get that junk at a reliable interval of 20hrz or every 50ms which is in acordance with the the Max is suposed to be doing, I suspect this is because of that inverting? What exactly needs to be done to make the Uart usefull on this sensor? (sorry I wish my question could be more direct but I'm just a programer....:cry:)

Thanks for the help!
By nihil
#22031
If you're getting garbage over UART, make sure you have the baud rate and flow control set properly. The sensor defaults to 9600 8n1, are you sure you're setting that up on the AVR?

The 20Hz/50ms timing is just the maximum speed the device can be read at, not an indication of its communication. What programming environment are you using?
User avatar
By jessewelling
#22034
I'm using avr-gcc on a linux box.

I'm fairly certain I've got the right set up because on the same UART I'm sending output to a Serial LCD from Sparkfun and it has the same settings right? I mean the Maxbotix doesn't say any thing about a start bit but Serial LCD does. I thought almost all serial has a start bit, and they only specify how many stop bits there are. Am I wrong?

Any ways I have some of those 74LS05 inverters. So i'm going to put the Sonar on an o-scope to see what it's doing, I'll make it work one way or another. :wink:
By nihil
#22056
What version of avr-libc are you using? There's a bug in earlier versions of delay.h (whatever comes with Debian stable) that gave me lots of trouble with UART stuff. But, I guess if you're using a serial LCD the same way, it must be working?

Though, I have to ask, why waste the UART on the sonar module? PWM or ADC would be much easier, and leave the UART open for other stuff.
User avatar
By jessewelling
#22071
In a word...accuracy. The ADC is pretty noisy, and all the timers are being used up for other things.
The RX on that uart is wasted because the TX goes to the serial LCD any ways.....so why not? :P