蓝牙模块和WiFi模块的使用
1、蓝牙模块的使用
将蓝牙模块的TX和RX分别连接到单片机的RX和TX引脚上面。
我们写一个程序:手机通过蓝牙模块控制单片机的LED1的亮灭
#include <REGX52.H>
#include "intrins.h"
#include <string.h>
sfr AUXR = 0X8E;
sbit LED1 = P3^7;
char dma_js[5];//定义5个字节的字符数据来存储上位机发送来的字符串
char dma_fs[] = "wohaoshuai\r\n";
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //波特率9600
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x40; //8位数据,可变波特率
REN = 1;
AUXR = 0x01;
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
TR1 = 1; //启动定时器1
ES = 1;//开启串口中断
EA = 1;//开启中断总开关
}
void sendByte(char data_sj)
{
SBUF = data_sj;
while(!TI);
TI = 0;
}
void sendString(char *str)
{
while(*str != '\0')
{
sendByte(*str);
str++;
}
}
void main()
{
LED1 = 1;
UartInit();
while(1)
{
Delay300ms();
sendString(dma_fs);
Delay1000ms();
}
}
/*
中断函数中让控制LED1状态的方法1:
*/
//void UART_Handler() interrupt 4
//{
// static int i = 0;
// if(RI == 1)
// {
// RI = 0;
// dma_js[i]= SBUF;
// i++;
// if(i > 5)//如果i等于6,代表数组已经存满了,
// i = 0;
// if(dma_js[0] == 'o'&& dma_js[3] == 'n')//输入open
// {
// LED1 = 0;
// i = 0;
// memset(dma_js,'\0',5);//清空字符数组里面的字符串
// }
// if(dma_js[0] == 'c'&& dma_js[4] == 'e')//输入close
// {
// LED1 = 1;
// i = 0;
// memset(dma_js,'\0',5);
// }
// }
//}
/*
中断函数中让控制LED1状态的方法2:
*/
//void UART_Handler() interrupt 4
//{
// static int i = 0;
// char mark;
// if(RI == 1)
// {
// RI = 0;
// mark = SBUF;
// if(mark == 'o'|| mark == 'c')//如果发送来的是字符串中有'o'或者有'c'
// {
// i = 0;
// }
// dma_js[i] = mark;//则把o/c存放在数组dma_js的第一位
// i++; //在o/c之后的字符依次存放。
// if(i == 5)//字符串超过了数组,超过的部分依次从第一位开始存放
// {
// i = 0;
// }
// if(dma_js[0]=='o' && dma_js[3] == 'n')//open开灯
// {
// LED1 = 0;
// i = 0;
// memset(dma_js,'\0',5);
// }
// if(dma_js[0]=='c' && dma_js[4] == 'e')//close开灯
// {
// LED1 = 1;
// i = 0;
// memset(dma_js,'\0',5);
// }
// }
//}
/*
方法2不太好,因为open和close中都存在字符‘o’,当发送字符串close时,我本来想关灯的,但是程序执行时,
先检测到字符‘c’,所以数组依次存放'c','l',但是第3个字符是‘o’,它也满足判断条件,所以把‘o’存放在
数组的第一位把c覆盖了,然后后面的字符依次存放。所以如果输入的字符串是close,则存放在数组中的是ose。
所以我们把close里面的判断改为dma_js[0]=='o' && dma_js[2] == 'e'。但是这样又存在问题了,如果输入
open时。它也满足这个判断条件,灯不会被点亮。所以使用“数组头位法”,应该尽量避免重复的字符。例如方法3
*/
/*
中断函数中让控制LED1状态的方法3:
*/
void UART_Handler() interrupt 4
{
static int i = 0;
char mark;
if(RI == 1)
{
RI = 0;
mark = SBUF;
if(mark == 'o'|| mark == 'c')//如果发送来的是字符串中有'o'或者有'c'
{
i = 0;
}
dma_js[i] = mark;//则把o/c存放在数组dma_js的第一位
i++; //在o/c之后的字符依次存放。
if(i == 5) //字符串超过了数组,超过的部分依次从第一位开始存放
{
i = 0;
}
if(dma_js[0]=='o' && dma_js[1] == 'p')//op开灯
{
LED1 = 0;
i = 0;
memset(dma_js,'\0',2);
}
if(dma_js[0]=='c' && dma_js[1] == 'l')//cl开灯
{
LED1 = 1;
i = 0;
memset(dma_js,'\0',2);
}
}
}
若上位机发送发字符串是open 第一次中断发生,i 等于 0,o被存储在dma_js[0]中,i 等于1。
第二个字符p被成功写入SBUF后,调用第二次中断函数,p被存储在dma_js[1]中,i等于2。
当最后一个字符n被成功写入SBUF中后,调用中断函数,n被存储在dma_js[3]中,i等于4。
然后就能进入下面的判断语句,让LED1点亮,然后让i 等于0(以便下次调用中断函数,让第一个写入SBUF里面的字符存储在dma_js数组的第一位)。
memset()是清空函数,把字符数组里面的字符串清空,以便存储下次来的字符串。
2、WiFi模块的使用
WiFi模块的使用比蓝牙模块要复杂一些,因为WiFi模块需要AT指令对它进行一些配置。
下面是一些AT指令对WiFi模块的操作:
AT+RST//重启模块
AT+UART=9600,8,1,0,0 //配置为波特率9600,8位数据传输,1位停止位
AT+CWMODE=3 //设置模块的工作模式,1是station(设备)模式 ,2是AP(路由)模式 ,3是双模
AT+CWJAP="ChinaNet-2.4G-8704","这里写你家的wifi密码"//模式接入家中路由器配置
AT+CIFSR //查询模块的IP地址
AT+CIPSTART="TCP","192.168.101.174",8880 //让模块连接到移动设备的ip地址
AT+CIPSEND=4 //设置即将发送数据的长度 (这里是4个字节)
AT+CIPMODE=1 //开启透传模式
AT+CIPSEND //wifi模块开始发送数据,如果WiFi模块只接收移动设备发送来的数据,这个指令不用配置
如果是单片机通过wifi模块给移动设备发送数据,这个指令需要配置
//在透传发送数据过程中,若识别到单独的⼀包数据 “+++”,则退出透传发送
- 电脑通过USB转TTL,然后连接到WiFi模块。所以电脑可以通过串口助手软件,向WiFi模块发出AT指令来对他进行配置
- 其中蓝框里面的字符是,WiFi模块接收到AT指令后发出的回应,这些字符串在WiFi模块里面自动生成,然后返回发送给电脑。
(我们通过对这些字符串的辨别,来判断AT指令是否让WiFi模块配置成功。)
由此可见:
如图,通过移动设备,将字符串发送给wifi模块,模块传送给PC1然后通过串口助手显示出来,
而PC1将wsnibb字符串通过串口助手发送给WiFi模块,模块将字符串发送给移动设备。
- 将PC1换位单片机,且AT指令通过SBUF发送给WiFi模块,进行对模块的配置。并且单片机给WiFi模块发送字符串,然后wifi模块将字符串发送给PC2
代码:
#include <REGX52.H>
#include "intrins.h"
#include <string.h>
sfr AUXR = 0X8E;
sbit LED1 = P3^7;
char dma_js[6];
char dma_fs[] = "wohaoshuai\r\n";
code char CQWF[] = "AT+RST\r\n";//重启WiFi模块的指令
code char PZMS[] = "AT+CWMODE=3\r\n";
code char LJWL[] = "AT+CWJAP=\"ChinaNet-2.4G-8704\",\"18784970569\"\r\n";//连接家里路由器的指令
char LJIP[] = "AT+CIPSTART=\"TCP\",\"192.168.101.174\",8880\r\n";//连接PC2ip的指令
char TCMS[] = "AT+CIPMODE=1\r\n";//配置位透出模式的指令
char FSSJ[] = "AT+CIPSEND\r\n";//开始发送数据的指令
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //波特率9600
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR = 0x01;
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
TR1 = 1; //启动定时器1
}
void sendByte(char data_sj)
{
SBUF = data_sj;
while(!TI);
TI = 0;
}
void sendString(char *str)
{
while(*str != '\0')
{
sendByte(*str);
str++;
}
}
void main()
{
int j ,k;
j = k = 0;
LED1 = 1;
UartInit();
sendString(CQWF);//重启wifi模块
Delay1000ms();
Delay1000ms();
sendString(PZMS);
Delay1000ms();
Delay1000ms();
sendString(LJWL);//连接家里路由器
for(j = 0 ;j<=5 ;j++) //需要延时,AT指令发送给WiFi模块后,wifi模块需要反应一段时间才会做出相应的动作
{
Delay1000ms();
}
sendString(LJIP);//连接移动设备ip
for(k = 0; k<=5 ;k++)
{
Delay1000ms();
}
sendString(TCMS);//配置位透传模式
Delay1000ms();
sendString(FSSJ);//开始发送数据
Delay1000ms();
LED1 = 0; //执行完指令后让LED1点亮
while(1)
{
Delay300ms();
sendString(dma_fs);
Delay1000ms();
}
}
已然成功。
【注意】
1、要使用wifi模块前,先要知道连接WiFi模块移动设备的ip地址,以便进行AT指令的配置
2、要移动设备和WiFi模块要在同意路由器下。
3、配置WiFi模块的波特率和工作模式的指令,只需要配置一次,重新上电后就是配置后的样子。
- 编写代码让移动设备通过WiFi模块控制单片机的LED1灯的亮灭。
代码:
#include <REGX52.H>
#include "intrins.h"
#include <string.h>
sfr AUXR = 0X8E;
sbit LED1 = P3^7;
char dma_js[2];
char dma_fs[] = "wohaoshuai\r\n";
code char CQWF[] = "AT+RST\r\n";
code char PZMS[] = "AT+CWMODE=3\r\n";
code char LJWL[] = "AT+CWJAP=\"ChinaNet-2.4G-8704\",\"18784970569\"\r\n";
char LJIP[] = "AT+CIPSTART=\"TCP\",\"192.168.101.174\",8880\r\n";
char TCMS[] = "AT+CIPMODE=1\r\n";
char FSSJ[] = "AT+CIPSEND\r\n";
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //波特率9600
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x40; //8位数据,可变波特率
REN = 1;
AUXR = 0x01;
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
TR1 = 1; //启动定时器1
}
void UART_interrupt_Init()
{
ES = 1;//开启串口中断
EA = 1;//开启中断总开关
}
void sendByte(char data_sj)
{
SBUF = data_sj;
while(!TI);
TI = 0;
}
void sendString(char *str)
{
while(*str != '\0')
{
sendByte(*str);
str++;
}
}
void main()
{
int j ,k;
j = k = 0;
LED1 = 1;
UartInit();
sendString(CQWF);//重启wifi模块
Delay1000ms();
Delay1000ms();
sendString(PZMS);
Delay1000ms();
Delay1000ms();
sendString(LJWL);//连接家里路由器
for(j = 0 ;j<=5 ;j++)
{
Delay1000ms();
}
sendString(LJIP);//连接移动设备ip
for(k = 0; k<=5 ;k++)
{
Delay1000ms();
}
sendString(TCMS);//配置位透传模式
Delay1000ms();
sendString(FSSJ);//开始发送数据
Delay1000ms();
UART_interrupt_Init();//打开中断
LED1 = 0;//让LED1亮,代表WiFi模块连接成功
while(1)
{
Delay300ms();
sendString(dma_fs);
Delay1000ms();
}
}
void UART_Handler() interrupt 4
{
static int i = 0;
char data_js;
if(RI)
{
RI = 0;
data_js = SBUF;
if(data_js == 'o' || data_js == 'c')
{
i = 0;
}
dma_js[i] = data_js;
i++;
if(i == 2)
i = 0;
if(dma_js[0] == 'o' && dma_js[1] == 'p')//输出op
{
LED1 = 0;
memset(dma_js,'\0',2);
}
if(dma_js[0] == 'c' && dma_js[1] == 'l')//输入cl
{
LED1 = 1;
memset(dma_js,'\0',2);
}
}
}
其实这段代码不好,因为单片机给WiFi模块发送AT指令后,通过延时的方式来等待WiFi模块的操作,假如WiFi模块接收到AT指令后,做出相应的操作但是没有成功(例如连接移动设备的IP没有成功),我们也不知道。但是单片机依然会把下一个AT指令发送给WiFi模块,所以这是一个不好的现象。
我们可以通过wifi模块接收到AT指令后,对做出相应的回应的字符串进行判断,来设置下一步相应的操作,而不是无脑的发送AT指令给WiFi模块。
例如:
蓝色框里面的字符串就是WiFi模块接收到AT指令并操作成功后,返回给单片机的字符串。单片机接收到这些字符串可以做出相应的判断。
代码优化:
#include <REGX52.H>
#include "intrins.h"
#include <string.h>
/*
发送:AT+RST //重启WiFi模块
返回:ready
发送:AT+CWMODE=1 //配置工作模式
返回:OK
发送:AT+CWJAP="ChinaNet-2.4G-8704","18784970569"//连接路由器
返回:WIFI CONNECTED
WIFI GOT IP
OK
发送:AT+CIPSTART="TCP","192.168.101.2",8880//连接移动设备的IP
返回:CONNECT
OK
发送:AT+CIPMODE=1//透出模式
返回:OK
发送:AT+CIPSEND//开始发送
返回:OK
*/
sfr AUXR = 0X8E;
sbit LED1 = P3^7;
sbit LED2 = P3^6;
char buffer[2];//定义2个字节的字符串数组,用来接收WiFi模块响应后,返回的字符串。
char dma_fs[] = "wohaoshuai\r\n";
code char CQWF[] = "AT+RST\r\n"; //wifi模块重启
code char LJWL[] = "AT+CWJAP=\"ChinaNet-2.4G-8704\",\"18784970569\"\r\n";
char LJIP[] = "AT+CIPSTART=\"TCP\",\"192.168.101.2\",8880\r\n";
char TCMS[] = "AT+CIPMODE=1\r\n"; //透传模式
char FSSJ[] = "AT+CIPSEND\r\n"; //开始发送
char Flag_OK = 0;
char Flag_IP = 0;
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //波特率9600
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR = 0x01;
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES = 1;//开启串口中断
EA = 1;//开启中断总开关
}
void sendByte(char data_sj)
{
SBUF = data_sj;
while(!TI);
TI = 0;
}
void sendString(char *str)
{
while(*str != '\0')
{
sendByte(*str);
str++;
}
}
void main()
{
LED1 = LED2 = 1;
UartInit();
Delay1000ms();
sendString(CQWF);
Delay300ms();
//1.连接路由器
sendString(LJWL);
while(!Flag_IP); //WIFI GOT IP
while(!Flag_OK); //OK
Flag_OK = 0;
LED1 = 0; //连接路由器成功后,LED1亮
//2.连接移动设备ip
Delay300ms(); //延时一下,不让它做完判断后立马发送
sendString(LJIP);
while(!Flag_OK);
Flag_OK = 0;
LED2 = 0; //连接路IP成功后,LED2亮
//3.配置位透传模式
Delay300ms();
sendString(TCMS);
while(!Flag_OK);
Flag_OK = 0;
//4.开始发送数据
Delay300ms();
sendString(FSSJ);
while(!Flag_OK);
LED2 = 1; //可以开始发送数据后,LED2灭
while(1)
{
Delay300ms();
sendString(dma_fs);
Delay1000ms();
}
}
void UART_Handler() interrupt 4
{
char temp;
static int i = 0;
if(RI)
{
RI = 0;
temp = SBUF;
if(temp == 'I'||temp == 'O'|| temp == 'o'|| temp == 'c')
{
i = 0;
}
buffer[i] = temp;
i++;
if(i == 2)
i = 0;
if(buffer[0] == 'I' && buffer[1] == 'P')//接收到的字符串为WIFI GOT IP中的IP
{
Flag_IP = 1;
memset(buffer,'\0',2);
}
if(buffer[0] == 'O' && buffer[1] == 'K')//接收到的字符串为OK
{
Flag_OK = 1;
memset(buffer,'\0',2);
}
if(buffer[0] == 'o' && buffer[1] == 'p')//输出open
{
LED1 = 0;
memset(buffer,'\0',2);
}
if(buffer[0] == 'c' && buffer[1] == 'l')//输入close
{
LED1 = 1;
memset(buffer,'\0',2);
}
}
}