Publicidade:

quarta-feira, 30 de dezembro de 2015

Arduino - Como gravar o bootloader (e sketch) em um Atmega328P-PU Standalone

Nesse artigo vou tentar descrever os passos que segui até conseguir carregar o bootloader em um Atmega328p-PU. 

Já fazia um tempo que eu havia comprado alguns kits para Arduino Standalone, como esse mostrado na imagem abaixo, mas que por preguiça acabaram ficando guardados. Hoje então resolvi fazer alguns testes com um e gravar o bootloader nele. Ele possui alguns componentes mínimos que geralmente são usados em placas Standalones, como o regulador de tensão, capacitores, o cristal oscilador, o Atmega328P e um slote onde CI será encaixado na placa.



O Procedimento não é algo tão complicado, mas podemos dizer que é um pouco chato de se fazer, pelo menos foi a impressão que tive ao tentar e vendo vários comentários na internet de pessoas que tiveram as mesmas dificuldades. Por algum motivo não consegui logo de começo, mesmo seguindo os procedimentos descritos em alguns artigos por ai. Mas depois de insistir um pouco consegui sem maiores problemas, por isso resolvi escrever mostrando os passos que segui.

Quando trabalhamos com o Arduino, os pinos do Atmega não ficam explicitos, então a imagem abaixo é bom guia pra nos orientarmos qual pino do Atmega é o seu correspondente do Arduino.


Mas antes de iniciarmos a ligação entre o Arduino e o Atmega, vamos deixar o Arduino Uno configurado para ser um programador ISP. Para isso, abra o arquivo que já está na própria IDE do Arduino, através do menu Arquivo --> exemplos --> ArduinoISP.




Com o arquivo Aberto, basta fazer o upload para o Arquivo Uno.

Com o Arduino Uno Configurado, iremos agora fazer a ligação entre os componentes, conforme a imagem abaixo. Nesse esquema que está abaixo, inicialmente eu não tinha utilizado aquele resistor de pullup de 10K para o pino de reset do Atmega. Mas depois de tentar algumas vezes e não conseguir, encontrei um artigo no qual o mesmo foi utilizado, então resolvi mante-lo, apesar de posteriormente eu ter testado sem o mesmo, e o upload foi feito do mesmo jeito. Mas aconselho manter o resistor. No Arduino Uno, também podemos notar um capacitor eletrolítico de 10uF. Também não tenho certeza se ele é exatamente necessário, mas por desencargo, mantive o mesmo conectado



Pinagem:


  ATmega328 | Arduino Uno 
19 | 13
18 | 12
17 | 11
1 (reset) | 10         
7, 20 |  5V  
  8, 22 |  Gnd  

Aqui podemos ver a montagem que eu fiz (ainda sem o resistor de 10K)



Com todos os componentes conectados, agora é hora de configurarmos a IDE do Arduino para fazermos o upload do bootloader. Pra isso iremos configurar a IDE como se estivéssemos programando um "Arduino Duemilanove or Diecimila", indo em Ferramentas --> Placa --> Arduino Duemilanove or Diecimila, como mostrado na imagem abaixo.




O Próximo passo é informar que iremos utilizar o ATmega328. Pra isso vamos em ferramentas --> Processador --> ATmega328.



O próximo passo agora é configurar o Programador para "Arduino as ISP".



Agora, com todos os passos anteriores configurados, é só gravar o booteloder. Pra isso vá em Ferramentas --> Gravar Bootloader. Como mostrado na imagem abaixo. Aguarde terminar o procedimento. Se tudo ocorreu certo, o pino 13 irá piscar, caso tenha um led conectado a ele. Apesar que nas imagens não aparece o led ligado, é interessante para fins de testes ligar um resistor e um led em série no pino 19 do Atmega (Conhecido como pino 13 no Arduino).



Com o bootloader gravado, é hora de testar o upload de um sketch qualquer. Pra isso abra o sketch que você deseja gravar no Atmega. faça as ligações dos componentes que serão necessários e então faça o upload da sketch, através da Opção "Carregar usando o programador" como mostrado na imagem abaixo.

