STM32物联网项目-通过ESP12S模块连接TCP服务器

通过ESP12S模块连接TCP服务器

可参考STC15实战的WiFi通信:http://t.csdn.cn/Aw0Uc

ESP-12S模块

STM32物联网项目-通过ESP12S模块连接TCP服务器_第1张图片

引脚功能定义

STM32物联网项目-通过ESP12S模块连接TCP服务器_第2张图片

实验目标

STM32通过串口与ESP-12S模块通信,控制模块连接路由器,然后连接服务器,将实战板的SHT30获取到的环境温湿度值上传到服务器,服务器可以下发指令,控制实战板的蜂鸣器开启与关闭,控制继电器吸合断开

实验使用到的AT指令

指令 响应 说明
AT OK 测试AT启动
ATE0 OK 关闭回显功能
AT+CWMODE_CUR=1 OK 设置模块为Station模式
AT+CWAUTOCONN=1 OK 设置上电自动连接AP
AT+CWSTARTSMART=2 OK 开启SmartConfig(智能配网),类型:AirKiss
AT+CWSTOPSMART OK 停止SmartConfig
AT+CIFSR OK 查询本地IP地址
AT+CIPSTART=“TCP”,“192.168.10.6”,8888 OK或者ERROR 建立TCP连接
AT+CIPMODE=1 OK 设置传输模式为透传模式
AT+CIPSEND > 发送数据
+++ 退出透传模式,回到AT指令模式

上面指令除了最后的”+++“不用在发送时添加回车换行,其他指令都要在末尾添加回车换行,如调用函数发送AT指令:

SendAT("AT\r\n");

CubeMX配置

GPIO配置

实验用到了数码管、触摸按键、LED灯、继电器,NPN输出这几个外设,配置对应的引脚,PF11是WiFi模块的使能引脚,PF12是WiFi模块的重启引脚,SCL和SDA是IIC通信引脚,与SHT30通信用的

STM32物联网项目-通过ESP12S模块连接TCP服务器_第3张图片

蜂鸣器用定时器1产生PWM信号控制

STM32物联网项目-通过ESP12S模块连接TCP服务器_第4张图片

串口2波特率配置为115200,因为WiFi模块默认波特率为115200

STM32物联网项目-通过ESP12S模块连接TCP服务器_第5张图片

使能DMA发送和DMA接收,用DMA搬运WiFi模块与单片机之间的通信数据,增加CPU效率

STM32物联网项目-通过ESP12S模块连接TCP服务器_第6张图片

另外开启串口1,将WiFi模块与单片机通信的数据通过串口1打印到串口助手上,方便查看通信过程与调试

程序

代码量太大,记录一些重要的步骤

UART2.c

串口2发送数组和字符串的函数都是调用串口DMA发送,当调用SendArray函数时,DMA会自动将指针p_Arr指向的数组里的内容搬运到串口2发送,搬运的数组长度为LEN;SendString函数同理

/*
* @name   SendArray
* @brief  发送数组
* @param  p_Arr:数据首地址,LEN:数组长度
* @retval None   
*/
static void SendArray(uint8_t* p_Arr,uint16_t LEN)
{
    HAL_UART_Transmit_DMA(&huart2,p_Arr,LEN);
}

/*
* @name   SendString
* @brief  发送字符串
* @param  p_Str:字符串首地址
* @retval None   
*/
static void SendString(uint8_t* p_Str)
{
    HAL_UART_Transmit_DMA(&huart2,p_Str,strlen((const char*)p_Str));
}

System.c

主函数中,先调用SHT30相关函数获取温湿度值,然后显示在数码管上,配网函数通过触摸按键3外部中断长按2s来触发,TC连接状态位TCP_Connect_Status初始化为FALSE,表示没连接上TCP服务器,进入判断里,TCP重连定时器TCP_Reconnect_Timer初始化为10s,默认一上电就连接一次服务器,如果服务器连接成功,就调用ESP_12S.Transfer_SHT30()函数来发送温湿度值;如果服务器连接失败,则函数里判断有没有获取到IP地址,如果没有IP地址,则自动调用配网操作

