今天学习了野火的wifi控制部分的代码,自己解析和简化了一下代码来做了个笔记,我很菜的勿喷。
1、简化后的文件夹中的内如图: 因为只要控制蜂鸣器,所以只保留了Beep这部分,原本的LED和温湿度我删除了
2、分析main.c文件
#include "stm32f10x.h" #include "bsp_usart1.h" #include "bsp_SysTick.h" #include "bsp_esp8266.h" #include "test.h" #include "bsp_beep.h" /** * @brief 主函数 * @param 无 * @retval 无 */ int main ( void ) { /* 初始化 */ USARTx_Config (); //初始化串口1 SysTick_Init (); //配置 SysTick 为 1ms 中断一次 ESP8266_Init (); //初始化WiFi模块使用的接口和外设 Beep_Init (); printf ( "\r\n野火 WF-ESP8266 WiFi模块测试例程\r\n" ); //打印测试例程提示信息 ESP8266_StaTcpClient_UnvarnishTest (); while ( 1 ); }这部分很简单,基本看了就明白了
2、系统定时器部分,野火的没做如何修改 (1)bsp_SysTick.h
#ifndef __SYSTICK_H #define __SYSTICK_H #include "stm32f10x.h" #define Delay_ms(x) Delay_us(1000*x) //单位ms void SysTick_Init( void ); void TimingDelay_Decrement( void ); void Delay_us ( __IO u32 nTime ); #endif /* __SYSTICK_H */(2)bsp_SysTick.c
#include "bsp_SysTick.h" static __IO u32 TimingDelay = 0; /** * @brief 启动系统滴答定时器 SysTick * @param 无 * @retval 无 */ void SysTick_Init( void ) { /* SystemFrequency / 1000 1ms中断一次 * SystemFrequency / 100000 10us中断一次 * SystemFrequency / 1000000 1us中断一次 */ if ( SysTick_Config(SystemCoreClock / 1000000) ) // ST3.5.0库版本 { /* Capture error */ while (1); } // 关闭滴答定时器 SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; } /** * @brief ms延时程序,1us为一个单位 * @param * @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 1us = 1us * @retval 无 */ void Delay_us( __IO u32 nTime ) { TimingDelay = nTime; // 使能滴答定时器 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; while( TimingDelay != 0 ); } /** * @brief 获取节拍程序 * @param 无 * @retval 无 * @attention 在 SysTick 中断函数 SysTick_Handler()调用 */ void TimingDelay_Decrement(void) { if ( TimingDelay != 0x00 ) { TimingDelay --; } }3、中断函数文件 里面添加的函数我做了个简要注释 stm32f10x_it.c
void macESP8266_USART_INT_FUN ( void ) { uint8_t ucCh; //定义中间量接收传给STM32串口的数据 if ( USART_GetITStatus ( macESP8266_USARTx, USART_IT_RXNE ) != RESET ) //为真表明STM32这边有数据接收到 { ucCh = USART_ReceiveData( macESP8266_USARTx ); //ucCh用来作为“temp”缓存接收到的数据 if ( strEsp8266_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) ) //预留1个字节写结束符(也就是说接收的数据最多是1023个字节) strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ++ ] = ucCh; //到这里就可以看出只要“strEsp8266_Fram_Record .InfBit .FramLength<1024”,那么就将8位读buff得到的ASCII循环赋值给串口接收数据缓冲区“strEsp8266_Fram_Record .Data_RX_BUF” } if ( USART_GetITStatus( macESP8266_USARTx, USART_IT_IDLE ) == SET ) //数据帧接收完毕 { strEsp8266_Fram_Record .InfBit .FramFinishFlag = 1; //接收完数据,那么方向位就要发生改变,表明消息完成了APP->STM32的变化 ucCh = USART_ReceiveData( macESP8266_USARTx ); //由软件序列清除中断标志位(先读USART_SR,然后读USART_DR) } }4、与电脑连接,通过串口1测试部分(主要用途就是来看测试通信的情况) bsp_usart1.h
#ifndef __USART1_H #define __USART1_H #include "stm32f10x.h" #include <stdio.h> /**************************USART参数定义********************************/ #define macUSART_BAUD_RATE 115200 #define macUSARTx USART1 #define macUSART_APBxClock_FUN RCC_APB2PeriphClockCmd #define macUSART_CLK RCC_APB2Periph_USART1 #define macUSART_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd #define macUSART_GPIO_CLK RCC_APB2Periph_GPIOA #define macUSART_TX_PORT GPIOA #define macUSART_TX_PIN GPIO_Pin_9 #define macUSART_RX_PORT GPIOA #define macUSART_RX_PIN GPIO_Pin_10 #define macUSART_IRQ USART1_IRQn #define macUSART_INT_FUN USART1_IRQHandler void USARTx_Config ( void );bsp_usart1.c
#include "bsp_usart1.h" /** * @brief USARTx GPIO 配置,工作模式配置。115200 8-N-1 * @param 无 * @retval 无 */ void USARTx_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; /* config USART1 clock */ macUSART_APBxClock_FUN(macUSART_CLK, ENABLE); macUSART_GPIO_APBxClock_FUN(macUSART_GPIO_CLK, ENABLE); /* USART1 GPIO config */ /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = macUSART_TX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(macUSART_TX_PORT, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = macUSART_RX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(macUSART_RX_PORT, &GPIO_InitStructure); /* USART1 mode config */ USART_InitStructure.USART_BaudRate = macUSART_BAUD_RATE; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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(macUSARTx, &USART_InitStructure); USART_Cmd(macUSARTx, ENABLE); } /// 重定向c库函数printf到USART1 int fputc(int ch, FILE *f) { /* 发送一个字节数据到USART1 */ USART_SendData(macUSARTx, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(macUSARTx, USART_FLAG_TXE) == RESET); return (ch); } /// 重定向c库函数scanf到USART1 int fgetc(FILE *f) { /* 等待串口1输入数据 */ while (USART_GetFlagStatus(macUSARTx, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(macUSARTx); }看到这我发现这两个.h和.c的文件只是做了个初始化串口1和重定向C库的工作,不像学习串口收发时写了一堆发送数据函数并在stm32f10x_it.c中写了串口中断发送数据的指令,往后看就明白了。
5、wife串口初始化部分 bsp_esp8266.h
#ifndef __BSP_ESP8266_H #define __BSP_ESP8266_H #include "stm32f10x.h" #include "common.h" #include <stdio.h> #include <stdbool.h> #if defined ( __CC_ARM ) #pragma anon_unions #endif /******************************* ESP8266 数据类型定义 ***************************/ typedef enum{ STA, AP, STA_AP } ENUM_Net_ModeTypeDef; typedef enum{ enumTCP, enumUDP, } ENUM_NetPro_TypeDef; 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 RX_BUF_MAX_LEN 1024 //最大接收缓存字节数 extern struct 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; }; } strEsp8266_Fram_Record; /******************************** ESP8266 连接引脚定义 ***********************************/ #define macESP8266_CH_PD_APBxClock_FUN RCC_APB2PeriphClockCmd #define macESP8266_CH_PD_CLK RCC_APB2Periph_GPIOB #define macESP8266_CH_PD_PORT GPIOB #define macESP8266_CH_PD_PIN GPIO_Pin_8 #define macESP8266_RST_APBxClock_FUN RCC_APB2PeriphClockCmd #define macESP8266_RST_CLK RCC_APB2Periph_GPIOB #define macESP8266_RST_PORT GPIOB #define macESP8266_RST_PIN GPIO_Pin_9 #define macESP8266_USART_BAUD_RATE 115200 #define macESP8266_USARTx USART3 #define macESP8266_USART_APBxClock_FUN RCC_APB1PeriphClockCmd #define macESP8266_USART_CLK RCC_APB1Periph_USART3 #define macESP8266_USART_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd #define macESP8266_USART_GPIO_CLK RCC_APB2Periph_GPIOB #define macESP8266_USART_TX_PORT GPIOB #define macESP8266_USART_TX_PIN GPIO_Pin_10 #define macESP8266_USART_RX_PORT GPIOB #define macESP8266_USART_RX_PIN GPIO_Pin_11 #define macESP8266_USART_IRQ USART3_IRQn #define macESP8266_USART_INT_FUN USART3_IRQHandler /*********************************************** ESP8266 函数宏定义 *******************************************/ #define macESP8266_Usart( fmt, ... ) USART_printf ( macESP8266_USARTx, fmt, ##__VA_ARGS__ ) #define macPC_Usart( fmt, ... ) printf ( fmt, ##__VA_ARGS__ ) #define macESP8266_CH_ENABLE() GPIO_SetBits ( macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN )//****************** #define macESP8266_CH_DISABLE() GPIO_ResetBits ( macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN ) #define macESP8266_RST_HIGH_LEVEL() GPIO_SetBits ( macESP8266_RST_PORT, macESP8266_RST_PIN ) #define macESP8266_RST_LOW_LEVEL() GPIO_ResetBits ( macESP8266_RST_PORT, macESP8266_RST_PIN ) /****************************************** ESP8266 函数声明 ***********************************************/ void ESP8266_Init ( void ); //ESP8266初始化函数 void ESP8266_Rst ( void ); //重启WF-ESP8266模块 bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime ); //ESP8266_Cmd(用于发送指令被多个函数用到) void ESP8266_AT_Test ( void ); //对WF-ESP8266模块进行AT测试启动 bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode ); //ESP8266_Net_Mode_Choose(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode ); //WF-ESP8266模块创建WiFi热点 bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx ); //WF-ESP8266模块启动多连接 bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver ); //WF-ESP8266模块开启或关闭服务器模式 bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId ); //WF-ESP8266模块发送字符串 uint8_t ESP8266_CIPAP ( char * pApIp ); //设置模块的 AP IP #endifbsp_esp8266.c
#include "bsp_esp8266.h" #include "common.h" #include <stdio.h> #include <string.h> #include <stdbool.h> #include "bsp_SysTick.h" static void ESP8266_GPIO_Config ( void ); static void ESP8266_USART_Config ( void ); static void ESP8266_USART_NVIC_Configuration ( void ); struct STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 }; /***** * @brief ESP8266初始化函数(在main.c文件中被调用) * @param 无 * @retval 无 */ void ESP8266_Init ( void ) { ESP8266_GPIO_Config (); ESP8266_USART_Config (); macESP8266_RST_HIGH_LEVEL(); macESP8266_CH_DISABLE(); } /***** * @brief 初始化ESP8266用到的GPIO引脚(被本.c文件中的ESP8266_Init ( void )函数调用) * @param 无 * @retval 无 */ static void ESP8266_GPIO_Config ( void ) { /*定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef GPIO_InitStructure; /* 配置 CH_PD 引脚*/ macESP8266_CH_PD_APBxClock_FUN ( macESP8266_CH_PD_CLK, ENABLE ); GPIO_InitStructure.GPIO_Pin = macESP8266_CH_PD_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init ( macESP8266_CH_PD_PORT, & GPIO_InitStructure ); /* 配置 RST 引脚*/ macESP8266_RST_APBxClock_FUN ( macESP8266_RST_CLK, ENABLE ); GPIO_InitStructure.GPIO_Pin = macESP8266_RST_PIN; GPIO_Init ( macESP8266_RST_PORT, & GPIO_InitStructure ); } /***** * @brief 初始化ESP8266用到的 USART(被本.c文件中的ESP8266_Init ( void )函数调用) * @param 无 * @retval 无 */ static void ESP8266_USART_Config ( void ) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; /* config USART clock */ macESP8266_USART_APBxClock_FUN ( macESP8266_USART_CLK, ENABLE ); macESP8266_USART_GPIO_APBxClock_FUN ( macESP8266_USART_GPIO_CLK, ENABLE ); /* USART GPIO config */ /* Configure USART Tx as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = macESP8266_USART_TX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(macESP8266_USART_TX_PORT, &GPIO_InitStructure); /* Configure USART Rx as input floating */ GPIO_InitStructure.GPIO_Pin = macESP8266_USART_RX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(macESP8266_USART_RX_PORT, &GPIO_InitStructure); /* USART1 mode config */ USART_InitStructure.USART_BaudRate = macESP8266_USART_BAUD_RATE; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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(macESP8266_USARTx, &USART_InitStructure); /* 中断配置 */ USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断 USART_ITConfig ( macESP8266_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断 ESP8266_USART_NVIC_Configuration (); USART_Cmd(macESP8266_USARTx, ENABLE); } /***** * @brief 配置 ESP8266 USART 的 NVIC 中断(在本.c文件的ESP8266_USART_Config ( void )函数中被调用,配置中断优先级) * @param 无 * @retval 无 */ static void ESP8266_USART_NVIC_Configuration ( void ) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the NVIC Preemption Priority Bits */ NVIC_PriorityGroupConfig ( macNVIC_PriorityGroup_x ); /* Enable the USART2 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = macESP8266_USART_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /*** * 函数名:ESP8266_Rst(在bsp_esp8266.c文件中的ESP8266_AT_Test函数中被调用) * 描述 :重启WF-ESP8266模块 * 输入 :无 * 返回 : 无 * 调用 :被 ESP8266_AT_Test 调用 */ void ESP8266_Rst ( void ) { #if 0 ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 ); #else macESP8266_RST_LOW_LEVEL(); Delay_ms ( 500 ); macESP8266_RST_HIGH_LEVEL(); #endif } /**** * 函数名: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; //从新开始接收新的数据包 macESP8266_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'; macPC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF ); 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_AT_Test(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) * 描述 :对WF-ESP8266模块进行AT测试启动 * 输入 :无 * 返回 : 无 * 调用 :被外部调用 */ void ESP8266_AT_Test ( void ) { char count=0; macESP8266_RST_HIGH_LEVEL(); Delay_ms ( 1000 ); while ( count < 10 ) { if( ESP8266_Cmd ( "AT", "OK", NULL, 500 ) ) return; ESP8266_Rst(); ++ count; } } /**** * 函数名:ESP8266_Net_Mode_Choose(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) * 描述 :选择WF-ESP8266模块的工作模式 * 输入 :enumMode,工作模式 * 返回 : 1,选择成功 * 0,选择失败 * 调用 :被外部调用 */ bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode ) { switch ( enumMode ) { 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_BuildAP(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) * 描述 :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(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) * 描述 :WF-ESP8266模块启动多连接 * 输入 :enumEnUnvarnishTx,配置是否多连接 * 返回 : 1,配置成功 * 0,配置失败 * 调用 :被外部调用 */ bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx ) { char cStr [20]; sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) ); // 0:单连接模式 1:多连接模式; return ESP8266_Cmd ( cStr, "OK", 0, 500 ); } /***** * 函数名:ESP8266_StartOrShutServer(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) * 描述 :WF-ESP8266模块开启或关闭服务器模式 * 输入 :enumMode,开启/关闭 * :pPortNum,服务器端口号字符串 * :pTimeOver,服务器超时时间字符串,单位:秒 * 返回 : 1,操作成功 * 0,操作失败 * 调用 :被外部调用 */ bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver ) { char cCmd1 [120], cCmd2 [120]; if ( enumMode ) { sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum ); 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_SendString(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) * 描述 :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 ) { macESP8266_Usart ( "%s", pStr ); bRet = true; } else { 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 ); bRet = ESP8266_Cmd ( pStr, "SEND OK", 0, 500 ); } return bRet; } /***** * 函数名:ESP8266_CIPAP(被test.c文件中的ESP8266_StaTcpClient_UnvarnishTest ( void )函数调用) * 描述 :设置模块的 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; }bsp_esp8266.h和bsp_esp8266.c文件用来初始化与esp8266模块相连接的串口(这里用到了串口Usart3),并且通过在bsp_esp8266.c中写的函数,在下面的test.c文件中调用实现esp8266模块有关AT指令的设置(类似于之前介绍过的蓝牙)。这部分我也是借鉴野火的wifi程序,但因为这个实验只涉及到一个app控制beep响不响的实验,因此删除了许多无关的esp8266的设置程序。
common.h
#ifndef __COMMON_H #define __COMMON_H #include "stm32f10x.h" /******************************* 宏定义 ***************************/ #define macNVIC_PriorityGroup_x NVIC_PriorityGroup_2 /********************************** 函数声明 ***************************************/ //******void USART_printf ( USART_TypeDef * USARTx, char * Data, ... ); //类似C语言库中的sprintf的声明:int sprintf(char *str, const char *format, ...): //str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。 //例如:char str[80]; float M_PI=3.14;sprintf(str, "Pi 的值 = %f", M_PI);puts(str);(Put必须加不然不显示在屏幕上)编译的结果Pi 的值 = 3.141593 #endif /* __COMMON_H */common.c
#include "common.h" #include "stm32f10x.h" #include <stdarg.h> static char * itoa ( int value, char * string, int radix ); /* * 函数名:USART2_printf * 描述 :格式化输出,类似于C库中的printf,但这里没有用到C库 * 输入 :-USARTx 串口通道,这里只用到了串口2,即USART2 * -Data 要发送到串口的内容的指针 * -... 其他参数 * 输出 :无 * 返回 :无 * 调用 :外部调用 * 典型应用USART2_printf( USART2, "\r\n this is a demo \r\n" ); * USART2_printf( USART2, "\r\n %d \r\n", i ); * USART2_printf( USART2, "\r\n %s \r\n", j ); */ void USART_printf ( USART_TypeDef * USARTx, char * Data, ... ) { const char *s; int d; char buf[16]; va_list ap; va_start(ap, Data); while ( * Data != 0 ) // 判断是否到达字符串结束符 { if ( * Data == 0x5c ) //'\' { switch ( *++Data ) { case 'r': //回车符 USART_SendData(USARTx, 0x0d); Data ++; break; case 'n': //换行符 USART_SendData(USARTx, 0x0a); Data ++; break; default: Data ++; break; } } else if ( * Data == '%') { // switch ( *++Data ) { case 's': //字符串 s = va_arg(ap, const char *); for ( ; *s; s++) { USART_SendData(USARTx,*s); while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET ); } Data++; break; case 'd': //十进制 d = va_arg(ap, int); itoa(d, buf, 10); for (s = buf; *s; s++) { USART_SendData(USARTx,*s); while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET ); } Data++; break; default: Data++; break; } } else USART_SendData(USARTx, *Data++); while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET ); } } /* * 函数名:itoa * 描述 :将整形数据转换成字符串 * 输入 :-radix =10 表示10进制,其他结果为0 * -value 要转换的整形数 * -buf 转换后的字符串 * -radix = 10 * 输出 :无 * 返回 :无 * 调用 :被USART2_printf()调用 */ static char * itoa( int value, char *string, int radix ) { int i, d; int flag = 0; char *ptr = string; /* This implementation only works for decimal numbers. */ if (radix != 10) { *ptr = 0; return string; } if (!value) { *ptr++ = 0x30; *ptr = 0; return string; } /* if this is a negative value insert the minus sign. */ if (value < 0) { *ptr++ = '-'; /* Make the value positive. */ value *= -1; } for (i = 10000; i > 0; i /= 10) { d = value / i; if (d || flag) { *ptr++ = (char)(d + 0x30); value -= (d * i); flag = 1; } } /* Null terminate the string. */ *ptr = 0; return string; } /* NCL_Itoa */这段common.c和common.h一开始我没看懂,然后我将这部分注释掉就明白了这两个文件的作用了,重定义了esp8266相连的串口3的发送(给APP的)数据的方式。
6、蜂鸣器相连的GPIO的初始化 bsp_beep.h
#ifndef __BEEP_H_ #define __BEEP_H_ #include "stm32f10x.h" /******************** BEEP 引脚配置参数定义 **************************/ #define macBEEP_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd #define macBEEP_GPIO_CLK RCC_APB2Periph_GPIOA #define macBEEP_PORT GPIOA #define macBEEP_PIN GPIO_Pin_8 /******************** BEEP 函数宏定义 **************************/ #define macBEEP_ON() GPIO_SetBits ( macBEEP_PORT, macBEEP_PIN ) #define macBEEP_OFF() GPIO_ResetBits ( macBEEP_PORT, macBEEP_PIN ) /************************** BEEP 函数声明********************************/ void Beep_Init ( void ); #endif /* __BEEP_H_ */bsp_beep.c
#include "..\User\Beep\bsp_beep.h" static void Beep_GPIO_Config ( void ); void Beep_Init ( void ) { Beep_GPIO_Config (); macBEEP_OFF (); // 关闭蜂鸣器 } static void Beep_GPIO_Config ( void ) { /*定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef GPIO_InitStructure; /*开启GPIOB和GPIOF的外设时钟*/ macBEEP_GPIO_APBxClock_FUN ( macBEEP_GPIO_CLK, ENABLE ); /*选择要控制的GPIOG引脚*/ GPIO_InitStructure.GPIO_Pin = macBEEP_PIN; /*设置引脚模式为通用推挽输出*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*设置引脚速率为50MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIOG6*/ GPIO_Init ( macBEEP_PORT, & GPIO_InitStructure ); } /*********************************************END OF FILE**********************/5、程序的重要部分,这个地方我的精简了,注释详细看一下就明白的(我感觉这部分才是main.c秃头呀 ) test.h
#ifndef __TEST_H #define __TEST_H #include "stm32f10x.h" #include "bsp_esp8266.h" /********************************** 用户需要设置的参数**********************************/ #define macUser_ESP8266_BulitApSsid "YehuoLink" //要建立的热点的名称 #define macUser_ESP8266_BulitApEcn OPEN //要建立的热点的加密方式 #define macUser_ESP8266_BulitApPwd "wildfire" //要建立的热点的密钥 #define macUser_ESP8266_TcpServer_IP "192.168.1.1" //服务器开启的IP地址 #define macUser_ESP8266_TcpServer_Port "8080" //服务器开启的端口 #define macUser_ESP8266_TcpServer_OverTime "1800" //服务器超时时间(单位:秒) /********************************** 测试函数声明 ***************************************/ void ESP8266_StaTcpClient_UnvarnishTest ( void ); #endiftest.c
#include "test.h" #include "bsp_esp8266.h" #include "bsp_SysTick.h" #include <stdio.h> #include <string.h> #include <stdbool.h> #include "bsp_beep.h" ```cpp /** * @brief ESP8266 (Sta Tcp Client)透传 * @param 无 * @retval 无 */ void ESP8266_StaTcpClient_UnvarnishTest ( void ) { uint8_t ucId; //uc:通信;ID:用户 uint8_t ucBuzzerStatus = 0; //蜂鸣器的状态 char cStr [ 100 ] = { 0 }, cCh; //stm32要通过esp8266发送出去的数据 char * pCh; printf ( "\r\n正在配置 ESP8266 ......\r\n" ); macESP8266_CH_ENABLE(); //模块使能高电平有效 ESP8266_AT_Test (); //对WF-ESP8266模块进行AT测试启动 ESP8266_Net_Mode_Choose ( AP ); //选择WF-ESP8266模块的工作模式:AP模式 while ( ! ESP8266_CIPAP ( macUser_ESP8266_TcpServer_IP ) ); //设置模块的 AP IP:192.168.1.1 while ( ! ESP8266_BuildAP ( macUser_ESP8266_BulitApSsid, macUser_ESP8266_BulitApPwd, macUser_ESP8266_BulitApEcn ) ); //WF-ESP8266模块创建WiFi热点;热点名称:YehuoLink,热点秘钥:wildfire(目前好像没什么用感觉,用自制的APP也能实现wife控制);热点的加密方式:OPEN(无密码,连网时不用输密码了) ESP8266_Enable_MultipleId ( ENABLE );//WF-ESP8266模块启动多连接(,DISABLE=0单连接,ENABLE = 1,多连接,少了这个端口配置就不对了), 只有非透传模式 (AT+CIPMODE=0),才能设置为多连接;如果建?立了了 TCP 服务器?,想切换为单连接,必须关闭服务器(AT+CIPSERVER=0),服务器?仅?支持多连接 while ( ! ESP8266_StartOrShutServer ( ENABLE, macUser_ESP8266_TcpServer_Port, macUser_ESP8266_TcpServer_OverTime ) );//WF-ESP8266模块开启或关闭服务器模式;参数2:服务器端口8080;参数3:服务器超时时间 strEsp8266_Fram_Record .InfBit .FramLength = 0; strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0; while ( 1 ) { if ( strEsp8266_Fram_Record .InfBit .FramFinishFlag ) //strEsp8266_Fram_Record .InfBit .FramFinishFlag 是串口发送的方向位;1:表示信息从APP传至STM32(类似以前写的51蓝牙的方向位) { USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, DISABLE ); //禁用串口接收中断(上面的方向位置1,说明串口接收到数据,要进行判断处理了,这是应关闭接收中断防止其他中断源进来) strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0'; if ( ( pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "CMD_BUZZER_" ) ) != 0 ) //strstr() 函数搜索一个字符串在另一个字符串中的第一次出现,该函数返回字符串的其余部分(从匹配点)。如果未找到所搜索的字符串,则返回 false。 { cCh = * ( pCh + 11 );//配合上面的strstr();例如strstr(helloworld!,word),则返回world!,+11是同样的道理,看跟着的第十二位那个带的是0还是1,来做case判断 switch ( cCh ) { case '0': macBEEP_OFF (); ucBuzzerStatus = 0; break; case '1': macBEEP_ON (); ucBuzzerStatus = 1; break; default: break; } sprintf ( cStr, "CMD_BUZZER_%d_ENDBUZZER_END", ucBuzzerStatus ); //将返回信息赋值给字符串cStr,返回给APP的字符串cStr,例如蜂鸣器开则返回:CMD_BUZZER_1_ENDBUZZER_END } if ( ( pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD," ) ) != 0 ) {//AT指令中“+IPD”为—接收网络数据 命令 ucId = * ( pCh + strlen ( "+IPD," ) ) - '0'; ESP8266_SendString ( DISABLE, cStr, strlen ( cStr ), ( ENUM_ID_NO_TypeDef ) ucId );//WF-ESP8266模块发送字符串(发送返回信息字符串cStr) } strEsp8266_Fram_Record .InfBit .FramLength = 0; //接收缓冲区计数器清零,类似[counter++]后counter清零 strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0; //接收标志位15清零 USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断(再把串口接收中断打开,准备接收APP发来的下一次指令) } } }**注意:**因为这里用到了系统定时,因此要在中断服务函数里的
void SysTick_Handler(void){ }里加一句“TimingDelay_Decrement(); ”因为回来自己搞项目的时候,移植程序的时候这个没加,编译没错但一直找不到项目不能正常运行的问题(秃头)
7、图片展示: (1)按下开发板的复位按键: 通过串口1和串口调试初始可看到如下情况,表明程序初始化完成,已进入等待app指令的阶段 (2)手机APP连接esp8266模块发出的热点
(3)APP发送指令给单片机,单片机执行 发送CMD_BUZZER_1:继电器开 发送CMD_BUZZER_0:继电器关 这个APP是我网上下载的,不是用野火的。要是想直接制作这种能够实现appwife控制的单片机的软件的话,建议学习一下appinventor在线开发,很简单,之前也讲过自制蓝牙控制的APP。不过appinventor里没有wifi控制的组件,要自己网上下载一个插进平台里去
