Archive for February, 2016

Measuring Distance with an HC-SR04

Tuesday, February 16th, 2016

The HC-SR04 is a cheap (in terms of money)  module that can measure distances using ultrasound. The module uses a 40 KHz tone, which is of course way above what any human can hear, to measure the distance. It works as follows.

  • It expects a 10µs TTL, i.e. 0-5V, pulse on its ‘Trigger’ input
  • It will then send out a sound
  • Waits until the sound comes back and calculate the distance
  • Create a pulse on the ‘Echo’ output. The length of the pulse will correspond to the distance measured

I used a ATMega328p MCU to control the HC-SR04.

HCSR04

The yellow channel shows the outgoing pulse to the ‘Trigger’ input of the HCSR04. The blue channel shows the signal coming back on the ‘Echo’ output the length of it being proportional to the distance measure. The OLED display shows the values measured. The first few values are for debugging the last shows the measured and calculated distance in meters. In the top right the HCSR04 is visible sitting on my laser distance meter. Compare the value of that 0.156 to the one on the OLED display 0.150. They are pretty close.

The main parts of the program consist of:

  • an ISR (Interrupt Service Routine) to be called when the echo pin goes to high
  • a timer to measure the length of the pulse sent by the HC-SR04

One thing to keep in mind that it is not the time between starting the HC-SR04 and the start of the echo pulse that should be measured but the length of the echo pulse. That is to say it is not really the echo the HC-SR04 just sends you back the measure distance and the simplest way is to vary the length of the signal.

My ATMega328p is clocked at 8MHz. The supply voltate is 3.3V to stay compatible with my RPi. The HCSR04 however needs to be connected to a 5V supply. Obviously you need to connect the grounds of both power supplies to make it work. The ‘Trigger’ input was connected directly to the ATMega328p since it produces a 3.3V high and that is well within the limits of what is considered ‘high’ in TTL. However the ‘Echo’ pin I connected through a two resistor voltage divider (i.e. two resistors in series, one connected to the ‘Echo’ ouput and the other to ground while the middle is the ‘Echo’ that goes to the ATMega. The one connected to the ground divided by both, times the 5V should be somewhat below 3.3V.

Note that the code should be optimized, obviously, for any real application. Note also that the following is not complete (since I already deleted the code but I’ll recreate it some time and update this) just showing the idea. I used the OLED from a previous post for the output.

volatile uint16_t MeasureCount;
ISR (INT0_vect)
{
	// Reset timer
	TCNT1H = 0;
	TCNT1L = 0;
	// Wait until pind goes back to zero
	
	while( PIND & EchoPin );
	
	uint16_t LSB = TCNT1L;
	uint16_t MSB = TCNT1H;
	uint16_t Pulses = ( MSB << 8 ) | LSB;
	//Pulses = 65535;
	float Distance = ( (float) Pulses * 343.2f ) / ( 2.0f * 8000000.0f ) + 0.0005f;
	uint16_t Whole = (int)Distance;
	uint16_t Partial = (int)( ( Distance  - Whole ) * 1000.0f );
	++MeasureCount;
	sprintf( Message0, "M %06u H = %u L = %u %u", MeasureCount, MSB, LSB, Pulses );
	sprintf( Message4, "%u.%03u Meters", Whole, Partial );
}

void Init()
{
	cli();
	strcpy( (char*)Message4, "Started Hello World");
	DDRB = 0;  // All pins input
	DDRB |= 1;
	DDRB  |= BlinkPin; // Blinkping output
	PORTB &= ~BlinkPin; // Make pins low to start

	// turns on pin change interrupts
	PCICR |= 1;
	//
	DDRB |= PulsePin; // Pulse pin output
	PORTB  |= EchoPin;    // Enable pull up
	PCMSK0 |= EchoPin;    // turn on interrupts on pins
	
	sei();
	
}
u8g_t u8g;

void u8g_setup(void)
{
	u8g_InitI2C(&u8g, &u8g_dev_ssd1306_128x64_i2c, U8G_I2C_OPT_NONE);
	u8g_Begin( &u8g );
}
void StartMeasure()
{
	cli();
	PORTB |= PulsePin;
	_delay_us( 11 );
	PORTB &= ~PulsePin;
        // I used a small delay here, sometimes it seemed to immediately start measuring, maybe it picked up the pulse I sent
        // So wait just a little bit
	_delay_us( 2 );
	sei();
}
void draw()
{
   u8g_SetFont(&u8g, u8g_font_6x10);

   u8g_DrawStr(&u8g, 0, 10, Message0 );
   u8g_DrawStr(&u8g, 0, 21, Message1 );
   u8g_DrawStr(&u8g, 0, 32, Message2 );
   u8g_DrawStr(&u8g, 0, 43, Message3 );
   u8g_DrawStr(&u8g, 0, 54, Message4 );
}

int main(void)
{
	Init();
	u8g_setup();
	
	strcpy( Message4, "Hello world" );
		
        StartMeasure();
	u8g_FirstPage(&u8g);
        while(1)
        {
	  do
	  {

	    draw();
	  } 
          while ( u8g_NextPage(&u8g) );
     }
  }
	
}

 

