Monday, December 14, 2015

Using an ATTiny85 to control a relay based on an LM34 temperature reading

The following code uses an ATTiny85 to turn a relay on and off based on a temperature reading from the LM34 temperature sensor. I used this to turn a freezer on and off to help save energy and to prevent the freezer from actually freezing anything.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
 * LM34.c
 *
 * Created: 4/13/2015 10:35:05 PM
 *  Author: Jacob
 */


#include <avr/io.h>
#include <util/delay.h>

#define relay PB1 //The relay is connected to PB1 on the ATTiny85
#define led PB0 //The indicator LED is connect to PB0 on the ATTiny85

void ledAlert() //Function used to blink the LED at a fast pulse, used for alerting user if there is an error with the cooling system
{
 PORTB ^= (1 << led); //Toggle the LED
 _delay_ms(250); //LED state changes every 250 milliseconds
}

void initADC() {
 
 DDRB |= (1 << relay); //Sets the relay pin as an output
 DDRB |= (1 << led); //Sets the led pin as an output
 
 ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
 //Setting a 1 to "ADEN" enables the ADC feature
 //Setting a 1 to "ADPS2, ADPS1, ADPS0" sets the pre-scaler to divide the clock by 128
 ADMUX |= (0<<REFS0)|(0<<REFS1); //Reference = Vcc
 ADMUX |= (1<<ADLAR); //Left adjust ADC results
 ADMUX |= (1<<MUX1); //Select ADC3 (pin 2)
 ADMUX |= (1<<MUX0); //Select ADC3 (pin 2)
 ADCSRA |= (1 << ADATE); //Free running mode
 ADCSRB &= ~((1<<ADTS2)|(1<<ADTS1)|(1<<ADTS0)); //First three bits of ADCSRB needs to be 000 to select free running mode
 ADCSRA |= (1<<ADEN); //Completes the initialization of ADC
 ADCSRA |= (1<<ADSC); //Start ADC conversions
  
}

int main(void)
{
 initADC(); //Initialize the registers so the ATTiny85 can perform Analog to Digital Conversions
    while(1)
 {
  if(ADCH > 19) //(19/255) * 5 = 39.2 degrees //If the temperature is above 39 degrees, Turn the relay and led on
  {
   PORTB |= (1 << relay);
   PORTB |= (1 << led);
   while(ADCH > 18); //35.3 //While the temperature is greater than 35 degrees, stay here to temporarily lock it in place
  }
  else //If the temperature is below 39 degrees, turn the relay off so the beer doesn't freeze
  {
   PORTB &= (0 << relay); //Turn relay off if the temperature is acceptable (below 38 degrees)
   PORTB &= (0 << led); //Turn led off if the temperature is acceptable (below 38 degrees)
  }
    }
}
 
/*
8 bit value to degrees F
15 -> 29.4
16 -> 31.3
17 -> 33.3
18 -> 35.3
19 -> 37.2
20 -> 39.2
21 -> 41.1
22 -> 43.1
23 -> 45.1
*/


I don't have a wiring diagram or pictures to show as I no longer need this project. But this is a good example to show how to read an analog input into the ATTiny85 using the ADC.

Sunday, August 2, 2015

QU-BD Two-Up 3D printer

Last Sunday I got a 3D printer of my own! Here is a link where I will be uploading parts I create. I plan on designing parts for my own 3D printer (I have the QU-BD Two Up) and I thought it would be useful to others if I share it online.


Messy messy wiring...

Custom and cheap spool holder, about $4 worth of parts



Monday, May 4, 2015

AVR-C Programming - Basic Outputs

My next few posts will be about Atmel AVR programming. I've recently stopped using Arduino and decided to program AVR's strictly in C. In this post it's going to be about controlling the outputs on the AVR. This is very comparable to using digitialWrite(13, HIGH);. The mini project for this post is to make a string of LEDs light up in sequential order. What's really nice about using AVRs is that the code, for the most part, is portable to different types of AVR's.

