AVR navigation in well known terrain

My garage is no longer a black hole. In outer space, a black hole brings back light with a long series of uncomfortable side effects. Overheating, explosions, and there is no way you can control what direction you are going when the dark turns to light. My garage lights up when it sees the brake lights on my car, and guide me to the same spot every time. My garage can even communicate over Bluetooth.

Garage – black hole: 1-0

keep reading: LED strips, Digital to Analog converter and more parking literature

AVR Backup support saves money and relationships

It’s me, I crash the family car.

Luckily, my wife can almost never be blamed for any of our car incidents. If she were to cause some trouble, I would probably stigmatize her and blame her for being a typical woman. I would say she is stressed out over normal traffic and putting on makeup in the rear view mirror while driving. She would feel very bad, and probably try to camouflage the dents with mascara or whatever black she has in her purse.

She makes a mess inside the car, though. She believes the car is an extension of her purse, and throws bags, receipts and extra pairs of shoes everywhere. But that can easily be cleaned out.

I run into poles in parking lots and my own garage.

And this is where the AVR is coming to my rescue: I’m making a device that turns on the lights in the garage for me when it sees my brake lights, backing in.

When it is rainy and dark (the average weather in Bergen) the rearview mirrors cover with rain drops, dispersing my visual rays into a blur. The garage opening is a narrow black hole. You might think that this black hole has so high gravity that it sucks the car in, but no, the only mass in there is a set of spare wheels and years of dust.

I think the garage was built sometime in the medieval, when people were tiny and families didn’t travel much. I might be wrong about history, but the garage is small. Leaving little space on either side or in front of the car when it is parked and the gate is closed. So I need light to see. Automatic lights.

I could of course switch on the lights when I’m out opening the gate, but that would be a change of routine. And the brain is rigged to celebrate lazy repetitiveness in the daily operations, and punish any attempt on changing. Try brushing your teeth with the hand that normally just hangs around while teeth get their daily shampoo, and you will feel the backlash from the hub. I might be able to turn on the garage light every time I open the gate, but I might also end up forgetting to put on pants or bring the kids. Not something I’m willing to risk, so I make something new and slightly useful to do the job.

brainparts
The brain loves creativity. Learning new habits takes rounds and rounds of repetition

You got the concept? I back up to the garage, a light sensor sees my brake lights, and turns on LED strips in the garage to illuminate my path of easy parking. No more expensive and embarrassing repairs on the car or the garage.

