RT-Thread使用webserver(lwip协议栈自带httpd )

电子说

1.3w人已加入

描述

参考正点原子的 网络实验10 NETCONN_WEBserver实验和《lwIP开发指南》。

开发环境:野火的stm32f407,rt-thread studio版本是版本: 2.2.6,stm32f4的资源包为0.2.2,rt-thread版本为4.0.3。

以RT-Thread中Lan8720和lwip协议栈的使用文章创建的工程为基础。

httpd(The Apache HTTP Server)的官方网址。

在rtthread工程中新建文件夹webserver,存放webserver相关文件。

对工程进行编译,正常通过。

需要修改的代码,过程如下:

rt-threadcomponentsnetlwip-2.0.2srcincludelwipappshttpd_opts.h 文件中的宏定义

LWIP_HTTPD_CGI 默认为0,改为1
LWIP_HTTPD_SSI 默认为0,改为1
HTTPD_USE_CUSTOM_FSDATA默认为0
LWIP_HTTPD_DYNAMIC_FILE_READ默认为0,改为1
将 rt-threadcomponentsnetlwip-2.0.2srcappshttpd文件夹 添加构建
httpd文件夹下的fsdata.c 排除构建。

在主函数中增加如下代码

extern void httpd_init(void);
httpd_init();
while (count++)
{
LOG_D("Hello RT-Thread!");
rt_thread_mdelay(10000);
}

编译正常,下载到开发板,效果如图1:

LwIP协议栈

如何使用自己的网页呢?修改如下:
将rt-threadcomponentsnetlwip-2.0.2srcappshttpd文件夹下的fsdata.c替换成自己的fsdata.c,(使用makefsdata.exe这个软件自动生成即可)。

在webserve文件夹下创建httpd_cgi_ssi.c文件(CGI和SSI句柄函数)
参考原子的代码,修改如下:

