Arduino의 ESP8266 Wi-Fi 모듈에 대한 기본 작업
언제 에스프레소 시장에 첫 번째 모듈 출시 와이파이 통합된 ESP8266 과 펌웨어 AT 명령을 사용하여 이를 처리하기 위해 우리 사용자가 관심을 가졌던 것은 이를 어셈블리에 통합하는 것이었습니다. 마이크로 컨트롤러 문제는 (이전의) 어둠을 아는 것으로 축소되었습니다. ESP8266 AT 명령 테이블, 먹이가 필요하거나 ESP8266 펌웨어 업데이트.
그런 다음 프로그램을 프로그래밍하기 위한 대안이 빠르게 도착했습니다. ESP8266 및 모듈 구현 와이파이 다른 우려를 불러일으키는 매우 다른 형식: 선택할 ESP8266 Wi-Fi 모듈 다양한 안테나(외부 안테나 포함)의 범위 또는 어셈블리에 이러한 새 모듈의 물리적 통합에 따라 달라집니다.
물론 이러한 모든 변화로 인해 가장 기본적인 측면, 즉 기업의 가장 기본적인 관리가 강조되지 않았을 수도 있습니다. ESP8266 와이파이 모듈. 이기는 하지만 극성.es 이용안내를 확인하실 수 있습니다. ESP8266 그리고 일반적인 방식으로 작동을 설명하기 위한 일부 응용 프로그램이 있습니다. ESP8266 와이파이 모듈 특히 기사에서 AT 명령을 사용하여 ESP8266 wifi 모듈을 사용하여 Arduino에서 HTTP 쿼리를 작성하는 라이브러리, 독자의 인상은 사용자에게 도움이 되도록 몇 가지 기본 정보를 추가하는 것이 유용할 것이라고 제안합니다. ESP8266 자체 구현을 수행합니다.
작업을 위한 기본 작업에 대해 논의합니다. ESP8266 일반적인 솔루션을 제안하는 것은 매우 다른 여러 부분의 목표입니다. 기사 내용을 이해하는 데 도움이 되도록 다음 색인을 참고할 수 있습니다.
- 직렬 포트를 통해 컴퓨터에서 ESP8266 Wi-Fi 모듈을 제어하세요.
- esptool을 사용하여 펌웨어 업데이트
- 모듈에 주문 보내기
- ESP8266에서 데이터 수신
- 콘텐츠 내 텍스트를 검색하여 반응 분석
- 응답 수신을 위한 대기 시간을 제한하세요.
- 여러 AT 명령으로 정의된 복잡한 작업을 실행합니다.
직렬 포트를 통해 컴퓨터에서 ESP8266 Wi-Fi 모듈을 제어하세요.
접시에서 아두 이노 그리고 당신의 IDE 의 작동을 모니터링하는 것이 가능합니다. ESP8266 와이파이 모듈, 보내다 ESP8266 AT 명령 답을 확인하기는 하지만 컴퓨터에서 터미널 형태의 애플리케이션을 사용하는 것이 훨씬 더 편리합니다.
어떤 보드인지에 따라 아두 이노 사용하면 하나의 하드웨어 직렬 포트만 사용할 수 있으므로 전송 및 수신에 약간의 불편이 추가됩니다. 컴퓨터와 일부 마더보드의 직렬 통신 애플리케이션에서는 통신 속도를 변경하는 것이 훨씬 더 편안합니다. 아두 이노 (그리고 어떤 상황에서는) 더 빠른 직렬 통신 속도, 특히 최신 버전의 기본 속도인 115200보드를 지원하지 않습니다. 펌웨어.
약 모니터링을 위해 어떤 프로그램을 사용해야 할까요? ESP8266 직렬 포트를 사용하여, 필요와 선호도에 따라 선택할 수 있는 것이 많습니다. 요즘에는 클래식을 더 많이 사용하고 있어요 큐트컴 (위 스크린샷의 것) 특정 내용을 반복하는 것이 매우 편안하기 때문입니다. ESP8266 Wi-Fi 모듈 AT 주문 프로젝트 테스트 중.
직렬 콘솔로 작동하는 프로그램에 대한 일부 권장 사항은 이미 여기에 나와 있습니다. 예를 들어 이야기할 때 컴퓨터에서 UART 직렬 장치를 제어하기 위한 PuTTY. 퍼티뛰어난 애플리케이션일 뿐만 아니라 대부분의 데스크톱 운영 체제에서 사용할 수 있습니다. 게다가 다음과 같이 퍼티 직렬 포트와 콘솔을 모두 사용하여 콘솔 역할을 하는 데 사용할 수 있습니다. 인터넷 프로토콜 제품군(TCP/IP), 다음에서 작동하는 것을 포함하여 TLS는 구성하고 사용법에 익숙해지는 데 드는 (약간의) 시간을 보상하는 것 이상의 일반적인 도구가 됩니다.
직렬 통신 소프트웨어 외에도 연결 ESP8266 와이파이 모듈 항구로 USB 컴퓨터에도 변환기가 필요합니다 USB 시리즈 TTL. 소프트웨어의 경우와 마찬가지로 포트를 변환하는 데만 사용되는 여러 버전이 있습니다. USB 직렬 포트에서 TTL (1 유로로 얻을 수 있음) 다른 프로토콜을 에뮬레이션할 수 있는 프로토콜(예: SPI o I2C).
직렬 콘솔 역할을 하는 프로그램과 마찬가지로 하드웨어는 다음을 통해 컴퓨터와 통신합니다. USB 논리 회로(단지 ESP8266)는 마이크로 제어 응용 프로그램 개발자의 작업에서 일반적인 도구가 될 것이므로 가능한 한 빨리 도구 상자에 넣어서 작업할 가치가 있습니다. ESP8266 와이파이 모듈 얻을 수 있는 절호의 기회입니다.
변환기 USB a UART TTL 또한 이를 사용하는 회로의 동작을 모니터링하는 데에도 사용할 수 있습니다. ESP8266, 이를 위해 모니터링하려는 출력은 고속 다이오드(RX)를 사용하여 변환기의 데이터 입력(RX)에 직렬로 연결됩니다. 1N4148, 예를 들어)와 저항기(예를 들어 2K2)가 서로 병렬로 연결되어 있습니다. 이러한 설정은 하드웨어 직렬 스니퍼처럼 작동합니다.
위 이미지의 스니퍼는 확실히 초보적이지만(무엇보다도 버퍼)은 어셈블리의 작동을 모니터링하기에 충분합니다. 아두 이노 과 ESP8266.
이전 구성표에서 스니퍼를 제거하면 연결 방법을 보여주는 회로도 ESP8266 와이파이 모듈 접시에 아두 이노. 3V3에서 공급하는 것 외에도 통합의 리셋 핀과 활성화 핀을 하이 레벨(활성화)에 연결해야 합니다. 물론 한 쪽의 RX 핀은 다른 쪽의 TX에 연결되어야 합니다.
이전 다이어그램을 단순화하기 위해 플레이트가 표시되었습니다. 아두 이노 3V3에서 전원이 공급되고 직렬 포트의 전압도 3V3으로 가정됩니다. 당신이 사용하는 경우 마이크로 컨트롤러 손상되지 않도록 직렬 포트의 다른 신호 레벨(일반적으로 5V)이 필요합니다. ESP8266, 사용 레벨 변환기 아래 다이어그램과 같습니다. 이 회로는 많은 상용 기성 모듈 구현에서 자주 발견됩니다.
ESP8266 펌웨어 업데이트
라스 ESP8266 AT 명령, 종료, 모듈의 기본 속도... 버전에 따라 다릅니다. ESP8266 펌웨어. 모든 모듈의 버전이 동일하고 가능하다면 최신 버전인지 확인하는 것이 가장 좋습니다.
불행하게도 대부분의 ESP8266 Wi-Fi 모듈 모델 4Mbit만 있으므로 최신 버전을 설치할 수 없습니다. 설치할 수 있는 최신(공식) 펌웨어 버전 ESP8266 Wi-Fi 모듈 4Mbit(대부분)는 0.9.4이며 버전 0.2를 포함합니다. ESP8266 AT 명령.
요약하자면, 펌웨어를 업데이트하려면 다음이 필요합니다.
-
해당 펌웨어 버전을 다운로드하세요.. github의 Espressif 폴더에 있는 4Mbit 메모리 모듈의 최신(공식) 버전. 에서 에스프레소 웹사이트 최신 버전의 펌웨어를 다운로드할 수 있지만, 설치된 모듈에 충분한 메모리가 있는지 확인하는 것이 매우 중요합니다.
-
최신 버전의 펌웨어 설치 도구를 다운로드하세요.. 내가 가장 좋아하는 것은 특히 에 쓰여진 것 Python이므로 모든 플랫폼에서 작동합니다. 다운로드하는 것 외에도 다음을 사용하여 설치할 수도 있습니다.
pip install esptool
(opip2
opython -m pip
…). 물론, 에스프레소 자체 도구도 제공하지만 현재는 Windows에서만 사용할 수 있습니다. -
다운로드한 파일 준비; 액세스 가능한 폴더에 압축을 풀고 필요한 경우 도구를 실행 가능하게 만듭니다. 특히, 내 경우에는 그 이후로 GNU / 리눅스,와
chmod +x esptool
-
변환기를 사용하여 모듈을 컴퓨터에 연결하십시오. USB UART TTL 3V3에서 작동하는 것 또는 5V에서 작동하는 경우 레벨 변환기를 사용하십시오. 전원 외에도 TX를 변환기의 RX에 연결해야 합니다. USB UART TTL, RX에서 TX로, 낮은 레벨(GND)의 GPIO0 및 높은 레벨의 GPIO2(내 테스트에서는 낮은 레벨에서 연결하고 연결을 끊는 데 모두 작동했습니다). 모듈에 GPIO15 연결이 없는 경우(ESP-12에서 발생) 낮은 레벨에 연결해야 합니다. 일반적으로 작동 중에 높은 레벨에 있는 RESET은 연결되지 않은 상태로 두거나 저항기(예: 10K)를 통해 높은 레벨에 연결할 수 있습니다. 녹음을 시작하기 전에 장치를 연결하여 재설정해야 할 수도 있기 때문입니다. 낮은 수준으로.
모듈의 전원을 켜면 업데이트가 가능하지만, 연결 오류가 표시되면 재설정해야 합니다. 낮은 레벨에서 RESET을 잠시 연결한 후 업데이트 프로세스를 위해 연결하지 않고 그대로 유지합니다.
모듈에는 절반 암페어 소비 피크 (일부 사용자에 따르면 최대 600mA) 따라서 특히 펌웨어 업데이트의 경우 이러한 소비를 지원할 수 있는 전원 공급 장치를 사용하는 것이 중요합니다. -
도구를 실행하여 펌웨어 업데이트. 제 경우에는 3단계의 도구와 펌웨어 문서를 동일한 폴더에 저장했기 때문에 콘솔에서 실행합니다.
cd ~/Datos/firmwareESP8266
(도구와 펌웨어가 포함된 폴더로 변경)./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
속도를 설정합니다 ESP8266 (내 경우에는 115200 보드) 그리고--port
연결되는 직렬 포트(제 경우에는 에뮬레이트된 첫 번째 USB)입니다. 펌웨어를 구성하는 다양한 문서는 뒤쳐집니다.write_flash
주소 앞에는 업데이트 페이로드가 포함된 user1.bin 문서가 있습니다.
ESP8266 Wi-Fi 모듈에 명령 보내기
제어하려면 ESP8266 컴퓨터에서 시작해야 할 것입니다 앱 구성 ① 변환기가 연결된 포트를 선택하는 것으로 충분합니다. USB UART TTL, 같은 /dev/USB0
GNU/Linux 및 이와 유사한 것 또는 이와 유사한 것 COM6
Windows에서는 ② 속도를 선택합니다. ESP8266, 아마도 115200 보드, ③ 패리티나 핸드셰이크 없이 8개의 데이터 비트와 XNUMX개의 정지 비트를 설정하고, ④ 라인 끝을 설정합니다. 펌웨어, 거의 항상 CR+LF.
애플리케이션이 구성되면(또는 적절한 경우 저장 및 선택되면) 연결을 열어라 (위 예제의 스크린샷에서 각각 "open device" 및 "open"은 큐트컴 y 퍼티) 다음 주소로 주문을 보낼 수 있습니다. ESP8266.
에서 볼 수 있듯이 ESP8266 AT 명령 테이블, 활성화, 비활성화, 값 설정 및 참조 형식은 상당히 예측 가능하지만 일반적으로 모두 기억하는 것은 쉽지 않으며 참조하려면 준비해야 할 수도 있습니다.
방법 enviar AT 주문 al ESP8266 와이파이 모듈 부터 아두 이노 매우 간단합니다. ① 통신을 구성합니다. Serial.begin(115200);
(또는 여러 하드웨어 직렬 포트가 있는 보드의 경우 Serial1, Serial2…) 및 ② 형식을 사용하여 명령을 보냅니다. 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() { } |
위의 예는 메시지를 보내는 방법을 보여줍니다. ESP8266 Wi-Fi 모듈 AT 주문 부터 아두 이노. 이 경우에 설명되어 있습니다. AT+CWJAP
, 액세스 포인트에 연결하는 데 사용됩니다. 이 명령은 액세스 포인트 식별자(SSID) 및 키는 모두 따옴표로 묶어 객체가 됩니다. Srtring
이스케이프 코드(\"
). 주문을 완료하려면 다음을 사용하세요. \r\n
에 해당하는 CR
y LF
.
직렬 포트가 항상 식별되는 것은 아니라는 점을 기억하십시오. Serial
(특정 접시에서는 그럴 수 있습니다. Serial1
, Serial2
…) 사용된 포트 개체는 매크로에 할당하여 정의되었습니다. PUERTO_SERIE
. 사용된 보드 유형을 감지하면 직렬 포트 선택에 약간의 지능이 추가될 수 있습니다. 나중에 유형을 알아내는 방법에 대해 알아보겠습니다. 아두 이노. 나머지 정의는 반복(및 실수)을 방지하고 변경하기 쉽도록 상수 값에 "이름을 지정"할 수 있는 일반적인 정의입니다.
위의 예는 ESP8266 와이파이 모듈 표시된 액세스 포인트에 연결했지만 이전에 이미 연결되었습니까? 연결이 작동했나요? 이를 알려면 우리는 '듣기'가 필요합니다. ESP8266
ESP8266 Wi-Fi 모듈에서 데이터 수신
위에서 설명한 데이터 스니퍼를 컴퓨터에 연결하면 무엇을 볼 수 있습니까? 아두 이노 에 보냈습니다 ESP8266 그리고 그의 반응. 에서 읽으려면 아두 이노 감지하는 데 필요한 정보를 처리합니다. Serial.available()
데이터가 도착했는지, 그렇다면 다음과 같이 로드하세요. Serial.read()
. 다음 예에서는 응답을 읽는 방법을 보여줍니다. AT+CWJAP?
, 액세스 포인트에 연결되어 있는지 보고합니다.
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(); } } |
접시에 담긴 것처럼 아두 이노 우노 (및 기타) 직렬 모니터를 열면 프로그램이 재설정되며 직렬 콘솔에서 볼 수 있습니다. 아두 이노 당신이 보내는 정보 ESP8266 아래 이미지의 스크린샷과 같이.
ESP8266 Wi-Fi 모듈에서 보낸 응답 분석
우리는 도달한 정보를 읽는 방법을 이미 살펴보았습니다. 아두 이노 ~에서 ESP8266. 당신이 처리해야 할 문제는 그것이 언제 도착하기 시작할지, 도착하는 데 얼마나 걸릴지, 얼마나 걸릴지 알 수 없다는 것입니다... 그리고 응답을 기다리는 것은 그다지 효율적이지 않습니다. ESP8266 허락하지 않고 받아들인다. 마이크로 컨트롤러 그동안 다른 작업을 수행하세요.
이러한 상황을 관리하는 간단한 방법은 다음과 같습니다. 구체적인 답변을 찾기 위해 수신된 데이터를 반복합니다. 예를 들어 수신된 텍스트에서 검색을 계속할지 여부와 텍스트에서 도착한 정보를 기반으로 수행해야 하는 작업을 결정하는 표시기(플래그 또는 부울 변수)를 활성화합니다. ESP8266. 응답이 도착하는 동안 마이크로 컨트롤러 다른 업무에 전념할 수 있다, 예를 들어 센서로부터 데이터를 수신하고 처리합니다.
ESP8266에서 받은 정보에서 텍스트를 검색합니다.
다음에서 나오는 텍스트를 검색하려면 ESP8266 할 수있다 받은 각 편지를 찾고 있는 메시지에 해당하는 편지와 비교하세요.. 비교할 문자를 가리키는 카운터(또는 포인터)를 사용해야 합니다. 만약에 캐릭터가 도착했다면 ESP8266 메시지에서 검사 중인 것과 동일하면 카운터가 진행되고, 다르면 초기화됩니다.
끝에 도달했음을 알기 위해 검색된 메시지의 다음 문자가 참조되며 이는 0이 됩니다(\0
) 또는 메시지의 길이는 카운터와 비교하여 비교가 완료되었는지 확인하기 위해 저장됩니다. ESP8266 와이파이 모듈 원하는 메시지를 보냈습니다.
다음 예에서는 다음 명령을 사용합니다. AT+CWLAP
그러면 액세스 포인트 목록이 반환되고 그 안에서 "wifi polaridad.es"라는 액세스 포인트가 검색됩니다. 마지막 문자가 0인지 확인하기로 선택했지만 버퍼 검색된 텍스트만 저장하고 그 길이를 알 수 있으며, 해당 개수의 올바른 문자가 수신되었는지 확인할 수도 있습니다. 와 LED 핀 2에 연결하면 예상한 텍스트가 발견되었다고 보고됩니다.
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 } } } } |
이전 예제의 코드에서는 다음을 수행하는 방법도 볼 수 있습니다. 보드 유형에 따라 직렬 포트를 선택하십시오. 아두 이노 사용된. 이 예에서는 프로젝트에 세 가지 유형의 보드가 있다고 가정합니다. 아두 이노 우노, 하나 아두 이노 메가 2560 및 아두 이노 레오나르도. 당신이 아두 이노 우노 그것은 사용될 것이다 Serial
그렇지 않으면 Serial1
.
접시로 작업하면 아두 이노 레오나르도 동일한 방법을 사용하여 프로그램을 중지하고 콘솔(연결된 직렬 포트)을 기다릴 수 있습니다. Serial
) 사용할 수 있습니다.
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 |
ESP8266 응답에서 여러 텍스트 찾기
이전 예의 코드는 사용자가 보낸 정보에서 텍스트를 검색하는 데 사용됩니다. ESP8266 그러나 응답에는 작업에 따라 다른 정보가 포함될 수 있습니다. 다음 예의 간단한 사례로 시작하기 위해 MCU ESP8266 es OK
작업이 올바르게 수행되고 ERROR
그렇지 않으면 주문과 마찬가지로 AT+CWJAP?
, 이는 다음과 같은지 확인하는 역할을 합니다. 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 | #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 } } } } } |
여러 개의 가능한 메시지와 일치하는 항목을 검색하는 동일한 방법의 새로운 구현을 통해 수신된 응답에 따라 다양한 작업 중에서 선택할 수 있습니다. ESP8266, 간단히 LED 동.
응답을 받는 데 걸리는 시간을 제한하세요.
현재까지 관련 문제에 대한 언급은 없습니다: 작업 실패를 고려하기 전 최대 대기 시간(타임아웃). 어떠한 이유로든 해당 회사와 연결이 된 경우 ESP8266 와이파이 모듈, 액세스 포인트가 있는 모듈, 인터넷이 있는 액세스 포인트 또는 예를 들어 가상의 서버를 사용할 수 없는 경우 프로그램이 한 지점에서 무기한 대기로 차단될 수 있으므로 이러한 상황에 대한 응답을 명시해야 합니다. 최대 대기 시간은 전체 애플리케이션에 대해 구성할 수 있습니다. 일반적으로 이 경우 더 "관대"하거나 각 작업에 대해 개별 대기 시간을 프로그래밍할 수 있습니다.
(적어도) 특정 시간 간격이 지났는지 확인하려면 일반적으로 계정이 시작된 순간의 '시간'을 현재 '시간'에서 빼고 그 차이가 원하는 한도보다 큰지 확인합니다.. 이 "시간"은 실시간일 필요는 없으며 일반적으로 해당 시간 이후 경과된 간격에 해당합니다. MCU 시간 계산을 시작하십시오. 흥미로운 것은 절대 시간이 아니라 경과 시간이기 때문에 이는 프로그램에 영향을 미치지 않습니다.
일반적으로 특정 간격이 경과했는지 확인하려면 다음 유형의 표현식이 사용됩니다.
1 | (unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo |
변수 milisegundos_al_empezar
다음의 값을 포함합니다. millis()
실행 중 특정 순간의 시간이 측정되므로 이름이 "크로노미터"라는 단어를 나타내는 것은 이상한 일이 아닙니다. 변수 intervalo_de_tiempo
이전 표현식을 true로 만드는 최대 밀리초 수를 포함합니다. 즉, 시간 초과를 나타냅니다. 이는 일반적으로 상수(또는 매크로)이며 이전 경우와 마찬가지로 이름에 "TIMEOUT"이라는 단어가 자주 표시됩니다. 매우 짧은 간격으로 작업하는 경우 다음을 사용할 수 있습니다. micros()
대신 millis()
(밀리초 대신 마이크로초) 비록 덜 일반적이고 덜 정확합니다.
1 | (unsigned long)(millis()–cronometro)>TIMEOUT |
긴 정수 아두 이노 (unsigned long
)은 4바이트(32비트)를 차지하므로 표현할 수 있는 가장 큰 값은 4294967295(2에서 시작하므로 32의 XNUMX 빼기 XNUMX승)입니다. 접시에 아두 이노 지속적으로 실행되는 동안 밀리초 카운터는 대략 50일마다 재설정(XNUMX으로 돌아감)됩니다. 부호 없는 데이터 유형을 빼는 경우 동일한 동작이 재현되므로(카운터 뒤집기) 시간 제한을 무기한으로 제어할 수 있습니다.
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; } } } |
위의 코드는 시간 초과 제한의 매우 기본적인 구현 앞의 예와 관련하여 표시된 행을 통합합니다. 타임아웃 검증은 서버로부터 도착한 데이터를 처리한 후 수행되므로 ESP8266 와이파이 모듈, 지정된 대기 시간보다 수신이 오래 걸리더라도 작업이 성공한 것으로 간주될 수 있습니다.
여러 AT 명령으로 정의된 복잡한 작업을 실행합니다.
이를 활용하는 응용 프로그램의 목적에 대한 예제 참조가 있습니다. ESP8266 와이파이 모듈, 그럴 것 같아 웹 서비스를 통해 액세스되는 데이터베이스에 정보를 저장합니다. 온도를 추적하기 위해. 다음 코드는 일정 시간 간격마다 아날로그 입력에 연결된 센서를 읽고 평균값을 계산한 후 더 긴 시간 간격 후에 이를 웹 서버로 보냅니다(스타일 만약 IoT)를 통해 청원서 HTTP (포스트, 받기…).
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”); } } |
이 온도 기록 예에서는 웹 서버가 5분마다 액세스됩니다. 가용성이 특별히 높지는 않지만 제안이 효과가 있을 것으로 예상됩니다. 그러나 더 높은 녹음 빈도가 필요한 경우 다른 리소스(예: 데이터 버퍼 전송을 기다리는 중, 서버가 참석할 수 있을 때 여러 개를 보내고 사용할 수 없을 때를 위해 저장합니다. 데이터를 기록해야 하는 빈도가 훨씬 더 높을 경우, 다른 유형의 프로토콜이 대안으로 제안되어야 합니다. HTTP 아니면 교체해도 된다 TCP 로 UDP 일부 데이터를 잃어버리더라도 대부분의 데이터를 필요한 속도로 전송할 수 있습니다.
온도를 전송하기 위해 수행되는 작업을 구성하는 작업은 다음과 같습니다.
- Wi-Fi 모듈 재설정
- 현재 액세스 포인트에서 연결을 끊습니다(기본 연결이 있는 경우).
- 설정을 지정합니다. 예시에서는 연결 모드(단순)와 Wi-Fi 통신에서의 역할(스테이션)을 구성해야 한다고 가정합니다.
- 액세스 포인트에 연결
- 연결이 올바른지 확인합니다. (실제로는 진입점입니다.) 연결이 없으면 처음부터 프로세스를 시작합니다.
- 서버에 연결
- 요청 보내기 HTTP 저장될 데이터와 함께
작업 순서는 정확히 이와 같을 필요는 없으며(작업은 그렇더라도) 각 단계에는 여러 가지가 필요할 수 있습니다. ESP8266 AT 명령예를 들어 위에 나열된 구성에는 다음 두 가지가 필요합니다. AT+CIPMUX=0
y AT+CWMODE=1
.
ESP8266의 작업을 나타내는 데이터 구조
이전 예에서는 매우 기본적인 방식이지만 문제에 대한 일반적인 솔루션이 이미 제안되었습니다. 가능한 응답과 각 경우에 취해야 하는 조치를 저장하는 데이터 구조를 사용합니다.; 작업을 보내고, 응답을 기다리고, 응답이 의미하는 바에 따라 진행합니다. 각각의 복잡한 작업에는 여러 가지가 필요하기 때문에 ESP8266 AT 명령, 데이터 구조는 작업을 후속 또는 이전의 다른 작업과 연결해야 하며, 이는 각 경우의 응답에 따라 수행되어야 합니다. ESP8266.
이전 예에서는 메시지가 응답 내에서 검색되었습니다. ESP8266 성공 또는 오류로 해석되었습니다. 수신된 모든 텍스트에 대한 수신(및 분석) 외에도 일반적인 최소값을 얻으려면 메시지 완성에도 참석하는 것이 좋습니다. 즉, 가용성에 대한 것입니다. ESP8266 와이파이 모듈 새로운 주문을 받기 위해. 이런 식으로 우리가 호출할 수 있는 상태(예: "wifi available")로의 변경은 액세스 포인트의 이름을 수신하고 텍스트를 수신하는 것일 수 있습니다. ERROR
또는 텍스트 OK
의미합니다 ESP8266 응답을 마쳤으니 이제 다음 응답을 보낼 수 있습니다 ESP8266에 대한 AT 명령.
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; |
위의 코드는 벡터(operacion
) 전체 작업을 구성하는 연속 작업의 텍스트를 저장합니다. 2차원 배열이 사용됩니다(mensaje
) 세 가지 응답을 분석합니다. 위에서 설명한 것처럼 정답 또는 오답을 나타내는 메시지 외에 응답의 끝을 나타내는 메시지도 찾아보아야 합니다. 모든 작업에 가능한 답변 수가 동일한 것은 아닙니다. 응답 수가 적은 경우 분석에서 가능한 가장 적은 수의 주기를 소비하는 빈 메시지를 사용할 수 있습니다(그래도 이것이 가장 최적의 방법은 아닙니다). 논리적으로, 비록 그것이 모두 가능하지는 않더라도 모든 작동 가능성을 포함하려면 추구되는 최소 응답 수(예에서는 3개)가 필요합니다.
가능한 답에 관해 이야기할 때, 이 예는 임의의 형식으로 데이터를 수신하는 데 그다지 유용하지 않다는 것을 이미 알 수 있습니다. ESP8266 와이파이 모듈, 그러나 문제는 다음과 함께 사용하는 맥락에서 마이크로 컨트롤러 보통 일이 아니다. 가장 일반적인 방법은 연결된 센서에서 수집한 데이터를 전송하거나 센서가 제어하는 액추에이터로 수행할 작업에 대한 정보를 받는 것입니다. 아주 잘 예측할 수 있는 매우 귀중한 정보입니다.
이전 데이터 구조에서는 분석되는 가능한 응답을 표현하기 위해 했던 것처럼, 각 경우에 수행해야 하는 연산을 결정하기 위해 2차원 행렬도 사용됩니다(siguiente_operacion
). 구체적으로 우리는 세 가지 유형의 메시지에 응답하기로 선택했습니다. ① 임의의 텍스트(LITERAL
) Wi-Fi 액세스 포인트와 서버에 연결되어 있는지 확인하기 위해, ② 프로세스 오류를 감지하기 위한 텍스트(FALLO
) 및 ③ 작업이 성공적으로 완료되었음을 나타내는 텍스트(ACIERTO
).
마지막으로, 포기하기 전 최대 대기 시간을 설정하는 벡터가 두 개 더 있습니다(timeout
)을 지정하고 (configuracion
) 응답을 기다리지 않고 작업이 종료되는 경우(ESPERAR_RESPUESTA
) 및 통신 종료를 나타내는 메시지. 메모리를 절약할 수 있는 방법의 예를 설명하기 위한 이 마지막 벡터는 구성 바이트의 비트와 함께 작동하여 다양한 상태를 나타냅니다.
첫 번째 ESP8266 AT 명령 데이터 구조에서는 항상 성공 또는 오류 메시지가 될 수 있는 응답을 기대합니다. 에러가 발생하면 모듈을 재시작하고 다시 시작하며, 동작이 정상이라는 메시지가 나오면 다음 모듈로 넘어갑니다.
서버에 연결되면 패턴이 변경됩니다. 이 경우에는 ①전송할 데이터 패킷의 길이를 전송하고 ②요청을 작성해야 합니다. HTTP 고정된 텍스트와 서버에 저장하기 위해 전송된 (온도의) 값으로 구성됩니다. 이 데이터의 준비는 각 배송마다 수행되며 이를 두 개(길이 알림) 또는 세 개(요청 보내기)로 나누어야 합니다. HTTP)에 ESP8266 AT 주문. 작업이 분할된 마지막 부분만 응답을 기다립니다.
이 경우 문제 없이 작동하지만(모듈이 사용 중이라는 경고) 데이터 길이가 더 커지면 데이터 블록을 더 작은 조각으로 나누어야 하며 대기를 구현해야 할 수도 있습니다. 모듈이 데이터를 채우지 않고 데이터를 보낼 시간을 주기 위해 온도 판독이 완료되었습니다. 버퍼.
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(); |
이전에 이미 설명한 다른 매크로와 함께 위의 예제 코드는 응답을 기다릴지 여부를 지정하는 다양한 상태를 정의하는 방법과 해당되는 경우 응답이 완료되었음을 나타내는 메시지를 보여줍니다.
코드의 다른 지점에서와 같이 작업이 전송됩니다(평균 온도를 전송해야 할 때, 작업의 대기 시간이 초과된 경우, 현재 작업이 성공적으로 완료되었을 때...). 그러나 이를 수행하는 방법은 다음과 같습니다. 전 세계적으로 확립되어 매크로로 정의되었습니다. ENVIAR_OPERACION
배송과 관련된 단계를 그룹화합니다.
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(); |
다음은 예제의 메인 프로그램 코드이다. 가장 외부적인 업무는 온도를 샘플링하여 평균을 계산하는 일을 담당하며 일정 시간마다 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 | #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 } } } |
논리적으로 이전 코드에서 여러 가지 최적화 작업을 수행할 수 있지만 이는 어떻게 ESP8266 일반적인 방식에서는 일부 측면에만 집중할 가치가 있으며 첫 번째는 데이터 구조입니다. 논리적인 것은 맞는 것 같다. 프로그래밍 언어 데이터 구조를 사용합니다(struct
) 처리 중인 정보를 나타냅니다.: ESP8266 AT 명령 그리고 분석된 메시지.
구조(struct
) 예제 배열(이를 기반으로 함) 대신 데이터를 저장하는 것은 간단하며 더 우아한 코드가 생성될 수 있지만 결과가 향상된다는 의미는 아닙니다. 의 사용이 제시하는 진정한 대안 struct
아래 설명된 대로 구현하는 것입니다. "내부" 데이터를 포함하는 구조의 가변 길이 그들이 언급하는 것입니다. 예를 들어 이러한 방식으로 작업에서 분석할 고정된 수의 응답을 가질 필요는 없습니다.
이 접근 방식은 솔루션을 구현하는 가장 좋은 방법임을 시사하지만 단점은 이 방법이 필요하다는 것입니다. 동적 메모리 할당을 사용합니다. 이는 위험한 작업입니다. 마이크로 컨트롤러 런타임에 얼마나 많은 메모리가 사용될지 신중하게 측정해야 합니다., 컴파일러는 이에 대해 거의 경고할 수 없으며 프로그램 실행에 치명적인 결과를 가져오는 메모리(또는 스택)를 소진할 가능성이 있기 때문입니다.
코드를 최적화하는 과정에서 많은 양의 텍스트를 사용하는 이러한 유형의 프로그램에서 메모리 공간을 절약할 수 있다 SRAM 프로그램 메모리에 텍스트 문자열 저장 (플래시) 매크로와 함께 F()
. 다음 스크린샷에서는 일반적인 텍스트 사용과 매크로 사용을 통한 다양한 프로그램 및 동적 메모리 분포를 볼 수 있습니다. F()
.
로부터 도착한 정보에 따라 실행되는 조치에 대하여 ESP8266 와이파이 모듈, 코드에서 메시지를 확인하고 수신된 내용에 따라 둘 중 하나를 수행하는 대신 이 데이터 구조에 저장할 수 있습니다. 상태 표시기 대신 각 작업을 수행하는 함수에 대한 포인터 (플래그)는 애플리케이션이 예를 들어 메인 루프 내에서 관리를 담당하는 특정 상태를 경고합니다.
다음은 요청 데이터를 저장하는 구조의 예입니다. ESP8266 (데이터 유형 operacion_esp8266
) 및 해당 응답(데이터 유형 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; |
작업을 나타내는 구조( ESP8266 와이파이 모듈)은 응답이 정의되는 구조와 연산의 구조에 대한 응답의 구조를 말하며, 둘 다 먼저 선언해야합니다, 새 데이터 유형을 정의한 다음 해당 내용을 정의합니다.
이전 예제에서는 이를 포함하는 프로그램이 다음을 사용하도록 선택했다고 간주합니다. 상태 표시기, 이는 해당 값으로 표시된 하나 이상의 작업을 수행하는 코드에서 액세스할 수 있는 변수에 해당해야 합니다. 의 응답에 있는 경우 ESP8266 특정 텍스트를 분석할 때 상태는 해당 응답의 구조를 나타내는 값을 취합니다.
앞서 말했듯이 상태 표시기를 대체하거나 보완하는 또 다른 대안은 다음과 같습니다. 참조 구조에 함수 저장 (포인터)의 응답에서 특정 텍스트를 발견할 때 호출됩니다. 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; |
이전 예에서는 응답을 처리하는 데 사용되는 데이터 구조에 추가되었습니다. ESP8266 와이파이 모듈 유형의 데이터를 반환하는 (가정) 함수에 대한 포인터 float
(아날로그 판독의 가중치 값일 수 있음) 2바이트가 인수로 제공됩니다(2개 unsigned char
이는 아날로그 입력을 읽는 핀일 수 있으며 가상 통합의 활성화를 활성화하는 핀일 수 있습니다.
개발 중 MCU, 대규모 시스템의 개발 스타일에서 발생하는 것과는 달리 어셈블리를 제어하는 응용 프로그램의 (전역) 동작을 정의할 때 전역 변수를 사용하는 것은 그리 드문 일이 아니므로 이러한 유형의 정의를 찾는 것은 특별히 드물지 않습니다. 매개변수가 없고 값을 반환하지 않는 함수로, 다음과 같습니다. void (*accion)();
이러한 방식으로 데이터를 표현하는 경우 다음을 사용합니다. struct
가변 길이 데이터의 경우 메모리를 동적으로 할당해야 합니다. malloc()
(o new()
, 객체를 사용하는 경우), 할당된 메모리 양을 매개 변수로 사용하고 예약된 메모리 영역의 시작 부분에 대한 포인터를 반환합니다. 와 함께 sizeof()
저장된 유형에 사용된 요소 수를 곱하면 필요한 메모리 양을 얻을 수 있습니다. 이를 사용하거나 사용하지 않은 예는 아래 스크린샷에서 볼 수 있습니다. malloc()
; 첫 번째 경우에는 프로그램이 사용하는 메모리에 주의하세요. 이 함수가 포함된 라이브러리를 로드해야 합니다.
에 대한 작업인 경우 ESP8266 와이파이 모듈 프로그램 실행 전반에 걸쳐 달라질 수 있으므로 사용되지 않는 메모리를 해제해야 합니다. free()
(o delete()
, 객체인 경우). 컴파일러(GCC)는 메모리 분할을 피하기 위해 프로그램을 최적화하지만, 확실히 성능은 정적으로 할당된 메모리를 사용하여 작업하는 것만큼 최적이 아닐 것입니다.
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 } } } |
이 예(두 구현 모두)에서는 별 의미가 없지만 다른 경우에 적용할 수 있도록 작업을 일반화하려면 다음 사항에 유의해야 합니다. 데이터 전송은 항상 동일한 프로토콜을 반복합니다. 전송할 바이트 수를 알리고 표시기(>)를 기다린 후 데이터를 보냅니다..
이 예에서는 한 번만 사용되므로(전체 요청이 하나의 패킷에서 이루어짐) 그다지 유용해 보이지는 않지만 일반적으로 동일한 작업에서 여러 번의 전송을 수행해야 할 수도 있습니다. 메모리 오버플로를 방지하기 위해 조각화해야 하는 상당한 양의 데이터가 전송됩니다. ESP8266.
이 동작을 구현하기 위해 연결의 마지막 두 요소를 사용하여 데이터가 전송될 때마다 데이터가 해당 값으로 채워지도록 할 수 있습니다. 첫 번째 경우에는 전송된 바이트 수이고 두 번째 경우에는 ( ) 요청의 일부가 전송됩니다.
전송되어야 하는 다양한 요소의 할당 및 전송을 반복하려면 벡터에 저장할 수 있습니다. 이 새로운 벡터는 지금까지의 마지막 작업이 아닌 복잡한 작업의 끝을 결정하는 벡터가 될 것입니다.
1 코멘트