/*
* @name   Run
* @brief  系统运行
* @param  None
* @retval None   
*/
static void Run()
{
  float   Temp_float = 0;
  uint16_t Temp_uint  = 0;
  //调用SHT30周期检测函数
  SHT30.Measure_Period_Mode();

  //判断温度正负
  if(SHT30.fTemperature < 0)
  {
    Temp_float = 0 - SHT30.fTemperature;
    Display.Disp_Other(Disp_NUM_4,0x40,Disp_DP_OFF);
  }
  else
  {
    Temp_float = SHT30.fTemperature;
    Display.Disp_Other(Disp_NUM_4,0x00,Disp_DP_OFF);
  }

  //显示温度
  Temp_uint = (uint16_t)(Temp_float*10); //将温度值乘以10,显示小数点后一位
  Display.Disp_Hex(Disp_NUM_3,Temp_uint/100,Disp_DP_OFF);   //显示十位
  Display.Disp_Hex(Disp_NUM_2,Temp_uint%100/10,Disp_DP_ON);  //显示个位,开启小数点
  Display.Disp_Hex(Disp_NUM_1,Temp_uint%10,Disp_DP_OFF);    //显示小数点后一位

  //显示湿度
  Display.Disp_Hex(Disp_NUM_6,SHT30.ucHumidity/10,Disp_DP_OFF);
  Display.Disp_Hex(Disp_NUM_5,SHT30.ucHumidity%10,Disp_DP_OFF);

  //配网
  ESP_12S.SmartConfig();

  //连接TCP服务器
  if(ESP_12S.TCP_Connect_Status == FALSE)
  {
    if(ESP_12S.TCP_Reconnect_Timer >= TIMER_10s)
    {
      //连接TCP服务器
      ESP_12S.TCP_Connect_Server();
      ESP_12S.TCP_Reconnect_Timer = 0;
    }
  }
  
  //传输SHT30的数据
  ESP_12S.Transfer_SHT30();

  //延时
  HAL_Delay(500);
}

ESP-12S.c

智能配网函数SmartConfig,如果模块已经连上了服务器就会开启透传模式,再次配网的话就要先发送“+++”退出透传模式,然后就是发送智能配网的AT指令,并检测模块是否回应AP连接成功应答,再判断是配网成功还是失败,失败就不清除标志位,下个循环继续进入配网模式,因为没有连接AP后续连接TCP服务器就没有意义

/*
* @name   SmartConfig
* @brief  智能配网
* @param  AT_command:AT指令,Respond_Str:模块回应
* @retval None   
*/
static void SmartConfig()
{
    if(ESP_12S.SmartConfig_Flag == TRUE)
    {
        //关闭指示灯
        LED.LED_Fun(LED2,LED_OFF);
        LED.LED_Fun(LED3,LED_OFF);

        //退出透传模式
        *(UART2.pucSend_Buffer+0) = '+';
        *(UART2.pucSend_Buffer+1) = '+';
        *(UART2.pucSend_Buffer+2) = '+';
        UART2.SendArray(UART2.pucSend_Buffer,3);
        HAL_Delay(1000);

        //发送配网AT指令
        SendAT((uint8_t*)"AT\r\n",(uint8_t*)"OK");    //测试AT
        SendAT((uint8_t*)"ATE0\r\n",(uint8_t*)"OK");  //关闭回显
        SendAT((uint8_t*)"AT+CWMODE_CUR=1\r\n",(uint8_t*)"OK");    //设置模块为station模式
        SendAT((uint8_t*)"AT+CWAUTOCONN=1\r\n",(uint8_t*)"OK");   //设置上电自动连接AP
        SendAT((uint8_t*)"AT+CWSTARTSMART=2\r\n",(uint8_t*)"OK"); //开启SmartConfig,Airkiss类型

        printf("Start SmartConfig:\r\n");
        //等待配网,3分钟超时退出
        Timer6.usDelay_Timer = 0;
        while(Timer6.usDelay_Timer < TIMER_3min)
        {
            //DMA重新接收设置
            ESP_12S.DMA_Receive_Set();

            //LED2指示灯快闪
            HAL_Delay(100);
            LED.LED_Fun(LED2,LED_Flip);

            //打印接收缓存的数据
            printf("%s",UART2.pucRec_Buffer);

            //判断接收缓存中是否有正确应答
            if(strstr((const char*)UART2.pucRec_Buffer, "connected") != NULL) //成功连接到AP
            {
                SendAT((uint8_t*)"AT+CWSTOPSMART\r\n",(uint8_t*)"OK"); //停止SmartConfig
                break;
            }
        }

        //输出信息
        //如果定时器小于3分钟的,说明是配网成功退出的循环
        if(Timer6.usDelay_Timer < TIMER_3min)
        {
            printf("\r\n\r\nSmartConfig success!\r\n");     //打印配网成功信息
            ESP_12S.TCP_Connect_Status = FALSE;             //TCP连接标志位清零
            ESP_12S.TCP_Reconnect_Timer = TIMER_10s;        //立即重连服务器
            ESP_12S.SmartConfig_Flag = FALSE;               //清除配网标志位
        }
        //否则定时器大于3分钟,说明没配网成功,超时退出
        else
        {
            printf("\r\n\r\nSmartConfig Fail!\r\n");        //打印配网失败信息 
            ESP_12S.TCP_Connect_Status = FALSE;             //TCP连接标志位清零
            ESP_12S.TCP_Reconnect_Timer = 0;

            //配网失败则不清除标志位,继续配网,因为没配网后续操作没意义
        }

        //关闭LED灯
        LED.LED_Fun(LED2,LED_OFF);
    }
}