Galaxy S3 Compass Incorrect Values

Sunday, February 7th, 2016

Hmph, spent an afternoon debugging my Galaxy S3 Sensor app since it stopped working, checked all code changes for the last year then checked all the transformations etc. until I realized the compass sensor itself gave invalid values.

As a reminder to myself. Seems that you sometimes need to calibrate it:

  1. Phone
  2. *#0*#
  3. In the test menu press sensors
  4. Immediately start rotating the phone around all its axes until the little compass at the bottom of the screen shows 3.
  5. Then lay it flat on the table and check that it displays the correct values (comparing it with a real compass) while rotating it over 360°
  6. If not correct go back to the sensor menu and repeat from 3 onwards.

 

Controlling 1306 128×64 OLED Display with an ATMega328P

Wednesday, February 3rd, 2016

Note that I mostly build on what other people researched and just put those results together however it is nice to have everything in one place. All credits go to the various authors I link to except for the glue in between (i.e. Atmel Studio part). So this will be mainly a starting point to the various sites.

This is a lot of text and I probably will spice it up a bit in the future with pictures of scantily dressed women, I mean boring diagrams and photos of ATMega328p’s.

Ok, with that out of the way let’s start. First off what do we need:

  1. Raspberry Pi
  2. ATMega328P
  3. Breadboard
  4. Wires to connect stuff
  5. Optional 5 * 1K resistors (to protect your Raspberry Pi).
  6. And of course an OLED display
  7. Windows (I do it on windows you have to improvise for Linux however most or almost all tutorial are for Linux so you should be OK there).
  8. Atmel Studio

 

ATMega328P

ATMega328P’s are fond of breadboards and easily trapped in one. No worries though, I added a life support system to feed it.

 

Setting up and connecting the ATMega328P to your RPi

For that go to this site BUT instead of using the pin assignment for the ATTiny go to this site. Admire the ATMega328P with its many pins for a while and in the mean time I am going to get a cup of coffee while you  lookup and connect the corresponding pins for the ATMega328P.

So you’re finally back (I drank coffee, cleaned the house and destroyed some IC’s with static electricity in the mean time but that’s OK).

Atmel Studio

We will be using Atmel Studio to compile stuff and then scp the resulting binary to your Raspberry.

  1. Download Atmel Studio. You probably have to supply your email and you get some nice ‘Maker’ info from Atmel. Your are now an official ‘Maker’ 🙂
  2. Install Atmel Studio. This is Visual Studio under the hood so if you are familiar with it you feel right at home. If not and haven’t used any IDE before, you are probably looking at a confusing quagmire of User Interface Elements. Don’t worry though, I’ve got you covered, even if you haven’t got the remotest clue what you’re doing or even what we’re trying to accomplish here in the first place.
  3. Start it and after a while you arrive at the welcome page.
  4. Select ‘New Project…
  5. Select ‘GCC Executable Project’
  6. Give it an original name (like OLED).
  7. Now there is a device selection window (may not be the top window). Click on it and select  ATMega328P
  8. You are in your little project but as good cut & paste developers we are not going to program, yet…
  9. Instead, of writing the lower layers, I downloaded the UG8 library for AVR and build on the Herculean job other developers have done.
  10. Once downloaded unzip it and descent into the ug8lib/src dir.
  11. In another window go into your Atmel studio source dir (one deeper than where your *.atsln file is). So if you named the project OLED you should select that dir twice to get there.
  12. Select all ‘.c’ and ‘.h’ files and copy them to from ug8lib/src and copy them to the second window.
  13. Now in Atmel studio the right pane should contain ‘Solution Explorer’ (if you didn’t mess with the windows).
  14. Now right click on the project (not the solution which is the topmost node) and select ‘Add’->’Add Existing Item…’
  15. Select all ‘.c’ and ‘.h’ files that you copied there to add them to the project.
  16. Go to Build->Configuration Manager and select ‘Release’ as active build.

