【嵌入式開發】利用ESP8266獲取附近WIFI資訊
一、準備
- 一塊塊裝好AT韌體的8266晶片
- 一臺裝了linux的嵌入式開發板
- 將晶片與開發板進行連線
二、AT+CWLAP——掃描當前可用的 AP
通過傳送AT+CWLAP
,可捕獲周圍的AP資訊,下面是檢視官方AT文件後得到的資訊:
在超級終端中嘗試,其中新刷入的韌體要啟動WIFI模式,啟動指令:AT+CWMODE_DEF=3
三、在主程式中實現UART通訊
由於我用的是改造過的韌體,波特率和官方的不一樣,所以在使用的時候請改一下波特率,在程式碼的巨集定義部分。
int main(int argc, char *argv[])
{
int fd, res;
struct termios oldtio, newtio;
char ch;
char buf[256] = {0};
printf("Start...\n");
//-----------開啟uart裝置檔案------------------
fd = open(UART_DEVICE, O_RDWR|O_NOCTTY);//沒有設定O_NONBLOCK,所以這裡read和write是阻塞操作
if (fd < 0) {
perror(UART_DEVICE);
exit (1);
}
else
printf("Open %s successfully\n", UART_DEVICE);
//-----------設定操作引數-----------------------
tcgetattr(fd, &oldtio);//獲取當前操作模式引數
memset(&newtio, 0, sizeof(newtio));
//波特率 資料位=8 使能資料接收
newtio.c_cflag = BAUDRATE|CS8|CLOCAL|CREAD;
newtio.c_iflag = IGNPAR;
//newtio.c_oflag = OPOST | OLCUC; //
/* 設定為正規模式 */
//newtio.c_lflag = ICANON;
tcflush(fd, TCIFLUSH);//清空輸入緩衝區和輸出緩衝區
tcsetattr(fd, TCSANOW, &newtio);//設定新的操作引數
//------------向urat傳送資料-------------------
char writeBuf[32] = "AT+CWLAP\r\n";
res = write(fd, writeBuf, 32);
printf("Writing: %s\n", writeBuf);
//-------------從uart接收資料-------------------
string allReturnBuf = "";
string s_buf;
printf("Reading...\n");
while(1) {
res = read(fd, buf, 64);//程式將在這裡掛起,直到從uart接收到資料(阻塞操作)
if (res == 0)
continue;
buf[res] = '\0';
// printf("res = %d, buf = %s\n", res, buf);//將uart接收到的字元打印出來
// 由於每次最多隻能拿32位資料,所以要一直獲取直到指令返回資訊全部取回
s_buf = buf;
allReturnBuf += s_buf;
// 判斷AT返回命令是否到頭
if (isEnd(allReturnBuf)) {
// for (int i = 0; i < allReturnBuf.size(); i++) {
// if ('\n' == allReturnBuf[i]) cout << "\\n";
// else if ('\0' == allReturnBuf[i]) cout << "\\0";
// else if ('\r' == allReturnBuf[i]) cout << "\\r";
// else cout << allReturnBuf[i];
// }
cout << "response:\n" << allReturnBuf;
cout << endl;
displayRes(selectWifiInfo(allReturnBuf));
break;
}
}
//------------關閉uart裝置檔案,恢復原先引數--------
close(fd);
printf("Close %s\n", UART_DEVICE);
tcsetattr(fd, TCSANOW, &oldtio); //恢復原先的設定
return 0;
}
四、實現對命令返回尾部的判斷
由於每次通過UART收到的資訊是固定位數的,例如在我的是每次接受32位,所以要不斷收集返回資訊並判斷,直到判斷出是指令返回結尾。
// 通過判斷字串的最後是否為 ERROR\r\n 或 OK\r\n 來判斷命令輸出是否結束
bool isEnd(string &str) {
if (str.size() < 4) return false;
string last4(str, str.size() - 4, 4);
if ("OK\r\n" == last4) {
cout << "AT response OK!" << endl;
return true;
}
if (str.size() >= 7) {
string last7(str, str.size() - 7, 7);
if ("ERROR\r\n" == last7) {
cout << "AT response ERROR!" << endl;
return true;
}
}
}
五、對返回資訊進行處理
下面函式用於分隔字串
//split a string by a pattern
vector<string> split(string str, string pattern) {
vector<string> ret;
if(pattern.empty()) return ret;
size_t start=0,index=str.find_first_of(pattern,0);
while(index!=str.npos) {
if(start!=index)
ret.push_back(str.substr(start,index-start));
start=index+1;
index=str.find_first_of(pattern,start);
}
if(!str.substr(start).empty())
ret.push_back(str.substr(start));
return ret;
}
// 用於篩選通過 AT+CWLAP 取回的資訊
vector< vector<string> > selectWifiInfo(string &str) {
/* AT+CWLAP 命令獲取格式
+CWLAP:<ecn>,<ssid>,<rssi>,<mac>,<channel>,<freq offset>,
<freq cali>,<pairwise_cipher>,<group_cipher>,<bgn>,<wps>
AT+CWLAP 獲取樣例
+CWLAP:(4,"MastarB",-74,"30:fc:68:bf:c5:cd",1,9,0,4,4,7,1)
AT+CWLAP 引數說明
<ecn>:加密方式
<ssid>:字串引數,AP 的 SSID
<rssi>:訊號強度
<mac>:字串引數,AP 的 MAC 地址
<channel>:通道號
<freq offset>:AP 頻偏,單位:kHz。此數值除以 2.4,可得到 ppm 值
<freq cali>:頻偏校準值
*/
vector<string> lines = split(str, "\n"); //lines of response
// 通過長度將有用資訊篩選
vector<string>::iterator iter = lines.begin();
while(iter != lines.end()) {
if ((*iter).size() <= 15) {
lines.erase(iter);
} else {
iter++;
}
}
vector< vector<string> > result;
// 裁剪有用資訊
for (int i = 0; i < lines.size(); i++) {
string info = string(lines[i].begin(), lines[i].end() - 1);
result.push_back(split(info, ","));
}
return result;
}
六、將RSSI轉換成距離
// 將RSSI轉換成距離
float rssiTodis(int RSSI) {
float iu, distance;
iu = (float)(RSSI - A) / (float)N;
distance = pow(10, iu);
return distance;
}
七、完整程式碼
/*
Author: [email protected]
Date: 2018.03.24
Used for getting the rssi of the wifi nearby from 8266.
*/
#include <sys/types.h>
#include <iterator>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <iostream>
#include <iomanip>
#include <math.h>
#include <sstream>
#define BAUDRATE B38400
#define UART_DEVICE "/dev/ttyS3"
#define FALSE -1
#define TRUE 0
#define N 40 //N = 10 * n ,其中n為環境衰減因子,3.25-4.5
#define A 51 //接收機和發射機間隔1m時的訊號強度
using namespace std;
// my functions
vector<string> split(string str, string pattern);
bool isEnd(string &str);
vector< vector<string> > selectWifiInfo(string &str);
float rssiTodis(int RSSI);
void displayRes(vector< vector<string> > result);
int main(int argc, char *argv[])
{
int fd, res;
struct termios oldtio, newtio;
char ch;
char buf[256] = {0};
printf("Start...\n");
//-----------開啟uart裝置檔案------------------
fd = open(UART_DEVICE, O_RDWR|O_NOCTTY);//沒有設定O_NONBLOCK,所以這裡read和write是阻塞操作
if (fd < 0) {
perror(UART_DEVICE);
exit(1);
}
else
printf("Open %s successfully\n", UART_DEVICE);
//-----------設定操作引數-----------------------
tcgetattr(fd, &oldtio);//獲取當前操作模式引數
memset(&newtio, 0, sizeof(newtio));
//波特率 資料位=8 使能資料接收
newtio.c_cflag = BAUDRATE|CS8|CLOCAL|CREAD;
newtio.c_iflag = IGNPAR;
//newtio.c_oflag = OPOST | OLCUC; //
/* 設定為正規模式 */
//newtio.c_lflag = ICANON;
tcflush(fd, TCIFLUSH);//清空輸入緩衝區和輸出緩衝區
tcsetattr(fd, TCSANOW, &newtio);//設定新的操作引數
//------------向urat傳送資料-------------------
char writeBuf[32] = "AT+CWLAP\r\n";
res = write(fd, writeBuf, 32);
printf("Writing: %s\n", writeBuf);
//-------------從uart接收資料-------------------
string allReturnBuf = "";
string s_buf;
printf("Reading...\n");
while(1) {
res = read(fd, buf, 64);//程式將在這裡掛起,直到從uart接收到資料(阻塞操作)
if (res == 0)
continue;
buf[res] = '\0';
// printf("res = %d, buf = %s\n", res, buf);//將uart接收到的字元打印出來
// 由於每次最多隻能拿32位資料,所以要一直獲取直到指令返回資訊全部取回
s_buf = buf;
allReturnBuf += s_buf;
// 判斷AT返回命令是否到頭
if (isEnd(allReturnBuf)) {
// for (int i = 0; i < allReturnBuf.size(); i++) {
// if ('\n' == allReturnBuf[i]) cout << "\\n";
// else if ('\0' == allReturnBuf[i]) cout << "\\0";
// else if ('\r' == allReturnBuf[i]) cout << "\\r";
// else cout << allReturnBuf[i];
// }
cout << "response:\n" << allReturnBuf;
cout << endl;
displayRes(selectWifiInfo(allReturnBuf));
break;
}
}
//------------關閉uart裝置檔案,恢復原先引數--------
close(fd);
printf("Close %s\n", UART_DEVICE);
tcsetattr(fd, TCSANOW, &oldtio); //恢復原先的設定
return 0;
}
// 通過判斷字串的最後是否為 ERROR\r\n 或 OK\r\n 來判斷命令輸出是否結束
bool isEnd(string &str) {
if (str.size() < 4) return false;
string last4(str, str.size() - 4, 4);
if ("OK\r\n" == last4) {
cout << "AT response OK!" << endl;
return true;
}
if (str.size() >= 7) {
string last7(str, str.size() - 7, 7);
if ("ERROR\r\n" == last7) {
cout << "AT response ERROR!" << endl;
return true;
}
}
}
//split a string by a pattern
vector<string> split(string str, string pattern) {
vector<string> ret;
if(pattern.empty()) return ret;
size_t start=0,index=str.find_first_of(pattern,0);
while(index!=str.npos) {
if(start!=index)
ret.push_back(str.substr(start,index-start));
start=index+1;
index=str.find_first_of(pattern,start);
}
if(!str.substr(start).empty())
ret.push_back(str.substr(start));
return ret;
}
// 用於篩選通過 AT+CWLAP 取回的資訊
vector< vector<string> > selectWifiInfo(string &str) {
/* AT+CWLAP 命令獲取格式
+CWLAP:<ecn>,<ssid>,<rssi>,<mac>,<channel>,<freq offset>,
<freq cali>,<pairwise_cipher>,<group_cipher>,<bgn>,<wps>
AT+CWLAP 獲取樣例
+CWLAP:(4,"MastarB",-74,"30:fc:68:bf:c5:cd",1,9,0,4,4,7,1)
AT+CWLAP 引數說明
<ecn>:加密方式
<ssid>:字串引數,AP 的 SSID
<rssi>:訊號強度
<mac>:字串引數,AP 的 MAC 地址
<channel>:通道號
<freq offset>:AP 頻偏,單位:kHz。此數值除以 2.4,可得到 ppm 值
<freq cali>:頻偏校準值
*/
vector<string> lines = split(str, "\n"); //lines of response
// 通過長度將有用資訊篩選
vector<string>::iterator iter = lines.begin();
while(iter != lines.end()) {
if ((*iter).size() <= 15) {
lines.erase(iter);
} else {
iter++;
}
}
vector< vector<string> > result;
// 裁剪有用資訊
for (int i = 0; i < lines.size(); i++) {
string info = string(lines[i].begin(), lines[i].end() - 1);
result.push_back(split(info, ","));
}
return result;
}
// 將RSSI轉換成距離
float rssiTodis(int RSSI) {
float iu, distance;
iu = (float)(RSSI - A) / (float)N;
distance = pow(10, iu);
return distance;
}
// 用於命令列展示結果
void displayRes(vector< vector<string> > result) {
if (result.size() == 0) cout << "NO WIFI INFO!" << endl;
cout << std::left << setw(40) << setfill(' ') << "| NAME";
cout << setw(10) << setfill(' ') << "| CHANNEL";
cout << setw(10) << setfill(' ') << "| RSSI";
cout << setw(10) << setfill(' ') << "| DIS(m)";
cout << setw(30) << setfill(' ') << "| MAC" << endl;
int temp;
for (int i = 0; i < result.size(); i++) {
cout <<" " << setw(40) << setfill(' ') << result[i][1];
cout << setw(10) << setfill(' ') << result[i][4];
cout << setw(10) << setfill(' ') << result[i][2];
temp = (result[i][2][1] - '0') * 10 + (result[i][2][2] - '0');
cout << setw(10) << setiosflags(ios::fixed) << setprecision(2)
<< setfill(' ') << rssiTodis(temp);
cout << setw(30) << setfill(' ') << result[i][3];
cout << endl;
}
cout << endl;
}
相關推薦
【嵌入式開發】利用ESP8266獲取附近WIFI資訊
一、準備 一塊塊裝好AT韌體的8266晶片 一臺裝了linux的嵌入式開發板 將晶片與開發板進行連線 二、AT+CWLAP——掃描當前可用的 AP 通過傳送AT+CWLAP,可捕獲周圍的AP資訊,下面是檢視官方AT文件後得到的資訊:
【嵌入式開發】Linux上位機通過esptool燒寫ESP8266
前言 本教程針對非官方開發板、無狀態轉換按鈕、須通過gpio口控制esp8266進入下載狀態並實現esp8266韌體更新的嵌入式linux裝置。雖然esp8266有線上更新的功能,但由於開發需求不得不研究相關知識,而網上資料甚少,特此補充。 準備 上位機
【嵌入式開發】自定義AT指令實現sniffer網路嗅探功能
基礎 該功能是在NON-OS SDK下實現的。 Non-OS SDK 是不不基於作業系統的 SDK,提供 IOT_Demo 和 AT 的編譯。Non-OS SDK 主要使⽤用定時器和回撥函式的方式實現各個功能事件的巢狀,達到特定條件下觸發特定功能函式的目
【嵌入式開發】時鐘初始化 ( 時鐘相關概念 | 嵌入式時鐘體系 | Lock Time | 分頻引數設定 | CPU 非同步模式設定 | APLL MPLL 時鐘頻率設定 )
本部落格的參考文章及相關資料下載 : 一. 時鐘相關概念解析 1. 相關概念術語 (1) 時鐘脈衝訊號 時鐘脈衝訊號 : 1.概念 : 按照 一定的電壓幅度 和 一定的時間間隔 , 連續發出的 脈衝
【嵌入式開發】樹莓派+官方攝像頭模組+VLC串流實時輸出網路視訊流
sudo apt-get update sudo apt-get install vlc sudo raspivid -o - -t 0 -w 640 -h 360 -fps 25|cvlc -vvv stream:///dev/stdin --sout \'#standard{access=http,
【微信公眾平臺開發】利用百度接口,制作一鍵導航功能
顯示 12px font -c cati blog ltr vertica 拾取 微信開發中,非常多商家用戶都要求點詳細地址。能在百度或者soso地圖上面顯示自己的地址。 而這種功能。利用百度api接口地圖標點功能就能夠非常easy實現。 1.功能說明例如以下:
【項目】利用node開發一個博客網站
get請求 用戶 eat func 讀取 req 教程 並發 布局 項目:利用node開發一個博客網站 首先你要先安裝node(這個在網上都是有教程的) [點擊前往中文網站]:(http://nodejs.cn/) [點擊前往英文網站]:(https://nodejs.or
【以太坊開發】利用Oraclize開發一個投注合約(一):原理介紹
智慧合約的作用很多,但是很多資料還是要基於網際網路,那麼如何在合約中獲取網際網路中的資料?Oraclize就是為了這個目的而誕生的。 本篇介紹如何利用Oraclize開發一個投注智慧合約,開始coding之前,這一節講述一下理論。 工作原理: 智慧合約通過對Oraclize釋出一個合約之間的呼叫請求來獲
【以太坊開發】利用Oraclize開發一個投註合約(一):原理介紹
tween 協議 簡單方法 type callback 使用 抓取 獲取 num 智能合約的作用很多,但是很多數據還是要基於互聯網,那麽如何在合約中獲取互聯網中的數據?Oraclize就是為了這個目的而誕生的。 本篇介紹如何利用Oraclize開發一個投註智能合約,開始co
【嵌入式Linux】ARM開發板通過NFS掛載Linux主機實現檔案共享
一般在Linux主機上arm-linux-gcc編譯程式,然後將該生成的可執行檔案傳送給ARM開發板,ARM開發板再執行該檔案。 (主機Linux系統)--->(ARM開發板Linux系統) 傳送檔案的過程可以採用NFS,FTP等多種方法 採用NFS實現遠端掛載,ARM
【嵌入式基礎】嵌入式軟體開發:筆試總結
從CSDN各個部落格上摘選的一些容易做錯的嵌入式軟體的筆試題,做一下記錄,讓自己記住。程式語言的基礎考察1、以下程式碼執行結果為:#include <iostream> using namespace std; int func(int x) { int
【嵌入式開發板學習分享】2016年最新迅為4412開發板手冊
看到群裡提供了最新的嵌入式開發板4412手冊看著還挺詳細的確實用心,立即收藏,由於檔案過大,上傳到網盤供需要的朋友下載: 版本19 前言23 嵌入式開發板必須注意的問題25 名詞解釋26 一 iTOP-4412 開發板介紹27 1.1 嵌入式開發板平臺簡要介紹27 1.
【ARM-LInux開發】利用scp 遠端上傳下載檔案/資料夾
scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] [-l limit] [-o ssh_option] [-P port] [-S program] [[[email protected]]host1:]file1
【ARM-Linux開發】【CUDA開發】【視訊開發】關於Linux下利用GPU對視訊進行硬體加速轉碼的方案
最近一直在研究Linux下利用GPU進行硬體加速轉碼的方案,折騰了很久,至今沒有找到比較理想的硬加速轉碼方案。似乎網上討論這一方案的文章也特別少,這個過程中也進行了各種嘗試,遇到很多具體問題,以下便對之前所作的一些工作做一些總結和分享,省的時間長了自己也忘記了,也希望後來
【Unity開發】Unity獲取裝置螢幕解析度
using UnityEngine; using System.Collections; public class ExampleClass : MonoBehaviour { void S
【嵌入式基礎】嵌入式軟體開發——嵌入式軟體工程師經典筆試題
從CSDN各個部落格上摘選的一些容易做錯的嵌入式軟體的筆試題,做一下記錄,讓自己記住。 1、用預處理指令#define 宣告一個常數,用以表明1年中有多少秒(忽略閏年問題) 解答:這一題主要容易錯的地方就是:意識到這個表示式將使一個16位機的整型數溢位,因此要用到
【DSP開發】序列 RapidIO: 高效能嵌入式互連技術
作者: 德州儀器技術應用工程師 馮華亮/ Brighton Feng/ [email protected] 摘要 序列RapidIO針對高效能嵌入式系統晶片間和板間互連而設計,它將是未來十幾年中嵌入式系統互連的最佳選擇。 本文比較RapidIO和傳統互連技術的優點;介紹RapidIO協議架構,包格式
【Android基礎】利用Intent在Activity之間傳遞數據
一次 there center ack and block for success display 前言: 上一篇文章給大家聊了Intent的使用方法。怎樣用Intent啟動Activity和隱式Intent。這一篇文章給大家聊聊怎樣利用Intent在Activit
【遊戲開發】淺談遊戲開發中常見的設計原則
依賴關系 unity 說過 srp des log gof https 類繼承 俗話說得好:“設計模式,常讀常新~”。的確,每讀一遍設計模式都會有些新的體會和收獲。馬三不才,才讀了兩遍設計模式(還有一遍是在學校學的),屬於菜鳥級別的。這次準備把閱
【Web開發】Mean web開發 01-Express實現MVC模式開發
http scripts send javascrip 模板引擎 指令 開發環境 depend filter 簡介 Mean是JavaScript的全棧開發框架。更多介紹 用Express實現MVC模式開發是Mean Web全棧開發中的一部分。 Express 是一個基於