Pra fugir um pouco do blink padrão do Arduino, fiz um blink "mais legal", que não utiliza o delay. e sim uma classe temporizadora desenvolvida por mim, que ainda não falei sobre ela, mas em breve farei um artigo explicando como ela funciona. O Código está mais abaixo.





/*********************************************************************************************************
************************************CLASSE MYTIMER********************************************************
**********************************************************************************************************/
struct MyTimerSequence{
  unsigned long * times;
  unsigned int size;
  unsigned int repeat;
};
class MyTimer{
  private:
    boolean          _enable;
    unsigned long    _mref;
    unsigned long    _mref_disable;
    unsigned long    _time_disable;
    MyTimerSequence *_sequences;
    long             _lag;
    int              _quantidade;
    int              _index_time;
    int              _last_index_time;
    int              _index_sequence;
    int              _last_index_sequence;
    void             (*_onChanging)( int index_sequence, int index_time ); //ponteiro para funcao do evento onChanging
    void             (*_onEnable)();
    void             (*_onDisable)();
  public:
    MyTimer(MyTimerSequence * sequences, int quantidade, long lag, unsigned long mref){
      _lag = lag;
      _mref = mref;
      _sequences = sequences;
      _quantidade = quantidade;
      _time_disable = 0;
      _enable = false;
      _undetermine();
    }
     
    void _undetermine(){
      _index_time          = -1;
      _last_index_time     = -1;
      _index_sequence      = -1;
      _last_index_sequence = -1;
      update();
    }
    void setSequences(MyTimerSequence * sequences, int quantidade){
      _sequences = sequences;
      _quantidade = quantidade;
      _undetermine();
      update();
    };
    void setMillisRef(unsigned long mref)                  { _mref    = mref;        _undetermine();    }
    void setLag(long lag)                                  { _lag     = lag;         _undetermine();    }
    boolean isChanging()                                   { return (( _index_time != _last_index_time)||( _index_sequence != _last_index_sequence))&&(_enable); }
    boolean isIndexTime(int index_sequence, int index_time){ return ( _index_time == index_time)&&(_index_sequence == index_sequence)&&(_enable);   }
    void setOnChanging( void (*onChanging)(int, int) )     { _onChanging = onChanging;                  }
    void setOnEnable  ( void (*onEnable)() )               { _onEnable   = onEnable;                    }
    void setOnDisable ( void (*onDisable)() )              { _onDisable  = onDisable;                   }
    void update();
     
    void enable()  { _enable = true;  if ( _onEnable )  { (*_onEnable )(  ); }  } 
    void disable() { _enable = false; if ( _onDisable ) { (*_onDisable)(  ); }  } 
     
    void setTimeDisable(unsigned long time){ _time_disable = time; _mref_disable = millis(); } 
};
void MyTimer::update(){
  if ((millis() - _time_disable > _mref_disable) && (_time_disable > 0)) { disable(); }  //verifica se está configurado pra desabilitar por time
  if (!_enable) { return; }
   
  unsigned long s = 0;
  for (int i=0; i<_quantidade;i++){ 
    for (int j=0; j<_sequences[i].repeat; j++){
      for (int k=0; k<_sequences[i].size; k++){
        s += _sequences[i].times[k]; 
      }
    }
  }
  long adjustment      = _mref % s;
  long rest            = (millis() + s - adjustment - _lag) % s;
  _last_index_time     = _index_time;
  _last_index_sequence = _index_sequence;
   
   
  boolean ind_break = false;
  s = 0;
  for (int i=0; i<_quantidade;i++){ 
    for (int j=0; j<_sequences[i].repeat; j++){
      for (int k=0; k<_sequences[i].size; k++) {
        s += _sequences[i].times[k]; 
        if (rest < s) {  
          _index_time = k; 
          _index_sequence = i;
          ind_break = true;
          break; 
        } 
      }
      if (ind_break) { break; }
    }
    if (ind_break) { break; }
  }
  if ( isChanging() && _onChanging ) { (*_onChanging)(  _index_sequence, _index_time  ); }
}
/*********************************************************************************************************
************************************FIM CLASSE MYTIMER****************************************************
**********************************************************************************************************/
 