Of course there will be an AVR controlling the lights, and I will use a Light Dependent Resistor (LDR) to see the brake lights. The PCB layout will be similar to my shelf light project, but this time I will use the Analog to Digital Converter (ADC) in the AVR. The ADC turns the resistance readings from the LDR into a number, and I can set a threshold for when to turn on and off the LED strips (which I will mount in the garage. Also, I will add a serial connection with a bluetooth device to help me calibrate the sensor, and perhaps add more features later on. It will run of grid power with a 12V DC converter in the socket.

Sounds fun?

A cap, some Wire, and (broken chips / burn = zero)

The ZIF Atmega burner I made required an upgrade after some use.

Moving from the breadboard setup I had before to burn Atmegas to my ZIF burner has been a great upgrade for me, it takes much faster, I don’t make as many mistakes as before, and the derivative of how many chips I break pr burn (or time) dived really deep, before leveling around zero.

1. When using avrdude to burn the chip, it would sometimes give an error telling me that the chip signature was wrong. I found that adding a capacitor over the power supply and ground eliminated this problem

2. The underside of the PCB was unprotected, and could easily scratch the living room table (where I fiddle), and it was easy to cause shorts by placing the PCB on something, like the a screwdriver. The nice solution would be to cover the PCB with a plastic plate, or maybe box it up, but I chose quick and dirty, and soldered some wire to both ends of the PCB and shaped them as feet.

3. I forgot to install a resistor to the LED, so it quickly burnt out. As the LED was wired in parallel with the power for the chip, it didn’t matter for the performance, but a shining light always makes a project look better, and it’s a verification that the connector is installed properly.

Meet ZIF burner V2.

With caps, resistor, and protection.
With caps, resistor, and protection.

My new friend, Atmel Studio, and how easy everything is when you can see clear

This article is in a series about making a shelf with lights controlled by an AVR.
Read about 
 - designing and building the book-case
 - understanding Mosfets
 - and coding the AVR, and improving it using Atmel Studio

A returning stick in my wheels of programming is the lack of a decent step by step debugger. Often I fly off a mental cliff wondering what hit me, and how I caused this mess.

My previous setup with Notepad++, AVRDude and ArduinoISP worked well, but wouldn’t let me go through my code step by step to evaluate and debug. I found that Atmel Studio has step by step debugging of code. Since the cheap and versatile Atmega168 chips use are from the same manufacturer, I gave the free Atmel Studio a try.

The coding environment is a little slow at startup, but does the work elegantly. It has nice color codings for C, and it has quick setup features to get going with making. Atmel studio is based on Microsoft Visual Studio Express 2010, which I am familiar with from some game programming in Python and C#. So with the already mentioned debug function built in, this is a better tool than my previous setup.

But Microsoft Visual Studio takes care of the C coding and the color layout, the big feature of Atmel Studio is the parts library, readily available datasheets, and the Simulator. The simulator shows every register in the chip, and indicates if a bit is set or zero, and if it changed in the latest clock cycle. The parts library I haven’t dived into as I am quite satisfied with the Atmega168 for now, and I’m used to look for datasheets online anyway, so the biggest feature for me (without looking for more features) is the simulator, which I will talk more about.

I do appreciate the strong datasheets for the Atmega AVR’s, but nothing beats seeing every change that occurs in the processor as the code progresses, in terms of understanding (not in terms of speed). Let’s bring in my shelf light project to show better how the simulator helped me.

PWM fader

Preparing for the Wife Acceptance Test (WAT) of my homemade shelf, built after the expensive one she wants to buy, adding a fade function to my shelf lighting will give me some extra points, and increase the chances of my shelf (and AVR) ending up in the living room.

In my original code, PWM switched the lights to another intensity at every button press. Now I’m adding a gradient to the way the lights change. So for a case where I wanted the lights to reduce gently down to a given setting, the code ended up like this:

		//set output to medium
		while(OCR2B > 100){
			OCR2B -= 1;
			_delay_ms(5);
		}

Now, before I added the _delay_ms(5), I got no fading effect of the lights. I checked the datasheet over and over again, and looked at other peoples code, but I could not see how my code differed from anyone else, or why my code failed.

In the Atmel Studio Simulator I can see what happens every tick of time in the CPU (and timers), and I found that the OCR2B register is only updated with a new value whenever the Timer reaches 255 (or zero), to avoid a broken PWM signal. When I set a new OCR2B value for almost every clock tick (it takes some ticks for each while loop), the OCR2B might not be set before the while loop has been run so many times that the fading is over.

I probably wouldn’t have understood this without the visualization from the simulator in Atmel Studio, but I found that the light intensity changed after every fade cycle, when I let the code run freely to wait for a new click on the button. So I clicked my way through 255 timer steps, to get my suspicion verified, to find that the OCR2B register was updated with the value I set only when the timer tipped over from max to min.

The solution was to add a very short delay, to allow the timer to reach to 255 and loop back to zero, and set the new value of OCR2B, and hence fade the light down for every loop.

I haven’t figured out the timer registers fully, there are some flags that can be set and zeroed out, maybe one of these can be used to get a faster setting of the OCR2B register.

The studio feels like home

Atmel Studio has been a very good new friend on my path, where software and hardware merges in an AVR. The visualization from the simulator and the debugger has made coding experience much better. Not that I necessarily make less mistakes, but Atmel Studio equips me with some much clearer glasses in the struggle against deep cliffs and frustrating hours.

BTW: I’m not very fan of using the _delay function, as it locks the CPU down to doing nothing. In my later code I will try to implement use of the timers built into the Atmega for making breaks, such as wait until the timer1 has counted to 255 10k times before progressing.

BTW2: I can only handle a certain amount of software challenges pr day, so I quickly gave up using the Atmel Studio to run AVRDude and ArduinoISP to burn my code to my chip. Maybe another day I’ll feel braver.

No more screwdriver on Atmega. I’m making a ZIF AVR burner

Atmega breadboard burner
Atmega breadboard burner

When making a project with an AVR chip like the Atmega 168, the chip will be moved from the burning station to the project PCB many times, and my setup with burning on a breadboard, and installing in a dock on the PCB. Now I need a smarter way to burn the AVR with new updates, which does not require a screw driver and bending on the Atmega to get it re-made.

PCB Layout
ZIF and LED on PCB

A Zero Insert Force (ZIF) socket is a good solution to the challenge, as it is easy to mount, and easy to use. It is a little larger than just a socket, but it is (I hope) a lasting device, that can be used over and over again.

On the Arduino, there is an ICSP pin section with six pins, for power, ground, communication and reset. These pins are used to program the Atmega 328 on the Arduino, so the. All the pins can be used for burning an external Atmega, except for the reset pin. The reset pin resets the 328 on the Arduino, and is used as part of the programming of the 328, not for burning an external AVR. Hence a single cable to pin 10 on the Arduino is necessary.

A later add-on is to install headers on the side of the ZIF, and solder these to the pins on the ZIF. That would make me the owner of a ZIFuino.

Soldering connector
Soldering connector

The ZIF is placed on a PCB so that it has equal space on each side. The pins on the ZIF are soldered to the PCB one by one, and I later connect wires on the backside of the PCB. Note that the pins don’t go all the way up to the top of the green box, where the lock and release handle is positioned. Next to the lock and release handle of the ZIF is the 6 pin connector. I used two three-pin headers, inserted them into the connector, so the headers were held in place while I soldered the headers to the the PCB. Another good way to solder headers is to set the headers in a breadboard, and then lay the PCB over, and solder. That didn’t work in this project, as the ZIF socket is taller than the headers.

6 pin connector cable
6 pin connector cable

I made a cable package with six cables, connected to a six pin connector in each end. I soldered all six cables in one end. In the other I left the reset cable out, and soldered on a single wire, to be connected to pin 10 on the Arduino. After soldering I added some heat shrink tube to protect the cables.

Unfortunately, I forgot a resistor for the LED, so the lamp burnt out with a blink when I powered up. The 5V input, running through the 1.7V LED gave too much current flowing through. I resolder the LED and add a 220 ohm resistor.

ZIF programmer
ZIF programmer

Back at the computer desk, I plugged the 6 pin connector to the Arduino ISCP and the free wire to pin 10, and inserted the connector on the PCB, and voila, no more screwdrivers and tongs to get the Atmega out of the mill.


I have later fixed and improved this project a bit, as the AVR burner randomly failed to recognize the chip in 1 of 2 attempts.

 

Code for the shelf

Much code ends up on the shelf for a later project. My project is making a shelf with lights coming out of a couple of LED Strips, and the code goes into an Atmega 168, installed in the shelf.

This article is in a series about making a shelf with lights controlled by an AVR.
Read about 
 - designing and building the book-case
 - understanding Mosfets
 - and coding the AVR, and improving it using Atmel Studio

Before we look at the C code that goes into the Atmega, let’s have a quick look at how to get started with AVR programming. I have read an excellent book on AVR programming, which game insight to how the Atmel chip works, and how to utilize its amazing features. I bough the Atmega chips from RS Online, who has a very good selection, a decent web page and fast and free delivery over 500 NOKs in Norway. Other stuff you need is a breadboard, some wires, a text editor (Notepad ++), and WINAVR to make you able to speak C to your chip. There are many good tutorials on getting started with AVR coding online.

Ok, to my own work. The Atmega 168 is coded to feed a MOSFET with varying voltage, controlled by a single button on the PCB. The Atmega will cycle through a Pulse Width Modulation (PWM) sequence where the output voltage is reduced, to choke the MOSFET and dim the attached LED strip.

First, some declarations to get the code started.

Atmega 168 pinout
Atmega 168 pinout
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define LED_PORT                PORTC
#define LED_PIN                 PINC
#define LED_DDR                 DDRC

#define STBYLED                 PC3
#define PWRLED                	PC4

#define BUTTON_PORT             PORTD
#define BUTTON_PIN              PIND
#define BUTTON_DDR              DDRD

#define BUTTON                  PD1
#define STRIP_DDR               DDRD
#define LED_STRIP		PD3	//OC2B

The #define syntax define constants that cannot change during the program. This saves space compared to a variable defined later in the program.

With constants from the io.h library, I give my own name to the PORTs, PINs and DDRs I will use in the code. Note that the LED strip is connected to PD3, which is one of six PWM outputs in the Atmega. There are 3 timers that can be used, and they each have 2 pins they can run interrupts on. The reason I chose PD3 is the position of the pin compared to the PCB layout.

The button is on the same PORT as he LED strip, PORTD, so I will have to be very specific on how I define input and output DDRs in the program.

The delay.h library is necessary to waste time in the program.

Moving on,

static inline void initTimers(void){
	// timer 2
	TCCR2A |= (1 << WGM20); //set fast PWM bit 1
	TCCR2A |= (1 << WGM21); // set fast PWM bit 2
	TCCR2B |= (1 << CS21); // set divide by 8 (frequency)
	TCCR2A |= (1 << COM2B1); // set output to OC2B == PD3
}
Atmega 168 Timer register
Atmega 168 Timer register

This function is described in the previous blog post, setting up the timer register for PWM.

void updateState(uint8_t LIGHTSTATE){
	// TODO add dimming / smooth transitions
	switch (LIGHTSTATE){
		case 1:
		BUTTON_PORT |=(1 << LED_STRIP); //LED STRIP on button port, power on
		// turn PWM on and output to pin
		TCCR2A |= (1 << WGM20); //set fast PWM bit 1
		TCCR2A |= (1 << WGM21); // set fast PWM bit 2
		TCCR2B |= (1 << CS21); // set divide by 8 (frequency)
		TCCR2A |= (1 << COM2B1); // set output to OC2B == PD3
		//set output to max
		while(OCR2B < 255){
			OCR2B += 1;
			_delay_ms(3);
		}
		break;
		case 2:
		//set output to medium
		//OCR2B = 127; // 2.39V
		while(OCR2B > 100){
			OCR2B -= 1;
			_delay_ms(5);
		}
		break;
		case 3:
		//set output to low
		while(OCR2B > 5){
			OCR2B -= 1;
			_delay_ms(10);
		}
		break;
		case 0:
		//set output to 0
		TCCR2A = 0x00; // turn off PWM and interrupts from timer
		BUTTON_PORT &= ~(1 << LED_STRIP); // turn off LED_STRIP, sink to ground
		break;
	}
}

The updateState function takes an integer LIGHTSTATE, which runs through a switch statement to set the PWM output of pin PD3 (defined in the previous function). If LIGHTSTATE == 1, the timer2 registry is set in the Atmega hardware, overkill the first time it is run, but when LIGHTSTATE == 0, the PWM settings are removed, and hence they must be redefined here every time.

The OCR2B sets the number where the timer will send a low signal to the output pin PD3. The timer continuously counts from zero to 255, turning back to zero again. The timer turns the output pin high (5V) every time it drops to zero, and turns it low again (ground) when it reaches the number set in the OCR2B register. Through the cases one, two and three, the OCR2B value is set lower, giving a lower average output voltage that the MOSFET will read.

When LIGHTSTATE == 0, the PWM is turned off, and the current in PIN PD3 is drained to ground. This is to fully turn off the power on the MOSFET.

Note that the output pin can only output HIGH and LOW (5V and ground), and the PWM is turning the pin on and off so fast that the voltage read from the output is somewhere between 5V and ground. It is not possible to output an intermediate voltage without use of external circuitry. PWM is a very useful tool, and as the code shows, it runs without using CPU power, all is done by separate timers, built in to the Atmega chip.

Now the main program with a setup part, and a loop, running as long as there is power on the PCB.

int main (void){
	uint8_t lightState = 0;
	initTimers();
	// --init AVR banks --//
	BUTTON_DDR = 0x00; // button ddr to input (default)
	STRIP_DDR |=(1<< LED_STRIP); // LED Strip on same DDR as button, set to output
	BUTTON_PORT |= (1<< BUTTON); // set pull-up on button pin
	
	LED_DDR = 0xff; // turn set LED DDR to output
	LED_PORT |= (1<<PWRLED); //Turn on power light
	while(1){
		// if ((BUTTON_PIN & (1<<BUTTON)) ==0){
		if (bit_is_clear(BUTTON_PIN, BUTTON)){
			LED_PORT |= (1<<STBYLED); //Turn on standby light
			_delay_ms(500); //doubles as debounce  NOTE: rewrite for timer if more actions
			LED_PORT &= ~(1<<STBYLED); //Turn off standby light
			lightState += 1;
			if (lightState >3){
				lightState = 0;
			}
			updateState(lightState);
		}
	}
	return(0); //will never happen
}

The setup part is PORT, DDR and PIN handling to setup the LEDs on the PCB for power and standby. The standby light is used as an indicator that the button is pressed (no real standby mode used, the Atmega is not using much current anyway).

The STRIP_DDR and BUTTON_DDR points to the same Data Direction Register (DDR), and I chose to set all pins on the port to input, except for the LED strip, which is output. The button is set as an input pin, and with the internal pull-up resistor activated. The pull-up is a resistor connected to 5V, so when the switch is closed, currents flow the voltage on the pin drops to zero. The resistor limits the flow of current, so the chip is not shorted. The pull-up resistor is built into the pins of the Atmega, so no external resistor is needed, just a 1 in the BUTTON_PORT register.

For the LED lights, the DDR is set to output, and the PWRLED (red) is always turned on. (I got the LED lights a bit too cheap on ebay, so I think they will last shorter than the PCB and shelf. One green light failed during testing).

The bit_is_clear() function is defined in io.h, and checks a given pin to see if it is high or low. When the BUTTON (PD1) is clear, it means the button is pressed, as the voltage goes low, when the switch shorts the pin to ground. When the button is pressed, the lightState integer is increased with 1, and the updateState function is run with the lightState variable as input.

And that’s the magic, the next post will be on how I built the shelf itself, and how (if) it all fits together in our living room. (Or the shed if the Wife Approval Test (WAT) fails).

MOSFET 101 – 2 lessons learned and a working AVR project

This article is in a series about making a shelf with lights controlled by an AVR.
Read about 
 - designing and building the book-case
 - understanding Mosfets
 - and coding the AVR, and improving it using Atmel Studio
MOSFET IRLB8721. From left: Gate, Drain, Source.
MOSFET IRLB8721. From left: Gate, Drain, Source.
MOSFET test jig with Arduino
MOSFET test jig with Arduino. Lit up by a piece of LED Strip

This post shows how I am making the circuit board for a shelf light with an Atmel Atmega168 controlling a Mosfet. And I have come to the point where I let the 240 volt wild wall horse loose on my first Atmega project. Through a 12V AC to DC converter, of course.

It didn’t work.

But I’m very happy to share why. If I wasn’t able to tell you, I wouldn’t be happy at all.

First: wrong reference voltage on MOSFET
I placed the MOSFET on high side (positive) of the LED strips. That’s a mistake because the gate voltage on the MOSFET is a reference relative to the source, and 5V (full PWM) isn’t much compared to 12V of the flowing current. When I place it after the LED strips (negative), the source is connected to ground, and 5V from the Atmega is much higher than the zero volts of ground. Hence current flows. After fixing this, when I apply voltage through PWM from the Atmega, it has the same zero reference (ground), and the gate opens for current.

Second: wiring it the wrong way
wiring of the MOSFET goes: input to Drain, and output to Source. I did it the other way around.

I hooked up my Arduino to the computer to do some MOSFET testing, it’s very fast to run a program with analogWrite to see if the MOSFET responds to the PWM output. I opened the Fade example sketch in the Arduino software, and just set my own brightness to test with varying light intensity. Even faster testing is to connect the 5V or 3.3V outputs on the Arduino to the MOSFET (ensure common ground).

NOTE: when testing with two power sources, make sure they are grounded together, otherwise, the strangest behaviour from the MOSFET will be seen as voltage is always relative to another point. If the base (ground) is not defined and equal for the two power sources, the behaviour will be spurious.

My new PCB now looks like the Fritzing attached, I had to redo some soldering and move some wires to get there, but the initial design was more “there I did it” than “optimimum, optima, optimus”, so I guess that wasn’t too bad after all.

And now the circuit it actually works!

I have purchased several types of LED strips from ebay (all from this dealer), and they come with varying light intensity (power usage) and color.

A LED strip is a 12V section of 3 LED’s and a resistor in series. They light up very brightly, can run a little warm, glue to a surface, and consume less than 200mA for half a meter. They can easily be cut and soldered at every 10 cm, and can be wired together in series.

In my next blog post I’ll share the rest of the code for the Atmega, how I use one button to cycle through power settings.

An advice on resoldering: Use a vacuum de-solder pump. It’s easy to use, and it actually removes excess solder from the PCB. The solder wick you can buy has never helped me anything, it takes long time to heat up the solder through the wick, heating everything else up as well, and it never sucks all the solder you would like to.

Final, working PCB for shelf light. Fixed MOSFET mistakes
Final, working PCB for shelf light. Fixed MOSFET mistakes

Shelf light AVR with pulse width modulation PWM

This article is in a series about making a shelf with lights controlled by an AVR.
Read about 
 - designing and building the book-case
 - understanding Mosfets
 - and coding the AVR, and improving it using Atmel Studio

As you read, I’m making a shelf light controlled by an Atmega 168 on a circuit board I’ve laid out fairly simple.

The requirements for the board is to

  • Take 12V input power
  • Deliver 12V for LED strip lightning
  • Provide 5V for Atmega chip
  • Have a button to switch light status on/dim/off
  • Have indicator lights for power and button presses

The power control is done with a Mosfet transistor. A transistor is an electric switch which can be compared to a gate valve in a river. If voltage is applied to the gate, a valve opens in the river, and the water is allowed to flow in the river. Actually a Mosfet has the above mentioned behaviour, a transistor normally responds to current, not voltage.

So in this project, the voltage to the Mosfet transistor (controlling the light intensity of the LED strip) comes from the amazing, cheap and Norwegian Atmega chip. Since the Atmega is a digital chip, you can’t expect anything but zero and ones, or 5V or 0V from an output. If we stick to on/off that might be good enough, but since we want to be able to dim the lights with this chip, we need a way to get intermediate power levels.

Atmega 168 pinout
Atmega 168 pinout

I could probably use different output pins, and have different resistors on these to apply different voltages to the Mosfet, but a simpler solution is called Pulse Width Modulation PWM. PWM runs on internal timers in the Atmega, flipping off the output power when it has counted to a predefined number between 0 and 255 (8 bit), and on again when it reaches 255 and goes back to 0.

With PWM the output pin switches between 0 and 5V hundreds of times pr second, and if a Voltmeter is held to the output pin, it will read the average output voltage. (An Oscilloscope would show the pulses). This is how voltages between 0 and 5V is generated.

Let’s have a look at the code, how this is set up. Please refer to the datasheet for the Atmega for details.

static inline void initTimers(void){
	// timer 2
	TCCR2A |= (1 << WGM20); //set fast PWM bit 1
	TCCR2A |= (1 << WGM21); // set fast PWM bit 2
	TCCR2B |= (1 << CS21); // set divide by 8 (frequency)
	TCCR2A |= (1 << COM2B1); // set output to OC2B == PD3
}

I use the timer 2 for the LED strip because the OC2B pin is positioned  very good on the PCB layout I have chosen (pin 5 in the pinout above). This is set with the TCCR2A registry bit BOM2B1 set to 1. In the TCCR2A/B registries the timer mode (Fast PWM) is also set, as well as the timer speed. The Atmega 168 runs at 1 MHz out of the box (and I intend to keep it that way), and the CS21 bit set it TCCR2B sets a divide by 8 factor for the timer speed. So for every eight CPU tick, the timer ticks one. This gives a tick time for the timer of 1/(1 Mhz / 8) = 8 microseconds. Since the timer counts to 255 before it returns to 0, the total time per pulse is 4.1 milliseconds. Or 244 switching cycles pr second.

The timer in PWM mode actually controls the output pin itself, so no pin control is necessary, other than setting it up for output in.

Let’s have a look at the function that cycles every time the button is pressed, to alter the output of the LED strip.

void updateState(uint8_t LIGHTSTATE){
    switch (LIGHTSTATE){
        //TODO adjust these numbers to match MOSFET
        case 1:
        //set output to max
        OCR2B = 255; // 4.66V
        break;
        case 2:
        //set output to medium
        OCR2B = 127; // 2.39V
        break;
        case 0:
        //set output to 0
        OCR2B = 5; // 0.25V
        break;
    }
}

The OCR2B is the register where the compare value for the timer is set, so when the timer reaches the number specified, it turns off the output pin OC2B, and keeps counting to 255, before returning to 0 and turning on OC2B.

Expansion possibilities with shelf light.

This article is in a series about making a shelf with lights controlled by an AVR.
Read about 
 - designing and building the book-case
 - understanding Mosfets
 - and coding the AVR, and improving it using Atmel Studio

My shelf needs light, and I am making a simple circuit to control the light, based on an Atmega 168 and a transistor. It will have indicator lights, a switch, input power and output power. And many, many more features if I ever decide to expand. The light itself is a LED strip bought on ebay.

The Atmega AVR has loads of functions I don’t plan to use here, like timers, digital to analog converters, interrupts, and communication protocols. What I will use is one of the output rails for lighting LEDs, one rail for button switch, and one for controlling the transistor input voltage by PWM. By using different rails for each of the features, I hope to reduce the number of and severity of mistakes.

Circuit soldered and ready for Atmega chip
Circuit soldered and ready for Atmega chip. Sitting on my wonderful Hakko

This is actually my first implementation of an AVR in a project except for light flashing, so I will be documenting each step of the code.

You can see the circuit soldered to a PCB sitting on my Hakko soldering station. The circuit consists of a 5v regulator for the AVR (7805), a transistor to control the output power to the LED strips, and a switch for turning on and off the LED strip, as well as dimming it.

With the Atmega chip as base and free space on the PCB, I could potentially add

  • a motor that can open and close a door
  • an ultrasonic sensor for variable light intensity
  • a display showing jokes
  • a husher for the kids (the slapper is not so popular with my wife)
  • or whatever imagination can think of

Fritzing is a great tool to design and illustrate circuits, and I have made a version showing the concept on breadboard, and the final PCB.

Breadboard layout of circuit. Designed with fritzing.
Breadboard layout of circuit. Designed with fritzing.
PCB layout of circuit. Designed with fritzing.
PCB layout of circuit. Designed with fritzing.

Moving to the code part of the project, I have to reference the fantastic book I have read to learn how the Atmega AVR works, Make: AVR Programming by Elliot Williams. If you want to be able to make anything smart, cool, amazing, flashy, noisy, ridiculous or clever; read this book and get making.

More details on building and coding in the next blog post, for now we can agree that I am making an on/off switch, with some serious expansion capabilities.

168’s on the table

I ordered a batch of Atmega 168’s from RS-online and finally I have the same chip as the book Make: AVR Programming by Elliot Williams is referring to through the book.

Initially I tried to make the Atmega328 work in the same manner as described for the 168, but I found that setting up the 328 to be a standalone chip loaded through an Arduino as ISP requires a crystal and two capasitors. I don’t know why, but this is the solution I have read about several places online, also without any good reasoning. The 328 should be perfectly able to run by itself without the crystals.

Anyway the 168 works fine, easier setup without the crystal and caps.

I have a LED-strip from RadioShack that I had to make my own code for to make it work with the 328 on a breadboard. For some reason, the timing of the signals from an Arduino and the 328 on a breadboard (with 16MHz crystal) isn’t the same, so the LED-strip wouldnt light up. By writing some assembly code (do nothing, do nothing, do nothing), I managed to time the 328 to do an almost-good enough job. The LED-strip requires signals of about 70ns (nanoseconds).

Soon I will try out the original code for the Arduino to see if I can make it run the LED-strip.