ESP-12S.c

DMA接收设置,准备接收WiFi模块返回的应答时,先关闭DMA接收,把接收缓存里的内容清除,再开启DMA接收,DMA接收完数据则进入空闲中断

/*
* @name   DMA_Receive_Set
* @brief  DMA接收设置
* @param  None
* @retval None   
*/
static void DMA_Receive_Set()
{
    //先关闭串口2的DMA接收
    HAL_UART_DMAStop(&huart2);
    //清除接收缓存
    Public.Memory_Clr(UART2.pucRec_Buffer,strlen((const char*)UART2.pucRec_Buffer));
    //再开启串口2的DMA接收
    HAL_UARTEx_ReceiveToIdle_DMA(&huart2,UART2.pucRec_Buffer,PUCREC_BUFFER_LEN);
}

CallBack.c

DMA搬运的数据有两种类型,一种是WiFi模块返回的应答,另一种是模块连接上服务器后,服务器下发指令到模块,模块再将指令传到穿串口,所以WiFi模块的应答可以直接从接收缓存里找,如果是服务器下发指令控制继电器和蜂鸣器,则在空闲中断回调函数中调用接收服务器信息函数,执行服务器指令,控制继电器或者蜂鸣器

/*
* @name   HAL_UARTEx_RxEventCallback
* @brief  串口接收完成空闲中断回调函数
* @param  huart:串口指针,Size:接收的数据大小
* @retval None   
*/ 
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  //接收完成串口数据后,触发空闲中断,在这里处理接收数据
  if(huart->Instance == huart2.Instance)
  {
    ESP_12S.Receive_Information();
  }
}
/*
* @name   Receive_Information
* @brief  接收服务器返回数据
* @param  None
* @retval None   
*/
static void Receive_Information()
{
    if(ESP_12S.TCP_Connect_Status == TRUE)
    {
        //如果不是配网才发送
        if(ESP_12S.SmartConfig_Flag == FALSE)
        {
            printf("Received information from the TCP server\r\n");
        }
        printf("%s\r\n",UART2.pucRec_Buffer);
        
        //切换继电器状态
        if(strstr((const char*)UART2.pucRec_Buffer,"Relay Flip") != NULL)
        {
            Relay.Relay_Flip();
        }

        //切换蜂鸣器状态
        if(strstr((const char*)UART2.pucRec_Buffer,"Buzzer Flip") != NULL)
        {
            Buzzer.Buzzer_Flip();
        }

        //DMA重新接收设置,接收TCP服务器的新指令
		ESP_12S.DMA_Receive_Set();
    }

实验结果

STM32物联网项目-通过ESP12S模块连接TCP服务器_第7张图片

STM32物联网项目-通过ESP12S模块连接TCP服务器_第8张图片

TCP服务器连接成功

STM32物联网项目-通过ESP12S模块连接TCP服务器_第9张图片

服务器接收到SHT30采集的温湿度

STM32物联网项目-通过ESP12S模块连接TCP服务器_第10张图片

你可能感兴趣的:(STM32物联网项目,stm32,单片机,物联网,arm,学习)