【STM32F413H Discovery Kit 试用】HTTP 服务器
介绍了使用 STM32F413H Discovery Kit 开发板 WiFi 模组实现 HTTP 网页服务器的搭建。
简介
超文本传输协议(Hyper Text Transfer Protocol,HTTP)是标准的应用层协议,用作服务器和客户端之间的请求响应协议,通常运行在 TCP 之上。广泛应用于物联网(IoT)与嵌入式开发,可以实现设备端的远程网络控制、传感器数据采集等。
日常使用浏览器打开的网页使用的就是HTTP 协议。这里基于开发板和 WiFi 模组建立 HTTP 网络服务器,并通过浏览器访问该服务器。
工程测试
使用 STM32CubeIDE 软件打开测试工程 STM32F413\STM32Cube_FW_F4_V1.28.0\Projects\STM32F413H-Discovery\Applications\WIFI\WiFi_HTTP_Server
该工程可利用板载 WiFi 模组实现 HTTP 网页服务器的构建。
打开 Application
- User
- main.c
文件,输入关键信息后构建工程并运行。
代码
输入可检索到的 WiFi 信息,包括 SSID 和 PASSWORD;
#include "main.h"
#define SSID "xxx"
#define PASSWORD "xxxxxx"
#define LCD_USE
#define PORT 80
typedef enum
{
WS_IDLE = 0,
WS_CONNECTED,
WS_DISCONNECTED,
WS_ERROR,
} WebServerState_t;
static uint8_t http[1024];
static uint8_t resp[1024];
uint16_t respLen;
uint8_t IP_Addr[4];
uint8_t MAC_Addr[6];
int32_t Socket = -1;
static WebServerState_t State = WS_ERROR;
static ADC_HandleTypeDef AdcHandle;
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
static WIFI_Status_t SendWebPage(uint8_t ledIsOn, uint8_t temperature);
static void WebServerProcess(void);
static uint32_t TEMP_SENSOR_Init(void);
static uint32_t TEMP_SENSOR_GetValue(void);
int main(void)
{
#if defined (LCD_USE)
uint8_t modulestr[20] = {0};
#endif /* LCD_USE */
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Configure LED3 and LED4 */
BSP_LED_Init(LED3);
BSP_LED_Init(LED4);
/*Initialize Temperature sensor */
TEMP_SENSOR_Init();
/* WIFI Web Server demonstration */
#if defined (LCD_USE)
BSP_LCD_InitEx(LCD_ORIENTATION_LANDSCAPE_ROT180);
BSP_LCD_DisplayOn();
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_SetBackColor(LCD_COLOR_BLUE);
BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
BSP_LCD_FillRect(0, 0, BSP_LCD_GetXSize(), (BSP_LCD_GetYSize() -200));
BSP_LCD_SetFont(&Font16);
BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
BSP_LCD_DisplayStringAt(10, 10, (uint8_t *)"WIFI Web", CENTER_MODE );
BSP_LCD_DisplayStringAt(10, 23, (uint8_t *)"Server demonstration", CENTER_MODE );
#endif /* LCD_USE */
/*Initialize and use WIFI module */
if(WIFI_Init() == WIFI_STATUS_OK)
{
#if defined (LCD_USE)
BSP_LCD_SetBackColor(LCD_COLOR_WHITE);
BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
BSP_LCD_DisplayStringAtLine(4, (uint8_t *)"ES-WIFI Initialized.");
#endif /* LCD_USE */
if(WIFI_GetMAC_Address(MAC_Addr) == WIFI_STATUS_OK)
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_DisplayStringAtLine(6, (uint8_t *)"es-wifi MAC Address:");
sprintf((char*)modulestr,"%X:%X:%X:%X:%X:%X.", MAC_Addr[0],
MAC_Addr[1],
MAC_Addr[2],
MAC_Addr[3],
MAC_Addr[4],
MAC_Addr[5]);
BSP_LCD_DisplayStringAtLine(7, (uint8_t *) modulestr);
#endif /* LCD_USE */
}
else
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(6, (uint8_t *)"CANNOT get MAC address");
#endif /* LCD_USE */
BSP_LED_On(LED4);
}
if( WIFI_Connect(SSID, PASSWORD, WIFI_ECN_WPA2_PSK) == WIFI_STATUS_OK)
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
BSP_LCD_DisplayStringAtLine(9, (uint8_t *)"es-wifi connected");
#endif /* LCD_USE */
if(WIFI_GetIP_Address(IP_Addr) == WIFI_STATUS_OK)
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_DisplayStringAtLine(10, (uint8_t *)"es-wifi IP Address :");
sprintf((char*)modulestr,"%d.%d.%d.%d", IP_Addr[0],
IP_Addr[1],
IP_Addr[2],
IP_Addr[3]);
BSP_LCD_DisplayStringAtLine(11, (uint8_t *) modulestr);
BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
BSP_LCD_DisplayStringAtLine(13, (uint8_t *)"Start HTTP Server... ");
BSP_LCD_DisplayStringAtLine(14, (uint8_t *)"Wait for connection... ");
#endif /* LCD_USE */
State = WS_IDLE;
}
else
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(12, (uint8_t *)"es-wifi CANNOT get IP address");
#endif /* LCD_USE */
BSP_LED_On(LED4);
}
}
else
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(11, (uint8_t *)"es-wifi NOT connected\n");
#endif /* LCD_USE */
BSP_LED_On(LED4);
}
}
else
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(4, (uint8_t *)"WIFI cannot be initialized.\n");
#endif /* LCD_USE */
BSP_LED_On(LED4);
}
while(1)
{
WebServerProcess ();
}
}
static void WebServerProcess(void)
{
uint8_t LedState = 0, temp;
switch(State)
{
case WS_IDLE:
Socket = 0;
WIFI_StartServer(Socket, WIFI_TCP_PROTOCOL, "", PORT);
if(Socket != -1)
{
#if defined (LCD_USE)
BSP_LCD_ClearStringLine(14);
BSP_LCD_DisplayStringAtLine(13, (uint8_t *)"HTTP Server Started");
#endif /* LCD_USE */
State = WS_CONNECTED;
}
else
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(13, (uint8_t *)"ERROR : Connection cannot be established");
#endif /* LCD_USE */
State = WS_ERROR;
}
break;
case WS_CONNECTED:
WIFI_ReceiveData(Socket, resp, 1200, &respLen);
if( respLen > 0)
{
if(strstr((char *)resp, "GET")) /* GET: put web page */
{
temp = TEMP_SENSOR_GetValue();
if(SendWebPage(LedState, temp) != WIFI_STATUS_OK)
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(14, (uint8_t *)"ERROR : Cannot send web page");
#endif /* LCD_USE */
State = WS_ERROR;
}
}
else if(strstr((char *)resp, "POST"))/* POST: received info */
{
if(strstr((char *)resp, "radio"))
{
if(strstr((char *)resp, "radio=0"))
{
LedState = 0;
BSP_LED_Off(LED3);
}
else if(strstr((char *)resp, "radio=1"))
{
LedState = 1;
BSP_LED_On(LED3);
}
temp = TEMP_SENSOR_GetValue();
if(SendWebPage(LedState, temp) != WIFI_STATUS_OK)
{
#if defined (LCD_USE)
BSP_LCD_SetTextColor(LCD_COLOR_RED);
BSP_LCD_DisplayStringAtLine(14, (uint8_t *)"ERROR : Cannot send web page");
#endif /* LCD_USE */
State = WS_ERROR;
}
}
}
}
if(WIFI_StopServer(Socket) == WIFI_STATUS_OK)
{
WIFI_StartServer(Socket, WIFI_TCP_PROTOCOL, "", PORT);
}
else
{
State = WS_ERROR;
}
break;
case WS_ERROR:
default:
break;
}
}
static WIFI_Status_t SendWebPage(uint8_t ledIsOn, uint8_t temperature)
{
uint8_t temp[50];
uint16_t SentDataLength;
WIFI_Status_t ret;
/* construct web page content */
strcpy((char *)http, (char *)"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n");
strcat((char *)http, (char *)"<html>\r\n<body>\r\n");
strcat((char *)http, (char *)"<title>STM32 Web Server</title>\r\n");
strcat((char *)http, (char *)"<h2>InventekSys : Web Server using Es-Wifi with STM32</h2>\r\n");
strcat((char *)http, (char *)"<br /><hr>\r\n");
strcat((char *)http, (char *)"<p><form method=\"POST\"><strong>Temp: <input type=\"text\" size=2 value=\"");
sprintf((char *)temp, "%d", temperature);
strcat((char *)http, (char *)temp);
strcat((char *)http, (char *)"\"> <sup>O</sup>C");
if (ledIsOn)
{
strcat((char *)http, (char *)"<p><input type=\"radio\" name=\"radio\" value=\"0\" >LED off");
strcat((char *)http, (char *)"<br><input type=\"radio\" name=\"radio\" value=\"1\" checked>LED on");
}
else
{
strcat((char *)http, (char *)"<p><input type=\"radio\" name=\"radio\" value=\"0\" checked>LED off");
strcat((char *)http, (char *)"<br><input type=\"radio\" name=\"radio\" value=\"1\" >LED on");
}
strcat((char *)http, (char *)"</strong><p><input type=\"submit\"></form></span>");
strcat((char *)http, (char *)"</body>\r\n</html>\r\n");
ret = WIFI_SendData(0, (uint8_t *)http, strlen((char *)http), &SentDataLength);
if((ret == WIFI_STATUS_OK) && (SentDataLength != strlen((char *)http)))
{
ret = WIFI_STATUS_ERROR;
}
return ret;
}
static uint32_t TEMP_SENSOR_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/* ADC1 Periph clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
/* Configure the ADC peripheral */
AdcHandle.Instance = ADC1;
AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
AdcHandle.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
AdcHandle.Init.ContinuousConvMode = ENABLE; /* Continuous mode enabled to have continuous conversion */
AdcHandle.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */
AdcHandle.Init.NbrOfDiscConversion = 0;
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Conversion start not triggered by an external event */
AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
AdcHandle.Init.NbrOfConversion = 1;
AdcHandle.Init.DMAContinuousRequests = DISABLE;
AdcHandle.Init.EOCSelection = DISABLE;
if (HAL_ADC_Init(&AdcHandle)== HAL_OK)
{
/* Configure ADC Temperature Sensor Channel */
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) == HAL_OK)
{
return 0;
}
}
return 1;
}
static uint32_t TEMP_SENSOR_GetValue(void)
{
if(HAL_ADC_Start(&AdcHandle) == HAL_OK)
{
if(HAL_ADC_PollForConversion(&AdcHandle, 1000)== HAL_OK)
{
return ((((HAL_ADC_GetValue(&AdcHandle) * VREF)/MAX_CONVERTED_VALUE) - VSENS_AT_AMBIENT_TEMP) * 10 / AVG_SLOPE) + AMBIENT_TEMP;
}
}
return 0xFFFFFFFF;
}
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
HAL_StatusTypeDef ret = HAL_OK;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 200;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
RCC_OscInitStruct.PLL.PLLR = 2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if(ret != HAL_OK)
{
Error_Handler();
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3);
if(ret != HAL_OK)
{
Error_Handler();
}
}
static void Error_Handler(void)
{
/* User may add here some code to deal with this error */
while(1)
{
}
}
效果
LCD 显示
连接 WiFi 无线网络,给出开发板设备 IP 地址,并提示等待连接
检测到地址被访问,LCD 提示 HTTP 服务开始
在同一网络下输入 LCD 显示的设备 IP 地址,如 192.168.1.122
网页显示
- 设备名称
InventekSys : Web Server using Es-Wifi with STM32
- 温度传感器转换值
- 板载 LED 控制选项
可实现网页端获取温度信息,以及 LED 控制。
总结
本文介绍了 STM32F413H Discovery kit 开发板实现 HTTP 服务器的搭建以及相关测试,分析了关键工程代码,并对测试方法和测试结果进行了必要的说明。