WIFI(1)
目录
WIFI(1)
回顾
WIFI模块
-- 1、AP模式:(服务器)应用:主要是用来让用户设置自身的wifi密码
-- 2、STA模式:可以获取时间获取天气
应用:
代码编写
回顾
-- SPI&FLASH
应用:读写
关注点:写:写入地址 数据大小 (写入数据之前,要先擦除。擦除函数需要一定的时间,大量擦除之前最好要加延时)
对于flash咱们能够操作的最小单位是:页
读:读出的地址 储存数据空间的大小
(读写都不要出现数组越界的现象(不要数组的长度过大))
栈区:存放的是局部变量(栈区空间不要开的太大,不要定义一个数据长度很大的数组)
理论内容要掌握(重要):
SPI的工作原理,FLASH的时序图
WIFI模块
-- 我们讲的这个WIFI模块用来干什么?为了让设备进行联网:用来更新时间,天气信息,还有就是连接云服务器
-- 哪些模块能让设备联网呢?
wifi模组:esp8266,esp32 (联网需要依靠热点,局域网通信)
4G模组, Nb模组。。。
ESP8266:WIFI MCU
ESP32:集成wifi和蓝牙 厂家乐鑫
例如:ESP8266开发板-----硬件产品
ESP8266模组:开发:底层固化软件。
esp8266和esp32可以更新固件
-- 底层固件是什么?类似于前面讲的语音模块的固件(su03t)
-- esp8266会用到AT指令集
-- 什么是AT指令集?
-- 查看手册
-
指令格式:(AT)开头 +数据+ (回车+换行)结尾 串口传输方式:
默认波特率:115200
字符串:”AT+数据+换行”
串口转WIFI -
指令分类:3类
- 应用指令
-- esp8266和单片机通信的是串口通信,在通信过程中会用到AT指令。
-- ESP8266WIFI设置3种无线通信模式:
-
AP模式:ESP8266产生WIFI网络,其他设备加入该网络。
指的就是服务器模式。 -
无线终端模式(STA模式):加入别人创建WIFI网络,ESP8266加入该网络 -- 局域网通信(客户端),STA模式还可以连接手机热点
一个WIFI模块可以设置为AP模式,另一个WIFI模块可以设置为STA模式,这样两个模块就可以进行局域网通信了。
- 混合模式:上面两个模式都可以用,但是同一时间只能用一种模式。
-- WIFI模块,驱动依靠AT指令。想实现任何功能,都要依靠AT指令。想实现什么功能,就要找不同的AT指令。
-- AP模式和STA模式具体是怎么实现的? 找一找实现这两种模式需要什么AT指令,顺序是什么?
-- 注意这里可以先把代码编写好,然后再去查找AT指令,这样就可以直接在串口助手中试了
-- 注意:代码编译成功后,进入串口调试,打开串口后,记得复位,之后再输指令
-- 如何向wifi模块发送这个指令?通过串口连接
-- 1、AP模式:(服务器)应用:主要是用来让用户设置自身的wifi密码
-- 可以通过指令集的官方文档看指令的具体用法
-- 注意:AT指令是以换行符为结束,要将串口助手中的发送新行选中。
-- tip:要发送多条指令时:
-- 注意:指令要按顺序执行
AP模式的AT指令:
1、"AT\r\n"发一个基本的AT指令,查看模块是否正常工作(检测一个AT指令的模块是好是坏
-- 注意:AT和OK都是wifi模块发的
2、"AT+RST\r\n":模块复位
3、"AT+CWMODE=2\r\n" :设置WiFi模块的模式 (1:STA模式 2:AP模式 3:混合模式)
4."AT+CWSAP="ESP8266","1234567890",5,3\r\n" //设置模块的热点名称和密码(但是这个wifi不能联网)注意:密码是8位及以上,根据指令集文档可以看出
5."AT+CIPMUX=1\r\n" 启动多连接模式
6、"AT+CIFSR\r\n" 获取本地的IP地址
7."AT+CIPSERVER=1,8086\r\n" 设置本地的端口号,连接的时候需要用到该端口号
8.AT+CIPSTO=5000 设置超时时间(设不设无所谓)
-- 要想进行通信,手机应该先连接到ESP8266模块产生的热点,然后下载APP
-- 之后,先连接本地IP(就是上面执行指令生成的本地IP)
-- 连接成功后,会有显示
-- 之后输入wifi和密码,然后发送
-- 发送成功过后, 串口上将会显示出连接自己的方法,将得到的数据解析出来,存在flash里,解析数据,得到名称密码,保存到FLASH里面,后续要连接WiFi的时候,就可以直接从flash里读了
-- 效果图
-- 2、STA模式:可以获取时间获取天气
-- 上网搜索AT指令:
-- 注意:指令要按顺序执行
1、"AT\r\n"发一个基本的AT指令,查看模块是否正常工作(检测一个AT指令的模块是好是坏
2、"AT+RST\r\n":模块复位
3、"AT+CWMODE=1\r\n" :设置WiFi模块的模式 (1:STA模式 2:AP模式 3:混合模式)
4、"AT+CIPMUX=0\r\n", //设置模块为单路连接模式(不写也可以,因为默认是单路模式)
5、"AT+CWJAP="WIFI名称","密码"\r\n"(热点必须是2.4G频段) //连接网络(注意:不要将wifi设置成5G)
6、"AT+CIPSTART="TCP","pinduoduo.com",80\r\n"//连接TCP服务器,taobao.com是服务器IP地址,8080是服务器端口。
7、"AT+CIPMODE=1\r\n" //开启透传模式
8、AT+CIPSEND //开始发送数据
-- 下面如何从淘宝服务器中获取时间?
-- 之后再向WIFI模块发送指令,不会再当作指令,而是当作数据发送给拼多多服务器。例如获取拼多多服务器时间的指令"GET http://api.pinduoduo.com/api/server/_stm\r\n"
-- 注意:与服务器通信完成后,再退出透传和关闭服务器,因为退出后将无法通信。
-- 9、"+++" //退出透传(注意:不加换行,要将串口助手中的“发送新行取消选中”)(退出之后不能再与服务器进行通信,所以一般在要退出服务器时(或者要连其他服务器),再写指令)
-- 发送完"+++"指令后串口不会发送任何数据
-- 注:发送完"+++"指令后,注意将串口助手中的“发送新行重新选中”
-- 10、"AT+CIPCLOSE\r\n" //关闭服务器
-- 连接不同的服务器应该如何操作:
- 1、退出透传
- 2、关闭上一个服务器
- 3、连接新的服务器
- 4、开启透传
- 5、启动发送
指令上面都有
应用:
-- 1、获取拼多多服务器的时间:
-
依次执行上述指令,拼多多的IP是pinduoduo.com,端口号是80,连接服务器,继续执行指令,知道执行完发送数据的指令后,执行从拼多多服务区获取时间的指令"GET http://api.pinduoduo.com/api/server/_stm\r\n"//访问这个地址,这个可以在网上搜到
-
之后,会获得一个时间戳,要将时间解析出来(将年月日时分秒解析出来)
获得的单位是毫秒,要去掉后三位,还要讲字符串转成数字(atoi,atol,atoll(这三个有不同的数字转换范围))再传给RTC
-- 2、之后换服务器换成苏宁的服务器,获取苏宁服务器的时间,步骤和上面一样。
-
先发送"+++"指令,退出透传
-
再发送退出服务器的指令"AT+CIPCLOSE\r\n"
-
之后再连接苏宁服务器,苏宁服务器的IP是suning.com,端口号是80
-
连接之后,开启透传模式
-
之后开启发送数据
-
发送获取suning服务器的指令,"AT+CIPSTART="TCP","suning.com",80\r\n"
-- 年份4字节,月份和日都是2字节
-- 首先解析第一个字节,是{,怎么定位到要解析的字节呢,笨方法直接数,一个字节一个字节数,这里数的话是从第13位开始就是sysTime2的数据。
-- 可以用函数找,strstr字符串查找函数,找到第一个字节的位置,然后从该位置开始解析。
查找第一个数的话,可以用strstr函数,找“sysTIME”,得到的是他的首地址,然后根据地址偏移偏过去。
tip:注意,有的指令不能乱用,例如
代码编写
- 1、查看单片机原理图找到wifi模块对应引脚,分别是PB10,PB11和PE6
虽然原理图上显示使能引脚连接的是电压, 但实际的板子上没有焊接相关的器件,所以还是要在代码中使能(也就是将带使能引脚置1)
- 2、根据原理图上找到的相关引脚配置IO
//时钟 B端口 USART3(外设自身也有时钟)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //看数据手册在哪条线上 - APB1
//IO PA9/PA10
GPIO_InitTypeDef GPIO_InitStructure = {0}; //定义结构体变量,并且将结构体变量赋初值
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PA9 复用推挽
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //ESP_EN使能引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_6);//置1//使能位置一
- 3、配置串口3和中断
USART_InitTypeDef USART_InitStructure = {0};
USART_InitStructure.USART_BaudRate = 115200; //波特率 常用的是4800 9600 115200
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_Tx | USART_Mode_Rx;//模式
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3,ENABLE);//开启串口 //使能或者失能 USART 外设(一般外设都要写这个)
//使能中断源 //串口有10个,用哪一个就要开哪一个中断源
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
//中断
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能(使能哪个中断通道,就要写哪个(必须写)中断服务函数)
NVIC_Init(&NVIC_InitStructure);
- 4、编写发送函数
-- 需要发送的AT指令是不定长的,所以需要写一个不定长发送函数
void uart3_tx(uint8_t data)
{
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET){}
USART_SendData(USART3, data);
}
void uart3_txstr(uint8_t *buff)
{
while( *buff ) //字符串结尾是\0,就是数字0,遇到0结束
{
uart3_tx(*buff);
buff++;
}
}
- 5、中断服务函数
-- 想看到wifi模块回应的响应,例如AT指令回应ok,还需要些接收的代码。写在中断服务函数里。
-- 接收到函数还需要被我们知道,要通道串口调试工具显示(xcom)出来,但是中断函数里面不能写printf函数,我们可以写其他的代替。
-- 已知printf的本质是串口1的发送(函数),
USART_SendData(USART1, data);
-- 串口1会将数据传给串口调试工具(xcom)显示出来,那么我们就可以利用串口1发送数据将数据显示在串口调试工具中
-- 注意:这里串口3和串口1的波特率要一致
void USART3_IRQHandler(void)//串口收到1字节数据,中断就会被触发一次
{
uint8_t data;
//判断接收中断是否发生
if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
//处理中断:保存数据
data = USART_ReceiveData(USART3);
USART_SendData(USART1, data);
//usart1_len %= 10;//对10求余,他就一直会小于10
//清理终端
USART_ClearITPendingBit(USART3,USART_IT_RXNE);
}
}