Almost there, our project is pretty much ready but we need to correct settings.

  1. Again in the ‘Solution Explorer’ (the right window). Right click again on the project node (still not the top node) and select properties.
  2. Basically if you look in the ug8lib dir there was a Makefile and I just set all the options according to that (if I could find them).
  3. Build->Configuration->Select Release
  4. Select ‘Toolchain’
  5. Select the following options for Avr Gnu Compiler:
  6. General: -mcall-prologues
  7. General: -funsigned-char
  8. General: -funsigned-bitfields
  9. Preprocessor: Unseselect everything (should already be unselected)
  10. Symbols: Click on the green + symbol and add ‘F_CPU=8000000’ this is your processor speed 8MHz.
  11. Optimization: Select Optimize for size (-Os) in the drop-down list
  12. Optimization: Select everything except -mshort-calls
  13. Warnings: Select -Wall
  14. AVR Gnu Linker:
  15. General: -WL  (actually not sure if it is an L or the number 1)
  16. Optimization: -WL –gc-sections

Then Build->Clean Build (not really necessary probably) followed by Build->Rebuild All. Now pray to your favorite God. I pray to the god of Jesus but you can pray to yours and we will see who’s build succeed :-).

If there are almost no errors. I got a warning about a pointer that was incompatible, however when I searched the source code for that, it was because they defined a function pointer as taking a parameter as ‘void *’ instead of the pointer to the function you assign it to, is using. Since they were the same size it isn’t a problem.

Now go into the OLED dir where you copied the .c and .h file and there should be a directory ‘Release’. If there isn’t but there is a ‘Debug’ instead you didn’t select the right project build in Build->Configuration Manager.

In that directory there should be a file ending in *.hex and that file is your program and need to be copied to your Raspberry Pi.

Modify the Raspberry Pi project for your hex file

Now in the source I assume the clock is 8MHz (#define F_CPU  8000000) so we must ‘fuse‘ the ATMega to 8MHz (i.e. turn of the clock divider):

sudo /usr/local/bin/avrdude -p m328p -P /dev/spidev0.0 -c linuxspi -b 10000 -U lfuse:w:0xE2:m

When you went through the instruction on this site, you ended up with a blinky program in the blinky directory.

cp -R that blinky dir to an OLED dir and instead of the Makefile we can use the following script (I just looked at the Makefile from this  site so all credits go to the original author ):

sudo gpio -g mode 22 out
sudo gpio -g write 22 0
sudo /usr/local/bin/avrdude -p m328p -P /dev/spidev0.0 -c linuxspi -b 10000 -U flash:w:OLED.hex
sudo gpio -g write 22 1

 

By running the above commands you flash your program to the ATMega328p.

It should write and verify just as with the blinky app.

 

Hooking up the Display

With the display in front of you the pin assignment is GND, VCC, CLCK, DATA. Make sure to flip it vertically so they stay in the same order now connect them as follows:

  • GND connect to the GND of you breadboard
  • Make sure you use the 3.3 V of your RPi not the 5V.
  • VCC connect to the 3.3V
  • CLK connect to the upper right pin (assuming pin 1 (with the notch) is at the top left) of the ATMega328p i.e. pin 28 top right pin
  • DATA connect to the second pin at the upper right (i.e. the pin just below where we connected CLK) i.e. pin 27

Grand Finale

Connect the reset pin i.e. the upper pin at the left (the one with the notch) to Gnd and then to the VCC to reset the device.

The device should now display ‘Hello world’. In the picture below it shows ‘Does it work?’ because I attached it to my RF433 receiver (and I sent that string from my RPi).

OLDE

Final result. The (pretty bad) signal is from my RF433Mhz receiver. My RPi sends a string using a RF433 transmitter which is then received and decoded by an assembly routine I wrote for the ATMega328.  The resulting string is then displayed instead of the standard ‘Hello world’ string. Admittedly currently the string is only correctly decoded once in several times due to noise on the wires.