unsigned long seq01[] = {750};
unsigned long seq02[] = {60, 60};
unsigned long seq03[] = {200};
 
MyTimerSequence sequences[] = { 
                                 { seq01, sizeof(seq01)/sizeof(unsigned long), 1},
                                 { seq02, sizeof(seq02)/sizeof(unsigned long), 10},
                                 { seq03, sizeof(seq03)/sizeof(unsigned long), 1},
                                 { seq02, sizeof(seq02)/sizeof(unsigned long), 6},
                                 { seq03, sizeof(seq03)/sizeof(unsigned long), 1},
                                 { seq02, sizeof(seq02)/sizeof(unsigned long), 3}
                              } ;
 
  
MyTimer t1(sequences, sizeof(sequences)/sizeof(MyTimerSequence), 0, 0);  //tem um atraso de 100 milissegundos em relação a referencia 0
    
void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
   
  t1.setOnChanging( onChanging_t1 );
  t1.enable();
}
  
void loop() {  
  t1.update();
}
  
void onChanging_t1(int sequence, int index ) {
  digitalWrite(13, LOW); 
  if (index == 0 && (sequence == 1 || sequence == 3 || sequence == 5)){ digitalWrite(13, HIGH);  }
   
}


E como fazer o upload através do Arduino Mega (ou outras placas Arduino)?

O Mesmo procedimento mostrado anteriormente também pode ser feito através do Arduino Mega, ou ainda com outros Arduinos. O Procedimento é fazer o upload da sketch ArduinoISP (mostrado lá no início) para o Arduino Mega e seguir os demais passos mostrados anteriormente, apenas tomando o cuidado na hora de ligar os pinos, que são diferentes do uno:


    ATmega328 | Arduino Mega
            19 | 52 (SCK)
              18 | 50 (MISO)
              17 | 51 (MOSI)
  1 (reset) | 53 (RST)
7, 20 | 5V   
  8, 22 | Gnd   

Para outras Placas, certifique-se de utilizar os pinos corretos, pra isso terá que descobrir quais são os pinos ISP: SCK, MISO, MOSI e RST


terça-feira, 29 de dezembro de 2015

Arduino - Programando o Pro mini com o Uno ou com o Mega

Uma das coisas legais dos Arduinos, é que existem várias versões e cada versão com suas vantagens, seja em tamanho, custo, capacidade de processamento, etc. 


Uma das versões que eu gosto é o Pro mini que consegue reunir quase todos os itens mencionados anteriormente, pequeno, barato e poderoso, tudo em uma pequena plaquinha de 3,4 x 1,9 cm, 8 pinos analógicos, 14 pinos digitais, sendo 6 pwm, botão de reset, led no pino 13 e outro led indicador de energizado e opera a velocidade de 16MHz. Quanto a memória, o Pro Mini disponibiliza 16Kb para memória flash, sendo 2Kb utilizados pelo bootloader, 1Kb de SRAM e 512 bytes de EEPROM. Sem dúvida é uma boa candidata para tirar do papel aquele projeto que você já vem querendo implementar há algum tempo.

Um detalhe importante é que os conectores não vêm soldados na placa, ficando a cargo de quem for utilizá-la escolher qual o melhor tipo de conector a ser utilizado, o que lhe dá a vantagem de poder soldar apenas os pinos que serão de fato necessários de acordo com o projeto a ser implementado. Uma dica quando for soldar os conectores, é usar um pouco de pasta de solda nos terminais, o que facilita bastante conseguir uma solda mais uniforme sem que sobre solda.





Na imagem acima pode-se notar que os 4 primeiros conectores ficaram com a solda "grossa". Como não gostei muito do resultado tentei passar um pouco de pasta de solda, e o resultado foi bem melhor como pode ser observado nos pinos mais à direita.

