前々々回から始めた 「ESP32を使ってWi-Fiしてみる」の第4回目(完結編)です。
今回は コーディングと動作の確認を行います。
投稿時の開発環境を記しておきます。
PC:Windows10 OS
IDE: STM32CubeIDE Version1.6.0
Configurator: STM32CubeMX Version6.2.0
Board: STM32Nucleo-F401RE
Module: ESP32-DevKitC-VE
ATコマンド試験用 USBシリアルモジュール: AE-FT234X
プロジェクトにファイルを追加する
serial.h と serial.c を追加します。
serial.h
#ifndef INC_SERIAL_H_
#define INC_SERIAL_H_
#define BUF_SIZE 256
void uartBufferClear();
void uartPut(uint8_t c);
uint8_t uartGet();
uint8_t uartReadable();
uint8_t uartWritable();
#endif /* INC_SERIAL_H_ */
serial.c
#include // uintxx_t
#include "serial.h"
static uint16_t _rp, _wp;
static uint8_t _buf[BUF_SIZE];
void uartBufferClear()
{
_rp = _wp = 0;
memset(_buf, 0, BUF_SIZE);
}
void uartPut(uint8_t c)
{
_buf[_wp] = c;
_wp = (_wp + 1) % BUF_SIZE;
}
uint8_t uartGet()
{
uint8_t c = _buf[_rp];
_rp = (_rp + 1) % BUF_SIZE;
return c;
}
/***
uint8_t uartReadable()
{
return (_rp == _wp) ? 0 : 1;
}
***/
#include "cmsis_gcc.h"
uint8_t uartReadable()
{
uint8_t ret;
__disable_irq();
if (_rp == _wp)
{
ret = 0;
}
else
{
ret = 1;
}
__enable_irq();
return ret;
}
uint8_t uartWritable()
{
return ((_wp + 1) % BUF_SIZE) ? 0 : 1;
}
割り込みハンドラ関数に手を加える
stm32f4xx_it.c を編集します。
Project Explorer – F401WiFiUartLL – Core – Src から stm32f4xx_it.c をダブルクリックして開きます。
#include "serial.h"
#define PARITY_ENABLED 0
として USART1 の割り込みハンドラ関数に以下のコードを書きます。
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if (LL_USART_IsActiveFlag_ORE(USART1)) // Over run error
{
LL_USART_ReceiveData8(USART1); // 読み捨てる
}
else if (LL_USART_IsActiveFlag_FE(USART1)) // Framing error
{
LL_USART_ReceiveData8(USART1); // 読み捨てる
}
#ifdef PARITY_ENABLED
else if (LL_USART_IsActiveFlag_PE(USART1)) // Parity error
{
LL_USART_ReceiveData8(USART1); // 読み捨てる
}
#endif
else if (LL_USART_IsActiveFlag_RXNE(USART1))
{
uartPut((uint8_t)LL_USART_ReceiveData8(USART1));
}
/* USER CODE END USART1_IRQn 0 */
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
main.cを編集する
冗長ですけれど、、
uint8_t readStrings();
uint8_t comm();
void transmitStrings(USART_TypeDef *USARTx, const char* p);
uint8_t buffer[256];
uint8_t* wp = buffer;
uint8_t readStrings()
{
uint8_t c;
uint32_t tickstart = HAL_GetTick();
uint32_t timeout = 3000;
while (HAL_GetTick() - tickstart < timeout)
{
while (uartReadable())
{
c = uartGet();
if ('\r' == c)
{
if (wp == buffer) // \r\n\r\nの対策
continue;
*wp = '\0';
wp = buffer;
return 1;
}
else if ('\n' != c)
{
*wp++ = c;
if ((int)(wp-buffer) >= sizeof(buffer) - 1)
{
// error
wp = buffer;
return 0;
}
}
}
}
return 0;
}
uint8_t comm()
{
const char* str0 = "ATE0\r\n"; // Echo off
const char* str1 = "AT+CWMODE=1\r\n";
const char* str2 = "AT+CWJAP=\"Buffalo-X-XXXX\",\"YYYYYYYYYYYYY\"\r\n"; // "ID","password"
const char* str3 = "AT+CIPSTART=\"TCP\",\"192.168.11.4\",1024\r\n";
const char* str4 = "AT+CIPMODE=1\r\n";
const char* str5 = "AT+CIPSEND\r\n";
const char* str6 = "Hello AT Commands.\r\n";
const char* str7 = "+++";
const char* str8 = "AT+CWQAP\r\n";
transmitStrings(USART1, str0);
HAL_Delay(500);
if (readStrings())
{
if (!strncmp(buffer, "ATE0", 4))
{
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
;
}
else
{
return 0;
}
}
}
else if (!strncmp(buffer, "OK", 2))
{
;
}
else
{
return 0;
}
}
else // timeout
{
return 0;
}
transmitStrings(USART1, str1);
HAL_Delay(500);
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
;
}
else
{
return 0;
}
}
else // timeout
{
return 0;
}
transmitStrings(USART1, str2);
HAL_Delay(1000);
if (readStrings())
{
if (!strncmp(buffer, "WIFI DISCONNECT", 15))
{
HAL_Delay(1000);
if (readStrings())
{
if (!strncmp(buffer, "WIFI CONNECTED", 14))
{
HAL_Delay(500);
}
else
{
return 0;
}
}
else
{
return 0;
}
if (readStrings())
{
if (!strncmp(buffer, "WIFI GOT IP", 11))
{
HAL_Delay(500);
}
else
{
return 0;
}
}
else
{
return 0;
}
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
HAL_Delay(500);
}
else
{
return 0;
}
}
else
{
return 0;
}
}
else if (!strncmp(buffer, "WIFI CONNECTED", 14))
{
HAL_Delay(1000);
if (readStrings())
{
if (!strncmp(buffer, "WIFI GOT IP", 11))
{
HAL_Delay(1000);
}
else
{
return 0;
}
}
else
{
return 0;
}
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
HAL_Delay(500);
}
else
{
return 0;
}
}
else
{
return 0;
}
}
else if (!strncmp(buffer, "OK", 2))
{
;
}
}
transmitStrings(USART1, str3);
HAL_Delay(1000);
if (readStrings())
{
if (!strncmp(buffer, "CONNECT", 7))
{
HAL_Delay(500);
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
transmitStrings(USART1, str4);
HAL_Delay(500);
}
else
{
return 0;
}
}
}
else if (!strncmp(buffer, "OK", 2))
{
transmitStrings(USART1, str4);
HAL_Delay(500);
}
else
{
return 0;
}
}
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
transmitStrings(USART1, str5);
HAL_Delay(500);
}
else
{
return 0;
}
}
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
transmitStrings(USART1, str6);
HAL_Delay(500);
}
else
{
return 0;
}
}
transmitStrings(USART1, str7);
HAL_Delay(500);
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
;
}
else if (!strncmp(buffer, ">", 1))
{
;
}
else
{
return 0;
}
}
transmitStrings(USART1, str8);
if (readStrings())
{
if (!strncmp(buffer, "OK", 2))
{
;
}
else if (!strncmp(buffer, ">", 1))
{
;
}
else
{
return 0;
}
}
return 1; // success comm
}
void transmitStrings(USART_TypeDef *USARTx, const char* p)
{
uint8_t *data = (uint8_t*)p;
for (int i = 0; i < strlen(p); i++)
{
LL_USART_TransmitData8(USARTx, *data++);
while (!LL_USART_IsActiveFlag_TXE(USARTx))
{
;
}
}
}
main.c whileループの周辺
/* USER CODE BEGIN SysInit */
HAL_Delay(5000); // ESP32 起動時のメッセージを捨てる
uartBufferClear();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
uint8_t result = comm();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
ビルドしてエラーがないことを確認しておきます。
PCのサーバーを待ち受け状態にしておき、プログラムを動作させます。
comm()の str6 "Hello AT Commands." がサーバー側に届けば成功です。
str2 にはルーター等 AP(アクセスポイント)のID と パスワードを設定する必要があります。
str0 はエコーをoffにするコマンドです。
デフォルトでエコーがonになります。
受信電文の判定にエコーがあるとやっかいなので、エコーをoffにしています。
ESP32は、この設定を不揮発性メモリに記憶してくれないようなので電源を入れなおすたびに設定しなおす必要があります。
コードの概要
serial.h, serial.c は裏方さん。
割り込みハンドラで、データを受信していればバッファに1バイトずつ書き込みを行います。
いわゆるリングバッファで、サイズ256バイトのバッファにグルグルと書き込みます。
当然ながら1週分の書き込みが行われる前に読み出す必要があります。
ESP32のATコマンド用ファームは起動後、いくつかのメッセージを出力します。
その部分をバッファに取り込みたくないので、HAL_Delay(5000)しています。
comm()でコマンドを投げて応答を確認しながら次の手順に進んでいます。
transmitStrings()は電文を出力する関数です。
対話しながら次のシーケンスに進むので、送信に割り込みは使いませんでした。
readStrings()でバッファにデータがあれば、あるだけ取り出しを行います。
CR (\r) のところで電文の終わりとして \0 に置き換えて文字列としての区切りをつけています。
\r\n\r\n のように CR LF が続けて来ることがあるために以下の対策をしました。
if (wp == buffer) // \r\n\r\nの対策
contirnu;
comm()の部分は冗長になってしまいました。
簡単かつ実験的にやるならば
電文を送って、充分な時間待ち の繰り返しでも うまく動くかも知れません。
いかがでしたか?
皆さまの環境では、うまく動きましたか?
お疲れさまでした。