Parts needed:

  • 8 LEDs
  • 8 200-400 ohm resistors
  • Breadboard
  • Wires
  • 5V voltage source
  • ATMega1284P (or almost any other AVR chip)
  • AVR Programmer (I'm using the Atmel ICE)


Take a look at the datasheet for the ATMega1284P so we can pick which port to use to hook the LEDs up to. On page 2 it shows the pinout for the AVR (I'm using a PDIP type). I'm going to use port B because they aren't separated and are on the same side of the chip which makes wiring a little bit easier.

Attach everything as shown in the breadboard image below:


Now all we have left to connect is a power source and our programming cable. Looking at the pinout for the 1284, we need to hook up pin 10 to 5V, pin 11 to Ground, pin 6 to the MOSI of the programming cable, pin 7 to the MISO of the programming cable, pin 8 to the SCK of the programming cable, and pin 9 to the RESET of the programming cable. One thing that originally confused me when coming from Arduino to just AVR's was that you need an external power supply to power the chip. At least with the Atmel ICE, there is no built in power source, unlike on the Arduino.
Both of these images are helpful for wiring up the programming cable.
 
When looking at the programming cable, the notch is on the left with the cable facing up (towards you)

Now that everything is connected we can finally open up Atmel Studio and start programming!

Create a new project from the start page when it first launches. Name it and save it wherever you want. The default location should be fine. Make sure that you're using a GCC C Executable File in the New Project wizard. Click Okay. Now select the chip you're using on the Device Selection window via the search bar or the list. I'm using the ATMega1284P so I selected that.

You will then have a blank program ready for your input!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/*
 * Basic_Output.c
 *
 * Created: 5/1/2015 3:03:57 PM
 *  Author: www.jacobantoun.com
 */ 


#include <avr/io.h>

int main(void)
{ 
    while(1)
    {
    }
}

First thing we need to do is setup PORTB as an output register. We would need to set the Data Direction for Register B (DDRB) to all 1's in main(). There's a few ways to do that:


1
2
DDRB = 0xFF; //Sets data direction register B as outputs using hex
DDRB = 0b11111111; //Sets data direction register B as outputs using binary

I prefer to use the hex method because it's less typing. (0xFF = 0b11111111)

The while loop inside of main is where our code will continuously run, it's very similar to how void loop() works on an Arduino.

That is where we will turn on our LEDs and look at some shiny goodness! There are multiple ways to turn the LEDs on. You can turn the whole port on at a time, or each bit in the port individually. I'll show you the whole port on first, then individually:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/*
 * Basic_Output.c
 *
 * Created: 5/1/2015 3:03:57 PM
 *  Author: www.jacobantoun.com
 */ 


#include <avr/io.h>

int main(void)
{
 DDRB = 0xFF;
 
    while(1)
    {
         PORTB = 0xFF; //Turns the whole port HIGH
    }
}

Inside of the main I set up the DDRB as an output register by setting each bit to 1. Inside of the while loop is where the whole port actually gets set high. By setting PORTB = 0xFF it sends a 1 to each bit in PORTB, which turns on every LED connected.

To turn on and off LEDs individually we would approach it like this:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * Basic_Output.c
 *
 * Created: 5/1/2015 3:03:57 PM
 *  Author: www.jacobantoun.com
 */ 


#include <avr/io.h>

int main(void)
{
 DDRB = 0xFF; // Set PORTB as an output register
 PORTB = 0; // Turn everything off
    while(1)
    {
         PORTB = (1 << PB1); // Turn on PortB, bit 1
         PORTB = (1 << PB2); // Turn on PortB, bit 2
         PORTB = (1 << PB7); // Turn on PortB, bit 7
    }
}


In the example above we are only turning on 3 bits from the port, bits 1, 2, and 7.

In the last example I'm going to show one more way of turning on individual bits, which is basically the same thing. In the example the goal is to have a single LED lit up moving up and down the port, it looks really cool.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Basic_Output.c
 *
 * Created: 5/1/2015 3:03:57 PM
 *  Author: www.jacobantoun.com
 */ 


#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
 int delayTime = 60; // Variable used to change the delay time easier
 DDRB = 0xFF; // Set PORTB as an output register
     while(1) {
          for(int x = 0; x < 7; x++) { // x is set to 7 since we have a total of 8 bits (starting from 0)
               PORTB = (1 << x); //set the x bit high (same thing as typing in PB1, PB2, PB....)
               _delay_ms(delayTime); // Wait a certain amount of time before going through the loop again
          }
          for(int x = 7; x > 0; x--) {
               PORTB = (1 << x);
               _delay_ms(delayTime);
          }
    }
}


In the above example on line 17 and 22, the (1 << x) is basically saying to only set high the x bit. Meaning that if you typed PORTB = (1 << 3), the 3rd bit (PB3) would be the only bit set high on that port.




Feel free to leave any questions in the comments!

Friday, May 16, 2014

Getting started with Arduino - Simple Outputs

I'm going to start a small Arduino introduction series. I think it's important that people understand what's happening exactly when they create their first blinky program. The three things that I'm going to cover in this post is:
1. Turning an LED on
2. Blinking an LED on and off
3. Fading an LED for loop
We're also going to talk about how to use the IDE briefly, just so you can follow along better.

These three tasks are relatively simple, but understanding these will let you control thousands of other devices, not just LEDs!

To create a new sketch, all you do is open up the IDE, which can be downloaded at Arduino.cc. Once opened there should be nothing except for an empty area. Every Arduino program needs two functions to compile. Those functions are void setup() and void loop(). Those can be seen in the picture below.

1
2
3
4
5
6
7
8
9
void setup() {


}

void loop() {


}

The setup() function only runs once on the Arduino. It's often used to set pin modes as either inputs or outputs, and can be used to initialize variables at startup.

The loop() function runs forever, until your board loses power, or you program a stopping point. It runs very very fast, and a majority of your code goes in here. 

Now I want to explain what the pinMode() command does. pinMode() tells the Arduino what to set each pin as, either an input or output. pinMode has two parameters. The first parameter tells the Arduino which pin you're talking to, and the second parameter defines it as an input or output. Look at the picture below to see it being used. The pinMode() is also usually found in the setup() function.

1
2
3
4
5
6
7
8
9
void setup() {
  pinMode(3, OUTPUT); //Setting pin 3 as an output on the Arduino
  pinMode(8, INPUT); //Setting pin 8 as an input on the Arduino
}

void loop() {


}

digitalWrite() is how we set an OUTPUT pin high or low, meaning 5 volts or 0 volts. digitalWrite() has two parameters. The first one is which Arduino pin you're talking to, and the second is HIGH or LOW. To blink an LED at a steady pace it would be done like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void setup() {
  pinMode(, OUTPUT); //Setting pin 3 as an output on the Arduino
}

void loop() {
 digitalWrite(3, HIGH);
 delay(500);
 digitalWrite(3, LOW);
 delay(500);
 
}

Above I use a delay() function. It only has one paramter, and it's in integer value in milliseconds. If you were to type
delay(500); 
The Arduino would pause what it was doing for 500 milliseconds and keep doing the command above it until the 500 milliseconds has passed.        

Another incredibly useful command would be analogWrite(). analogWrite() lets your vary the brightness of an LED or the speed of a motor. It uses something called pulse width modulation which does exactly what the name is. It varies the width of the HIGH LOW transitions to make it appear the voltage is changing, when in reality we're only changing the time that the pin is HIGH or LOW really fast. The parameters for analogWrite are the pin number, and a value between 0-255. 255 is a duty cycle of 100%, 127 would be 50%, and 0 would be 0%. It is very important to use a pin on the Arduino that is compatible with PWM. Look up the specs for your Arduino and use one of the pins that is useable with PWM.

To set an LED at half brightness it would look something like this:

1
2
3
4
5
6
7
void setup() {
  pinMode(3, OUTPUT);
}

void loop() {
  analogWrite(3, 127);
}


Now to fade an LED we would use a for loop. The for loop would need to control a variable to go from 0 - 255. When doing the the LED's brightness would ramp up, and with use of a second for loop, we can ramp it back down. The two loops would look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
void setup() {
  pinMode(3, OUTPUT); //Setting pin 3 as an output on the Arduino
}

