Criando Libs Arduino
Criando Libs Arduino
a sua – Parte 1
Como exemplo para este tutorial, iremos desenvolver uma biblioteca para utilização do
driver de motor NodeMCU
E foram as bibliotecas que ajudaram a tornar o Arduino tão popular, onde crianças e
adultos não precisam ser engenheiros ou desenvolvedores de software, para criarem
seus projetos e colocarem sua criatividade em prática. O próprio “jeitão” de escrever
código para Arduino segue o princípio da facilidade. Por exemplo a função
digitalWrite(pino, valor). Com apenas essa função ligamos ou desligamos um pino do
Arduino. Mas veja como ela é por dentro e o que teríamos que escrever caso não
usássemos as bibliotecas Arduino:
1
2
3 void
{
digitalWrite(uint8_t pin, uint8_t val)
4 uint8_t timer = digitalPinToTimer(pin);
5 uint8_t bit = digitalPinToBitMask(pin);
6 uint8_t port = digitalPinToPort(pin);
7 volatile uint8_t *out;
8
if (port == NOT_A_PIN) return;
9
10 // If the pin that support PWM output, we need to turn it off
11 // before doing a digital write.
12 if (timer != NOT_ON_TIMER) turnOffPWM(timer);
13
14 out = portOutputRegister(port);
15
16 uint8_t oldSREG = SREG;
cli();
17
18 if (val == LOW) {
19 *out &= ~bit;
20 } else {
21 *out |= bit;
}
22
23 SREG = oldSREG;
24}
25
26
Explore o seguinte link e descubra a origem das várias outras funções que facilitam o
desenvolvimento com Arduino como setup(), loop(), Serial.begin(), Serial.available(),
Serial.println(), digitalRead(), delay(), etc.
https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino
Mais a frente no tutorial iremos mostrar como construir cada um desses arquivos já com
foco no driver de motor para NodeMCU.
Para este tutorial escolhemos o driver de motor para NodeMCU. Esse driver é baseado
no CI L293D, controla até dois motores além de expor vários pinos do NodeMCU como
pinos digitais, UART e SPI. Podemos também utilizar uma fonte separada para os
motores. Veja na figura abaixo as indicações de cada parte do driver:
Note que temos as saídas para motor A-, A+, B-, B+. As saídas A- e B- são utilizadas
para configurar a força com que os motores irão girar. Para isso utilizaremos PWM. Já
as saídas A+ e B+, configuram o sentido de rotação dos motores.
Quando o NodeMCU é encaixado no driver os pinos ficam conectados da seguinte
maneira:
O funcionamento do driver é bem simples. Para controlar um motor basta conectar seus
terminais nos pinos A- e A+. No pino A- utilizamos PWM para configurar a força do
motor e no pino A+ o sentido. Então se utilizarmos 10% de força no pino A- e
utilizarmos nível 1 na saída A+, o motor gira para um lado com força de 10%. Se
utilizarmos força de 100% no pino A- e utilizarmos nível 1 na saída A+, o pino gira
com força total para um lado. Se utilizarmos nível 0 na saída A+, o motor gira para o
lado contrário.
1
2
void setup() {
3 pinMode(5, OUTPUT); // saída A-
4 pinMode(0, OUTPUT); // saída A+
5 pinMode(4, OUTPUT); // saída B-
6 pinMode(2, OUTPUT); // saída B+
}
7
8 void loop() {
9 analogWrite(5, 1024); // PWM no pino A-
10 digitalWrite(0, HIGH); // sentido no pino A+
11 analogWrite(4, 1024); // PWM no pino B-
12 digitalWrite(2, HIGH); // sentido no pino B+
delay(2000);
13
14 analogWrite(5, 1024); // PWM no pino A-
15 digitalWrite(0, LOW); // sentido no pino A+
16 analogWrite(4, 1024); // PWM no pino A-
17 digitalWrite(2, LOW); // sentido no pino B+
delay(2000);
18}
19
20
Agora que sabemos o funcionamento do nosso dispositivo (driver motor NodeMCU), já
podemos seguir com o desenvolvimento da biblioteca.
1. ir para frente
2. ir para trás
3. virar a esquerda
4. virar a direita
5. parar
goForward(uint16_t pwm)
goBackward(uint16_t pwm)
turnRight(uint16_t pwm)
turnLeft(uint16_t pwm)
stop()
Nossa biblioteca terá o nome de NodeMotorDriver, portanto nosso arquivo header terá
nome NodeMotorDriver.h
Dentro desse arquivo teremos uma classe com nome de nossa biblioteca. Dentro da
classe teremos nossas funções e variáveis que serão utilizadas.
1 class NodeMotorDriver
2 {
public:
3 NodeMotorDriver(uint8_t pinMotorA1, uint8_t pinMotorA2,
4 uint8_t pinMotorB1, uint8_t pinMotorB2);
5 void goForward(uint16_t pwm);
6 void goBackward(uint16_t pwm);
7 void turnRight(uint16_t pwm);
void turnLeft(uint16_t pwm);
8 void stop();
9
10 private:
11 uint8_t m_pinA1;
12 uint8_t m_pinA2;
13 uint8_t m_pinB1;
uint8_t m_pinB2;
14};
15
16
Veja que temos uma função ali que não estava em nosso planos:
Note também que temos as palavras public e private. Public significa que as funções e
variáveis estarão acessíveis para o usuário da biblioteca. Private restringe o uso de
funções e bibliotecas para apenas aquela classe em específico. Dependendo do tipo de
variável não há necessidade do usuário escrever um valor diferente naquela variável,
então utilizamos como private. Já as funções e variáveis públicas estarão disponíveis
para o usuário chamá-las ao decorrer do programa.
Ainda no arquivo header precisamos incluir outra biblioteca que é a Arduino.h. Incluir
essa biblioteca nos possibilita utilizar funções como pinMode(), digitalWrite(), etc. que
são funções do Arduino.
1#include <Arduino.h>
1#ifndef NodeMotorDriver_h
2#define NodeMotorDriver_h
3
4// código da classe aqui
5
6#endif
/*
1
NodeMotorDriver.h - Library for use with NodeMCU L293D driver
2 board
3 MIT License
4 */
5
6 // guarda de inclusão
#ifndef NodeMotorDriver_h
7 #define NodeMotorDriver_h
8
9 #include <Arduino.h>
10
11class NodeMotorDriver
12{
public:
13 NodeMotorDriver(uint8_t pinMotorA1, uint8_t pinMotorA2,
14uint8_t pinMotorB1, uint8_t pinMotorB2);
15 void goForward(uint16_t pwm);
16 void goBackward(uint16_t pwm);
void turnRight(uint16_t pwm);
17 void turnLeft(uint16_t pwm);
18 void stop();
19
20 private:
21 uint8_t m_pinA1;
22 uint8_t m_pinA2;
uint8_t m_pinB1;
23 uint8_t m_pinB2;
24};
25
26#endif
27
28
29
Arquivo source
Começando pela função construtora podemos ver a configuração do modo dos pinos
como OUTPUT e atribuição das variáveis membro da classe.
1
void NodeMotorDriver::goForward(uint16_t pwm)
2{
3 analogWrite(m_pinA1, pwm);
4 digitalWrite(m_pinA2, HIGH);
5 analogWrite(m_pinB1, pwm);
digitalWrite(m_pinB2, HIGH);
6}
7
Note que o valor de PWM será passado pelo usuário como um parâmetro na chamada
de função e os valores das variáveis membro já foram atribuídos pela função
construtora. As outras funções de movimento seguem a mesma lógica apenas alternando
entre HIGH e LOW.
1
void NodeMotorDriver::stop()
2{
3 analogWrite(m_pinA1, 0);
4 digitalWrite(m_pinA2, 0);
5 analogWrite(m_pinB1, 0);
digitalWrite(m_pinB2, 0);
6}
7
Não podemos esquecer também de incluir nosso arquivo header onde fizemos as
declarações de função.
#include "NodeMotorDriver.h"
/*
1 NodeMotorDriver.cpp - Library for use with NodeMCU L293D driver
2 board
3 MIT License
4 */
5
6 #include "NodeMotorDriver.h"
7 NodeMotorDriver::NodeMotorDriver(uint8_t pinMotorA1, uint8_t
8 pinMotorA2, uint8_t pinMotorB1, uint8_t pinMotorB2)
9 {
10 pinMode(pinMotorA1, OUTPUT);
11 pinMode(pinMotorA2, OUTPUT);
pinMode(pinMotorB1, OUTPUT);
12 pinMode(pinMotorB2, OUTPUT);
13 m_pinA1 = pinMotorA1; // speed
14 m_pinA2 = pinMotorA2; // direction
15 m_pinB1 = pinMotorB1; // speed
16 m_pinB2 = pinMotorB2; // direction
}
17
18void NodeMotorDriver::goForward(uint16_t pwm)
19{
20 analogWrite(m_pinA1, pwm);
21 digitalWrite(m_pinA2, HIGH);
analogWrite(m_pinB1, pwm);
22 digitalWrite(m_pinB2, HIGH);
23}
24
25void NodeMotorDriver::goBackward(uint16_t pwm)
26{
27 analogWrite(m_pinA1, pwm);
digitalWrite(m_pinA2, LOW);
28 analogWrite(m_pinB1, pwm);
29 digitalWrite(m_pinB2, LOW);
30}
31
void NodeMotorDriver::turnRight(uint16_t pwm)
32{
33 analogWrite(m_pinA1, pwm);
34 digitalWrite(m_pinA2, HIGH);
35 analogWrite(m_pinB1, pwm);
digitalWrite(m_pinB2, LOW);
36}
37
38void NodeMotorDriver::turnLeft(uint16_t pwm)
39{
40 analogWrite(m_pinA1, pwm);
41 digitalWrite(m_pinA2, LOW);
analogWrite(m_pinB1, pwm);
42 digitalWrite(m_pinB2, HIGH);
43}
44
45void NodeMotorDriver::stop()
46{
analogWrite(m_pinA1, 0);
47 digitalWrite(m_pinA2, 0);
48 analogWrite(m_pinB1, 0);
49 digitalWrite(m_pinB2, 0);
50}
51
52
53
54
55
56
57
58
Arquivo keywords.txt
Esse arquivo não é obrigatório mas é interessante para a experiência do usuário que irá
utilizar nossa biblioteca. Com ele podemos definir quais funções terão uma coloração
diferente quando se escreve código.
1
2 # Arduino IDE Keywords for Syntax Coloring
3
# Keyword for class NodeMotorDriver
4 NodeMotorDriver KEYWORD1
5
6 # Keyword for class functions
7 goForward KEYWORD2
8 goBackward KEYWORD2
turnRight KEYWORD2
9 turnLeft KEYWORD2
10stop KEYWORD2
11
Nome de classe deve utilizar KEYWORD1 e terá coloração laranja negrito. Nome de
função deve utilizar KEYWORD2 e terá coloração laranja.
Utilização da biblioteca
Pronto agora temos toda a biblioteca construída. Para utilizá-la devemos colocar os 3
arquivos dentro de uma pasta com o nome da biblioteca NodeMotorDriver, e copiar
para a pasta libraries da IDE Arduino.
Então basta incluir a biblioteca no código e utilizar as funções. Veja abaixo um pequeno
exemplo de código utilizando nossa biblioteca.
1
2 #include <NodeMotorDriver.h>
3
4 NodeMotorDriver nodeMotorDriver(5, 0, 4, 2);
5
6 void setup() {
7
8 }
9
void loop() {
10 nodeMotorDriver.goForward(1024);
11 delay(1000);
12 nodeMotorDriver.goBackward(500);
13 delay(1000);
14 nodeMotorDriver.turnRight(1024);
delay(1000);
15 nodeMotorDriver.turnLeft(500);
16 delay(1000);
17 nodeMotorDriver.stop();
18 delay(1000);
19}
20
No próximo post iremos mostrar como utilizar essa biblioteca arduino em um projeto
real de robô com NodeMCU e driver de motor controlado pelo celular. Fique ligado!
Veja também uma explicação em vídeo sobre criação de biblioteca Arduino no canal
WRKits:
Referências
https://www.arduino.cc/en/Hacking/LibraryTutorial
https://www.arduino.cc/en/Reference/APIStyleGuide
https://playground.arduino.cc/Code/Library
https://github.com/kecsot/Arduino-Motor-H-Bridge-L293d/tree/master/Motor
https://github.com/kecsot/Arduino-Motor-H-Bridge-
L293d/blob/master/Motor/Motor.cpp
https://github.com/kecsot/Arduino-Motor-H-Bridge-L293d/blob/master/Motor/Motor.h