Em geral os conectores a serem soldados são aqueles que permitem conectar a placa na protoboard ou ainda usar jumper, mas caso vc tenha em mente utilizar alguma outro tipo de conector, tenha certeza que você conseguirá fazer o upload do código após a soldagem, pois dependendo do conector escolhido, o processo de upload pode ficar um pouco mais complicado. Se Notar que será complicado fazer o upload depois de conectar os fios, tente fazer o upload do programa antes de soldar os conectores.

Para mais detalhes sobre as funcionalidades da plaquinha, vale a pena uma boa olhada na imagem abaixo:



Quanto a alimentação pode ser feita diretamente pelo pino Vcc com tensão já regulada em 5V ou através do pino RAW em até 12V pois a placa conta com um regulador de tensão.

Ele não é necessariamente o candidato ideal pra prototipagem, já que nesse quesito o Arduino Uno e o Mega ou outros são os mais indicados, por isso na hora de programá-lo, você irá precisar contar com alguns itens adicionais.

Conversor FTDI

Uma das formas de programa-lo é utilizando um conversor FTDI, o qual possui um conector USB. Porém nesse artigo não irei abordar o seu uso (mas talvez futuramente eu inclua aqui explicações de como utilizá-lo).


Arduino Uno com o Atmega Desencaixado

Outra possibilidade é utilizar um Arduino Uno sem o Atmega conectado na placa. Para isso siga as conexões mostradas abaixo mas com o Atmega desconectado.



Montado na protoboard com os pinos já soldados e com o Atmega removido:


Depois de tudo conectado é hora de configurar a IDE do Arduino para enviar o código para o Pro Mini. Para isso selecione a placa, conforme imagem a baixo.



Feito isso, selecione então o ATmega utilizado, no caso, ATMega328 (5V, 16MHz), como na imagem abaixo:



Agora é só enviar o código. No Exemplo que utilizei, liguei um potenciômetro ao pino A1, um led no pino 13 e outro led no pino 5. O led no pino 13 irá ficar piscando enquanto que o led no pino pwm será controlado através da leitura do pino analógico A1.

O Código possui uma classe temporizadora, a qual ainda irei fazer um outro artigo explicando melhor os detalhes de como ela funciona, mas já fiz outro artigo que abordo sobre temporização, que vale a pena dar uma olhada: http://fabianoallex.blogspot.com.br/2015/09/arduino-como-substituir-delay-pelo.html

Mas o código aqui pode ser qualquer outro que esteja programado para o que você deseja executar.

Código Utilizado:



/*********************************************************************************************************
************************************CLASSE MYTIMER********************************************************
**********************************************************************************************************/
struct MyTimerSequence{
  unsigned long * times;
  unsigned int size;
  unsigned int repeat;
};
class MyTimer{
  private:
    boolean          _enable;
    unsigned long    _mref;
    unsigned long    _mref_disable;
    unsigned long    _time_disable;
    MyTimerSequence *_sequences;
    long             _lag;
    int              _quantidade;
    int              _index_time;
    int              _last_index_time;
    int              _index_sequence;
    int              _last_index_sequence;
    void             (*_onChanging)( int index_sequence, int index_time ); //ponteiro para funcao do evento onChanging
    void             (*_onEnable)();
    void             (*_onDisable)();
  public:
    MyTimer(MyTimerSequence * sequences, int quantidade, long lag, unsigned long mref){
      _lag = lag;
      _mref = mref;
      _sequences = sequences;
      _quantidade = quantidade;
      _time_disable = 0;
      _enable = false;
      _undetermine();
    }
    
