Este projecto foi publicado em http://www.instructables.com/id/Perfboard-Hackduino-Arduino-compatible-circuit/ e utilizei o mesmo para arranjar uma forma de utilizar apenas o ATMega sem 'gastar' um Arduino.
Material utilizado:
28-pin DIP IC Socket
16 Mhz crystal
Push-button switch
10k ohm resistor
220R resistor
LED 5mm
LM7805 5v voltage regulator
2x 22pF capacitors
100 nF capacitor (decoupling)
22uF capacitor
ATMega168 c/ bootloader
Breadboard
Os pinos do ATMega168:
Esquema geral que fiz e utilizei que coloca o ATMega a funcionar:
Começamos pelo regulador de tensão LM7805, que permite ter uma saída de 5V constantes para alimentar o sistema e que pode ser alimentado de 7 a 35V:
Pino 1 = Entrada (7V - 35V)
Pino 2 = Ground (0V)
Pino 3 = Saída (5V)
Colocamos entre o pino 2 e o pino 3 do LM7805 um condensador de 100nF
No pino 9 e 10 do ATMega168 colocamos o cristal de 16Mhz
Ainda nos mesmos pinos, e a seguir ao cristal, colocamos um condensador em cada um de 22pF ligado ao Ground:
O pino 8 e o pino 22 do ATMega168 ligam ao Ground
O pino 7, pino 20 e o pino 21 do ATMega138 ligam ao VCC (+5V)
No pino 1 do ATMega168 (pino de Reset) ligamos uma resistência de 10k ao VCC (+5V), para que não faça reset acidentalmente.
Agora colocamos um botão de pressão para fazer Reset manual ao ATMega168, uma das 'patas' vai para Ground e a outra (separada) liga também ao Pino 1 do ATMega168 (ver esquema geral acima)
Adicionamos agora um LED ligado ao ATMega, para isso colocamos uma resistência de 220R no pino 19 (corresponde à saída digital 13), ligamos um LED 5mm com o lado positivo ('pata' maior) na resistência e o outro lado ao Ground.
Para finalizar colocamos o condensador de 22uF entre o VCC e o Ground da nossa alimentação (coloquei-o a seguir ao ATMega168)
Como teste coloquei o ATMega168 num Arduino e programei-o com o "Hello World" (blink Led), voltei a colocar o ATMega na breadboard, liguei uma fonte de alimentação ao LM7805 e ficou assim:
Podemos encontrar alguma informação na Web sobre ele e como descobrir quais os seus fios TX, RX e DTR (necessário para o reset automático do ATMega168), por exemplo: http://www.kwartzlab.ca/2010/04/reverse-engineering-cheap-ardu/
Para estabelecer comunicação entre o ATMega168 e o computador, através de um cabo destes ou de outro conversor deste tipo, basta cruzar o RX com o TX:
CABO
RX
TX
ATMega168
TX - Pino 3
RX - Pino 2
O RX do cabo liga ao pino 3 do ATMega168 e o TX do cabo liga ao pino 2 do ATMega168.
O fio DTR (envia sinal Ground) temos de o ligar ao pino 1 do ATMega168 para assim se conseguir fazer o reset automático no processo de upload, esquema completo com o TX, RX e DTR:
Atenção: Temos de adicionar um condensador de 100nF na ligação do DTR ao ATMega.
Neste caso o conversor usado é um que implementa o controlador FTDI (mas o efeito é igual ao do cabo Nokia):
Este conversor tem os seguintes pinos disponíveis:
VCC: Temos de ligar aqui +5V para o alimentar
Ground: Negativo da nossa fonte
RX: Sinal RX que vamos ligar ao pino 3 do ATMega168 (pino TX)
TX: Sinal TX que vamos ligar ao pino 2 do ATMega168 (pino RX)
Quanto ao DTR ele também tem disponível este sinal mas não nestes pinos e como tal não foi usado para facilitar as ligações, a única diferença é que quando se faz upload do sketch temos de fazer reset manual ao ATMega (através do botão de pressão que colocámos).
Ao instalar os respectivos drivers (da FTDI) e após o reconhecimento do ATMega168, devemos ficar com tudo detectado como porta COM no gestor de dispositivos do computador:
Após ter comunicação serial entre o ATMega168 e o computador adicionei como teste o circuito 3 Wires LCD, as ligações ao ATMega são apenas 3 (de acordo com o circuito do projecto):
Pino 1 HEF4094 liga ao pino 18 do ATMega168 (saída digital 12)
Pino 2 HEF4094 liga ao pino 17 do ATMega168 (saída digital 11)
Pino 3 HEF4094 liga ao pino 16 do ATMega168 (saída digital 10)
Esquema geral com o circuito do LCD 20x4 na versão 3 Wires:
Apenas para mostrar alguma informação no LCD, adicionei também o circuito Fan RPM (sinal do sensor ligado ao pino 4 do ATMega168 (saída digital 2)) que mostra a velocidade de uma ventoinha,
O código utilizado foi (LCD 3 Wires + Fan RPM):
// Example use of LCD3Wire library
// Almost a carbon-copy of LCD4BitExample.pde
#include <LCD3Wire.h>
// Arduino pins
#define LCD_LINES 4 // number of lines in your display
#define DOUT_PIN 11 // Dout pin
#define STR_PIN 12 // Strobe pin
#define CLK_PIN 10 // Clock pin
#define LED_PIN 13 // we'll use the debug LED to output a heartbeat
//create object to control an LCD.
LCD3Wire lcd = LCD3Wire(LCD_LINES, DOUT_PIN, STR_PIN, CLK_PIN);
//FAN:
int NbTopsFan;
int Calc;
char Calc2[32];
//The pin location of the sensor
int hallsensor = 2;
typedef struct{ //Defines the structure for multiple fans and their dividers
char fantype;
unsigned int fandiv;
}fanspec;
//Definitions of the fans
fanspec fanspace[3]={{0,1},{1,2},{2,8}};
char fan = 1; //This is the varible used to select the fan and it's divider, set 1 for unipole hall effect sensor
//and 2 for bipole hall effect sensor
void rpm () //This is the function that the interupt calls
{
NbTopsFan++;
}
//This is the setup function where the serial port is initialised,
//and the interrupt is attached
//FAN
void setup() {
digitalWrite(LED_PIN, HIGH); //light the debug LED
lcd.init();
lcd.clear();
lcd.printIn("ATmega168 by GrcByte");
delay(1000);
lcd.cursorTo(2, 0); //line=2, x=0.
lcd.printIn("Fan Speed Check");
delay(1000);
lcd.cursorTo(3, 0); //line=3, x=0.
lcd.printIn("RPM");
delay(1000);
digitalWrite(LED_PIN, LOW);
//optionally, now set up our application-specific display settings, overriding whatever the lcd did in lcd.init()
//lcd.commandWrite(0x0F);//cursor on, display on, blink on. (nasty!)
pinMode(LED_PIN, OUTPUT);
//FAN
pinMode(hallsensor, INPUT);
Serial.begin(9600);
attachInterrupt(0, rpm, RISING);
//FAN
}
void loop() {
NbTopsFan = 0; //Set NbTops to 0 ready for calculations
//sei(); //Enables interrupts
delay (1000); //Wait 1 second
//cli(); //Disable interrupts
Calc = ((NbTopsFan * 60)/fanspace[fan].fandiv); //Times NbTopsFan (which is apprioxiamately the fequency the fan is spinning at) by 60 seconds before dividing by the fan's divider
itoa (Calc, Calc2, 10);
//print something on the display
if(LCD_LINES==4){
lcd.cursorTo(4, 0); //line=4, x=0.
lcd.printIn(Calc2);
//lcd.cursorTo(4, 15); //line=4, x=15.
if (Calc==0) lcd.cursorTo(4, 0);{lcd.printIn("0");};
//lcd.printIn(" rpm");
//Serial.print (Calc, DEC); //Prints the number calculated above
//Serial.print (" rpm\r\n"); //Prints " rpm" and a new line
}
//scroll entire display 20 chars to left, delaying 50ms each inc
// lcd.leftScroll(20, 50);
}
e/ou
// Example use of LCD3Wire library
// Almost a carbon-copy of LCD4BitExample.pde
#include <LCD3Wire.h>
// Arduino pins
#define LCD_LINES 4 // number of lines in your display
#define DOUT_PIN 11 // Dout pin
#define STR_PIN 12 // Strobe pin
#define CLK_PIN 10 // Clock pin
#define LED_PIN 13 // we'll use the debug LED to output a heartbeat
//create object to control an LCD.
LCD3Wire lcd = LCD3Wire(LCD_LINES, DOUT_PIN, STR_PIN, CLK_PIN);
//FAN:
int Calc;
char Calc2[32];
volatile byte rpmcount;
unsigned int rpm;
unsigned long timeold;
//FAN
void setup() {
digitalWrite(LED_PIN, HIGH); //light the debug LED
lcd.init();
lcd.clear();
lcd.printIn("ATmega168 by GrcByte");
delay(2000);
lcd.cursorTo(1, 0); //line=2, x=0.
lcd.printIn("ATmega168 by GrcByte");
lcd.cursorTo(2, 0); //line=2, x=0.
lcd.printIn("Fan Speed Check");
delay(2000);
lcd.cursorTo(3, 0); //line=3, x=0.
lcd.printIn("...");
delay(2000);
digitalWrite(LED_PIN, LOW);
//optionally, now set up our application-specific display settings, overriding whatever the lcd did in lcd.init()
//lcd.commandWrite(0x0F);//cursor on, display on, blink on. (nasty!)
pinMode(LED_PIN, OUTPUT);
//FAN
Serial.begin(9600);
attachInterrupt(0, rpm_fun, RISING);
rpmcount = 0;
rpm = 0;
timeold = 0;
//FAN
}
void loop() {
//print something on the display
if(LCD_LINES==4){
if (rpmcount >= 20) {
//Update RPM every 20 counts, increase this for better RPM resolution,
//decrease for faster update
rpm = 30*1000/(millis() - timeold)*rpmcount;
itoa (rpm, Calc2, 10);
lcd.cursorTo(4, 0); //line=4, x=0.
lcd.printIn(Calc2);
lcd.cursorTo(4, 5); //line=4, x=15.
lcd.printIn(" rpm");
//Serial.print (Calc, DEC); //Prints the number calculated above
// Serial.print (" rpm\r\n"); //Prints " rpm" and a new line
timeold = millis();
rpmcount = 0;
}
}
//scroll entire display 20 chars to left, delaying 50ms each inc
// lcd.leftScroll(20, 50);
}
void rpm_fun()
{
rpmcount++;
//Each rotation, this interrupt function is run twice
}
//--
Como resultado final temos isto: