一、文章中要用的指令
指令 | 作用 |
AT+UART=115200,8,1,0,0 | 之前的51通讯是9600,这里的321用的是115200,需要改一下波特率 |
AT+CWMODE=X | X是1代表station(设备)模式 ,X是2代表AP(路由)模式 ,X是3.代表双模模式(工作模式在串口助手里已经设置为双模,掉电后自动保存,因此程序中并未体现配置工作模式,这个配置模式的指令写与不写均可以) |
AT+CWJAP="PEI","jmgcyjs." | 第一个引号里的是wifi的名称,第二个是WiFi密码,要注意的是,使用的时候一定要确保你的电脑和wifi模块连接的是一个wifi,否则无法成功。 |
AT+CIPSTART="TCP","192.168.1.112",8880 | 连接服务器,TCP代表客户端模式,电脑连接无线网地址192.168.1.112,8880代表端口号 |
AT+CIPMODE=1 | 透传指令,不用受发送次数还有发送字节大小限制 |
AT+CIPSEND | 开始发送 |
AT+RST | 重启指令 |
有关esp8266的烧录我在之前说过,有兴趣的可以看一看,http://t.csdnimg.cn/J3Sid
二、代码部分
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include <string.h>
#include <stdio.h>
uint8_t buf=0;//串口接收缓存(1字节)
#define UART1_REC_LEN 200//定义最大接收字节数 200,可根据需求调整
uint8_t UART1_RX_Buffer[UART1_REC_LEN];// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint16_t UART1_RX_STA=0;// 接收状态
// bit15, 接收完成标志
// bit14, 接收到0x0d
// bit13~0, 接收到的有效字节数目
void SystemClock_Config(void);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// 判断中断是由哪个串口触发的
if(huart->Instance == USART1)
{
// 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
if((UART1_RX_STA & 0x8000) == 0)
{
// 如果已经收到了 0x0d (回车),
if(UART1_RX_STA & 0x4000)
{
// 则接着判断是否收到 0x0a (换行)
if(buf == 0x0a)
{ // 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
UART1_RX_STA |= 0x8000;
if(!strcmp((const char*)UART1_RX_Buffer,"WIFI GOT IP"))
AT_Connect_Net_Flag = 1;
if(!strcmp((const char*)UART1_RX_Buffer,"OK"))
AT_OK_Flag = 1;
if(!strcmp((const char*)UART1_RX_Buffer,"L1"))
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
if(!strcmp((const char*)UART1_RX_Buffer,"L0"))
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
if(!strcmp((const char*)UART1_RX_Buffer,"FALL"))//连接网络不成功就会给单片机返回FALL
{
int i=0;
for(i=0;i<5;i++)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
HAL_Delay(1000);
}
}
memset(UART1_RX_Buffer,0,UART1_REC_LEN);
UART1_RX_STA=0;
}
else
// 否则认为接收错误,重新开始
UART1_RX_STA = 0;
}
else // 如果没有收到了 0x0d (回车)
{
//则先判断收到的这个字符是否是 0x0d (回车)
if(buf == 0x0d)
{
// 是的话则将 bit14 位置为1
UART1_RX_STA |= 0x4000;
}
else
{
// 否则将接收到的数据保存在缓存数组里
UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
UART1_RX_STA++;
// 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
if(UART1_RX_STA > UART1_REC_LEN - 1)
UART1_RX_STA = 0;
}
}
}
// 重新开启中断
HAL_UART_Receive_IT(&huart1, &buf, 1);
}
}
int fputc(int ch, FILE *f)
{
unsigned char temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,0xffff);
return ch;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
HAL_UART_Receive_IT(&huart1, &buf, 1);//系统滴答定时器,防止死机
HAL_UART_Transmit(&huart2,"let's go\r\n",strlen("let's go\r\n"),100);
printf("AT+CWJAP=\"PEI\",\"jmgcyjs.\"\r\n");//入网指令
while(!AT_OK_Flag)
HAL_Delay(50);
HAL_UART_Transmit(&huart2,"333\r\n",strlen("333\r\n"),100);
AT_OK_Flag = 0;
//发送连服务器指令并等待成功
printf("AT+CIPSTART=\"TCP\",\"192.168.1.105\",8880\r\n"); //连接服务器指令
while(!AT_OK_Flag)
HAL_Delay(100);
HAL_UART_Transmit(&huart2,"433\r\n",strlen("433\r\n"),100);
AT_OK_Flag = 0;
//发送透传模式指令并等待成功
printf("AT+CIPMODE=1\r\n"); //透传指令
while(!AT_OK_Flag)
HAL_Delay(50);
HAL_UART_Transmit(&huart2,"533\r\n",strlen("533\r\n"),100);
AT_OK_Flag = 0;
//发送数据传输指令并等待成功
printf("AT+CIPSEND\r\n");//数据传输开始指令
while(!AT_OK_Flag)
HAL_Delay(50);
HAL_UART_Transmit(&huart2,"633\r\n",strlen("633\r\n"),100);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_UART_Transmit(&huart2,"666\r\n",strlen("666\r\n"),100);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
三、思路分析
这里的思路和51哪里的差不多。都是通过串口将单片机中的指令发给ESP8266.但是与51不同是,51在调试中用的是一个串口单向的调试,而32的是用的双向两个串口调试。
51测试的思路
32的具体的思路是这样的,基于上一篇文章的串口基础上,每当执行到UART1_RX_STA |= 0x8000时,代表着单片机的接收寄存器已经完全收到了来自单片机内部printf重映射的指令或是网络调试助手的指令。
接着从头说起,上电之后首先要输入入网指令
printf("AT+CWJAP=\"PEI\",\"jmgcyjs.\"\r\n");
输入完成后进入中断回调函数,如果你的网络名称和密码都没问题,ESP8266会通过串口1给单片机回复对应的内容
WIFI CONNECTED
WIFI GOT IP
OK
如图所示
UART1_RX_STA |= 0x8000;下面的第一个if将会判断成功,将WIFI GOT IP返回值的标志位AT_Connect_Net_Flag 变为1,接着是ESP8266返回OK指令,就可以让OK返回值的标志位变为1,同时在main函数里在printf("AT+CWJAP=\"PEI\",\"jmgcyjs.\"\r\n")下面有while循环标志位的判断来确保每一步的进行都是正确的。每当OK返回值的标志位使用完后,就把OK返回值的标志位AT_OK_Flag变为0。等到下一次ESP8266回复给单片机OK时,就进入中断将AT_OK_Flag变为1,程序可以继续正常运行。
思路就是这这样一个思路。
接着就是
连接服务器指令是否成功, 透传指令是否成功 ,数据传输开始指令是否成功 ,如果成功ESP8266就都会返回OK.如果在哪一步不成功,就会卡到哪里一直死循环。
当然了,这里还是要细说一下,失败也是分情况的。第一种失败是入网指令的失败,这个时候如果你失败,ESP8266会给单片机返回FALL,这时候我们的LED1会亮灭5次。如果你是入网成功后的失败,那你就是会一直陷入死循环。
四、其它
1.关于while后面加延时,你可以不加,只要不死机。每个while的条件后面不是直接跟;而是跟的延时函数,这样可以避免死机。
2.HAL_NVIC_SetPriority(SysTick_IRQn,0,0);滴答定时器优先级提高,中断中加入了延时函数,如果不把滴答定时器优先级提高,也会死机。
3.全部成功后,进入网络助手后拾取指令完成后,一定记得要带上回车再点击发送,因为我们的串口输入判断\r\n是一个重要的依据,不能不带上回车。
4.按照51的写法,把指令写成数组
char LJWL[] = "AT+CWJAP=\"PEI\",\"jmgcyjs.\"\r\n"; //入网指令
char LJFWQ[] = "AT+CIPSTART=\"TCP\",\" 192.168.10.206\",8880\r\n"; //连接服务器指令
char TCMS[] = "AT+CIPMODE=1\r\n"; //透传指令
char SJCS[] = "AT+CIPSEND\r\n"; //数据传输开始指令
char CQMK[] = "AT+RST\r\n"; //重启模块指令
你可以写成printf(LJWL)的形式,意思就是这个就是把数组名为LJWL的数组里的内容发出去,也就是发送入网指令。前提是你要把你的wifi模块的波特率改过来才行。你也可以像我一样使用printf("AT+CWJAP=\"PEI\",\"jmgcyjs.\"\r\n");,二选一。使用printf(LJWL)记得把这5个字符串写入数组。
5.还有一点我要补充一下,不知道大家有没有注意到一个小细节
在第一章里,入网指令写的是AT+CWJAP="PEI","jmgcyjs."但是到了printf里我写的是printf("AT+CWJAP=\"PEI\",\"jmgcyjs.\"\r\n");。\"PEI\",\"jmgcyjs.\"\r\n和"PEI","jmgcyjs."一样吗?确实不一样。使用的场景不一样AT+CWJAP="PEI","jmgcyjs."是在串口助手里使用。写完这条指令后,点击发送新行就相当于回车换行的/r/n,而"AT+CWJAP=\"PEI\",\"jmgcyjs.\"\r\n"是在单片机内部使用,\"使用的是转义字符,简单里说就是让“不要有别的意思,就让它是个引号。大家也可以自己查一下关于转义字符的使用,我就不多说了。