void loop() {
 for(int i = 0; i <= 255; i++) {
   analogWrite(3, i);
   delay(10);
 }
 for(int j = 255; j >= 0; j--) {
   analogWrite(3, j);
   delay(10);
 }
}
The reason we use a 10 millisecond delay in the LED fading is so it doesn't happen so fast, and it looks better to the eyes!

In the for loop I have a counter 'i'. It starts at 0, and every 10 milliseconds it increments by 1 (that's what the i++ does). It then writes the value of 'i' to the second parameter of analogWrite and the LED then shows that brightness. Once the first for loop is completed, it moves on to the second one, which is just the opposite. It starts the LED off at full brightness, and brings it back down.

Another really cool and important topic is the use of variables. Variables make code much more readable and easier to debug when you're having problems. All you need to do is create a variable, set a value to it, and use it in your program instead of hardcoding in the pin numbers. An example is below. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int led = 3;

void setup() {
  pinMode(led, OUTPUT); //Setting pin 3 as an output on the Arduino
}

void loop() {
 for(int i = 0; i <= 255; i++) {
   analogWrite(led, i);
   delay(10);
 }
 for(int j = 255; j >= 0; j--) {
   analogWrite(led, j);
   delay(10);
 }
}


Notice how I removed the '3' in the analogWrite functions and replaced them with led. It makes the program look a little bit nicer I think.

Thanks everyone for reading! Next time we'll go over input devices, like switches, potentiometers, and LDR's (light dependent resistors).



Thursday, May 1, 2014

How to Create an Audio Amplifier with the LM386 OP AMP

This post isn't really anything Arduino related, but still a really cool project. I created an audio amplifier that you can connect to your iPod or whatever else you play music with and listen to it on a speaker.

In it's current state it's mono, but by adding a second speaker and second operational amplifier you can easily turn this into a stereo sound system.

I would highly recommend looking at the data sheet before building this. It shows you typical applications and other notes you would need if you were to design this from scratch. LM386 Datasheet

The parts needed for this are:
LM386 OP AMP x1
100uF Capacitor x1 [C2]
10uF Capacitor x1 [C1]
10 Ohm resistor x1 [R2]
1K Ohm resistor x1 [R1]
9 Volt Battery x1
10K ohm Potentiometer x1 [R6]
Speaker x1 (for mono)
9 Volt Battery snap x1
Audio Jack x1


The schematic for this is pretty simple, and fun to make. I think it's kinda nice making something that doesn't involve programming or micro controllers. I created the schematic using Eagle.


You can change the gain by adding a capacitor between pins 1 and 8. You can make the gain variable if you put a resistor in series with it. You can see that I did this at labels C1 and R1. I would reccomend you add a potentiometer instead of the resistor R1 so you can change the gain on the spot. If you don't put anything between pins 1 and 8, the built in 1.35K ohm resistor would set a gain of 20dB.

Capacitor C2 is used to help reduce noise to the speaker. It helps to remove constant DC voltage and only allows the audio waves to pass through.

If you wanted to make this stereo, you would need to repeat the circuit to be the same, except you would share the potentiometer that controls the gain between the two, and connect their grounds together. Inside of an audio cable there are 3 wires. Black for Ground, and the two other colors are for each audio channel. Connect one channel to one of the OP AMPS, and the other channel to the second one.

The next step is to solder this onto perfboard and put it in a nice enclosure. 

Here are some pictures of the one I made breadboarded up. 






Now here's some pictures of it being used with an oscilloscope so you can actually see the gain. 
It's hard to see the original signal a little bit but it's the bright small wave in the very center. The outside wave is actually the smaller signal amplified. Looks like it's amplifying very well! The gain might be set a little too high though, you can see in some spots how instead of a nice sinusoidal wave we get flatness at the top. That's because it's amplifying too much and is exceeding the OP AMPS power limits. This could be solved by using a 12 volt battery or greater compared to our 9 volt battery.

And here's just another view.

I hope you guys enjoyed this little project! My next couple of posts are going to be Intro to Arduino tutorials that I'm going to use for a school club I'm teaching. Those should be done fairly soon!