见博客:stm32f103c8t6新建固件库模板(可自取)
固件库模板
MDK5开发环境
stm32参考手册
UART串口协议
stm32中断概念
ESP8266模块资料
利用固件库模板点灯工程(下面第三行,手动狗头)
CH340 USB→TTL模块
ESP8266模块
手机软件
实验程序已经发布到百度网盘,本文末有链接可以自取
stm32参考手册
串口协议查看这篇博客USART串口协议
stm32中断概念STM32中断应用概括
ESP8266模块资料:ESP8266
串口调试工具 :https://pan.baidu.com/s/1V-jRJzb0INDXDLo9I4CJ6A 提取码:0000
网络助手(PC):https://pan.baidu.com/s/1EeDtr7eW-mIuOEZa1_4BWA 提取码:0000
网络调试助手(安卓)链接: https://pan.baidu.com/s/1uDGpyGt8VyUzcZXmWfTqhw 提取码: 0000
ESP8266
是一款超低功耗的UART-WiFi 透传模块,拥有业内极富竞争力的封装尺寸和超低能耗技术,专为移动设备和物联网应用设计,可将用户的物理设备连接到Wi-Fi 无线网络上
,进行互联网或局域网通信,实现万物互联功能。
标号 | PIN | 引脚说明 |
---|---|---|
1 | 3V3 | 模块供电正极 |
2 | RST | 低电平复位,高电平工作(默认高) |
3 | EN | 使能端,需要进入命令模式时接3.3V |
4 | TX | 发送端 |
5 | RX | 接收端 |
6 | IO0 | 工作模式选择:悬空:FlashBoot,工作模式;下拉:UARTDownload,下载模式 |
7 | IO2 | (1)开机上电时必须为高电平,禁止硬件下拉;(2)内部默认已拉高 |
8 | GND | 模块供电负极 |
本模块使用USART协议,具体请看下面两个博客,这里就不继续讲解了
USART串口协议
四、stm32-USART串口通讯(重定向、接发通信、控制LED亮灭)
ESP8266 支持 softAP 模式, station 模式, softAP + station 共存模式三种。
利用 ESP8266 可以实现十分灵活的组网方式和网络拓扑。
ESP8266 作为 softAP(热点
),手机、 电脑、 用户设备、 其他 ESP8266 station 接口等均可以作为 station(终端用户
) 连入ESP8266, 组建成一个局域网。
ESP8266 作为 station,通过路由器(AP) 连入 internet ,可向云端服务器上传、 下载数据。用户可随时使用移动终端(手机、 笔记本等) ,通过云端监控 ESP8266 模块的状况, 向 ESP8266 模块发送控制指令。
简单的来说就是ESP连接热点(可以上网),也可以手机上网,此时手机可以控制ESP8266
ESP8266 支持 softAP+station 共存的模式,用户设备、 手机等可以作为station 连入 ESP8266 的 softAP 接口,同时, 可以控制 ESP8266 的 station接口通过路由器(AP) 连入 internet。
透传, 即透明传输功能
。 Host 通过 uart 将数据发给ESP8266, ESP8266 再通过无线网络将数据传出去;ESP8266 通过无线网络接收到的数据,同理通过uart 传到 Host。 ESP8266 只负责将数据传到目标地址,不对数据进行处理,发送方和接收方的数据内容、 长度完全一致,传输过程就好像透明一样。
透传需要先建立连接:
Q: 什么是透传模式?
A: 透传模式影响发送数据的方式。
如果不开启透传模式,发送数据前都必须先发送指令AT+CIPSEND=,例如:
AT+CIPSEND=4
OK
> //在 > 后面输入要上传的数据
开启了透传模式:
AT+CIPMODE=1 进入透传模式
AT+CIPSEND 之后发送的所有内容将全部当成数据
退出透传模式: 发送数据"+++
"就可以了。注意:此时“+++”后面,不接发送新行
!
注意:透传只能在单连接模式下进行,所以在建立连接之前一定要用(AT+CIPMUX=0 设置单连接)
> AT+CIPMODE=1
> CIPMUX and CIPSERVER must be 0
命令 | 描述 |
---|---|
基础指令 | |
AT | 测试 AT 启动 |
AT+RST | 重启模块 |
AT+GMR | 查看版本信息 |
wifi 功能指令 | |
AT+CWMODE | 选择 WIFI 应用模式 |
AT+CWJAP | 加入 AP |
AT+CWLAP | 列出当前可用 AP |
AT+CWQAP | 退出与 AP 的连接 |
AT+CWSAP | 设置 AP 模式下的参数 |
AT+ CWLIF | 查看已接入设备的 IP |
TCP/IP 指令 | |
AT+CIPSTATUS | 获得连接状态 |
AT+CIPSTART | 建立 TCP 连接或注册 UDP 端口号 |
AT+CIPSEND | 发送数据 |
AT+CIPCLOSE | 关闭 TCP 或 UDP |
AT+CIFSR | 获取本地 IP 地址 |
AT+CIPMUX | 启动多连接 |
AT+CIPSERVER | 配置为服务器 |
AT+CIPMODE | 设置模块传输模式 |
AT+CIPSTO | 设置服务器超时时间 |
+IPD | 接收到的数据 |
AT命令的详细说明在ESP8266这里面什么都有
STA 模式: ESP8266模块通过路由器连接互联网,手机或电脑通过互联网实现对设备的远程控制。
配置步骤:
1. AT+CWMODE=1 设置模组为STA模式。(串口助手)
2. AT+CWLAP 查询附近 WIFI(串口助手)
3. AT+CWJAP="1202","12345678" 连接 WIFI(串口助手)
4. AT+CIPMUX=0 打开单连接(串口助手)
5. AT+CIPSTART="TCP","192.168.2.6",808 (自己对应的ip地址,端口号随便,只要没有被占用都行)
6. AT+CIPMODE=1 使用透传模式
7. AT+CIPSEND
AP 模式: ESP8266模块作为热点,实现手机或电脑直接与模块通信,实现局域网无线控制。
配置步骤:
1. AT+CWMODE=2
2. AT+CIPAP="192.168.4.1"
3. AT+CWSAP="ESP8266","12345678",1,0
4. AT+CIPMUX=1
5. AT+CIPSERVER=1,8888
6. AT+CIPSTO=1800
7. AT+CIFSR
使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;
初始化 GPIO,并将 GPIO 复用到 USART 上;
配置 USART 参数;
配置中断控制器并使能 USART 接收中断;
使能 USART;
在 USART 接收中断服务函数实现数据接收和发送。
四、stm32-USART串口通讯(重定向、接发通信、控制LED亮灭)
ESP8266的波特率为115200,8位数据位、1位停止位、无奇偶校验的通信格式。
AT+CWMODE=1 设置模组为STA模式。
AT+CWJAP=“XXX”,“XXXX” 连接 WIFI(必须为第3步能查找到的)
AT+CIPSTART=“TCP”,“192.168.2.6”,808 (自己对应的ip地址,端口号随便,只要没有被占用都行)
AT+CIPMODE=1 使用透传模式
AT+CIPSEND
四、stm32-USART串口通讯(重定向、接发通信、控制LED亮灭)
在USART1_IRQHandler方法下面添加 usart2的初始化和中断
struct STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 };
volatile uint8_t ucTcpClosedFlag = 0;
void uart2_init(u32 bound) {
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
//USART2_TX GPIOA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA2
//USART2_RX GPIOA.3初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3
//Usart2 NVIC 配置
NVIC_PriorityGroupConfig(macNVIC_PriorityGroup_x);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART2, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//使能串口总线空闲中断
USART_Cmd(USART2, ENABLE);
}
void USART2_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART2); //读取接收到的数据
//USART_SendData(USART1,Res);
if ( strEsp8266_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) ) //预留1个字节写结束符
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ++ ] = Res;
}
if ( USART_GetITStatus( USART2, USART_IT_IDLE ) == SET ) //数据帧接收完毕
{
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 1;
Res = USART_ReceiveData( USART2 );
ucTcpClosedFlag = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;
}
}
添加strHC05_Fram_Record结构体和uart2_init(u32 bound)函数
extern struct STRUCT_USARTx_Fram //串口数据帧的处理结构体
{
//STRUCT_USARTx_Fram 读取的数据
char Data_RX_BUF [ RX_BUF_MAX_LEN ];
union {
__IO u16 InfAll;
struct {
__IO u16 FramLength :15; // 14:0
__IO u16 FramFinishFlag :1; // 15
} InfBit;
};
}strUSART_Fram_Record,strEsp8266_Fram_Record;
//如果想串口中断接收,请不要注释以下宏定义
void uart1_init(u32 bound);
void uart2_init(u32 bound);
#include "esp8266.h"
#include "delay.h"
#include
#include
#include
/********************************************************************************
*
RST -- A4
EN -- A5
TX -- A2(USART2_TX)
RX -- A3(USART2_RX)
********************************************************************************/
static void ESP8266_GPIO_Config ( void );
/**
* @brief ESP8266初始化函数
* @param 无
* @retval 无
*/
void ESP8266_Init ( void )
{
ESP8266_GPIO_Config ();
ESP8266_RST_HIGH_LEVEL();
ESP8266_CH_DISABLE();
}
/**
* @brief 初始化ESP8266用到的GPIO引脚
* @param 无
* @retval 无
*/
static void ESP8266_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/* 配置 CH_PD 引脚*/
ESP8266_CH_PD_APBxClock_FUN ( ESP8266_CH_PD_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = ESP8266_CH_PD_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init ( ESP8266_CH_PD_PORT, & GPIO_InitStructure );
/* 配置 RST 引脚*/
ESP8266_RST_APBxClock_FUN ( ESP8266_RST_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = ESP8266_RST_PIN;
GPIO_Init ( ESP8266_RST_PORT, & GPIO_InitStructure );
}
/*
* 函数名:ESP8266_Cmd
* 描述 :对WF-ESP8266模块发送AT指令
* 输入 :cmd,待发送的指令
* reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
* waittime,等待响应的时间
* 返回 : 1,指令发送成功
* 0,指令发送失败
* 调用 :被外部调用
*/
bool ESP8266_Cmd ( char *cmd, char *reply1, char *reply2, u32 waittime )
{
strEsp8266_Fram_Record .InfBit .FramLength = 0; //从新开始接收新的数据包
ESP8266_Usart ( "%s\r\n", cmd );
if ( ( reply1 == 0 ) && ( reply2 == 0 ) ) //不需要接收数据
return true;
Delay_ms ( waittime ); //延时
//增加一个结束符。
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';
//将USART2接收到的东西全部打印出来,接收到的保存在这个数组里,
//通过串口1发送出来,这样就能看到,我们发送的指令的响应,是否出错,
//例如:发送AT,响应是OK, ESP_USART接收到的数据是AT OK.在交给USART1发送,在PC机的串口调试助手可以看到这些信息,
PC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF );
strEsp8266_Fram_Record .InfBit .FramLength = 0; //清除接收标志
strEsp8266_Fram_Record.InfBit.FramFinishFlag = 0;
if ( ( reply1 != 0 ) && ( reply2 != 0 ) )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) ||
( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
else if ( reply1 != 0 )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) );
else
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
}
/*
* 函数名:ESP8266_Rst
* 描述 :重启WF-ESP8266模块
* 输入 :无
* 返回 : 无
* 调用 :被 ESP8266_AT_Test 调用
*/
void ESP8266_Rst ( void )
{
#if 0
ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 );
#else
ESP8266_RST_LOW_LEVEL();
Delay_ms ( 500 );
ESP8266_RST_HIGH_LEVEL();
#endif
}
/*
* 函数名:ESP8266_DHCP_CUR
* 描述 :
:
0:设置 ESP8266 SoftAP
1:设置 ESP8266 Station
2:设置 ESP8266 SoftAP 和 Station
:
0:关闭 DHCP
1:开启 DHCP
* 输入 :None
* 返回 :1/0
* 调用 :ESP8266_StaTcpClient_Unvarnish_ConfigTest调用
*/
bool ESP8266_DHCP_CUR ( )
{
char cCmd [40];
//把格式数据写成串(函数指令)
sprintf ( cCmd, "AT+CWDHCP_CUR=1,1");
return ESP8266_Cmd ( cCmd, "OK", NULL, 500 );
}
bool ESP8266_AT_Test ( void )
{
char count = 0;
ESP8266_RST_HIGH_LEVEL();
printf("\r\nAT测试.....\r\n");
Delay_ms ( 2000 );
while ( count < 10 )
{
printf("\r\nAT测试次数 %d......\r\n", count);
if( ESP8266_Cmd ( "AT", "OK", NULL, 500 ) )
{
printf("\r\nAT测试启动成功 %d......\r\n", count);
return 1;
}
ESP8266_Rst();
++ count;
}
return 0;
}
/*
* 函数名:ESP8266_Net_Mode_Choose
* 描述 :设置WF模式—ESP8266工作方式
* 输入 :None
* 返回 :状态值
* 调用 :内部调用
*/
bool ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode)
{
switch (enumMode)
{
//设置WiFi模式
case STA :
return ESP8266_Cmd("AT+CWMODE=1", "OK", "no change", 2500);
case AP:
return ESP8266_Cmd("AT+CWMODE=2", "OK", "no change", 2500);
case STA_AP:
return ESP8266_Cmd("AT+CWMODE=3", "OK", "no change", 2500);
default:
return false;
}
}
/*
* 函数名:ESP8266_JoinAP
* 描述 :WF-ESP8266模块连接外部WiFi
* 输入 :pSSID,WiFi名称字符串
* :pPassWord,WiFi密码字符串
* 返回 : 1,连接成功
* 0,连接失败
* 调用 :被外部调用
*/
bool ESP8266_JoinAP(char *pSSID, char *pPassWord)
{
char cCmd [120];
//把格式数据写成串(函数指令)
sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord);
return ESP8266_Cmd ( cCmd, "OK", NULL, 1500 );
}
/*
* 函数名:ESP8266_BuildAP
* 描述 :WF-ESP8266模块创建WiFi热点
* 输入 :pSSID,WiFi名称字符串
* :pPassWord,WiFi密码字符串
* :enunPsdMode,WiFi加密方式代号字符串
* 返回 : 1,创建成功
* 0,创建失败
* 调用 :被外部调用
*/
bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode )
{
char cCmd [120];
sprintf ( cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", pSSID, pPassWord, enunPsdMode );
return ESP8266_Cmd ( cCmd, "OK", 0, 1000 );
}
/*
* 函数名:ESP8266_Enable_MultipleId
* 描述 :WF-ESP8266模块启动多连接
* 输入 :enumEnUnvarnishTx,配置是否多连接
* 返回 : 1,配置成功
* 0,配置失败
* 调用 :被外部调用
*/
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx )
{
char cStr [20];
//启动多连接
sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );
return ESP8266_Cmd ( cStr, "OK", 0, 500 );
}
/*
* 函数名:ESP8266_Link_Server
* 描述 :WF-ESP8266模块连接外部服务器,
* 输入 :enumE,网络协议
* :ip,服务器IP地址字符串
* :ComNum,服务器端口字符串
* :id,模块连接服务器的ID
* 返回 : 1,连接成功
* 0,连接失败
* 调用 :被外部调用
*/
bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char *ip, char *ComNum, ENUM_ID_NO_TypeDef id)
{
char cStr [100] = { 0 }, cCmd [120];
switch ( enumE )
{
case enumTCP:
//"TCP","iot.espressif.cn",8000
sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum );
break;
case enumUDP:
sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum );
break;
default:
break;
}
if ( id < 5 )
//建立TCP连接
sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr);
else
sprintf ( cCmd, "AT+CIPSTART=%s", cStr );
//如果连接已经存在,则返回ALREAY CONNECT
return ESP8266_Cmd ( cCmd, "OK", "ALREAY CONNECT", 4000 );
}
/*
* 函数名:ESP8266_StartOrShutServer
* 描述 :WF-ESP8266模块开启或关闭服务器模式
* 输入 :enumMode,开启/关闭
* :pPortNum,服务器端口号字符串
* :pTimeOver,服务器超时时间字符串,单位:秒
* 返回 : 1,操作成功
* 0,操作失败
* 调用 :被外部调用
*/
bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char *pPortNum, char *pTimeOver )
{
char cCmd1 [120], cCmd2 [120];
if ( enumMode )
{
//建立TCP服务器
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum );
//设置TCP服务器超出时间
sprintf ( cCmd2, "AT+CIPSTO=%s", pTimeOver );
return ( ESP8266_Cmd ( cCmd1, "OK", 0, 500 ) &&
ESP8266_Cmd ( cCmd2, "OK", 0, 500 ) );
}
else
{
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 0, pPortNum );
return ESP8266_Cmd ( cCmd1, "OK", 0, 500 );
}
}
/*
* 函数名:ESP8266_Get_LinkStatus
* 描述 :获取 WF-ESP8266 的连接状态,较适合单端口时使用
* 输入 :无
* 返回 : ESP8266 Station 接?口的状态
* 2: ESP8266 Station 已连接 AP,获得 IP 地址
* 3: ESP8266 Station 已建立 TCP 或 UDP 传输
* 4: ESP8266 Station 断开网络连接
* 0: ESP8266 Station 获取状态失败
* 调用 :被外部调用
*/
uint8_t ESP8266_Get_LinkStatus ( void )
{
//查询 WF-ESP8266 的连接状态
if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:2\r\n" ) )
return 2;
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:3\r\n" ) )
return 3;
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:4\r\n" ) )
return 4;
}
return 0;
}
/*
* 函数名:ESP8266_Get_IdLinkStatus
* 描述 :获取 WF-ESP8266 的端口(Id)连接状态,较适合多端口时使用
* 输入 :无
* 返回 : 端口(Id)的连接状态,低5位为有效位,分别对应Id5~0,某位若置1表该Id建立了连接,若被清0表该Id未建立连接
* 调用 :被外部调用
*/
uint8_t ESP8266_Get_IdLinkStatus ( void )
{
uint8_t ucIdLinkStatus = 0x00;
if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:0," ) )
//给第一位置1
ucIdLinkStatus |= 0x01;
else
//给第一位清0
ucIdLinkStatus &= ~ 0x01;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:1," ) )
ucIdLinkStatus |= 0x02;
else
ucIdLinkStatus &= ~ 0x02;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:2," ) )
ucIdLinkStatus |= 0x04;
else
ucIdLinkStatus &= ~ 0x04;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:3," ) )
ucIdLinkStatus |= 0x08;
else
ucIdLinkStatus &= ~ 0x08;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:4," ) )
ucIdLinkStatus |= 0x10;
else
ucIdLinkStatus &= ~ 0x10;
}
return ucIdLinkStatus;
}
/*
* 函数名:ESP8266_Inquire_ApIp
* 描述 :获取 ESP8266 的 AP IP
* 输入 :pApIp,存放 AP IP 的数组的首地址
* ucArrayLength,存放 AP IP 的数组的长度
* 返回 : 0,获取失败
* 1,获取成功
* 调用 :被外部调用
*/
uint8_t ESP8266_Inquire_ApIp ( char *pApIp, uint8_t ucArrayLength )
{
char uc;
char *pCh;
//查询本地 IP 地址
ESP8266_Cmd ( "AT+CIFSR", "OK", 0, 500 );
pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "APIP,\"" );
if ( pCh )
pCh += 6;
else
return 0;
for ( uc = 0; uc < ucArrayLength; uc ++ )
{
pApIp [ uc ] = * ( pCh + uc);
if ( pApIp [ uc ] == '\"' )
{
pApIp [ uc ] = '\0';
break;
}
}
return 1;
}
/*
* 函数名:ESP8266_UnvarnishSend
* 描述 :配置WF-ESP8266模块进入透传发送
* 输入 :无
* 返回 : 1,配置成功
* 0,配置失败
* 调用 :被外部调用
*/
bool ESP8266_UnvarnishSend ( void )
{
//先设置传输模式,如果连接断开会不断重连,除非+++
if ( ! ESP8266_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ) )
return false;
//在透传模式时,开始发送数据
return
ESP8266_Cmd ( "AT+CIPSEND", "OK", ">", 500 );
}
/*
* 函数名:ESP8266_ExitUnvarnishSend
* 描述 :配置WF-ESP8266模块退出透传模式
* 输入 :无
* 返回 : 无
* 调用 :被外部调用
*/
void ESP8266_ExitUnvarnishSend ( void )
{
Delay_ms ( 1000 );
ESP8266_Usart ( "+++" );
Delay_ms ( 500 );
}
/*
* 函数名:ESP8266_SendString
* 描述 :WF-ESP8266模块发送字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* :pStr,要发送的字符串
* :ulStrLength,要发送的字符串的字节数
* :ucId,哪个ID发送的字符串
* 返回 : 1,发送成功
* 0,发送失败
* 调用 :被外部调用
*/
bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char *pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId )
{
char cStr [20];
bool bRet = false;
//如果设置透传模式直接发送信息
if ( enumEnUnvarnishTx )
{
ESP8266_Usart ( "%s", pStr );
bRet = true;
}
else
//先看什么连接再发送数据的长度,再发送数据
{
//如果是多连接需要AT+CIPSEND=,把格式数据写成串
if ( ucId < 5 )
sprintf ( cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2 );
else
sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 );
//先返回>再接收串口数据
ESP8266_Cmd ( cStr, "> ", 0, 100 );
//如果数据发送成功,返回:SEND OK,否则SEND FATL
bRet = ESP8266_Cmd ( pStr, "SEND OK", 0, 500 );
}
return bRet;
}
/*
* 函数名:ESP8266_ReceiveString
* 描述 :WF-ESP8266模块接收字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* 返回 : 接收到的字符串首地址
* 调用 :被外部调用
*/
char *ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx )
{
char *pRecStr = 0;
strEsp8266_Fram_Record .InfBit .FramLength = 0;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
while ( ! strEsp8266_Fram_Record .InfBit .FramFinishFlag );
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';//增加一个结束符。
if ( enumEnUnvarnishTx )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
else
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" ) )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
}
return pRecStr;
}
/*
* 函数名:ESP8266_CWLIF
* 描述 :查询已接入设备的IP
* 输入 :pStaIp,存放已接入设备的IP
* 返回 : 1,有接入设备
* 0,无接入设备
* 调用 :被外部调用
*/
uint8_t ESP8266_CWLIF ( char *pStaIp )
{
uint8_t uc, ucLen;
char *pCh, * pCh1;
ESP8266_Cmd ( "AT+CWLIF", "OK", 0, 100 );
pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "," );
if ( pCh )
{
pCh1 = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "AT+CWLIF\r\r\n" ) + 11;
ucLen = pCh - pCh1;
}
else
return 0;
for ( uc = 0; uc < ucLen; uc ++ )
pStaIp [ uc ] = * ( pCh1 + uc);
pStaIp [ ucLen ] = '\0';
return 1;
}
/*
* 函数名:ESP8266_CIPAP
* 描述 :设置模块的 AP IP
* 输入 :pApIp,模块的 AP IP
* 返回 : 1,设置成功
* 0,设置失败
* 调用 :被外部调用
*/
uint8_t ESP8266_CIPAP ( char *pApIp )
{
char cCmd [ 30 ];
sprintf ( cCmd, "AT+CIPAP=\"%s\"", pApIp );
if ( ESP8266_Cmd ( cCmd, "OK", 0, 5000 ) )
return 1;
else
return 0;
}
/*
* 函数名:ESP8266_CIPAP
* 描述 :设置模块的 AP IP
* 输入 :pApIp,模块的 AP IP
* 返回 : 1,设置成功
* 0,设置失败
* 调用 :被外部调用
*/
uint8_t ESP8266_CIPSTA ( char *pStaIp )
{
char cCmd [ 30 ];
sprintf ( cCmd, "AT+CIPSTA=\"%s\"", pStaIp );
if ( ESP8266_Cmd ( cCmd, "OK", 0, 5000 ) )
return 1;
else
return 0;
}
#ifndef __ESP8266_H_
#define __ESP8266_H_
#include "stm32f10x.h"
#include "sys.h"
#include "usart.h"
#include
#include
/******************************* ESP8266 数据类型定义 ***************************/
//工作模式
typedef enum
{
STA,
AP,
STA_AP
} ENUM_Net_ModeTypeDef;
//网络协议
typedef enum
{
enumTCP,
enumUDP,
} ENUM_NetPro_TypeDef;
//模块连接服务器的ID
typedef enum
{
Multiple_ID_0 = 0,
Multiple_ID_1 = 1,
Multiple_ID_2 = 2,
Multiple_ID_3 = 3,
Multiple_ID_4 = 4,
Single_ID_0 = 5,
} ENUM_ID_NO_TypeDef;
//
typedef enum
{
OPEN = 0,
WEP = 1,
WPA_PSK = 2,
WPA2_PSK = 3,
WPA_WPA2_PSK = 4,
} ENUM_AP_PsdMode_TypeDef;
/******************************** ESP8266 连接引脚定义 ***********************************/
#define ESP8266_CH_PD_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ESP8266_CH_PD_CLK RCC_APB2Periph_GPIOB
#define ESP8266_CH_PD_PORT GPIOB
#define ESP8266_CH_PD_PIN GPIO_Pin_8
#define ESP8266_RST_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ESP8266_RST_CLK RCC_APB2Periph_GPIOB
#define ESP8266_RST_PORT GPIOB
#define ESP8266_RST_PIN GPIO_Pin_9
#define ESP8266_USARTx USART2
#define DEBUG_USARTx USART1
/******************************* ESP8266 外部全局变量声明 *******************123********/
/*********************************************** ESP8266 函数宏定义 *******************************************/
#define ESP8266_Usart( fmt, ... ) USART_printf ( ESP8266_USARTx, fmt, ##__VA_ARGS__ )
#define PC_Usart( fmt, ... ) printf ( fmt, ##__VA_ARGS__ )
//#define macPC_Usart( fmt, ... )
#define ESP8266_CH_ENABLE() GPIO_SetBits ( ESP8266_CH_PD_PORT, ESP8266_CH_PD_PIN )
#define ESP8266_CH_DISABLE() GPIO_ResetBits ( ESP8266_CH_PD_PORT, ESP8266_CH_PD_PIN )
#define ESP8266_RST_HIGH_LEVEL() GPIO_SetBits ( ESP8266_RST_PORT, ESP8266_RST_PIN )
#define ESP8266_RST_LOW_LEVEL() GPIO_ResetBits ( ESP8266_RST_PORT, ESP8266_RST_PIN )
/******************************** ESP8266 函数声明 *********************************/
void ESP8266_Init ( void );
void ESP8266_Rst ( void );
bool ESP8266_Cmd ( char *cmd, char *reply1, char *reply2, u32 waittime );
bool ESP8266_AT_Test ( void );
bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode );
bool ESP8266_JoinAP ( char *pSSID, char *pPassWord );
bool ESP8266_BuildAP ( char *pSSID, char *pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode );
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx );
bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char *ip, char *ComNum, ENUM_ID_NO_TypeDef id);
bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char *pPortNum, char *pTimeOver );
uint8_t ESP8266_Get_LinkStatus ( void );
uint8_t ESP8266_Get_IdLinkStatus ( void );
uint8_t ESP8266_Inquire_ApIp ( char *pApIp, uint8_t ucArrayLength );
bool ESP8266_UnvarnishSend ( void );
void ESP8266_ExitUnvarnishSend ( void );
bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char *pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId );
char *ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx );
bool ESP8266_DHCP_CUR ( void );
uint8_t ESP8266_CWLIF ( char * pStaIp );
uint8_t ESP8266_CIPAP ( char * pApIp );
uint8_t ESP8266_CIPSTA ( char * pStaIp ); // new
//void ESP8266_AT_Test ( void );
#endif
#include "esp8266_test.h"
#include "esp8266.h"
#include
#include "led.h"
#include
#include
//volatile uint8_t ucTcpClosedFlag = 0;
bool ESP8266_AT_Test ( void );
/**
* @brief ESP8266 StaTcpClient Unvarnish 配置测试函数
* @param 无
* @retval 无
*/
void ESP8266_StaTcpClient_Unvarnish_ConfigTest(void)
{
printf( "\r\n正在配置 ESP8266 ......\r\n" );
printf( "\r\n使能 ESP8266 ......\r\n" );
ESP8266_CH_ENABLE();
while( ! ESP8266_AT_Test() );
while( ! ESP8266_DHCP_CUR () );
printf( "\r\n正在配置工作模式 STA ......\r\n" );
while( ! ESP8266_Net_Mode_Choose ( STA ) );
printf( "\r\n正在连接 WiFi ......\r\n" );
while( ! ESP8266_JoinAP ( User_ESP8266_ApSsid, User_ESP8266_ApPwd ) );
printf( "\r\n禁止多连接 ......\r\n" );
while( ! ESP8266_Enable_MultipleId ( DISABLE ) );
printf( "\r\n正在连接 Server ......\r\n" );
while( ! ESP8266_Link_Server ( enumTCP, User_ESP8266_TcpServer_IP, User_ESP8266_TcpServer_Port, Single_ID_0 ) );
printf( "\r\n进入透传发送模式 ......\r\n" );
while( ! ESP8266_UnvarnishSend () );
printf( "\r\n配置 ESP8266 完毕\r\n" );
printf ( "\r\n开始透传......\r\n" );
}
/**
* @brief ESP8266 检查是否接收到了数据,检查连接和掉线重连
* @param 无
* @retval 无
*/
void ESP8266_CheckRecvDataTest(void)
{
uint8_t ucStatus;
uint16_t i;
/* 如果接收到了串口调试助手的数据 */
if(strUSART_Fram_Record.InfBit.FramFinishFlag == 1)
{
for(i = 0; i < strUSART_Fram_Record.InfBit.FramLength; i++)
{
USART_SendData( ESP8266_USARTx,strUSART_Fram_Record.Data_RX_BUF[i]); //转发给ESP82636
while(USART_GetFlagStatus(ESP8266_USARTx,USART_FLAG_TC)==RESET) {} //等待发送完成
}
strUSART_Fram_Record .InfBit .FramLength = 0; //接收数据长度置零
strUSART_Fram_Record .InfBit .FramFinishFlag = 0; //接收标志置零
}
/* 如果接收到了ESP8266的数据 */
if(strEsp8266_Fram_Record.InfBit.FramFinishFlag)
{
for(i = 0; i < strEsp8266_Fram_Record .InfBit .FramLength; i++)
{
USART_SendData( DEBUG_USARTx,strEsp8266_Fram_Record .Data_RX_BUF[i]); //转发给ESP82636
while(USART_GetFlagStatus(DEBUG_USARTx,USART_FLAG_TC)==RESET) {}
}
strEsp8266_Fram_Record .InfBit .FramLength = 0; //接收数据长度置零
strEsp8266_Fram_Record.InfBit.FramFinishFlag = 0; //接收标志置零
}
if ( ucTcpClosedFlag ) //检测是否失去连接
{
ESP8266_ExitUnvarnishSend (); //退出透传模式
do ucStatus = ESP8266_Get_LinkStatus (); //获取连接状态
while ( ! ucStatus );
if ( ucStatus == 4 ) //确认失去连接后重连
{
printf ( "\r\n正在重连热点和服务器 ......\r\n" );
while ( ! ESP8266_JoinAP ( User_ESP8266_ApSsid, User_ESP8266_ApPwd ) );
while ( ! ESP8266_Link_Server ( enumTCP, User_ESP8266_TcpServer_IP, User_ESP8266_TcpServer_Port, Single_ID_0 ) );
printf ( "\r\n重连热点和服务器成功\r\n" );
}
while ( ! ESP8266_UnvarnishSend () );
}
}
#ifndef __ESP8266_TEST_H
#define __ESP8266_TEST_H
#include "stm32f10x.h"
/********************************** 用户需要设置的参数**********************************/
#define User_ESP8266_ApSsid "ChinaNet-057B" //要连接的热点的名称
#define User_ESP8266_ApPwd "abc1314520" //要连接的热点的密钥
#define User_ESP8266_TcpServer_IP "192.168.2.6" //要连接的服务器的 IP
#define User_ESP8266_TcpServer_Port "808" //要连接的服务器的端口
/********************************** 外部全局变量 ***************************************/
extern volatile uint8_t ucTcpClosedFlag;
extern int read_dht11_finish;
/********************************** 测试函数声明 ***************************************/
void ESP8266_StaTcpClient_Unvarnish_ConfigTest(void);
void ESP8266_CheckRecvDataTest(void);
#endif
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "esp8266.h"
#include "esp8266_test.h"
#include "stm32f10x.h"
#include "stdio.h"
int main()
{
uart1_init(115200); //串口初始化为115200
uart2_init(115200); //串口初始化为115200
/* 初始化 */
LED_GPIO_Config();
ESP8266_Init ();
ESP8266_StaTcpClient_Unvarnish_ConfigTest(); //对ESP8266进行配置
while(1)
{
ESP8266_CheckRecvDataTest();
}
}
stm32f103c8t6自带一个led灯,使用PC13引脚就行了,
切记尽量避免使用PB3、PB4,具体看stm32f103c8t6使用PB3和PB4做普通GPIO使用时发现异常
#include "led.h" //绑定led.h
void LED_GPIO_Config(void) {
GPIO_InitTypeDef GPIO_InitStruct; //初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。
//开启RCC时钟
RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK, ENABLE);
//配置初始化,推挽输出方式和LED_G_GPIO_PIN管脚、赫兹
GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
//GPIO口初始化
GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
}
#ifndef __LED_H_
#define __LED_H_
#include "stm32f10x.h"
#include "sys.h"
#define LED_G_GPIO_PIN GPIO_Pin_13
#define LED_G_GPIO_PORT GPIOC
#define LED_G_GPIO_CLK RCC_APB2Periph_GPIOC
//使用位带操作来实现操作某个IO口的 1个位,由sys.h实现
#define LED PCout(13)
void LED_GPIO_Config(void); //函数定义
#endif
usart.c 、usart.h 、esp8266.c、esp8266.h等文件和实现穿透的代码一样,
#include "esp8266_test.h"
#include "esp8266.h"
#include
#include "led.h"
#include "delay.h"
#include
#include
uint8_t ucId, ucLen;
uint8_t ucLed1Status = 0;
char cStr [ 100 ] = { 0 }, cCh;
char *pCh, * pCh1;
//volatile uint8_t ucTcpClosedFlag = 0;
bool ESP8266_AT_Test ( void );
/**
* @brief ESP8266 ApTcpServer 配置测试函数
* @param 无
* @retval 无
*/
void ESP8266_ApTcpServer_ConfigTest(void)
{
printf( "\r\n正在配置 ESP8266 ......\r\n" );
printf( "\r\n使能 ESP8266 ......\r\n" );
ESP8266_CH_ENABLE();
while( ! ESP8266_AT_Test() );
printf( "\r\n正在配置工作模式为 AP ......\r\n" );
while( ! ESP8266_Net_Mode_Choose ( AP ) );
printf( "\r\n正在创建WiFi热点 ......\r\n" );
while ( ! ESP8266_CIPAP ( User_ESP8266_TcpServer_IP ) ); //设置模块的 AP IP
while ( ! ESP8266_BuildAP ( User_ESP8266_BulitApSsid, User_ESP8266_BulitApPwd, User_ESP8266_BulitApEcn ) );
printf( "\r\n允许多连接 ......\r\n" );
while( ! ESP8266_Enable_MultipleId ( ENABLE ) );
printf( "\r\n开启服务器模式 ......\r\n" );
while ( ! ESP8266_StartOrShutServer ( ENABLE, User_ESP8266_TcpServer_Port, User_ESP8266_TcpServer_OverTime ) );
ESP8266_Inquire_ApIp ( cStr, 20 );
printf ( "\n本模块WIFI为 %s,密码开放\nAP IP 为:%s,开启的端口为:%s\r\n手机网络助手连接该 IP 和端口,最多可连接5个客户端\n",
User_ESP8266_BulitApSsid, cStr, User_ESP8266_TcpServer_Port );
strEsp8266_Fram_Record .InfBit .FramLength = 0;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
printf( "\r\n配置 ESP8266 完毕\r\n" );
}
/**
* @brief ESP8266 检查接收信息并发送数据测试函数
* @param 无
* @retval 无
*/
void ESP8266_CheckRecvDataTest(void)
{
if ( strEsp8266_Fram_Record .InfBit .FramFinishFlag ) //如果有数据传输结束
{
USART_ITConfig ( ESP8266_USARTx, USART_IT_RXNE, DISABLE ); //禁用串口接收中断,防止影响
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';
printf("ucCh =%s\n", strEsp8266_Fram_Record .Data_RX_BUF);
if(strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "LED=1" )) //如果手机发送的数据存在LED=1,则if成立
{
PCout(13) = 1; //PC口13引脚输出,高电平
printf("\r\nLED灭\r\n");
Delay_ms(500); //已经在delay.h中初始化
}
else if(strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "LED=0" ))
{
PCout(13) = 0; //PC口13引脚输出,低电平
printf("\r\nLED亮\r\n");
Delay_ms(500);
}
if ( ( pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD," ) ) != 0 )
{
ucId = * ( pCh + strlen ( "+IPD," ) ) - '0';
ESP8266_SendString ( DISABLE, cStr, strlen ( cStr ), ( ENUM_ID_NO_TypeDef ) ucId );
}
strEsp8266_Fram_Record .InfBit .FramLength = 0;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
USART_ITConfig ( ESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断
}
}
#ifndef __ESP8266_TEST_H
#define __ESP8266_TEST_H
#include "stm32f10x.h"
/********************************** 用户需要设置的参数**********************************/
#define User_ESP8266_ApSsid "ChinaNet-057B" //要连接的热点的名称
#define User_ESP8266_ApPwd "abc1314520" //要连接的热点的密钥
#define User_ESP8266_TcpServer_IP "192.168.4.1" //要连接的服务器的 IP
#define User_ESP8266_TcpServer_Port "8888" //要连接的服务器的端口
#define User_ESP8266_BulitApSsid "ESP8266" //要建立的热点的名称
#define User_ESP8266_BulitApEcn OPEN //要建立的热点的加密方式
#define User_ESP8266_BulitApPwd "12345678" //要建立的热点的密钥
#define User_ESP8266_TcpServer_OverTime "1800" //服务器超时时间(单位:秒)
/********************************** 外部全局变量 ***************************************/
extern volatile uint8_t ucTcpClosedFlag;
extern int read_dht11_finish;
/********************************** 测试函数声明 ***************************************/
void ESP8266_ApTcpServer_ConfigTest(void);
void ESP8266_CheckRecvDataTest(void);
#endif
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "esp8266.h"
#include "esp8266_test.h"
#include "stm32f10x.h"
#include "stdio.h"
int main()
{
uart1_init(115200); //串口初始化为115200
uart2_init(115200); //串口初始化为115200
/* 初始化 */
LED_GPIO_Config();
ESP8266_Init ();
ESP8266_ApTcpServer_ConfigTest(); //对ESP8266进行配置
while(1)
{
ESP8266_CheckRecvDataTest();
}
}
本文选择的是ST_Link烧录工具
如果没有ID号看博客:ST-Link V2烧录问题(已解决)
这里PC13已经亮灭了就没有上传截图,大家自己可以试试
使用MCU完成透传功能:
链接:https://pan.baidu.com/s/1RugvDofb_JQDTqpoYFQ-8w 提取码:0000
ESP8266使用Ap模式控制mcu:
链接:https://pan.baidu.com/s/1Fol88R_HwS9LNbLXYpN5Iw 提取码:0000