    void _undetermine(){
      _index_time          = -1;
      _last_index_time     = -1;
      _index_sequence      = -1;
      _last_index_sequence = -1;
      update();
    }
    void setSequences(MyTimerSequence * sequences, int quantidade){
      _sequences = sequences;
      _quantidade = quantidade;
      _undetermine();
      update();
    };
    void setMillisRef(unsigned long mref)                  { _mref    = mref;        _undetermine();    }
    void setLag(long lag)                                  { _lag     = lag;         _undetermine();    }
    boolean isChanging()                                   { return (( _index_time != _last_index_time)||( _index_sequence != _last_index_sequence))&&(_enable); }
    boolean isIndexTime(int index_sequence, int index_time){ return ( _index_time == index_time)&&(_index_sequence == index_sequence)&&(_enable);   }
    void setOnChanging( void (*onChanging)(int, int) )     { _onChanging = onChanging;                  }
    void setOnEnable  ( void (*onEnable)() )               { _onEnable   = onEnable;                    }
    void setOnDisable ( void (*onDisable)() )              { _onDisable  = onDisable;                   }
    void update();
    
    void enable()  { _enable = true;  if ( _onEnable )  { (*_onEnable )(  ); }  } 
    void disable() { _enable = false; if ( _onDisable ) { (*_onDisable)(  ); }  } 
    
    void setTimeDisable(unsigned long time){ _time_disable = time; _mref_disable = millis(); } 
};
void MyTimer::update(){
  if ((millis() - _time_disable > _mref_disable) && (_time_disable > 0)) { disable(); }  //verifica se está configurado pra desabilitar por time
  if (!_enable) { return; }
  
  unsigned long s = 0;
  for (int i=0; i<_quantidade;i++){ 
    for (int j=0; j<_sequences[i].repeat; j++){
      for (int k=0; k<_sequences[i].size; k++){
        s += _sequences[i].times[k]; 
      }
    }
  }
  long adjustment      = _mref % s;
  long rest            = (millis() + s - adjustment - _lag) % s;
  _last_index_time     = _index_time;
  _last_index_sequence = _index_sequence;
  
  
  boolean ind_break = false;
  s = 0;
  for (int i=0; i<_quantidade;i++){ 
    for (int j=0; j<_sequences[i].repeat; j++){
      for (int k=0; k<_sequences[i].size; k++) {
        s += _sequences[i].times[k]; 
        if (rest < s) {  
          _index_time = k; 
          _index_sequence = i;
          ind_break = true;
          break; 
        } 
      }
      if (ind_break) { break; }
    }
    if (ind_break) { break; }
  }
  if ( isChanging() && _onChanging ) { (*_onChanging)(  _index_sequence, _index_time  ); }
}
/*********************************************************************************************************
************************************FIM CLASSE MYTIMER****************************************************
**********************************************************************************************************/

unsigned long seq01[] = {750};
unsigned long seq02[] = {60, 60};
unsigned long seq03[] = {200};

MyTimerSequence sequences[] = { 
                                 { seq01, sizeof(seq01)/sizeof(unsigned long), 1},
                                 { seq02, sizeof(seq02)/sizeof(unsigned long), 10},
                                 { seq03, sizeof(seq03)/sizeof(unsigned long), 1},
                                 { seq02, sizeof(seq02)/sizeof(unsigned long), 6},
                                 { seq03, sizeof(seq03)/sizeof(unsigned long), 1},
                                 { seq02, sizeof(seq02)/sizeof(unsigned long), 3}
                              } ;

 
MyTimer t1(sequences, sizeof(sequences)/sizeof(MyTimerSequence), 0, 0);  //tem um atraso de 100 milissegundos em relação a referencia 0
   
void setup() {
  Serial.begin(9600);
  
  pinMode(13, OUTPUT);
  pinMode(5, OUTPUT);
  
  t1.setOnChanging( onChanging_t1 );
  t1.enable();
}
 
void loop() {  
  t1.update();
  
  analogWrite(5, analogRead(A1)/4);
}
 
void onChanging_t1(int sequence, int index ) {
  digitalWrite(13, LOW); 
  if (index == 0 && (sequence == 1 || sequence == 3 || sequence == 5)){ digitalWrite(13, HIGH);  }
  
}


Via ISP (Arduino Uno e Mega)