#include
#include "lwip/tcp.h"
#include
#include
#include
int LED1=0;
int BEEP=0;
#define NUM_CONFIG_CGI_URIS (sizeof(ppcURLs) / sizeof(tCGI))
#define NUM_CONFIG_SSI_TAGS (sizeof(ppcTAGs) / sizeof(char *))
//extern short Get_Temprate(void);
//extern void RTC_Get_Time(u8 *hour,u8 *min,u8 *sec,u8 *ampm);
//extern void RTC_Get_Date(u8 *year,u8 *month,u8 *date,u8 *week);
//控制LED的CGI handler
const char* LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]);
const char* BEEP_CGI_Handler(int iIndex,int iNumParams,char *pcParam[],char *pcValue[]);
static const char *ppcTAGs[]= //SSI的Tag
{
"t", //ADC值
"w", //温度值
"h", //时间
"y" //日期
};
static const tCGI ppcURLs[]= //cgi程序
{
{"/leds.cgi",LEDS_CGI_Handler},
{"/beep.cgi",BEEP_CGI_Handler},
};
//当web客户端请求浏览器的时候,使用此函数被CGI handler调用
static int FindCGIParameter(const char *pcToFind,char *pcParam[],int iNumParams)
{
int iLoop;
for(iLoop = 0;iLoop < iNumParams;iLoop ++ )
{
if(strcmp(pcToFind,pcParam[iLoop]) == 0)
{
return (iLoop); //返回 iLOOP
}
}
return (-1);
}
//SSIHandlerÖ中adc处理函数
void ADC_Handler(char *pcInsert)
{
char Digit1=0, Digit2=0, Digit3=0, Digit4=0;
static uint32_t ADCVal = 0;
//ADCVal = Get_Adc_Average(5,10);//ADC1_CH5的电压值
ADCVal+=10;
ADCVal=ADCVal%3000;
//转换为 ADCVval * 0.8mv
ADCVal = (uint32_t)(ADCVal * 0.8);
Digit1= ADCVal/1000;
Digit2= (ADCVal-(Digit1*1000))/100 ;
Digit3= (ADCVal-((Digit1*1000)+(Digit2*100)))/10;
Digit4= ADCVal -((Digit1*1000)+(Digit2*100)+ (Digit3*10));
/* 准备添加到html中的数据 */
*pcInsert = (char)(Digit1+0x30);
*(pcInsert + 1) = (char)(Digit2+0x30);
*(pcInsert + 2) = (char)(Digit3+0x30);
*(pcInsert + 3) = (char)(Digit4+0x30);
}
//SSIHandler中需要用到的内部处理温度传感器
void Temperate_Handler(char *pcInsert)
{
char Digit1=0, Digit2=0, Digit3=0, Digit4=0,Digit5=0;
static short Temperate = 0;
//Temperate = Get_Temprate();
Temperate+=1.3;
Digit1 = Temperate / 10000;
Digit2 = (Temperate % 10000)/1000;
Digit3 = (Temperate % 1000)/100 ;
Digit4 = (Temperate % 100)/10;
Digit5 = Temperate % 10;
/* 准备添加到html中的数据 */
*pcInsert = (char)(Digit1+0x30);
*(pcInsert+1) = (char)(Digit2+0x30);
*(pcInsert+2) = (char)(Digit3+0x30);
*(pcInsert+3) = '.';
*(pcInsert+4) = (char)(Digit4+0x30);
*(pcInsert+5) = (char)(Digit5+0x30);
}
//SSIHandler中需要用到的处理RTC日时间的函数
void RTCTime_Handler(char *pcInsert)
{
static uint8_t hour,min,sec,ampm;
hour++;
min++;
sec++;
ampm++;
//RTC_Get_Time(&hour,&min,&sec,&m);
/* 准备添加到html中的数据 */
*pcInsert = (char)((hour/10) + 0x30);
*(pcInsert+1) = (char)((hour%10) + 0x30);
*(pcInsert+2) = ':';
*(pcInsert+3) = (char)((min/10) + 0x30);
*(pcInsert+4) = (char)((min%10) + 0x30);
*(pcInsert+5) = ':';
*(pcInsert+6) = (char)((sec/10) + 0x30);
*(pcInsert+7) = (char)((sec%10) + 0x30);
}
//SSIHandler中需要用到的处理RTC日期的函数
void RTCdate_Handler(char *pcInsert)
{
static uint8_t year,month,date,week;
//RTC_Get_Date(&year,&month,&date,&week);
year++;
month++;
date++;
week++;
/* 准备添加到html中的数据 */
*pcInsert = '2';
*(pcInsert+1) = '0';
*(pcInsert+2) = (char)((year/10) + 0x30);
*(pcInsert+3) = (char)((year%10) + 0x30);
*(pcInsert+4) = '-';
*(pcInsert+5) = (char)((month/10) + 0x30);
*(pcInsert+6) = (char)((month%10) + 0x30);
*(pcInsert+7) = '-';
*(pcInsert+8) = (char)((date/10) + 0x30);
*(pcInsert+9) = (char)((date%10) + 0x30);
*(pcInsert+10) = ' ';
*(pcInsert+11) = 'w';
*(pcInsert+12) = 'e';
*(pcInsert+13) = 'e';
*(pcInsert+14) = 'k';
*(pcInsert+15) = ':';
*(pcInsert+16) = (char)(week + 0x30);
}
//SSI的 Handler 句柄
static u16_t SSIHandler(int iIndex,char *pcInsert,int iInsertLen)
{
switch(iIndex)
{
case 0:
ADC_Handler(pcInsert);
break;
case 1:
Temperate_Handler(pcInsert);
break;
case 2:
RTCTime_Handler(pcInsert);
break;
case 3:
RTCdate_Handler(pcInsert);
break;
}
return strlen(pcInsert);
}
//CGI LED控制句柄
const char* LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
{
uint8_t i=0; //注意根据自己的GET的参数的多少来选择i值范围
iIndex = FindCGIParameter("LED1",pcParam,iNumParams); //找到LED的索引号
//只有一个CGI句柄 iIndex=0
if (iIndex != -1)
{
LED1=1;
for (i=0; i {
if (strcmp(pcParam[i] , "LED1")==0) //检查参数"led"
{
if(strcmp(pcValue[i], "LED1ON") ==0)
{
LED1=0;
rt_kprintf("LED1ONn");
}
else if(strcmp(pcValue[i],"LED1OFF") == 0)
{
LED1=1;
rt_kprintf("LED1OFFn");
}
}
}
}
if(LED1 == 0 && BEEP == 0) return "/STM32F407LED_ON_BEEP_OFF.shtml"; //
else if(LED1 == 0 && BEEP == 1) return "/STM32F407LED_ON_BEEP_ON.shtml"; //
else if(LED1 == 1 && BEEP == 1) return "/STM32F407LED_OFF_BEEP_ON.shtml"; //
else return "/STM32F407LED_OFF_BEEP_OFF.shtml"; //
}
//BEEP的CGI控制句柄
const char *BEEP_CGI_Handler(int iIndex,int iNumParams,char *pcParam[],char *pcValue[])
{
uint8_t i=0;
iIndex = FindCGIParameter("BEEP",pcParam,iNumParams); //找到BEEP的索引号
if(iIndex != -1) //找到BEEP的索引号
{
BEEP=0; //
for(i = 0;i < iNumParams;i++)
{
if(strcmp(pcParam[i],"BEEP") == 0) //
{
if(strcmp(pcValue[i],"BEEPON") == 0) //
{
BEEP = 1;
rt_kprintf("BEEPONn");
}
else if(strcmp(pcValue[i],"BEEPOFF") == 0) //
{
BEEP = 0;
rt_kprintf("BEEPOFFn");
}
}
}
}
if(LED1 == 0 && BEEP == 0) return "/STM32F407LED_ON_BEEP_OFF.shtml"; //
else if(LED1 == 0 && BEEP == 1) return "/STM32F407LED_ON_BEEP_ON.shtml"; //
else if(LED1 == 1 && BEEP == 1) return "/STM32F407LED_OFF_BEEP_ON.shtml"; //
else return "/STM32F407LED_OFF_BEEP_OFF.shtml"; //
}
//SSI句柄初始化
void httpd_ssi_init(void)
{
//配置内部温度传感器的SSI句柄
http_set_ssi_handler(SSIHandler,ppcTAGs,NUM_CONFIG_SSI_TAGS);
}
//CGI句柄初始化
void httpd_cgi_init(void)
{
//配置CGI句柄 LEDs control CGI) */
http_set_cgi_handlers(ppcURLs, NUM_CONFIG_CGI_URIS);
}

主函数中代码如下:

extern void httpd_ssi_init(void);
extern void httpd_cgi_init(void);
extern void httpd_init(void);
httpd_cgi_init();
httpd_ssi_init();
httpd_init();

重新编译,下载到开发板,在浏览器输入开发板ip地址,查看效果。效果如图2:

LwIP协议栈

LWIP HTTP 协议中默认只支持GET方法 但是一般提交表单时都用POST方法 而LWIPPOST方案需要自己实现 不过LWIP已经需要实现的函数申明在httpd.h中了。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分