Pengoperasian dasar pada modul wifi ESP8266 dari Arduino
Ketika Espresif meluncurkan modul pertama di pasar wifi dengan yang terintegrasi ESP8266 dan firmware yang dapat digunakan untuk menanganinya menggunakan perintah AT, yang kami minati sebagai pengguna adalah mengintegrasikannya ke dalam rakitan mikrokontroler dan masalahnya direduksi menjadi mengetahui (sebelumnya) kegelapan ESP8266 AT tabel perintah, kebutuhan makan atau Pembaruan firmware ESP8266.
Kemudian alternatif dengan cepat tiba untuk memprogram tersebut ESP8266 dan implementasi modul wifi format yang sangat berbeda yang menimbulkan kekhawatiran lain: modul wifi ESP8266 mana yang harus dipilih tergantung pada jangkauan antena yang berbeda (termasuk antena eksternal) atau integrasi fisik modul baru ini di rakitan kami.
Tentu saja, karena semua perubahan ini, penekanannya mungkin tidak ditempatkan pada aspek yang paling mendasar, yaitu pengelolaan yang paling mendasar Modul wifi ESP8266. Meskipun polaritas.es Anda dapat menemukan informasi tentang penggunaan ESP8266 dan ada beberapa aplikasi yang dimaksudkan untuk menjelaskan secara umum pengoperasiannya Modul wifi ESP8266 menggunakan perintah AT, terutama pada artikel di perpustakaan untuk membuat query HTTP dari Arduino dengan modul wifi ESP8266, kesan pembaca menunjukkan bahwa akan berguna untuk menambahkan beberapa informasi dasar untuk membantu pengguna ESP8266 untuk melaksanakan implementasinya sendiri.
Diskusikan operasi dasar untuk bekerja dengan ESP8266 dan mengusulkan solusi umum merupakan tujuan dari beberapa bagian yang sangat berbeda; Untuk membantu mengikuti isi artikel, indeks berikut dapat menjadi panduan:
- Kontrol modul wifi ESP8266 dari komputer melalui port serial
- Perbarui firmware dengan esptool
- Kirim pesanan ke modul
- Terima data dari ESP8266
- Analisis respons dengan mencari teks di konten
- Batasi waktu tunggu untuk menerima tanggapan
- Jalankan operasi kompleks yang ditentukan oleh beberapa perintah AT
Kontrol modul wifi ESP8266 dari komputer melalui port serial
Dari piring Arduino dan menggunakan milikmu IDE dimungkinkan untuk memantau pengoperasian a Modul wifi ESP8266, kirim Perintah ESP8266 AT dan lihat jawabannya tetapi jauh lebih mudah melakukannya dari komputer dengan aplikasi tipe terminal.
Tergantung pada papan mana Arduino digunakan, hanya satu port serial perangkat keras yang mungkin tersedia, yang menambah sedikit ketidaknyamanan dalam pengiriman dan penerimaan. Mengubah kecepatan komunikasi jauh lebih nyaman dalam aplikasi komunikasi serial dari komputer dan beberapa motherboard. Arduino (dan dalam beberapa keadaan) tidak mendukung kecepatan komunikasi serial yang lebih tinggi dengan baik, terutama 115200 baud, yang merupakan kecepatan default versi terbaru dari komunikasi serial firmware.
Tentang Program apa yang digunakan untuk memantau ESP8266 menggunakan port serial, ada banyak pilihan sesuai kebutuhan dan preferensi; akhir-akhir ini saya lebih banyak menggunakan yang klasik LucuCom (yang ada di screenshot di atas) karena sangat nyaman untuk saya ulangi tertentu Modul wifi ESP8266 AT pesanan dalam pengujian proyek.
Beberapa rekomendasi telah diberikan di sini mengenai program yang berfungsi sebagai konsol serial; Misalnya ketika berbicara tentang PuTTY untuk mengendalikan perangkat serial UART dari komputer. PuttySelain menjadi aplikasi luar biasa, aplikasi ini tersedia untuk sebagian besar sistem operasi desktop. Selanjutnya sebagai Putty dapat digunakan untuk bertindak sebagai konsol dengan port serial dan Keluarga protokol internet (TCP/IP), termasuk yang beroperasi TLS, menjadi alat umum yang lebih dari sekadar membayar (sedikit) waktu yang dihabiskan untuk mengonfigurasinya dan membiasakan penggunaannya.
Selain perangkat lunak komunikasi serial, untuk menghubungkan Modul wifi ESP8266 ke pelabuhan USB Komputer juga memerlukan konverter USB untuk seri TTL. Seperti halnya perangkat lunak, ada beberapa versi, yang hanya digunakan untuk mengonversi port USB pada port serial TTL (yang dapat diperoleh dari satu Euro) hingga yang dapat meniru protokol berbeda (seperti SPI o I2C).
Sama seperti program yang berfungsi sebagai konsol serial, perangkat keras untuk berkomunikasi melalui komputer USB dengan rangkaian logika (bukan hanya ESP8266) akan menjadi alat yang umum dalam pekerjaan pengembang aplikasi yang dikendalikan mikro, ada baiknya memilikinya di kotak peralatan sesegera mungkin dan bekerja dengannya Modul wifi ESP8266 Ini adalah peluang bagus untuk mendapatkannya.
Konverter USB a UART TTL Ini juga dapat digunakan untuk memantau perilaku rangkaian yang menggunakan ESP8266, untuk melakukan ini, output yang ingin Anda pantau dihubungkan secara seri ke input data (RX) konverter dengan dioda cepat ( 1N4148, misalnya) dan resistor (2K2, misalnya) yang paralel satu sama lain. Pengaturan seperti itu berfungsi seperti sniffer serial perangkat keras.
Meskipun sniffer pada gambar di atas tentu saja belum sempurna (antara lain tidak ada penyangga) cukup untuk memantau pengoperasian rakitan dengan Arduino dan ESP8266.
Menghapus sniffer dari skema sebelumnya, yaitu skema yang menunjukkan cara menghubungkan a Modul wifi ESP8266 ke piring Arduino. Selain mengumpankannya pada 3V3, pin reset dan pin aktivasi yang terintegrasi harus dihubungkan ke level tinggi (enable). Tentu saja, pin RX yang satu harus terhubung ke TX yang lain.
Untuk menyederhanakan diagram sebelumnya, sebuah pelat telah direpresentasikan Arduino diberi daya pada 3V3 dan tegangan pada port serial juga diasumsikan 3V3. Jika Anda menggunakan a mikrokontroler dengan level sinyal yang berbeda pada port serial (biasanya 5 V) akan diperlukan, agar tidak merusak ESP8266, Gunakan konverter tingkat seperti pada diagram di bawah ini. Sirkuit ini sering ditemukan di banyak implementasi modul komersial.
Perbarui firmware ESP8266
itu Perintah ESP8266 AT, penghentiannya, kecepatan default modul... tergantung pada versinya Firmware ESP8266. Yang terbaik adalah memastikan bahwa Anda memiliki versi yang sama di semua modul dan, jika mungkin, itu adalah versi terbaru.
Sayangnya, sebagian besar Model modul wifi ESP8266 Mereka hanya memiliki 4Mbit, jadi versi terbaru tidak dapat diinstal pada mereka. Firmware versi terbaru (resmi) yang dapat diinstal Modul wifi ESP8266 dengan 4 Mbit (sebagian besar) adalah 0.9.4 yang mencakup versi 0.2 tersebut Perintah ESP8266 AT.
Singkatnya, untuk memperbarui firmware yang Anda perlukan:
-
Unduh versi firmware yang sesuai. itu versi terbaru (resmi) untuk modul dengan memori 4 Mbit, terdapat di folder Espressif di github. Di Situs web espresif Anda dapat mengunduh firmware versi terbaru, namun sangat penting untuk memverifikasi bahwa modul yang memasangnya memiliki cukup memori.
-
Unduh alat instalasi firmware versi terbaru. Favorit saya adalah alat bantu yang tertulis di dalamnya Ular sanca, sehingga berfungsi pada platform apa pun. Selain bisa di download juga bisa di install dengan
pip install esptool
(opip2
opython -m pip
…). Tentu saja, Espresif Ia juga menawarkan alatnya sendiri tetapi saat ini hanya tersedia untuk Windows. -
Siapkan file yang diunduh; unzip ke dalam folder yang dapat diakses dan, jika perlu, jadikan alat tersebut dapat dieksekusi alat bantu, dalam kasus saya, sejak itu GNU / Linux, Dengan
chmod +x esptool
-
Hubungkan modul ke komputer menggunakan konverter USB UART TTL yang bekerja pada 3V3 atau gunakan konverter level jika berfungsi pada 5 V. Selain daya, Anda harus menghubungkan TX ke RX konverter USB UART TTL, RX ke TX, GPIO0 pada level rendah (GND) dan mungkin GPIO2 pada level tinggi (dalam pengujian saya, ini berhasil menghubungkannya pada level rendah dan memutusnya). Jika modul memiliki koneksi GPIO15 gratis (seperti yang terjadi pada ESP-12), modul harus terhubung ke level rendah. RESET, yang biasanya berada pada level tinggi selama pengoperasian, dapat dibiarkan tidak terhubung atau dihubungkan ke level tinggi melalui resistor (10K, misalnya), karena sebelum mulai merekam mungkin perlu mengatur ulang perangkat dengan menghubungkannya. ke tingkat yang rendah.
Dengan menyalakan modul, modul akan tersedia untuk diperbarui tetapi, Jika kesalahan koneksi ditampilkan, maka perlu diatur ulang menghubungkan RESET pada level rendah sesaat kemudian membiarkannya mengudara (tanpa menghubungkan) untuk proses update.
Modul ini memiliki konsumsi setengah ampere mencapai puncaknya (hingga 600 mA, menurut beberapa pengguna) sehingga penting untuk menggunakan catu daya yang mampu mendukung konsumsi tersebut, terutama untuk update firmware. -
Jalankan alat untuk memperbarui firmware. Dalam kasus saya, saya telah menyimpan dokumen alat dan firmware pada langkah 3 di folder yang sama, jadi saya jalankan dari konsol:
cd ~/Datos/firmwareESP8266
(ubah ke folder yang berisi alat dan firmware)./esptool.py --baud 115200 --port /dev/ttyUSB0 write_flash \
0x00000 ./boot_v1.1.bin \
0x01000 ./user1.bin \
0x7C000 ./esp_init_data_default.bin \
0x7E000 ./blank.bin
--baud
mengatur kecepatan ESP8266 (115200 baud dalam kasus saya) dan--port
port serial yang terhubung (dalam kasus saya, ditiru, USB pertama). Berbagai dokumen yang membentuk firmware tertinggalwrite_flash
didahului dengan alamat, dengan dokumen user1.bin berisi muatan pembaruan.
Kirim perintah ke modul wifi ESP8266
Untuk mengontrol ESP8266 dari komputer kita harus memulainya konfigurasikan aplikasi untuk itu cukup ① memilih port yang terhubung dengan konverter USB UART TTL, sesuatu seperti /dev/USB0
di GNU/Linux dan sejenisnya atau sejenisnya COM6
di Windows, ② pilih kecepatan di mana ESP8266, mungkin 115200 baud, ③ setel 8 bit data ditambah satu bit stop, tanpa paritas atau jabat tangan, dan ④ setel akhir baris, tergantung pada firmware, hampir selalu CR+LF.
Setelah aplikasi dikonfigurasi (atau, jika perlu, disimpan dan dipilih), aplikasi tersebut akan dikonfigurasi buka koneksi ("perangkat terbuka" dan "buka", masing-masing, pada tangkapan layar contoh di atas dengan LucuCom y Putty) dan Anda dapat mulai mengirim pesanan ke ESP8266.
Seperti yang dapat dilihat di ESP8266 AT tabel perintah, format untuk mengaktifkan, menonaktifkan, menetapkan nilai, dan merujuknya cukup dapat diprediksi, tetapi secara umum tidak mudah untuk mengingat semuanya dan Anda mungkin perlu memilikinya untuk merujuknya.
Cara mengirim AT pesanan al Modul wifi ESP8266 dari Arduino sangat sederhana: ① konfigurasi komunikasi dengan Serial.begin(115200);
(atau Serial1, Serial2… pada papan dengan beberapa port serial perangkat keras) dan ② mengirim perintah menggunakan format Serial.print(orden+"\r\n");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#define PUERTO_SERIE Serial // Objeto serie que corresponde a puerto serie hardware al que está conectado el módulo wifi ESP8266
#define VELOCIDAD_ESP8266 115200 // Velocidad, en baudios, a la que está configurado el ESP8266
#define IDENTIFICADOR_WIFI “polaridad.es” // SSID (Service Set Identifier)
#define CLAVE_WIFI “54lLij1RiTn3MEd3v41C” // Clave del punto de acceso wifi al que se conecta el ESP8266
void setup()
{
PUERTO_SERIE.begin(VELOCIDAD_ESP8266);
PUERTO_SERIE.print
(
“AT+CWJAP=\””+
String(IDENTIFICADOR_WIFI)+
“\”,\””+
String(CLAVE_WIFI)+
“\”\r\n”
);
}
void loop()
{
}
|
Contoh di atas menunjukkan cara mengirim Modul wifi ESP8266 AT pesanan dari Arduino. Dalam hal ini diilustrasikan AT+CWJAP
, yang digunakan untuk menyambung ke titik akses. Perintah ini menggunakan pengidentifikasi titik akses sebagai argumen (SSID) dan kuncinya, keduanya dalam tanda kutip, sehingga menjadi sebuah objek Srtring
dan sertakan dalam tanda kutip menggunakan kode escape (\"
). Untuk menyelesaikan pesanan, gunakan \r\n
yang sesuai dengan CR
y LF
.
Perlu diingat bahwa port serial tidak selalu diidentikkan dengan Serial
(di piring tertentu bisa Serial1
, Serial2
…) objek port yang digunakan telah ditentukan dengan menugaskannya ke makro PUERTO_SERIE
. Mendeteksi jenis papan yang digunakan dapat menambah sedikit kecerdasan pada pemilihan port serial; Nanti kita akan membahas bagaimana Anda bisa mengetahui jenisnya Arduino. Definisi lainnya adalah definisi biasa yang memungkinkan Anda "memberi nama" nilai konstanta agar tidak terulang (dan membuat kesalahan) dan membuatnya lebih mudah untuk diubah.
Contoh di atas seharusnya menghubungkan Modul wifi ESP8266 ke titik akses yang ditunjukkan tetapi apakah sudah terhubung sebelumnya? Apakah koneksinya berhasil? Untuk mengetahui hal ini, kita perlu “mendengarkan” apa yang dimaksud ESP8266
Terima data dari modul wifi ESP8266
Dengan menghubungkan data sniffer yang dijelaskan di atas ke komputer Anda dapat melihat apa Arduino telah mengirim ke ESP8266 dan tanggapannya. Untuk membaca dari Arduino dan memproses informasi di dalamnya perlu dideteksi dengan Serial.available()
jika ada data yang telah tiba dan jika demikian muatlah Serial.read()
. Contoh berikut menunjukkan cara membaca respons dari AT+CWJAP?
, yang akan melaporkan jika ada koneksi ke titik akses mana pun.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#define PUERTO_ESP8266 Serial // Objeto serie que corresponde a puerto serie hardware al que está conectado el módulo wifi ESP8266
#define VELOCIDAD_ESP8266 115200 // Velocidad, en baudios, a la que está configurado el ESP8266
char letra_recibida;
void setup()
{
PUERTO_ESP8266.begin(VELOCIDAD_ESP8266);
PUERTO_ESP8266.print(“AT+CWJAP?\r\n”);
}
void loop()
{
while(PUERTO_ESP8266.available())
{
letra_recibida=PUERTO_ESP8266.read();
}
}
|
Seperti di piring Arduino Uno (dan di tempat lain) membuka monitor serial akan mengatur ulang program, dapat digunakan untuk melihat di konsol serial Arduino informasi yang Anda kirim ke ESP8266 seperti yang ditunjukkan oleh tangkapan layar gambar di bawah ini.
Analisis respon yang dikirimkan oleh modul wifi ESP8266
Kita telah melihat bagaimana membaca informasi yang sampai Arduino dari ESP8266. Masalah yang harus anda hadapi adalah anda tidak tahu kapan mulai sampai, berapa lama sampainya, berapa lama... dan sangat tidak efisien menunggu respon dari pihak ESP8266 diterima tanpa membiarkan mikrokontroler melakukan tugas lain sementara itu.
Cara sederhana untuk mengelola keadaan ini adalah ulangi data yang diterima untuk mencari jawaban konkrit yang dengannya, misalnya, mengaktifkan indikator (bendera atau variabel Boolean) yang akan menentukan apakah akan melanjutkan pencarian dalam teks yang diterima dan tindakan apa yang harus dilakukan berdasarkan informasi yang diperoleh dari ESP8266. Sementara tanggapannya tiba mikrokontroler dapat mendedikasikan diri untuk tugas lain, misalnya menerima data dari sensor dan memprosesnya.
Cari teks dalam informasi yang diterima dari ESP8266
Untuk mencari teks yang berasal dari ESP8266 Anda bisa bandingkan setiap surat yang diterima dengan surat yang sesuai dengan pesan yang Anda cari. Penting untuk menggunakan penghitung (atau penunjuk) yang menunjuk ke huruf yang akan dibandingkan; Jika karakter yang berasal dari ESP8266 sama dengan yang diperiksa di pesan, penghitung maju, jika berbeda diinisialisasi.
Untuk mengetahui bahwa akhir telah tercapai, karakter berikutnya dari pesan yang dicari dikonsultasikan, yaitu nol (\0
) atau panjang pesan disimpan, dengan membandingkannya dengan penghitung, mengetahui apakah perbandingan telah selesai dan oleh karena itu Modul wifi ESP8266 telah mengirim pesan yang diinginkan.
Contoh berikut menggunakan perintah AT+CWLAP
yang akan mengembalikan daftar titik akses dan di dalamnya ada yang disebut "wifi polaridad.es" yang dicari. Meskipun kami telah memilih untuk memverifikasi bahwa karakter terakhir adalah nol, seperti penyangga Ia hanya menyimpan teks yang dicari dan diketahui panjangnya, dapat juga diperiksa apakah jumlah huruf yang benar telah diterima. Dengan LED terhubung ke pin 2 dilaporkan teks yang diharapkan telah ditemukan.
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
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define ORDEN “AT+CWLAP\r\n” // Buscar los puntos de acceso wifi disponibles. (Dependiendo de la versión del firmware) Las órdenes terminan en CR+LF
#define MENSAJE_BUSCADO “wifi polaridad.es” // Ver si está disponible el punto de acceso llamado “wifi polaridad.es”
#define LONGITUD_MENSAJE 18 // Se necesita guardar, al menos, 17 letras y el terminador \0
#define PIN_LED_ENCONTRADO 2 // Pin al que se conecta el LED que informa de que se ha encontrado el texto (el punto de acceso buscado está disponible)
#include <string.h> // strncpy
boolean esperando=true;
char buffer_mensaje;
char mensaje[LONGITUD_MENSAJE];
byte posicion_mensaje=0;
void setup()
{
pinMode(PIN_LED_ENCONTRADO,OUTPUT);
digitalWrite(PIN_LED_ENCONTRADO,LOW); // Apagar el LED (por ahora no se ha encontrado el mensaje)
strncpy(mensaje,MENSAJE_BUSCADO,LONGITUD_MENSAJE); // sizeof(mensaje)
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
SERIE.print(ORDEN); // Enviar la orden (consultar los puntos de acceso disponibles) al módulo wifi ESP8266
}
void loop()
{
if(esperando) // Buscará infinitamente hasta que llegue el texto esperado (y si no existe el punto de acceso nunca llegará ¡Es un ejemplo!)
{
while(SERIE.available()) // Si ha llegado algún dato por el puerto serie…
{
buffer_mensaje=SERIE.read(); // …almacenarlo en el buffer
if(buffer_mensaje==mensaje[posicion_mensaje]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
posicion_mensaje++; // Pasar a la siguiente letra del mensaje
if(mensaje[posicion_mensaje]==0) // ¿Ha terminado de analizarse todo el mensaje? (la última letra de la cadena de texto es \0)
{
esperando=false; // Si se ha terminado de analizar con éxito todo el mensaje ya no se está esperando
digitalWrite(PIN_LED_ENCONTRADO,HIGH); // Encender el LED para indicar que se ha encontrado el texto buscado
}
}
else // Si la letra que ha llegado por el puerto serie no corresponde con la buscada del mensaje…
{
posicion_mensaje=0; // …empezar desde la primera letra del texto buscado
}
}
}
}
|
Dalam kode contoh sebelumnya Anda juga dapat melihat caranya pilih port serial tergantung pada jenis papan Arduino digunakan. Contoh ini mengasumsikan bahwa Anda memiliki tiga jenis papan untuk proyek tersebut: satu Arduino Uno, sebuah Arduino mega 2560 dan arduino leonardo. Jika Anda bekerja dengan a Arduino Uno itu akan digunakan Serial
dan sebaliknya Serial1
.
Jika Anda bekerja dengan piring arduino leonardo Anda dapat menggunakan metode yang sama untuk menghentikan program dan menunggu konsol (port serial yang terkait dengannya Serial
) tersedia.
1
2
3
4
5
6
7
8
9
10
11
|
#ifdef ARDUINO_AVR_LEONARDO
#define SERIE Serial1
#define ESPERA_CONSOLA while(!Serial){} /* Esperar a la consola */
#else
#define ESPERA_CONSOLA /* Si no es un Arduino Leonardo no hace falta esperar a la consola */
#ifdef ARDUINO_AVR_MEGA2560
#define SERIE Serial1
#else // En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí
#define SERIE Serial
#endif
#endif
|
Cari berbagai teks dalam respons ESP8266
Kode pada contoh sebelumnya digunakan untuk mencari teks pada informasi yang dikirimkan oleh ESP8266 tetapi responsnya mungkin mencakup informasi yang berbeda tergantung pada operasinya. Misalkan, untuk memulai dengan kasus sederhana pada contoh berikutnya, yaitu teks yang dikirim oleh MCU ESP8266 es OK
ketika operasi dilakukan dengan benar dan ERROR
Jika tidak, seperti halnya pesanan AT+CWJAP?
, yang berfungsi untuk memverifikasi apakah Modul wifi ESP8266 sudah terhubung ke titik akses.
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
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define ORDEN “AT+CWJAP?\r\n” // Verificar que está conectado a un punto de acceso
#define CANTIDAD_MENSAJES 2 // Se distingue entre dos mensajes: acierto y error que se identificarán con true y false
#define MENSAJE_ACIERTO “OK”
#define MENSAJE_ERROR “ERROR”
#define LONGITUD_MENSAJE 6 // Se necesita guardar, al menos, 5 letras y el terminador \0 (Un pequeño desperdicio al hacer una matriz en la que todos los elementos ocupan como el mayor. Es admisible porque son muy pocos elementos y así no se complica este ejemplo inicial)
#define PIN_LED_ACIERTO 2 // Pin al que se conecta el LED que informa del acierto
#define PIN_LED_ERROR 3 // Pin al que se conecta el LED que informa del error
#include <string.h> // strncpy
boolean esperando=true; // Todavía no se ha encontrado el final del mensaje
char buffer_mensaje; // Para almacenar la última letra cargada desde el ESP8266
byte led_estado[CANTIDAD_MENSAJES]; // Un LED (pin) para cada estado
char mensaje[CANTIDAD_MENSAJES][LONGITUD_MENSAJE]; // Mensajes de acierto y error
byte posicion_mensaje[CANTIDAD_MENSAJES]; // Un contador de posición para cada mensaje
void setup()
{
led_estado[true]=PIN_LED_ACIERTO;
led_estado[false]=PIN_LED_ERROR;
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
pinMode(led_estado[numero_mensaje],OUTPUT); // Establecer el pin del LED
digitalWrite(led_estado[numero_mensaje],LOW); // Apagar el LED
posicion_mensaje[numero_mensaje]=0; // Inicializar a cero el número de letra a analizar de cada mensaje
}
strncpy(mensaje[true],MENSAJE_ACIERTO,LONGITUD_MENSAJE); // Preparar el mensaje de acierto
strncpy(mensaje[false],MENSAJE_ERROR,LONGITUD_MENSAJE); // Preparar el mensaje de error
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
SERIE.print(ORDEN); // Enviar la orden (verificar si existe conexión a un punto de acceso) al módulo wifi ESP8266
}
void loop()
{
if(esperando) // Buscará infinitamente hasta que llegue el texto esperado (y si no existe el punto de acceso nunca llegará ¡Es un ejemplo!)
{
while(SERIE.available()) // Si ha llegado algún dato por el puerto serie…
{
buffer_mensaje=SERIE.read(); // …almacenarlo en el buffer
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
if(buffer_mensaje==mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
posicion_mensaje[numero_mensaje]++; // Pasar a la siguiente letra del mensaje
if(mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]==0) // ¿Ha terminado de analizarse todo el mensaje actual? (la última letra de la cadena de texto es \0)
{
esperando=false; // Si se ha encontrado algún mensaje y ya no se está esperando
digitalWrite(led_estado[numero_mensaje],HIGH); // Encender el LED correspondiente al mensaje encontrado
}
}
else // Si la letra que ha llegado por el puerto serie no corresponde con la buscada del mensaje…
{
posicion_mensaje[numero_mensaje]=0; // …empezar desde la primera letra del texto buscado
}
}
}
}
}
|
Implementasi baru dari metode yang sama, yang mencari kecocokan dengan beberapa kemungkinan pesan, memungkinkan Anda memilih di antara tindakan yang berbeda tergantung pada respons yang diterima dari ESP8266, cukup nyalakan LED sesuai.
Batasi waktu yang diperlukan untuk menerima tanggapan
Sampai saat ini belum ada referensi yang dibuat mengenai isu yang relevan: the waktu tunggu maksimum (timeout) sebelum menganggap suatu operasi gagal. Jika karena alasan apa pun koneksi dengan Modul wifi ESP8266, modul dengan titik akses, titik akses dengan Internet atau, misalnya, server hipotetis tidak tersedia, program mungkin diblokir pada satu titik menunggu tanpa batas waktu, sehingga respons harus diartikulasikan untuk keadaan seperti itu. Waktu tunggu maksimum dapat dikonfigurasi untuk seluruh aplikasi, biasanya akan lebih "murah" dalam hal ini, atau waktu tunggu individual dapat diprogram untuk setiap operasi.
Untuk memeriksa bahwa (setidaknya) interval waktu tertentu telah berlalu "Waktu" saat akun dimulai biasanya dikurangi dari "waktu" saat ini dan diverifikasi bahwa perbedaannya lebih besar dari batas yang diinginkan. "Waktu" ini tidak harus waktu nyata, biasanya sesuai dengan interval yang telah berlalu sejak saat itu MCU mulai menghitung waktu; Hal ini tidak mempengaruhi program karena yang menarik adalah waktu yang telah berlalu dan bukan waktu absolut.
Biasanya, untuk memeriksa apakah interval tertentu telah berlalu, ekspresi tipe ini digunakan:
1
|
(unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo
|
Variabel milisegundos_al_empezar
mengandung nilai millis()
suatu momen tertentu dalam pelaksanaan yang waktunya ditentukan, sehingga tidak jarang namanya mengacu pada kata "kronometer". Variabel intervalo_de_tiempo
berisi jumlah milidetik maksimum yang membuat ekspresi sebelumnya menjadi benar, yaitu mewakili batas waktu; Biasanya berupa konstanta (atau makro) dan, seperti pada kasus sebelumnya, kata "TIMEOUT" sering muncul di namanya. Jika Anda bekerja dengan interval yang sangat pendek, Anda dapat menggunakannya micros()
di tempat millis()
(mikrodetik, bukan milidetik) meskipun ini jauh lebih jarang dan kurang tepat.
1
|
(unsigned long)(millis()–cronometro)>TIMEOUT
|
Bilangan bulat panjang masuk Arduino (unsigned long
) menempati 4 byte (32 bit), sehingga nilai terbesar yang dapat diwakilinya adalah 4294967295 (2 pangkat 32 dikurangi satu, karena dimulai dari nol). di piring Arduino Saat berjalan terus menerus, penghitung milidetik akan diatur ulang (kembali ke nol) kira-kira setiap 50 hari. Saat melakukan pengurangan dengan tipe data yang tidak ditandatangani, perilaku yang sama direproduksi (membalik penghitung) sehingga memungkinkan untuk mengontrol batas waktu tanpa batas.
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
71
72
73
74
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define ORDEN “AT+CWJAP?\r\n” // Verificar que está conectado a un punto de acceso
#define CANTIDAD_MENSAJES 2 // Se distingue entre dos mensajes: acierto y error que se identificarán con true y false
#define MENSAJE_ACIERTO “OK”
#define MENSAJE_ERROR “ERROR”
#define LONGITUD_MENSAJE 6 // Se necesita guardar, al menos, 5 letras y el terminador \0 (Un pequeño desperdicio al hacer una matriz en la que todos los elementos ocupan como el mayor. Es admisible porque son muy pocos elementos y así no se complica este ejemplo inicial)
#define PIN_LED_ACIERTO 2 // Pin al que se conecta el LED que informa del acierto
#define PIN_LED_ERROR 3 // Pin al que se conecta el LED que informa del error
#define TIMEOUT 5000 // Espera 5 segundos la respuesta del ESP8266 (y su análisis) antes de desistir
#include <string.h> // strncpy
boolean esperando=true; // Todavía no se ha encontrado el final del mensaje
boolean encontrado=false; // Salvo que se encuentre el punto de acceso se considera que la operación ha fracasado
char buffer_mensaje; // Para almacenar la última letra cargada desde el ESP8266
byte led_estado[CANTIDAD_MENSAJES]; // Un LED (pin) para cada estado
char mensaje[CANTIDAD_MENSAJES][LONGITUD_MENSAJE]; // Mensajes de acierto y error
byte posicion_mensaje[CANTIDAD_MENSAJES]; // Un contador de posición para cada mensaje
unsigned long cronometro;
void setup()
{
led_estado[true]=PIN_LED_ACIERTO;
led_estado[false]=PIN_LED_ERROR;
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
pinMode(led_estado[numero_mensaje],OUTPUT); // Establecer el pin del LED
digitalWrite(led_estado[numero_mensaje],LOW); // Apagar el LED
posicion_mensaje[numero_mensaje]=0; // Inicializar a cero el número de letra a analizar de cada mensaje
}
strncpy(mensaje[true],MENSAJE_ACIERTO,LONGITUD_MENSAJE); // Preparar el mensaje de acierto
strncpy(mensaje[false],MENSAJE_ERROR,LONGITUD_MENSAJE); // Preparar el mensaje de error
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
SERIE.print(ORDEN); // Enviar la orden (verificar si existe conexión a un punto de acceso) al módulo wifi ESP8266
cronometro=millis();
}
void loop()
{
if(esperando) // Buscará infinitamente hasta que llegue el texto esperado (y si no existe el punto de acceso nunca llegará ¡Es un ejemplo!)
{
while(SERIE.available()) // Si ha llegado algún dato por el puerto serie…
{
buffer_mensaje=SERIE.read(); // …almacenarlo en el buffer
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
if(buffer_mensaje==mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
posicion_mensaje[numero_mensaje]++; // Pasar a la siguiente letra del mensaje
if(mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]==0) // ¿Ha terminado de analizarse todo el mensaje actual? (la última letra de la cadena de texto es \0)
{
encontrado=numero_mensaje; // (numero_mensaje!=0) Hay conexión con el punto de acceso
esperando=false; // Si se ha encontrado algún mensaje y ya no se está esperando
digitalWrite(led_estado[numero_mensaje],HIGH); // Encender el LED correspondiente al mensaje encontrado
}
}
else // Si la letra que ha llegado por el puerto serie no corresponde con la buscada del mensaje…
{
posicion_mensaje[numero_mensaje]=0; // …empezar desde la primera letra del texto buscado
}
}
}
if((unsigned long)(millis()–cronometro)>TIMEOUT&&!encontrado) // Se ha superado el tiempo de espera y no hay conexión (se ha verificado que no hay o no ha llegado respuesta)
{
digitalWrite(PIN_LED_ERROR,HIGH); // Si ha superado el tiempo de espera encender el LED de error
esperando=false;
}
}
}
|
Kode di atas menunjukkan a implementasi yang sangat mendasar dari batasan waktu habis menggabungkan garis-garis yang ditandai sehubungan dengan contoh sebelumnya. Karena verifikasi batas waktu dilakukan setelah memproses data yang datang dari Modul wifi ESP8266, operasi dapat dianggap berhasil meskipun penerimaan memakan waktu lebih lama dari waktu tunggu yang ditentukan.
Jalankan operasi kompleks yang ditentukan oleh beberapa perintah AT
Untuk mendapatkan contoh referensi tujuan aplikasi yang mengeksploitasi tersebut Modul wifi ESP8266, anggap saja demikian menyimpan informasi dalam database yang diakses melalui layanan web untuk memantau suhu. Kode berikut membaca sensor yang terhubung ke input analog setiap interval waktu tertentu, menghitung nilai rata-rata dan, setelah interval waktu yang lebih lama, mengirimkannya ke server web (gaya IOT) melalui a petisi HTTP (POSKAN, DAPATKAN…).
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
|
#define PIN_TEMPERATURA A0 // Pin analógico al que se conecta la salida del sensor de temperatura LM35
#define INTERVALO_LECTURA_TEMPERATURA 30000 // Leer la temperatura cada 30 segundos (30*1000)
#define INTERVALO_GRABACION_TEMPERATURA 300000 // Grabar la media de la temperatura cada 5 minutos (5*60*1000)
unsigned long muestras=0; // Número de veces que se ha medido la temperatura (para calcular la media)
float temperatura; // de -55.0 °C a +150 °C | de -550 mV a +1500 mV | de 0 V a 2.050 V | analogRead*5.0/1023.0*100-55.0 -> analogRead/2.46-55.0
float media_temperaturas=0.0;
unsigned long cronometro_lectura_temperatura;
unsigned long cronometro_grabacion_temperatura;
void setup()
{
Serial.begin(9600);
cronometro_lectura_temperatura=millis();
cronometro_grabacion_temperatura=millis();
}
void loop()
{
if((unsigned long)(millis()–cronometro_lectura_temperatura)>INTERVALO_LECTURA_TEMPERATURA)
{
cronometro_lectura_temperatura=millis();
temperatura=analogRead(PIN_TEMPERATURA)/2.46–55.0;
muestras++;
media_temperaturas=(float)temperatura/(float)muestras+media_temperaturas*(float)(muestras–1)/(float)(muestras);
}
if((unsigned long)(millis()–cronometro_grabacion_temperatura)>INTERVALO_GRABACION_TEMPERATURA)
{
cronometro_grabacion_temperatura=millis();
// Aquí iría la parte del código que graba la temperatura. Para verificar el funcionamiento, en este ejemplo simplemente se muestra en la consola
Serial.println(“\nTemperatura media “+String(temperatura,DEC)+” °C (“+String((float)millis()/1000.0,DEC)+” s)\n”);
}
}
|
Dalam contoh pencatatan suhu ini, server web diakses setiap lima menit. Meskipun ketersediaannya tidak terlalu tinggi, proposal ini diharapkan dapat berhasil, namun jika diperlukan frekuensi pencatatan yang lebih tinggi, sumber daya lain harus diterapkan, misalnya, a penyangga data menunggu untuk dikirim, untuk mengirim beberapa saat server dapat hadir dan menyimpannya saat tidak tersedia. Jika frekuensi pencatatan data lebih besar lagi, jenis protokol lain harus diusulkan sebagai alternatif terhadap HTTP atau bahkan menggantinya TCP oleh UDP untuk dapat mengirim sebagian besar data dengan kecepatan yang diperlukan bahkan dengan mengorbankan sebagian data.
Operasi yang membentuk tugas yang harus dilakukan untuk mengirim suhu adalah:
- Setel ulang modul wifi
- Putuskan sambungan dari titik akses saat ini (jika ada sambungan default)
- Tetapkan pengaturannya. Misalnya, diasumsikan bahwa mode koneksi (sederhana) dan peran dalam komunikasi Wi-Fi (stasiun) harus dikonfigurasi.
- Hubungkan ke titik akses
- Pastikan koneksi sudah benar (sebenarnya ini adalah titik masuknya) Jika tidak ada koneksi, mulai proses dari awal
- Sambungkan ke server
- Kirim permintaan HTTP dengan data yang akan disimpan
Urutan operasi tidak harus persis seperti ini (walaupun operasinya persis seperti ini) dan setiap langkah mungkin memerlukan beberapa langkah Perintah ESP8266 ATMisalnya, konfigurasi yang tercantum di atas memerlukan dua: AT+CIPMUX=0
y AT+CWMODE=1
.
Struktur data untuk mewakili operasi pada ESP8266
Dalam contoh sebelumnya, meskipun dalam cara yang sangat mendasar, solusi umum untuk masalah ini sudah disarankan: menggunakan struktur data yang menyimpan kemungkinan tanggapan dan tindakan yang harus diambil dalam setiap kasus; kirim tindakan, tunggu tanggapan, dan lanjutkan sesuai dengan maksud tanggapan tersebut. Karena setiap operasi yang kompleks akan memerlukan beberapa Perintah ESP8266 AT, struktur data harus menghubungkan suatu operasi dengan operasi lain, berikutnya atau sebelumnya, yang harus dilakukan dalam setiap kasus tergantung pada respons dari ESP8266.
Dalam contoh sebelumnya, sebuah pesan dicari dalam respons dari ESP8266 dan itu diartikan sebagai keberhasilan atau kesalahan. Selain penerimaan (dan analisis) dari seluruh teks yang diterima, Untuk mendapatkan nilai minimum yang umum, disarankan untuk juga memperhatikan penyelesaian pesan atau, dengan kata lain, ketersediaan Modul wifi ESP8266 untuk menerima pesanan baru. Dengan cara ini, perubahan ke keadaan yang dapat kita panggil, misalnya, "wifi tersedia", dapat berupa menerima nama titik akses dan menerima teks ERROR
atau teksnya OK
akan berarti bahwa ESP8266 Anda telah menyelesaikan tanggapan dan sekarang Anda dapat mengirimkan tanggapan berikutnya Perintah AT ke ESP8266.
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
// inicializar_operaciones.h
// 0 Reiniciar el módulo wifi ESP8266
operacion[REINICIAR_ESP8266]=“AT+RST”;
mensaje[REINICIAR_ESP8266][FALLO]=mensaje_fallo;
mensaje[REINICIAR_ESP8266][ACIERTO]=“ready\r\n”;
mensaje[REINICIAR_ESP8266][LITERAL]=mensaje_vacio;
siguiente_operacion[REINICIAR_ESP8266][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[REINICIAR_ESP8266][ACIERTO]=DESCONECTAR_WIFI;
siguiente_operacion[REINICIAR_ESP8266][LITERAL]=DESCONECTAR_WIFI;
configuracion[REINICIAR_ESP8266]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[REINICIAR_ESP8266]=10000;
// 1 Desconectar del punto de acceso por defecto (si fuera el caso)
operacion[DESCONECTAR_WIFI]=“AT+CWQAP”;
mensaje[DESCONECTAR_WIFI][FALLO]=mensaje_fallo;
mensaje[DESCONECTAR_WIFI][ACIERTO]=mensaje_acierto;
mensaje[DESCONECTAR_WIFI][LITERAL]=mensaje_vacio;
siguiente_operacion[DESCONECTAR_WIFI][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[DESCONECTAR_WIFI][ACIERTO]=MODO_ESTACION;
siguiente_operacion[DESCONECTAR_WIFI][LITERAL]=MODO_ESTACION;
configuracion[DESCONECTAR_WIFI]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[DESCONECTAR_WIFI]=2500;
// 2 Establecer el modo de estación (no punto de acceso)
operacion[MODO_ESTACION]=“AT+CWMODE=1”;
mensaje[MODO_ESTACION][FALLO]=mensaje_fallo;
mensaje[MODO_ESTACION][ACIERTO]=mensaje_acierto;
mensaje[MODO_ESTACION][LITERAL]=mensaje_vacio;
siguiente_operacion[MODO_ESTACION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[MODO_ESTACION][ACIERTO]=MODO_SIMPLE;
siguiente_operacion[MODO_ESTACION][LITERAL]=MODO_SIMPLE;
configuracion[MODO_ESTACION]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[MODO_ESTACION]=2500;
// 3 Establecer el modo de conexión simple
operacion[MODO_SIMPLE]=“AT+CIPMUX=0”;
mensaje[MODO_SIMPLE][FALLO]=mensaje_fallo;
mensaje[MODO_SIMPLE][ACIERTO]=mensaje_acierto;
mensaje[MODO_SIMPLE][LITERAL]=mensaje_vacio;
siguiente_operacion[MODO_SIMPLE][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[MODO_SIMPLE][ACIERTO]=CONECTAR_WIFI;
siguiente_operacion[MODO_SIMPLE][LITERAL]=CONECTAR_WIFI;
configuracion[MODO_SIMPLE]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[MODO_SIMPLE]=2500;
// 4 Conectar al punto de acceso
operacion[CONECTAR_WIFI]=“AT+CWJAP=\”polaridad.es\”,\”54lLij1RiTn3MEd3v41C\””;
mensaje[CONECTAR_WIFI][FALLO]=mensaje_fallo;
mensaje[CONECTAR_WIFI][ACIERTO]=mensaje_acierto;
mensaje[CONECTAR_WIFI][LITERAL]=mensaje_vacio;
siguiente_operacion[CONECTAR_WIFI][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[CONECTAR_WIFI][ACIERTO]=VERIFICAR_CONEXION;
siguiente_operacion[CONECTAR_WIFI][LITERAL]=VERIFICAR_CONEXION;
configuracion[CONECTAR_WIFI]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[CONECTAR_WIFI]=20000;
// 5 Verificar si hay conexión
operacion[VERIFICAR_CONEXION]=“AT+CIPSTATUS”;
mensaje[VERIFICAR_CONEXION][FALLO]=mensaje_fallo;
mensaje[VERIFICAR_CONEXION][ACIERTO]=mensaje_acierto;
mensaje[VERIFICAR_CONEXION][LITERAL]=“STATUS:5”;
siguiente_operacion[VERIFICAR_CONEXION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[VERIFICAR_CONEXION][ACIERTO]=REINICIAR_ESP8266;
siguiente_operacion[VERIFICAR_CONEXION][LITERAL]=CONECTAR_SERVIDOR;
configuracion[VERIFICAR_CONEXION]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[VERIFICAR_CONEXION]=5000;
// 6 Conectar al servidor
operacion[CONECTAR_SERVIDOR]=“AT+CIPSTART=\”TCP\”,\”servidoriot.com\”,80″;
mensaje[CONECTAR_SERVIDOR][FALLO]=mensaje_fallo;
mensaje[CONECTAR_SERVIDOR][ACIERTO]=mensaje_acierto;
mensaje[CONECTAR_SERVIDOR][LITERAL]=“CONNECT”;
siguiente_operacion[CONECTAR_SERVIDOR][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[CONECTAR_SERVIDOR][ACIERTO]=INFORMAR_CANTIDAD;
siguiente_operacion[CONECTAR_SERVIDOR][LITERAL]=INFORMAR_CANTIDAD;
configuracion[CONECTAR_SERVIDOR]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[CONECTAR_SERVIDOR]=15000;
// 7 Avisar de la cantidad de datos que se envían
operacion[INFORMAR_CANTIDAD]=“AT+CIPSEND=”;
mensaje[INFORMAR_CANTIDAD][FALLO]=mensaje_vacio;
mensaje[INFORMAR_CANTIDAD][ACIERTO]=mensaje_acierto;
mensaje[INFORMAR_CANTIDAD][LITERAL]=mensaje_vacio;
siguiente_operacion[INFORMAR_CANTIDAD][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[INFORMAR_CANTIDAD][ACIERTO]=ENVIAR_CANTIDAD;
siguiente_operacion[INFORMAR_CANTIDAD][LITERAL]=ENVIAR_CANTIDAD;
configuracion[INFORMAR_CANTIDAD]=NO_ESPERAR_RESPUESTA;
timeout[INFORMAR_CANTIDAD]=1000;
// 8 Enviar cantidad
//operacion[ENVIAR_CANTIDAD]=”123″; // Definido para cada envío
mensaje[ENVIAR_CANTIDAD][FALLO]=sin_enlace;
mensaje[ENVIAR_CANTIDAD][ACIERTO]=“>”;
mensaje[ENVIAR_CANTIDAD][LITERAL]=mensaje_vacio;
siguiente_operacion[ENVIAR_CANTIDAD][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_CANTIDAD][ACIERTO]=ENVIAR_PREFIJO_PETICION;
siguiente_operacion[ENVIAR_CANTIDAD][LITERAL]=ENVIAR_PREFIJO_PETICION;
configuracion[ENVIAR_CANTIDAD]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[ENVIAR_CANTIDAD]=5000;
// 9 Enviar el prefijo de la petición
operacion[ENVIAR_PREFIJO_PETICION]=“GET /frigo03/almacenar_temperatura.php?temperatura=”;
mensaje[ENVIAR_PREFIJO_PETICION][FALLO]=mensaje_vacio;
mensaje[ENVIAR_PREFIJO_PETICION][ACIERTO]=mensaje_vacio;
mensaje[ENVIAR_PREFIJO_PETICION][LITERAL]=mensaje_vacio;
siguiente_operacion[ENVIAR_PREFIJO_PETICION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_PREFIJO_PETICION][ACIERTO]=ENVIAR_DATOS;
siguiente_operacion[ENVIAR_PREFIJO_PETICION][LITERAL]=ENVIAR_DATOS;
configuracion[ENVIAR_PREFIJO_PETICION]=NO_ESPERAR_RESPUESTA;
timeout[ENVIAR_PREFIJO_PETICION]=10000;
// 10 Enviar la temperatura
//operacion[ENVIAR_DATOS]=”+000.00″; // Definido para cada envío
mensaje[ENVIAR_DATOS][FALLO]=mensaje_vacio;
mensaje[ENVIAR_DATOS][ACIERTO]=mensaje_vacio;
mensaje[ENVIAR_DATOS][LITERAL]=mensaje_vacio;
siguiente_operacion[ENVIAR_DATOS][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_DATOS][ACIERTO]=ENVIAR_SUFIJO_PETICION;
siguiente_operacion[ENVIAR_DATOS][LITERAL]=ENVIAR_SUFIJO_PETICION;
configuracion[ENVIAR_DATOS]=NO_ESPERAR_RESPUESTA;
timeout[ENVIAR_DATOS]=5000;
// 11 Enviar el sufijo de la petición
operacion[ENVIAR_SUFIJO_PETICION]=” HTTP/1.1\r\nHost: www.servidoriot.com\r\nUser-Agent: ESP8266\r\nConnection: close\r\n\r\n”;
mensaje[ENVIAR_SUFIJO_PETICION][FALLO]=sin_enlace;
mensaje[ENVIAR_SUFIJO_PETICION][ACIERTO]=“CLOSED\r\n\r\nOK\r\n”;
mensaje[ENVIAR_SUFIJO_PETICION][LITERAL]=mensaje_vacio; // “SEND OK”
siguiente_operacion[ENVIAR_SUFIJO_PETICION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_SUFIJO_PETICION][ACIERTO]=VERIFICAR_CONEXION;
siguiente_operacion[ENVIAR_SUFIJO_PETICION][LITERAL]=VERIFICAR_CONEXION;
configuracion[ENVIAR_SUFIJO_PETICION]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[ENVIAR_SUFIJO_PETICION]=20000;
|
Kode di atas menggunakan vektor (operacion
) untuk menyimpan teks operasi berurutan yang membentuk tugas lengkap. Array dua dimensi digunakan (mensaje
) dengan tiga tanggapan yang dianalisis. Seperti dijelaskan di atas, perlu dicari pesan-pesan yang mewakili akhir dari respon selain pesan yang mewakili respon yang benar atau salah. Tidak semua operasi mempunyai jumlah kemungkinan jawaban yang sama; Jika responsnya lebih sedikit, pesan kosong dapat digunakan yang menggunakan jumlah siklus sekecil mungkin dalam analisisnya (meskipun demikian, ini bukan cara yang paling optimal). Logikanya, diperlukan jumlah minimum respons yang dicari (tiga pada contoh) untuk mencakup seluruh kemungkinan operasi, meskipun tidak semuanya memungkinkan.
Jika berbicara tentang kemungkinan jawaban, sudah terlihat bahwa contoh ini tidak terlalu berguna untuk menerima data dengan format sembarangan dari a Modul wifi ESP8266, tapi masalahnya, dalam konteks penggunaan dengan mikrokontroler itu tidak biasa; Hal yang paling umum adalah mengirimkan data yang dikumpulkan oleh sensor yang terhubung dan/atau menerima informasi tentang apa yang harus dilakukan dengan aktuator yang dikontrolnya. Informasi yang sangat berharga, yang dapat diprediksi dengan sangat baik.
Pada struktur data sebelumnya, seperti yang dilakukan untuk menyatakan kemungkinan respon yang dianalisis, matriks dua dimensi juga digunakan untuk menentukan operasi yang harus dilakukan dalam setiap kasus (siguiente_operacion
). Secara khusus, kami telah memilih untuk menanggapi tiga jenis pesan: ① teks arbitrer (LITERAL
) untuk memverifikasi apakah ada koneksi ke titik akses Wi-Fi dan server, ② teks untuk mendeteksi kesalahan dalam proses (FALLO
) dan ③ teks yang menunjukkan bahwa operasi berhasil diselesaikan (ACIERTO
).
Terakhir, ada dua vektor lagi untuk mengatur waktu tunggu maksimum sebelum menyerah (timeout
) dan tentukan (configuracion
) jika operasi berakhir tanpa menunggu respons (ESPERAR_RESPUESTA
) dan pesan yang menunjukkan akhir komunikasi. Vektor terakhir ini, untuk mengilustrasikan contoh bagaimana memori dapat disimpan, bekerja dengan bit-bit byte konfigurasi untuk menunjukkan keadaan yang berbeda.
Pertama Perintah ESP8266 AT struktur data selalu mengharapkan respon, yang dapat berupa pesan sukses atau pesan kesalahan. Ketika terjadi kesalahan, modul di-restart dan dimulai lagi dan jika pesan menunjukkan bahwa operasi sudah benar, maka akan dilanjutkan ke operasi berikutnya.
Ketika Anda sudah terhubung ke server, polanya berubah. Dalam hal ini perlu ① mengirimkan panjang paket data yang akan dikirim dan ② membuat permintaan HTTP dengan teks tetap ditambah nilai (suhu) yang dikirim untuk disimpan di server. Penyiapan data ini dilakukan pada setiap pengiriman dan perlu dibagi menjadi dua (beritahukan panjangnya) atau tiga (kirim permintaan HTTP) On ESP8266 SESUAI pesanan. Hanya bagian terakhir yang menjadi bagian operasi yang akan menunggu tanggapan.
Dalam hal ini akan bekerja tanpa masalah (mungkin memperingatkan bahwa modul sedang sibuk) tetapi ketika panjang data lebih besar maka blok data perlu dibagi menjadi bagian-bagian yang lebih kecil dan bahkan mungkin perlu untuk mengimplementasikan menunggu, sebagai dilakukan dengan pembacaan suhu, untuk memberikan waktu pada modul untuk mengirim data tanpa mengisinya penyangga.
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
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define REINICIAR_ESP8266 0 // Índice del vector de operaciones que representa la orden de reinicio del módulo wifi ESP8266
#define DESCONECTAR_WIFI 1
#define MODO_ESTACION 2
#define MODO_SIMPLE 3
#define CONECTAR_WIFI 4
#define VERIFICAR_CONEXION 5
#define CONECTAR_SERVIDOR 6
#define INFORMAR_CANTIDAD 7
#define ENVIAR_CANTIDAD 8
#define ENVIAR_PREFIJO_PETICION 9
#define ENVIAR_DATOS 10
#define ENVIAR_SUFIJO_PETICION 11
#define CANTIDAD_OPERACIONES 12 // Cantidad de operaciones que forma el cuerpo de la aplicación
#define FALLO 0 // Índice del vector de respuestas que representa el mensaje de error
#define FALLO_TERMINA 0B00000001 // 1<<FALLO
#define ACIERTO 1
#define ACIERTO_TERMINA 0B00000010 // 1<<ACIERTO
#define LITERAL 2
#define LITERAL_TERMINA 0B00000100 // 1<<LITERAL
#define CANTIDAD_RESPUESTAS 3 // Cantidad de posibles respuestas que se buscan en el texto recibido desde el ESP8266
#define ESPERAR_RESPUESTA 0B00001000 // 1<<CANTIDAD_RESPUESTAS
#define NO_ESPERAR_RESPUESTA 0B00000000
#define ENVIAR_OPERACION esperando_respuesta=true;SERIE.print(operacion[operacion_actual]);if(configuracion[operacion_actual]&ESPERAR_RESPUESTA){SERIE.print(“\r\n”);}for(unsigned char numero_respuesta=0;numero_respuesta<CANTIDAD_RESPUESTAS;numero_respuesta++){numero_caracter[numero_respuesta]=0;}cronometro_esp8266=millis();
|
Bersama dengan makro lain yang telah dijelaskan sebelumnya, contoh kode di atas menunjukkan bagaimana berbagai status ditentukan untuk menentukan apakah akan menunggu respons dan, jika berlaku, pesan apa yang menunjukkan bahwa respons telah selesai.
Seperti pada titik yang berbeda dalam kode, sebuah operasi akan dikirim (ketika tiba waktunya untuk mengirim suhu rata-rata, jika waktu tunggu suatu operasi terlampaui, ketika operasi saat ini berhasil diselesaikan...) tetapi bagaimana melakukannya adalah ditetapkan secara global, telah didefinisikan secara makro ENVIAR_OPERACION
yang mengelompokkan langkah-langkah yang terlibat dalam pengiriman.
1
2
3
4
5
6
7
8
9
10
11
12
|
// La macro ENVIAR_OPERACION corresponde con las operaciones:
esperando_respuesta=true;
SERIE.print(operacion[operacion_actual]);
if(configuracion[operacion_actual]&ESPERAR_RESPUESTA)
{
SERIE.print(“\r\n”);
}
for(unsigned char numero_respuesta=0;numero_respuesta<CANTIDAD_RESPUESTAS;numero_respuesta++)
{
numero_caracter[numero_respuesta]=0;
}
cronometro_esp8266=millis();
|
Berikut ini adalah kode program utama contohnya. Tugas paling eksternal adalah yang bertugas mengambil sampel suhu untuk menghitung rata-rata dan, setiap jangka waktu tertentu, dikirim ke server menggunakan Modul wifi ESP8266. Setelah setiap operasi dikirim, respons dianalisis untuk menentukan operasi berikutnya atau apakah tugas pengiriman informasi telah selesai.
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
#include “ESP8266_operacion_compleja_varias_ordenes_AT.h”
#define PIN_TEMPERATURA A0 // Pin analógico al que se conecta la salida del sensor de temperatura LM35
#define INTERVALO_LECTURA_TEMPERATURA 30000 // Leer la temperatura cada 30 segundos (30*1000)
#define INTERVALO_GRABACION_TEMPERATURA 300000 // Grabar la media de la temperatura cada 5 minutos (5*60*1000)
unsigned long muestras=0; // Número de veces que se ha medido la temperatura (para calcular la media)
float temperatura; // de -55.0 °C a +150 °C | de 0 V a 2.050 V | de -550 mV a +1500 mV | analogRead*5.0/1023.0*100-55.0 analogRead/2.46-55.0
float media_temperaturas=0.0;
unsigned long cronometro_lectura_temperatura;
unsigned long cronometro_grabacion_temperatura;
char *mensaje_fallo=“ERROR\r\n”;
char *mensaje_acierto=“OK\r\n”;
char *sin_enlace=“link is not\r\n”;
char *mensaje_vacio=“\f”;
char *operacion[CANTIDAD_OPERACIONES]; // Matriz de punteros a constantes de caracteres con las operaciones que se envían al ESP8266 (no solo órdenes AT, aunque seguro que algunas son órdenes AT)
char *mensaje[CANTIDAD_OPERACIONES][CANTIDAD_RESPUESTAS]; // Mensajes de respuesta
unsigned char siguiente_operacion[CANTIDAD_OPERACIONES][CANTIDAD_RESPUESTAS];
unsigned char configuracion[CANTIDAD_OPERACIONES];
unsigned int timeout[CANTIDAD_OPERACIONES];
unsigned char numero_caracter[CANTIDAD_RESPUESTAS];
unsigned int longitud_peticion;
char texto_longitud_peticion[4]; // 3 caracteres para almacenar la longitud de la petición en formato texto
char valor_enviado[9]; // signo + 4 enteros + punto + 2 decimales + \0 = 9
unsigned long cronometro_esp8266;
unsigned char operacion_actual; // Número de operación que se está procesando
unsigned char proxima_operacion; // Siguiente operación que se procesará cuando termine la actual
char lectura_serie;
boolean grabando_datos=false;
boolean esperando_respuesta;
void setup()
{
#include “inicializar_operaciones.h”
longitud_peticion=strlen(operacion[ENVIAR_PREFIJO_PETICION])+strlen(operacion[ENVIAR_SUFIJO_PETICION]);
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
//delay(8000); // En fase de pruebas se puede introducir un tiempo de espera para conectar una consola/sniffer
cronometro_lectura_temperatura=millis();
cronometro_grabacion_temperatura=millis();
}
void loop()
{
if((unsigned long)(millis()–cronometro_lectura_temperatura)>INTERVALO_LECTURA_TEMPERATURA)
{
cronometro_lectura_temperatura=millis();
temperatura=analogRead(PIN_TEMPERATURA)/2.46–55.0;
muestras++;
media_temperaturas=(float)temperatura/(float)muestras+media_temperaturas*(float)(muestras–1)/(float)(muestras);
}
if(grabando_datos)
{
if((unsigned long)(millis()–cronometro_esp8266)>timeout[operacion_actual]) // Si se ha superado el tiempo de espera máximo
{
operacion_actual=siguiente_operacion[operacion_actual][FALLO]; // Pasar a la operación correspondiente al error
ENVIAR_OPERACION
}
else // Si no se ha superado el tiempo de espera máximo
{
if(configuracion[operacion_actual]&ESPERAR_RESPUESTA) // Si la siguiente operación depende de la respuesta a la actual desde el ESP8266 hay que leer la información que llegue desde el puerto serie
{
while(SERIE.available())
{
lectura_serie=SERIE.read();
for(unsigned char numero_respuesta=0;numero_respuesta<CANTIDAD_RESPUESTAS;numero_respuesta++) // Comparar la letra cargada desde el puerto serie con la correspondiente de los mensajes disponibles
{
if(lectura_serie==mensaje[operacion_actual][numero_respuesta][numero_caracter[numero_respuesta]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
numero_caracter[numero_respuesta]++; // Como el carácter coincide, se puede comparar con el siguiente lo próximo que llegue por el puerto serie
if(mensaje[operacion_actual][numero_respuesta][numero_caracter[numero_respuesta]]==0) // Si el carácter que toca es \0 es que se ha terminado de analizar el mensaje
{
if(esperando_respuesta) // Todavía no se ha encontrado un mensaje que determine la siguiente operación
{
proxima_operacion=siguiente_operacion[operacion_actual][numero_respuesta]; // La próxima operación que habrá que procesar será la que indique el mensaje encontrado para la operación actual
esperando_respuesta=false; // Ya se ha encontrado un mensaje que determina la siguiente operación
}
if(configuracion[operacion_actual]&(1<<numero_respuesta)) // Si el mensaje encontrado es uno de los que terminan la operación…
{
if(operacion_actual+1==CANTIDAD_OPERACIONES) // Se ha completado la última operación de la tarea compleja
{
grabando_datos=false; // Se ha terminado la tarea compleja (grabar datos en el servidor)
}
else // No es la última operación de la tarea compleja, hay que seguir realizando otras operaciones
{
operacion_actual=proxima_operacion; // Ejecutar la siguiente operación
ENVIAR_OPERACION
}
}
}
}
else // Si la letra recibida no es igual que la correspondiente del mensaje
{
numero_caracter[numero_respuesta]=0; // Empezar a comparar desde la primera letra del mensaje
}
}
}
}
else // Si no hay que esperar datos desde el puerto serie
{
operacion_actual=siguiente_operacion[operacion_actual][ACIERTO];
ENVIAR_OPERACION
}
}
}
else
{
if((unsigned long)(millis()–cronometro_grabacion_temperatura)>INTERVALO_GRABACION_TEMPERATURA)
{
cronometro_grabacion_temperatura=millis();
dtostrf(media_temperaturas,4,2,valor_enviado); // snprintf(valor_enviado,9,”%+3.2f”,media_temperaturas); // printf y derivadas no funcionan en AVR
snprintf(texto_longitud_peticion,4,“%d”,longitud_peticion+strlen(valor_enviado));
grabando_datos=true;
operacion_actual=VERIFICAR_CONEXION;
operacion[ENVIAR_DATOS]=valor_enviado;
operacion[ENVIAR_CANTIDAD]=texto_longitud_peticion;
ENVIAR_OPERACION
}
}
}
|
Logikanya, beberapa tindakan pengoptimalan dapat dilakukan pada kode sebelumnya, tetapi karena ini adalah contoh untuk memahami caranya ESP8266 Secara umum, ada baiknya hanya berfokus pada beberapa aspek, yang pertama adalah struktur data. Tampaknya hal yang logis adalah menggunakan struktur data bahasa pemrograman (struct
) untuk mewakili informasi yang sedang diproses: itu Perintah ESP8266 AT dan pesan yang dianalisis.
Gunakan struktur (struct
) untuk menyimpan data alih-alih array contoh (berdasarkan array tersebut) adalah hal yang sepele dan, meskipun dapat menghasilkan kode yang lebih elegan, hal ini tidak berarti peningkatan apa pun pada hasilnya. Alternatif sebenarnya yang ditimbulkan oleh penggunaan struct
adalah menerapkan, seperti yang dijelaskan di bawah ini, panjang variabel dalam struktur yang berisi data "dalam". yang dirujuk oleh mereka. Dengan cara ini, misalnya, suatu operasi tidak perlu mempunyai jumlah respons yang tetap untuk dianalisis.
Pendekatan ini menunjukkan bahwa ini adalah cara terbaik untuk mengimplementasikan solusi, namun kelemahannya adalah hal ini diperlukan menggunakan alokasi memori dinamis, praktik berisiko bekerja dengan a mikrokontroler yang memerlukan pengukuran cermat tentang berapa banyak memori yang akan digunakan saat runtime, karena kompiler tidak akan dapat memperingatkan kita tentang hal ini dan ada kemungkinan tertentu akan menghabiskan memori (atau tumpukan) dengan konsekuensi fatal bagi eksekusi program.
Sehubungan dengan pengoptimalan kode, menarik untuk diingat bahwa, dalam program jenis ini, yang menggunakan teks dalam jumlah besar, dapat menghemat ruang memori SRAM menyimpan string teks dalam memori program (flash) dengan makro F()
. Dalam tangkapan layar berikut Anda dapat melihat program yang berbeda dan distribusi memori dinamis dengan penggunaan teks normal dan menggunakan makro F()
.
Sehubungan dengan tindakan yang dilakukan sesuai dengan informasi yang diperoleh dari Modul wifi ESP8266, sebagai alternatif untuk memeriksa pesan dari kode dan melakukan satu atau yang lain sesuai dengan apa yang diterima, dapat disimpan dalam struktur data ini penunjuk ke fungsi yang melakukan setiap tugas, bukan indikator status (bendera) yang memperingatkan keadaan tertentu yang menjadi tanggung jawab aplikasi untuk dikelola, misalnya, dalam loop utama.
Berikut ini adalah contoh struktur untuk menyimpan data permintaan ke ESP8266 (tipe datanya operacion_esp8266
) dan tanggapan mereka (tipe data respuesta_esp8266
).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
typedef struct estructura_operacion_esp8266 operacion_esp8266; // Se define el tipo de datos operacion_esp8266 que corresponde con la estructura (struct) llamada estructura_operacion_esp8266 que se define más adelante
typedef struct estructura_respuesta_esp8266 respuesta_esp8266; // Se define el tipo de datos respuesta_esp8266 que corresponde con la estructura (struct) llamada struct estructura_respuesta_esp8266 que se define más adelante
struct estructura_operacion_esp8266
{
char *peticion; // Datos que se envían al ESP8266 para iniciar una operación (como una orden AT, pero también algo como la petición a un servidor…)
unsigned char cantidad_respuestas; // Número de posibles respuestas del ESP8266 que se van a analizar, que puede ser variable en cada petición (no solo OK y ERROR)
unsigned char timeout; // Tiempo (segundos) que se espera la respuesta del ESP8266 antes de desistir
respuesta_esp8266 *respuesta; // Respuestas (estructura) que se esperan de esta operación
};
struct estructura_respuesta_esp8266
{
char *mensaje; // Mensaje que se espera recibir desde el ESP8266
unsigned char posicion_mensaje; // Posición (letra) que se está comparando con la recibida desde el ESP8266
//boolean estado; // El estado se representa por un valor booleano (por ejemplo ¿se ha encontrado ya esta respuesta? para no seguir buscándola)
//unsigned char *estado; // El estado se representa con un texto (de longitud variable)
unsigned char estado; // El estado se establece con 8 banderas, una por bit
operacion_esp8266 *operacion; // Puntero a operación que se ejecutará si se encuentra esta respuesta en el mensaje devuelto por el ESP8266
};
operacion_esp8266 comprobar_conexion;
respuesta_esp8266 respuesta_OK;
respuesta_esp8266 respuesta_ERROR;
|
Sebagai struktur yang mewakili operasi (data yang dikirim ke Modul wifi ESP8266) mengacu pada struktur yang menentukan respons, dan struktur respons terhadap struktur operasi, keduanya perlu dideklarasikan terlebih dahulu, dengan mendefinisikan tipe data baru, dan kemudian mendefinisikan isinya.
Contoh sebelumnya menganggap bahwa program yang menyertakannya telah memilih untuk menggunakan a indikator status, yang harus sesuai dengan variabel yang dapat diakses dari kode yang bertanggung jawab untuk melakukan satu atau operasi lain seperti yang ditunjukkan oleh nilai tersebut. Jika di respon dari ESP8266 Ketika teks tertentu dianalisis, keadaan mengambil nilai yang menunjukkan struktur respons yang sesuai.
Seperti disebutkan sebelumnya, alternatif lain, baik untuk menggantikan atau melengkapi indikator status, adalah menyimpan fungsi dalam struktur referensi (sebuah penunjuk) yang akan dipanggil saat menemukan teks tertentu dalam respons dari Modul wifi ESP8266.
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
|
typedef struct estructura_operacion_esp8266 operacion_esp8266; // Se define el tipo de datos operacion_esp8266 que corresponde con la estructura (struct) llamada estructura_operacion_esp8266 que se define más adelante
typedef struct estructura_respuesta_esp8266 respuesta_esp8266; // Se define el tipo de datos respuesta_esp8266 que corresponde con la estructura (struct) llamada struct estructura_respuesta_esp8266 que se define más adelante
struct estructura_operacion_esp8266
{
char *peticion; // Datos que se envían al ESP8266 para iniciar una operación (como una orden AT, pero también algo como la petición a un servidor…)
unsigned char cantidad_respuestas; // Número de posibles respuestas del ESP8266 que se van a analizar, que puede ser variable en cada petición (no solo OK y ERROR)
unsigned char timeout; // Tiempo (segundos) que se espera la respuesta del ESP8266 antes de desistir
respuesta_esp8266 *respuesta; // Respuestas (estructura) que se esperan de esta operación
};
struct estructura_respuesta_esp8266
{
char *mensaje; // Mensaje que se espera recibir desde el ESP8266
unsigned char posicion_mensaje; // Posición (letra) que se está comparando con la recibida desde el ESP8266
//boolean estado; // El estado se representa por un valor booleano (por ejemplo ¿se ha encontrado ya esta respuesta? para no seguir buscándola)
//unsigned char *estado; // El estado se representa con un texto (de longitud variable)
unsigned char estado; // El estado se establece con 8 banderas, una por bit
float (*accion)(unsigned char,unsigned char); // Puntero a la función que se llama si se encuentra la respuesta
operacion_esp8266 *operacion; // Puntero a operación que se ejecutará si se encuentra esta respuesta en el mensaje devuelto por el ESP8266
};
operacion_esp8266 comprobar_conexion;
respuesta_esp8266 respuesta_OK;
respuesta_esp8266 respuesta_ERROR;
|
Pada contoh sebelumnya telah ditambahkan struktur data yang digunakan untuk memproses respon dari Modul wifi ESP8266 sebuah penunjuk ke fungsi (seharusnya) yang mengembalikan tipe data float
(bisa berupa nilai tertimbang dari pembacaan analog) dan dua byte disediakan sebagai argumen (dua unsigned char
yang bisa menjadi pin dari mana input analog dibaca dan pin yang mengaktifkan ENABLE dari integrasi hipotetis).
Dalam pengembangan untuk MCU, bertentangan dengan apa yang terjadi dalam gaya pengembangan untuk sistem yang lebih besar, tidak jarang menggunakan variabel global ketika mendefinisikan perilaku (global) dari aplikasi yang mengontrol rakitan, sehingga tidak jarang menemukan definisi seperti ini. sebagai fungsi tanpa parameter dan tidak mengembalikan nilai, kira-kira void (*accion)();
Jika Anda bekerja dengan cara merepresentasikan data ini, gunakan struct
data dengan panjang variabel, perlu mengalokasikan memori secara dinamis malloc()
(o new()
, jika objek digunakan), yang akan menggunakan jumlah memori yang dialokasikan sebagai parameter dan mengembalikan pointer ke awal area memori yang dicadangkan. Dengan sizeof()
Berdasarkan jenis yang disimpan, dikalikan dengan jumlah elemen yang digunakan, Anda bisa mendapatkan jumlah memori yang dibutuhkan. Contoh dengan dan tanpa penggunaan dapat dilihat pada screenshot di bawah ini. malloc()
; Hati-hati dengan memori yang digunakan oleh program, dalam kasus pertama, Anda perlu memuat perpustakaan yang berisi fungsi ini.
Jika operasi pada Modul wifi ESP8266 akan bervariasi sepanjang eksekusi program, maka perlu mengosongkan memori yang tidak digunakan free()
(o delete()
, dalam hal menjadi objek). Meskipun masuk akal untuk mengharapkan bahwa kompiler (GCC) akan mengoptimalkan program untuk menghindari partisi memori, tentunya kinerjanya tidak akan seoptimal bekerja dengan memori yang dialokasikan secara statis.
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
error_operacion.mensaje=“ERROR\r\n”;
error_operacion.termina_operacion=true;
error_operacion.operacion=&reiniciar_esp8266;
error_enlace.mensaje=“link is not\r\n”;
error_enlace.termina_operacion=true;
error_enlace.operacion=&reiniciar_esp8266;
reiniciar_esp8266_correcto.mensaje=“ready\r\n”;
reiniciar_esp8266_correcto.termina_operacion=true;
reiniciar_esp8266_correcto.operacion=&desconectar_wifi;
desconectar_wifi_correcto.mensaje=mensaje_acierto;
desconectar_wifi_correcto.termina_operacion=true;
desconectar_wifi_correcto.operacion=&establecer_modo_estacion;
establecer_modo_estacion_correcto.mensaje=mensaje_acierto;
establecer_modo_estacion_correcto.termina_operacion=true;
establecer_modo_estacion_correcto.operacion=&establecer_modo_simple;
establecer_modo_simple_correcto.mensaje=mensaje_acierto;
establecer_modo_simple_correcto.termina_operacion=true;
establecer_modo_simple_correcto.operacion=&conectar_wifi;
conectar_wifi_correcto.mensaje=mensaje_acierto;
conectar_wifi_correcto.termina_operacion=true;
conectar_wifi_correcto.operacion=&verificar_conexion;
verificar_conexion_correcto.mensaje=“STATUS:5”;
verificar_conexion_correcto.termina_operacion=false;
verificar_conexion_correcto.operacion=&conectar_servidor;
verificar_conexion_terminado.mensaje=mensaje_acierto;
verificar_conexion_terminado.termina_operacion=true;
verificar_conexion_terminado.operacion=&reiniciar_esp8266;
conectar_servidor_correcto.mensaje=“CONNECT”;
conectar_servidor_correcto.termina_operacion=false;
conectar_servidor_correcto.operacion=&informar_cantidad;
conectar_servidor_terminado.mensaje=mensaje_acierto;
conectar_servidor_terminado.termina_operacion=true;
conectar_servidor_terminado.operacion=&reiniciar_esp8266;
informar_cantidad_correcto.mensaje=mensaje_acierto;
informar_cantidad_correcto.termina_operacion=true;
informar_cantidad_correcto.operacion=&enviar_cantidad;
enviar_cantidad_correcto.mensaje=“>”;
enviar_cantidad_correcto.termina_operacion=true;
enviar_cantidad_correcto.operacion=&enviar_prefijo;
enviar_prefijo_correcto.operacion=&enviar_datos;
enviar_datos_correcto.operacion=&enviar_sufijo;
enviar_sufijo_correcto.mensaje=“CLOSED\r\n\r\nOK\r\n”;
enviar_sufijo_correcto.termina_operacion=true;
enviar_sufijo_correcto.operacion=&verificar_conexion;
reiniciar_esp8266.peticion=“AT+RST”;
reiniciar_esp8266.timeout=15000;
reiniciar_esp8266.cantidad_respuestas=2;
reiniciar_esp8266.respuesta=malloc(sizeof(respuesta_esp8266*)*reiniciar_esp8266.cantidad_respuestas);
reiniciar_esp8266.respuesta[FALLO]=&error_operacion;
reiniciar_esp8266.respuesta[ACIERTO]=&reiniciar_esp8266_correcto;
desconectar_wifi.peticion=“AT+CWQAP”;
desconectar_wifi.timeout=2500;
desconectar_wifi.cantidad_respuestas=2;
desconectar_wifi.respuesta=malloc(sizeof(respuesta_esp8266*)*desconectar_wifi.cantidad_respuestas);
desconectar_wifi.respuesta[FALLO]=&error_operacion;
desconectar_wifi.respuesta[ACIERTO]=&desconectar_wifi_correcto;
establecer_modo_estacion.peticion=“AT+CWMODE=1”;
establecer_modo_estacion.timeout=2500;
establecer_modo_estacion.cantidad_respuestas=2;
establecer_modo_estacion.respuesta=malloc(sizeof(respuesta_esp8266*)*establecer_modo_estacion.cantidad_respuestas);
establecer_modo_estacion.respuesta[FALLO]=&error_operacion;
establecer_modo_estacion.respuesta[ACIERTO]=&establecer_modo_estacion_correcto;
establecer_modo_simple.peticion=“AT+CIPMUX=0”;
establecer_modo_simple.timeout=2500;
establecer_modo_simple.cantidad_respuestas=2;
establecer_modo_simple.respuesta=malloc(sizeof(respuesta_esp8266*)*establecer_modo_simple.cantidad_respuestas);
establecer_modo_simple.respuesta[FALLO]=&error_operacion;
establecer_modo_simple.respuesta[ACIERTO]=&establecer_modo_simple_correcto;
conectar_wifi.peticion=“AT+CWJAP=\”polaridad.es\”,\”54lLij1RiTn3MEd3v41C\””;;
conectar_wifi.timeout=20000;
conectar_wifi.cantidad_respuestas=2;
conectar_wifi.respuesta=malloc(sizeof(respuesta_esp8266*)*conectar_wifi.cantidad_respuestas);
conectar_wifi.respuesta[FALLO]=&error_operacion;
conectar_wifi.respuesta[ACIERTO]=&conectar_wifi_correcto;
verificar_conexion.peticion=“AT+CIPSTATUS”;
verificar_conexion.timeout=5000;
verificar_conexion.cantidad_respuestas=3;
verificar_conexion.respuesta=malloc(sizeof(respuesta_esp8266*)*verificar_conexion.cantidad_respuestas);
verificar_conexion.respuesta[FALLO]=&error_operacion;
verificar_conexion.respuesta[ACIERTO]=&verificar_conexion_correcto;
verificar_conexion.respuesta[OTRO_MENSAJE]=&verificar_conexion_terminado;
conectar_servidor.peticion=“AT+CIPSTART=\”TCP\”,\”servidoriot.com\”,80″;
conectar_servidor.timeout=15000;
conectar_servidor.cantidad_respuestas=3;
conectar_servidor.respuesta=malloc(sizeof(respuesta_esp8266*)*conectar_servidor.cantidad_respuestas);
conectar_servidor.respuesta[FALLO]=&error_operacion;
conectar_servidor.respuesta[ACIERTO]=&conectar_servidor_correcto;
conectar_servidor.respuesta[OTRO_MENSAJE]=&conectar_servidor_terminado; // OK, no significa que haya conexión pero sí termina la operación
informar_cantidad.peticion=“AT+CIPSEND=”;
informar_cantidad.timeout=1000;
informar_cantidad.cantidad_respuestas=1;
informar_cantidad.respuesta=malloc(sizeof(respuesta_esp8266*)*informar_cantidad.cantidad_respuestas);
informar_cantidad.respuesta[0]=&informar_cantidad_correcto;
//enviar_cantidad.peticion=””; // Se asigna cuando se conoce el valor que se va a enviar y se puede calcular la longitud que ocupa (número de caracteres)
enviar_cantidad.timeout=5000;
enviar_cantidad.cantidad_respuestas=2;
enviar_cantidad.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_cantidad.cantidad_respuestas);
enviar_cantidad.respuesta[FALLO]=&error_enlace;
enviar_cantidad.respuesta[ACIERTO]=&enviar_cantidad_correcto;
enviar_prefijo.peticion=“GET /frigo03/almacenar_temperatura.php?temperatura=”;
enviar_prefijo.timeout=10000;
enviar_prefijo.cantidad_respuestas=1;
enviar_prefijo.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_prefijo.cantidad_respuestas);
enviar_prefijo.respuesta[0]=&enviar_prefijo_correcto;
//enviar_datos.peticion=””; // Se asigna en cuando se conoce el valor que se va a enviar
enviar_datos.timeout=5000;
enviar_datos.cantidad_respuestas=1;
enviar_datos.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_datos.cantidad_respuestas);
enviar_datos.respuesta[0]=&enviar_datos_correcto;
enviar_sufijo.peticion=” HTTP/1.1\r\nHost: www.servidoriot.com\r\nUser-Agent: ESP8266\r\nConnection: close\r\n\r\n”;
enviar_sufijo.timeout=20000;
enviar_sufijo.cantidad_respuestas=2;
enviar_sufijo.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_sufijo.cantidad_respuestas);
enviar_sufijo.respuesta[FALLO]=&error_enlace;
enviar_sufijo.respuesta[ACIERTO]=&enviar_sufijo_correcto;
|
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define FALLO 0 // Índice del vector de respuestas que representa el mensaje de error
#define FALLO_TERMINA 0B00000001 // 1<<FALLO
#define ACIERTO 1
#define ACIERTO_TERMINA 0B00000010 // 1<<ACIERTO
#define OTRO_MENSAJE 2
#define OTRO_MENSAJE_TERMINA 0B00000100 // 1<<OTRO_MENSAJE
#define CANTIDAD_RESPUESTAS 3 // Cantidad de posibles respuestas que se buscan en el texto recibido desde el ESP8266
#define ESPERAR_RESPUESTA 0B00001000 // 1<<CANTIDAD_RESPUESTAS
#define NO_ESPERAR_RESPUESTA 0B00000000
#define ENVIAR_OPERACION esperando_respuesta=true;SERIE.print((*operacion_actual).peticion);if((*operacion_actual).cantidad_respuestas>1){SERIE.print(“\r\n”);for(unsigned char numero_respuesta=0;numero_respuesta<(*operacion_actual).cantidad_respuestas;numero_respuesta++){numero_caracter[numero_respuesta]=0;}}cronometro_esp8266=millis();
#define PIN_TEMPERATURA A0 // Pin analógico al que se conecta la salida del sensor de temperatura LM35
#define INTERVALO_LECTURA_TEMPERATURA 30000 // Leer la temperatura cada 30 segundos (30*1000)
#define INTERVALO_GRABACION_TEMPERATURA 300000 // Grabar la media de la temperatura cada 5 minutos (5*60*1000)
unsigned long muestras=0; // Número de veces que se ha medido la temperatura (para calcular la media)
float temperatura; // de -55.0 °C a +150 °C | de 0 V a 2.050 V | de -550 mV a +1500 mV | analogRead*5.0/1023.0*100-55.0 analogRead/2.46-55.0
float media_temperaturas=0.0;
unsigned long cronometro_lectura_temperatura;
unsigned long cronometro_grabacion_temperatura;
char *mensaje_acierto=“OK\r\n”;
typedef struct estructura_operacion_esp8266 operacion_esp8266; // Se define el tipo de datos operacion_esp8266 que corresponde con la estructura (struct) llamada estructura_operacion_esp8266 que se define más adelante
typedef struct estructura_respuesta_esp8266 respuesta_esp8266; // Se define el tipo de datos respuesta_esp8266 que corresponde con la estructura (struct) llamada struct estructura_respuesta_esp8266 que se define más adelante
struct estructura_operacion_esp8266
{
char *peticion; // Datos que se envían al ESP8266 para iniciar una operación (como una orden AT, pero también algo como la petición a un servidor…)
unsigned int timeout; // Tiempo (segundos) que se espera la respuesta del ESP8266 antes de desistir
bool espera_respuesta; // Si no espera respuesta en cuanto se termine de enviar la orden se puede pasar a la siguiente
unsigned char cantidad_respuestas; // Número de posibles respuestas del ESP8266 que se van a analizar, que puede ser variable en cada petición (no solo OK y ERROR)
respuesta_esp8266 **respuesta; // Respuestas (estructura) que se esperan de esta operación
};
struct estructura_respuesta_esp8266
{
char *mensaje; // Mensaje que se espera recibir desde el ESP8266
bool termina_operacion; // Cuando se termina de leer el mensaje ha terminado la operación
operacion_esp8266 *operacion; // Puntero a operación que se ejecutará si se encuentra esta respuesta en el mensaje devuelto por el ESP8266
};
operacion_esp8266 *operacion_actual; // Operación sobre el ESP8266 que se está ejecutando actualmente
operacion_esp8266 *proxima_operacion; // Siguiente operación que se procesará cuando termine la actual
unsigned int longitud_peticion; // Número de caracteres que ocupa la petición HTTP
char texto_longitud_peticion[4]; // 3 caracteres para almacenar la longitud de la petición en formato texto
char valor_enviado[9]; // signo + 4 enteros + punto + 2 decimales + \0 = 9
unsigned long cronometro_esp8266; // Cronómetro para controlar el tiempo máximo de respuesta del ESP8266 antes de desistir
char lectura_serie; // buffer con el carácter leído desde el ESP8266
boolean grabando_datos=false; // Verdadero cuando han terminado todas las operaciones necesarias para grabar los datos
boolean esperando_respuesta; // Verdadero si aún no se ha encontrado una de los mensajes que indica que ha terminado la respuesta
unsigned char numero_caracter[CANTIDAD_RESPUESTAS]; // Número de orden de la letra del mensaje-respuesta que se está almacenando (una matriz de, como máximo, el mayor número de respuestas posible)
operacion_esp8266 reiniciar_esp8266; // Reiniciar el módulo wifi ESP8266
operacion_esp8266 desconectar_wifi; // Desconectar del punto de acceso por defecto (si fuera el caso)
operacion_esp8266 establecer_modo_estacion; // Establecer el modo de estación (no punto de acceso)
operacion_esp8266 establecer_modo_simple; // Establecer el modo de conexión simple
operacion_esp8266 conectar_wifi; // Conectar al punto de acceso
operacion_esp8266 verificar_conexion; // Verificar si hay conexión
operacion_esp8266 conectar_servidor; // Conectar al servidor
operacion_esp8266 informar_cantidad; // Avisar de la cantidad de datos que se envían
operacion_esp8266 enviar_cantidad; // Enviar cantidad
operacion_esp8266 enviar_prefijo; // Enviar el prefijo de la petición
operacion_esp8266 enviar_datos; // Enviar la temperatura
operacion_esp8266 enviar_sufijo; // Enviar el sufijo de la petición
respuesta_esp8266 error_operacion; // Todas las respuestas “ERROR” reinician el módulo wifi ESP8266
respuesta_esp8266 error_enlace; // Las respuestas “link is not” también reinician el módulo wifi ESP8266
respuesta_esp8266 reiniciar_esp8266_correcto;
respuesta_esp8266 desconectar_wifi_correcto;
respuesta_esp8266 establecer_modo_estacion_correcto;
respuesta_esp8266 establecer_modo_simple_correcto;
respuesta_esp8266 conectar_wifi_correcto;
respuesta_esp8266 verificar_conexion_correcto;
respuesta_esp8266 verificar_conexion_terminado;
respuesta_esp8266 conectar_servidor_correcto;
respuesta_esp8266 conectar_servidor_terminado;
respuesta_esp8266 informar_cantidad_correcto;
respuesta_esp8266 enviar_cantidad_correcto;
respuesta_esp8266 enviar_prefijo_correcto;
respuesta_esp8266 enviar_datos_correcto;
respuesta_esp8266 enviar_sufijo_correcto;
void setup()
{
#include “inicializar_operaciones.h”
longitud_peticion=strlen(enviar_prefijo.peticion)+strlen(enviar_sufijo.peticion);
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
//delay(8000); // En fase de pruebas se puede introducir un tiempo de espera para conectar una consola/sniffer
cronometro_lectura_temperatura=millis();
cronometro_grabacion_temperatura=millis();
}
void loop()
{
if((unsigned long)(millis()–cronometro_lectura_temperatura)>INTERVALO_LECTURA_TEMPERATURA)
{
cronometro_lectura_temperatura=millis();
temperatura=analogRead(PIN_TEMPERATURA)/2.46–55.0;
muestras++;
media_temperaturas=(float)temperatura/(float)muestras+media_temperaturas*(float)(muestras–1)/(float)(muestras);
}
if(grabando_datos)
{
if((unsigned long)(millis()–cronometro_esp8266)>(unsigned long)(*operacion_actual).timeout) // Si se ha superado el tiempo de espera máximo
{
operacion_actual=(*(*operacion_actual).respuesta[FALLO]).operacion; // Pasar a la operación correspondiente al error
ENVIAR_OPERACION
}
else // Si no se ha superado el tiempo de espera máximo
{
if((*operacion_actual).cantidad_respuestas>1) // Si la siguiente operación depende de la respuesta a la actual desde el ESP8266 hay que leer la información que llegue desde el puerto serie
{
while(SERIE.available())
{
lectura_serie=SERIE.read();
for(unsigned char numero_respuesta=0;numero_respuesta<(*operacion_actual).cantidad_respuestas;numero_respuesta++) // Comparar la letra cargada desde el puerto serie con la correspondiente de los mensajes disponibles
{
if(lectura_serie==(*(*operacion_actual).respuesta[numero_respuesta]).mensaje[numero_caracter[numero_respuesta]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
numero_caracter[numero_respuesta]++; // Como el carácter coincide, se puede comparar con el siguiente lo próximo que llegue por el puerto serie
if((*(*operacion_actual).respuesta[numero_respuesta]).mensaje[numero_caracter[numero_respuesta]]==0) // Si el carácter que toca es \0 es que se ha terminado de analizar el mensaje
{
if(esperando_respuesta) // Todavía no se ha encontrado un mensaje que determine la siguiente operación
{
proxima_operacion=(*(*operacion_actual).respuesta[numero_respuesta]).operacion; // La próxima operación que habrá que procesar será la que indique el mensaje encontrado para la operación actual
esperando_respuesta=false; // Ya se ha encontrado un mensaje que determina la siguiente operación
}
if((*(*operacion_actual).respuesta[numero_respuesta]).termina_operacion) // Si el mensaje encontrado es uno de los que terminan la operación…
{
if(operacion_actual==&enviar_sufijo) // Se ha completado la última operación de la tarea compleja
{
grabando_datos=false; // Se ha terminado la tarea compleja (grabar datos en el servidor)
}
else // No es la última operación de la tarea compleja, hay que seguir realizando otras operaciones
{
operacion_actual=proxima_operacion; // Ejecutar la siguiente operación
ENVIAR_OPERACION
}
}
}
}
else // Si la letra recibida no es igual que la correspondiente del mensaje
{
numero_caracter[numero_respuesta]=0; // Empezar a comparar desde la primera letra del mensaje
}
}
}
}
else // Si no hay que esperar datos desde el puerto serie
{
operacion_actual=(*(*operacion_actual).respuesta[0]).operacion;
ENVIAR_OPERACION
}
}
}
else
{
if((unsigned long)(millis()–cronometro_grabacion_temperatura)>INTERVALO_GRABACION_TEMPERATURA)
{
cronometro_grabacion_temperatura=millis();
dtostrf(media_temperaturas,4,2,valor_enviado); // snprintf(valor_enviado,9,”%+3.2f”,media_temperaturas); // printf y derivadas no funcionan en AVR
snprintf(texto_longitud_peticion,4,“%d”,longitud_peticion+strlen(valor_enviado));
grabando_datos=true;
operacion_actual=&verificar_conexion;
enviar_datos.peticion=valor_enviado;
enviar_cantidad.peticion=texto_longitud_peticion;
ENVIAR_OPERACION
}
}
}
|
Meskipun dalam contoh ini (dalam kedua implementasi) hal ini tidak masuk akal, untuk menggeneralisasi operasi agar dapat diterapkan pada kasus lain, perlu diperhatikan bahwa pengiriman data selalu mengulangi protokol yang sama: memberitahukan jumlah byte yang akan dikirim, tunggu indikator (>) dan kirim data.
Karena dalam contoh ini hanya digunakan sekali (keseluruhan permintaan dibuat dalam satu paket), hal ini tampaknya tidak terlalu berguna tetapi, secara umum, mungkin perlu melakukan beberapa pengiriman dalam operasi yang sama, termasuk kasus di mana pengiriman harus dilakukan. dikirimkan sejumlah besar data yang harus difragmentasi untuk menghindari meluapnya memori ESP8266.
Untuk menerapkan perilaku ini, dua elemen koneksi terakhir dapat digunakan sehingga setiap kali data dikirim, data tersebut diisi dengan nilai yang sesuai: dalam kasus pertama, jumlah byte yang dikirim dan yang kedua, ( bagian dari) permintaan untuk dikirimkan.
Untuk mengulangi penugasan dan pengiriman elemen berbeda yang harus ditransmisikan dapat disimpan dalam vektor. Vektor baru inilah yang akan menentukan akhir dari operasi kompleks dan bukan operasi terakhir seperti selama ini.
komentar 1