Pra quem pretende utilizar o Arduino Pro Mini com uma certa frequencia, ter que retirar o ATMega do conector do Arduino Uno é um trabalho que pode se tornar um pouco chato, além de ter algum dos Arduinos Uno que não tem como desconectar o ATmega. Nesses casos, o mais recomendado é utilizar o a gravação através de ISP. Pra isso é necessário seguir alguns passos. Vou listá-los e mais abaixo demonstro como realizar cada um dos passos:

Obs.: Esses mesmos passos podem ser seguidos utilizando um Arduino Mega.

  - 1º Passo: Fazer o upload do Sketch "ArduinoISP" para o Arduino Uno (ou Mega).
  - 2º Passo: Conectar os Cabos entre o Arduino Uno (ou Mega) e o Pro Mini.
  - 3º Passo: Mudar a Placa para Arduino Pro ou Pro mini.
  - 4º Passo: Mudar o Programador para "Arduino as ISP".
  - 5º Passo: Fazer Uploado via Programador (Ctrl+Shift+U).
  - 6º Passo: Voltar as configurações iniciais. (Esse passo é só para não ter problemas ao voltar a programar o arduino UNO posteriormente).

1º Passo: Fazer o upload do Sketch "ArduinoISP" para o Arduino Uno (ou Mega).

A Sketch ArduinoISP está na própria IDE do Arduino, bastando entrar no menu Arquivo, Exemplos e Abrir "ArduinoISP", conforme imagem abaixo:


Com o Arquivo aberto, faça o upload do arquivo para o Arduino Uno (ou Mega).


2º Passo: Conectar os Cabos entre o Arduino Uno (ou Mega) e o Pro Mini.

Esquema Com o Arduino Uno:

       Pro mini | Arduino Uno
13 | 13
12 | 12
11 | 11
RST | 10   
Vcc |  5V
  Gnd |  Gnd 

Ligar um capacitor de 10uF no Reset do arduino Uno e no Gnd.







Esquema Com o Arduino Mega:

         Pro mini | Arduino Mega
13 | 52
12 | 50
11 | 51
RST | 53   
Vcc |  5V
  Gnd |  Gnd 

Ligar um capacitor de 10uF no Reset do arduino Uno e no Gnd.




3º Passo: Mudar a Placa para Arduino Pro ou Pro Mini.

Menu Ferramentas --> Placa --> Arduino Pro ou Pro Mini


Escolher o processador:

Menu Ferramentas --> Processador --> ATMega328 (5V, 16MHz)



4º Passo: Mudar o Programador para "Arduino as ISP"

Menu Ferrramentas --> Programador --> Arduino as ISP



5º Passo: Fazer Upload via Programador (Ctrl+Shift+U)

Nesse ponto aqui, por falta de atenção tive alguns problemas, pois tentei fazer o upload via comando tradicional, clicando no botão. Até que percebi que o Correto é enviar através de uma outra função, que fica no Menu Arquivo:

Com o Sketch que se deseja upar aberto
vá até o Menu Arquivo --> Carregar Usando Programador



Feito Isso, o Programa deve ser enviado para o Pro Mini.

6º Passo: Voltar as configurações iniciais.

Como esse procedimento exige muitas mudanças de configurações da IDE do Arduino, é recomendável que as configurações oginais sejam restauradas, para evitar da próxima vez que a IDE seja usada, não cause outros problemas, principalmente se for um computador utilizado por outros programadores. Deixe sempre do jeito que estava quando iniciou.




quinta-feira, 24 de dezembro de 2015

Arduino - Fonte capacitiva para Attiny85

Aplicações onde microcontroladores podem atuar são praticamente infinitas, não há limites de onde eles podem ser aplicados, basta uma boa ideia e alguém vai pensar "Será que dá pra fazer com Arduino?" e muitas vezes a resposta é: SIM, Dá! São projetos dos mais simples aos mais complexos, utilizando poucos, nenhum ou muitos sensores, shields ou módulos. Se comunicando ou não com outros microcontroladores ou computadores, smartphones, via rádio, via wi-fi, bluetooth... enfim, há uma gama enorme do que um microcontrolador pode fazer. Porém, qualquer projeto que seja, maior ou menor, com mais ou menos recursos, vai inevitavelmente precisar de uma fonte de alimentação, alguns deles irão exigir mais potência, outros nem tanto.

Assim como são amplas as possibilidades de projetos com microcontroladores, consequentemente devem ser amplos também os meios para que consigamos alimentá-los. Felizmente há diversas formas de conseguirmos energia elétrica, seja com baterias, pilhas, energia solar, energia alternada da rede, além de outras.

Mas a questão é, como escolher a forma de alimentar o circuito que seja mais adequada para o projeto pretendido? Pra isso devem ser levadas em considerações questões como, custo, espaço utilizado, peso, potência necessária, autonomia, riscos de falta de energia, segurança... enfim, cada tipo de alimentação possui suas vantagens e desvantagens. Escolher a mais adequada faz parte de qualquer projeto, e por isso, é importante que o projetista tenha conhecimento suficiente sobre as principais fontes de alimentação a serem utilizadas nesses projetos.

Quando se trata de alimentar circuitos através da rede energia de 127/220V-AC, a solução mais simples é sem dúvida comprar um fonte AC-DC de 5V pronta, que irá ser conectada em uma tomada normal e pronto, basta plugar no seu microcontrolador e ser feliz. Mas nem sempre essa alternativa é a melhor, pois a fonte pode ser cara para determinado projeto, ou pode ocupar muito espaço, ou ainda ser muito pesada. Talvez você não queira ter seu projeto com partes separadas, e o melhor seja ter fonte e microcontrolador todo em uma única placa, bastando ser ligada diretamente a rede de energia. Nesses casos talvez seja necessário projetar sua própria fonte e pra isso é preciso saber de antemão qual o consumo que seu projeto terá, espaço que deverá ocupar, quanto você vai querer gastar com componentes, etc.

Em alguns projetos simples, que não utilizam muita potência, uma fonte com alguns mili Amperes pode ser a solução. Uma opção para esses casos, são fontes AC-DC sem transformadores, como fontes capacitivas ou ainda fontes resistivas que em geral tem baixo custo dos componentes utilizados, dependendo de até quantos mA se deseja conseguir.

Há uma gama enorme de tipos de fontes que podem ser montadas a partir desses princípios. Basicamente a ideia é utilizar um resistor ou um capacitor pra diminuir a tensão ou a corrente. depois retificar a corrente e por fim regular e filtrar a tensão. São esses basicamente os componentes mais elementares de uma fonte.

Como não vou abordar todos os tipos de fontes que podem ser utilizados, vou deixar duas dicas de buscas no google: "Fonte sem Transformador" e "Transformerless".

No vídeo abaixo montei uma pequena fonte capacitiva que fornece em torno de 30 mA, suficiente pra alimentar um attiny85. Mas atenção, isso não significa que qualquer projeto que utilize um attiny85 irá rodar com essa fonte, se ele possuir mais sensores, ou outros componentes que demandem mais corrente ao mesmo tempo, esse projeto de fonte pode não ser suficiente, por isso todo o consumo do projeto deve ser muito bem calculado.

Atenção Novamente: Manusear diretamente 110/127V Oferece altos riscos de acidentes. Nunca faça nada que não tenha certeza que irá funcionar. Sem tiver dúvidas peça ajuda pra alguém com mais experiencia.





Para mais detalhes dos cálculos do capacitor utilizado, veja os dois vídeos abaixo, onde fiz uma fonte bem parecida, mas com a intenção de alimentar leds diretamente em uma rede de 127V-AC.





Conclusão:

Fontes de alimentação podem ser a parte mais simples ou mais complexa de um projeto, portanto dependendo do projeto a ser desenvolvido, saber dimensionar e escolher a fonte a ser utilizada pode evitar muita dor de cabeça.