Arduino 如何从 PHP 脚本中保存数据?
How can Arduino save data from PHP Script?
我创建了一个 PHP 脚本,这样我就可以从我的在线数据库中检索数据(MySQL)但是我无法将该信息传递给我的 arduino+Ethernet Shield(使用 Ethercard.h).
我只想获取我的 PHP 脚本作为字符串向量检索的所有内容。
我的 PHP 脚本的例子 returns:
ABCDF
GHYEJ
JDYDI
HSTSU
PIFYF
我希望它在我的 Arduino 中变成这样:
char* test = {"ABCDF", "GHYEJ". "JDYDI", "HSTSU", "PIFYF" };
谁能帮我解决这个问题?
编辑:
所以,我正在尝试@frarugi87 解决方案,但我遇到了 DNS 失败。这是我正在使用的代码:
#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>
#define HTTP_HEADER_OFFSET 0
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
static byte myip[] = {192,168,1,58};
static byte gatewayip[] = {192,168,1,1};
static byte dnsip[] = {8,8,8,8}; //Google DNS
const char website[] PROGMEM = "http://arksecurity.net16.net";
byte Ethernet::buffer[700];
static uint32_t timer = 0;
static void response_callback (byte status, word off, word len){
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}
void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
Serial.println("Failed to access Ethernet controller");
else
Serial.println("Ethernet controller initialized");
ether.staticSetup(myip, gatewayip, dnsip);
if(!ether.dnsLookup(website)){
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() > timer){
timer = millis() + 5000;
ether.browseUrl("/", "test.php", website, response_callback);
}
}
我是不是做错了什么?
Edit2:好的,我明白了 运行。 DNS 问题是由我的路由器引起的,所以我不得不将其设置为 192.168.1.1,而且我还必须对 ether.browseUrl 进行一些调整,因为它也返回错误。
这就是我的代码现在的样子:
#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>
#define HTTP_HEADER_OFFSET 50
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
static byte myip[] = {192,168,1,58};
static byte gatewayip[] = {192,168,1,1};
static byte dnsip[] = {192,168,1,1}; //Google DNS
const char website[] PROGMEM = "www.arksecurity.net16.net";
byte Ethernet::buffer[700];
static uint32_t timer = 0;
static void response_callback (byte status, word off, word len){
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}
void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
Serial.println("Failed to access Ethernet controller");
else
Serial.println("Ethernet controller initialized");
ether.staticSetup(myip, gatewayip, dnsip);
if(!ether.dnsLookup(website)){
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() > timer){
timer = millis() + 5000;
ether.browseUrl(PSTR("/test."),"php", website, response_callback);
}
}
现在我必须将获取的数据保存到 char* [] 中。有什么想法吗?
编辑 3:
这就是我的代码到目前为止的样子。问题是,在我进行的最后一次比较中 "for(int i=0; i < 20 - 1; i++)" 我得到了所有 "Wrong" 就像前两个响应回调一样,然后它开始像它应该的那样得到一个 "OK" 。是否符合预期?
之后,我想让它每天只调用一次 response_callback,比如在午夜。可能吗?
#define HTTP_HEADER_OFFSET 163
#define MAX_STRINGS 20
#define MAX_STRING_LENGTH 8
#define REQUEST_EVERY_X_MS 5000
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
const char website[] PROGMEM = "www.arksecurity.net16.net";
const char device[] = "0001";
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
String test2 = "1234";
char * comp[20];
uint8_t receivedResponse;
unsigned long timer;
byte Ethernet::buffer[700];
static void response_callback (byte status, word off, word len) {
int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat =(char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS - 1){
i_string++;
i_char = 0;
}
else
break;
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached)
}
}
receivedResponse = 1;
}
void setup() {
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
{
Serial.println("Failed to access Ethernet controller");
while(1);
}
else
Serial.println("Ethernet controller initialized");
Serial.println();
if (!ether.dhcpSetup())
{
Serial.println("Failed to get configuration from DHCP");
while(1);
}
else
Serial.println("DHCP configuration done");
if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
timer = millis() - REQUEST_EVERY_X_MS;
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() - timer > REQUEST_EVERY_X_MS){
timer += REQUEST_EVERY_X_MS;
receivedResponse = 0;
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);
while (!receivedResponse);
for(int i=0; i < 20 - 1; i++){
comp[i] = test[i];
if(test2.equals(comp[i])){
Serial.println("OK");
}
else
Serial.println("Wrong");
}
}
}
Edit4:让它与另一个比较一起工作。我希望它每 5 秒捕获一次数据,直到他收到任何东西并且他们让它等待很长时间。问题是当我让 timer2 = 500000;它实际上使它更快地捕获数据。这是为什么?
#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>
#define HTTP_HEADER_OFFSET 163
#define MAX_STRINGS 10
#define MAX_STRING_LENGTH 20
#define REQUEST_EVERY_X_MS 5000
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
const char website[] PROGMEM = "www.arksecurity.net16.net"; //link para o banco de dados do usuário em questão
const char device[] = "0001"; // adicionar aqui o número do dispositivo equivalente ao que aparece no Bando de Dados
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
String test2 = "9999";
//uint8_t receivedResponse;
unsigned long timer;
unsigned long timer2 = 5000;
byte Ethernet::buffer[700];
static void response_callback (byte status, word off, word len) {
for(int i=0;i<MAX_STRINGS;i++)
for(int j=0;j<=MAX_STRING_LENGTH;j++)
test[i][j] = 0;
int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS - 1){
i_string++;
i_char = 0;
}
else
break; // Limite de memória do Arduino
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached)
}
}
//receivedResponse[0] = 1;
}
void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0)
{
Serial.println("Failed to access Ethernet controller");
while(1);
}
else
Serial.println("Ethernet controller initialized");
Serial.println();
if (!ether.dhcpSetup())
{
Serial.println("Failed to get configuration from DHCP");
while(1);
}
else
Serial.println("DHCP configuration done");
if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
timer = millis() - timer2;
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() - timer > timer2)
{
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);
if(test[0][0] != 0){
Serial.println("Data Received");
Serial.println(test[0]);
Serial.println(test[1]);
Serial.println(test[2]);
Serial.println(test[3]);
Serial.println(test[4]);
Serial.println(test[5]);
timer2 = 500000;
}
else{
Serial.println("Nothing");
timer2 = 5000;
}
timer += timer2;
}
Edit5:我将这部分添加到我的代码中,这样我也可以将数据发送到我的服务器,但由于某种原因,我只发送了一个数据,即使我正在为它使用一个循环。为什么会这样?
代码:
for(int i = 0; i < countRegister ; i++)
{
register[i].toCharArray(tempRegister, 80);
ether.browserUrl(PTSR("/log.php"), tempRegister , browser_callback);
}
static void browser_callback (byte status, word off, word len)
{
Serial.println("Data sent");
}
首先,所有这些都没有经过测试。我还在等待我的董事会到达,所以...我正在使用我在互联网上找到的一套很棒的教程(但是它们是意大利语)。特别是 here 是关于如何从服务器获取数据的教程。
好的,首先您必须使用所有必需的参数设置 ENC28J60 板,例如 MAC 地址和 IP 配置。在示例中我使用了 DHCP,但您可以使用静态配置(希望您知道如何操作)。
然后您必须检查是否可以解析网站名称(DNS 查询)- 不确定是否真的有必要)。
然后只需轮询网站(在此示例中每 5 秒一次)并分析数据包。
代码如下:
#include <EtherCard.h>
#define HTTP_HEADER_OFFSET 0
static byte mymac[] = {0x12,0x34,0x56,0x78,0x90,0xAB};
char website[] PROGMEM = "www.yourwebsite.com";
byte Ethernet::buffer[700];
static uint32_t timer = 0;
static void response_callback (byte status, word off, word len) {
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}
void setup () {
Serial.begin(57600);
if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
{
Serial.println("Failed to access Ethernet controller");
while(1);
}
else
Serial.println("Ethernet controller initialized");
Serial.println();
if (!ether.dhcpSetup())
{
Serial.println("Failed to get configuration from DHCP");
while(1);
}
else
Serial.println("DHCP configuration done");
if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
ether.packetLoop(ether.packetReceive());
if (millis() > timer) {
timer = millis() + 5000;
ether.browseUrl("/", "yourpage.php", website, response_callback);
}
}
这个草图的输出,在串行控制台上,将是这样的(图片来自我之前提到的教程)
如您所见,在实际页面之前有一个 header。您只需要计算它们有多少个字符并将此值放入 HTTP_HEADER_OFFSET.
如果此 header 不同,另一种方法是在当前消息之前添加一些内容(例如将所有内容包装在 <body>
标记中)并搜索它。
无论如何,在 response_callback
函数中,您将在 Ethernet::buffer + off + header_offset
中拥有所有数据。然后你要解析它并把它放到一个数组中,但我希望你能自己做..
编辑:
要使用静态 IP,您必须这样设置:
static byte myip[] = {192,168,1,10};
static byte gatewayip[] = {192,168,1,1};
//static byte dnsip[] = {8,8,8,8}; // Google DNS; change if you want to use another
static byte dnsip[] = {192,168,1,1}; // The OP said that with google dns something was not working
...
ether.staticSetup(myip, gatewayip, dnsip);
编辑 2:
好吧,既然您已经有了字符串形式的数据,那么将它拆分成块真的很容易。一种可能的解决方案:
#define MAX_STRINGS 10
#define MAX_STRING_LENGTH 10
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
static void response_callback (byte status, word off, word len) {
for(int i=0;i<MAX_STRINGS;i++)
for(int j=0;j<=MAX_STRING_LENGTH;j++)
test[i][j] = 0;
int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS-1)
i_string++;
else
break; // Too many strings; discarding all the other ones
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached
}
}
}
如果其中一个长度小于 255,那么您可以将 int 计数器更改为 uint8_t。
编辑 3:
要将字符串检测为分隔符,有点棘手。例如,要检测 "<br>"
,您可以:
char separator[] = "<br>";
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
uint8_t stringDetected = 0;
if (i_char >= sizeof(separator))
{
int i_sep;
stringDetected = 1;
for (i_sep = 0; i_sep < sizeof(separator) && (stringDetected); i_sep++)
{ // You can try to detect it
if (test[i_string][i_char - sizeof(separator) + i_sep] != separator[i_sep]);
stringDetected = 0;
}
}
if (stringDetected)
{
test[i_string][i_char - sizeof(separator)] = '[=13=]';
if (i_string < MAX_STRINGS-1)
i_string++;
else
break; // Too many strings; discarding all the other ones
}
}
}
我希望这可行(也许你必须将计数器校正 +/-1(不知道 sizeof 是否会 return 尾随的 \0)。
请记住为单个字符串增加 space(它们也需要存储分隔符)
编辑 4:
至于测试错误,我想是因为你还没有收到回复。可以等响应回来再测试。
此外,我注意到计时器中的一个小错误:您必须将其设置为 unsigned long 并测试 millis() - timer 而不是 millis() > timer,否则您将在计时器翻转时遇到问题。我在这段代码中修复了它:
// Before the setup
#define REQUEST_EVERY_X_MS 5000
uint8_t receivedResponse;
unsigned long timer;
// At the end of setup
timer = millis() - REQUEST_EVERY_X_MS;
// Inside response callback
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
...
}
receivedResponse = 1;
// In the main loop
if (millis() - timer > REQUEST_EVERY_X_MS)
{
timer += REQUEST_EVERY_X_MS;
receivedResponse = 0;
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);
while (!receivedResponse);
for(int i=0; i < 20 - 1; i++)
{
comp[i] = test[i];
if(test2.equals(comp[i]))
Serial.println("OK");
else
Serial.println("Wrong");
}
}
至于每天执行一次,如果你想在午夜恰好执行它,你将需要一些方法来跟踪时间(例如 RTC 或使用以太网的 NTP 协议)。这不是很简单,但是您可以找到很多关于如何使用 RTC 的示例。
另一方面,如果您只想每天执行一次(无论何时),只需将定义 REQUEST_EVERY_X_MS
更改为正确的值(24h = 1440 min = 86400s = 86400000ms,所以 #define REQUEST_EVERY_X_MS 86400000
) 它应该在你打开它的那一刻 运行 然后每 24 小时。您最多可以使用 4294967294 毫秒或大约 49 天的周期。
编辑 5:
好的,看看其他人的想法(主要来自OP在下面评论中提供的link)看起来
- browseUrl 不喜欢在完成前一次之前被调用两次
- 回调不存在于中断中,而是存在于主代码中。因此您无法阻止该程序。
所以.. 尝试为后续调用实现此:
volatile uint8_t receivedResponse;
// in the main
for(int i = 0; i < countRegister ; i++)
{
register[i].toCharArray(tempRegister, 80);
receivedResponse = 0;
ether.browserUrl(PTSR("/log.php"), tempRegister , browser_callback);
while (!receivedResponse)
ether.packetLoop(ether.packetReceive());
}
// the callback
static void browser_callback (byte status, word off, word len)
{
Serial.println("Data sent");
receivedResponse = 1;
}
希望这能解决所有问题 ;)
我创建了一个 PHP 脚本,这样我就可以从我的在线数据库中检索数据(MySQL)但是我无法将该信息传递给我的 arduino+Ethernet Shield(使用 Ethercard.h).
我只想获取我的 PHP 脚本作为字符串向量检索的所有内容。
我的 PHP 脚本的例子 returns:
ABCDF
GHYEJ
JDYDI
HSTSU
PIFYF
我希望它在我的 Arduino 中变成这样:
char* test = {"ABCDF", "GHYEJ". "JDYDI", "HSTSU", "PIFYF" };
谁能帮我解决这个问题?
编辑: 所以,我正在尝试@frarugi87 解决方案,但我遇到了 DNS 失败。这是我正在使用的代码:
#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>
#define HTTP_HEADER_OFFSET 0
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
static byte myip[] = {192,168,1,58};
static byte gatewayip[] = {192,168,1,1};
static byte dnsip[] = {8,8,8,8}; //Google DNS
const char website[] PROGMEM = "http://arksecurity.net16.net";
byte Ethernet::buffer[700];
static uint32_t timer = 0;
static void response_callback (byte status, word off, word len){
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}
void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
Serial.println("Failed to access Ethernet controller");
else
Serial.println("Ethernet controller initialized");
ether.staticSetup(myip, gatewayip, dnsip);
if(!ether.dnsLookup(website)){
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() > timer){
timer = millis() + 5000;
ether.browseUrl("/", "test.php", website, response_callback);
}
}
我是不是做错了什么?
Edit2:好的,我明白了 运行。 DNS 问题是由我的路由器引起的,所以我不得不将其设置为 192.168.1.1,而且我还必须对 ether.browseUrl 进行一些调整,因为它也返回错误。 这就是我的代码现在的样子:
#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>
#define HTTP_HEADER_OFFSET 50
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
static byte myip[] = {192,168,1,58};
static byte gatewayip[] = {192,168,1,1};
static byte dnsip[] = {192,168,1,1}; //Google DNS
const char website[] PROGMEM = "www.arksecurity.net16.net";
byte Ethernet::buffer[700];
static uint32_t timer = 0;
static void response_callback (byte status, word off, word len){
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}
void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
Serial.println("Failed to access Ethernet controller");
else
Serial.println("Ethernet controller initialized");
ether.staticSetup(myip, gatewayip, dnsip);
if(!ether.dnsLookup(website)){
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() > timer){
timer = millis() + 5000;
ether.browseUrl(PSTR("/test."),"php", website, response_callback);
}
}
现在我必须将获取的数据保存到 char* [] 中。有什么想法吗?
编辑 3:
这就是我的代码到目前为止的样子。问题是,在我进行的最后一次比较中 "for(int i=0; i < 20 - 1; i++)" 我得到了所有 "Wrong" 就像前两个响应回调一样,然后它开始像它应该的那样得到一个 "OK" 。是否符合预期?
之后,我想让它每天只调用一次 response_callback,比如在午夜。可能吗?
#define HTTP_HEADER_OFFSET 163
#define MAX_STRINGS 20
#define MAX_STRING_LENGTH 8
#define REQUEST_EVERY_X_MS 5000
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
const char website[] PROGMEM = "www.arksecurity.net16.net";
const char device[] = "0001";
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
String test2 = "1234";
char * comp[20];
uint8_t receivedResponse;
unsigned long timer;
byte Ethernet::buffer[700];
static void response_callback (byte status, word off, word len) {
int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat =(char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS - 1){
i_string++;
i_char = 0;
}
else
break;
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached)
}
}
receivedResponse = 1;
}
void setup() {
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
{
Serial.println("Failed to access Ethernet controller");
while(1);
}
else
Serial.println("Ethernet controller initialized");
Serial.println();
if (!ether.dhcpSetup())
{
Serial.println("Failed to get configuration from DHCP");
while(1);
}
else
Serial.println("DHCP configuration done");
if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
timer = millis() - REQUEST_EVERY_X_MS;
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() - timer > REQUEST_EVERY_X_MS){
timer += REQUEST_EVERY_X_MS;
receivedResponse = 0;
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);
while (!receivedResponse);
for(int i=0; i < 20 - 1; i++){
comp[i] = test[i];
if(test2.equals(comp[i])){
Serial.println("OK");
}
else
Serial.println("Wrong");
}
}
}
Edit4:让它与另一个比较一起工作。我希望它每 5 秒捕获一次数据,直到他收到任何东西并且他们让它等待很长时间。问题是当我让 timer2 = 500000;它实际上使它更快地捕获数据。这是为什么?
#include <enc28j60.h>
#include <EtherCard.h>
#include <net.h>
#define HTTP_HEADER_OFFSET 163
#define MAX_STRINGS 10
#define MAX_STRING_LENGTH 20
#define REQUEST_EVERY_X_MS 5000
/* Setup for Ethernet Library */
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
const char website[] PROGMEM = "www.arksecurity.net16.net"; //link para o banco de dados do usuário em questão
const char device[] = "0001"; // adicionar aqui o número do dispositivo equivalente ao que aparece no Bando de Dados
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
String test2 = "9999";
//uint8_t receivedResponse;
unsigned long timer;
unsigned long timer2 = 5000;
byte Ethernet::buffer[700];
static void response_callback (byte status, word off, word len) {
for(int i=0;i<MAX_STRINGS;i++)
for(int j=0;j<=MAX_STRING_LENGTH;j++)
test[i][j] = 0;
int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS - 1){
i_string++;
i_char = 0;
}
else
break; // Limite de memória do Arduino
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached)
}
}
//receivedResponse[0] = 1;
}
void setup() {
Serial.begin(57600);
if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0)
{
Serial.println("Failed to access Ethernet controller");
while(1);
}
else
Serial.println("Ethernet controller initialized");
Serial.println();
if (!ether.dhcpSetup())
{
Serial.println("Failed to get configuration from DHCP");
while(1);
}
else
Serial.println("DHCP configuration done");
if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
timer = millis() - timer2;
}
void loop() {
word pos = ether.packetLoop(ether.packetReceive());
if (millis() - timer > timer2)
{
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);
if(test[0][0] != 0){
Serial.println("Data Received");
Serial.println(test[0]);
Serial.println(test[1]);
Serial.println(test[2]);
Serial.println(test[3]);
Serial.println(test[4]);
Serial.println(test[5]);
timer2 = 500000;
}
else{
Serial.println("Nothing");
timer2 = 5000;
}
timer += timer2;
}
Edit5:我将这部分添加到我的代码中,这样我也可以将数据发送到我的服务器,但由于某种原因,我只发送了一个数据,即使我正在为它使用一个循环。为什么会这样?
代码:
for(int i = 0; i < countRegister ; i++)
{
register[i].toCharArray(tempRegister, 80);
ether.browserUrl(PTSR("/log.php"), tempRegister , browser_callback);
}
static void browser_callback (byte status, word off, word len)
{
Serial.println("Data sent");
}
首先,所有这些都没有经过测试。我还在等待我的董事会到达,所以...我正在使用我在互联网上找到的一套很棒的教程(但是它们是意大利语)。特别是 here 是关于如何从服务器获取数据的教程。
好的,首先您必须使用所有必需的参数设置 ENC28J60 板,例如 MAC 地址和 IP 配置。在示例中我使用了 DHCP,但您可以使用静态配置(希望您知道如何操作)。
然后您必须检查是否可以解析网站名称(DNS 查询)- 不确定是否真的有必要)。
然后只需轮询网站(在此示例中每 5 秒一次)并分析数据包。
代码如下:
#include <EtherCard.h>
#define HTTP_HEADER_OFFSET 0
static byte mymac[] = {0x12,0x34,0x56,0x78,0x90,0xAB};
char website[] PROGMEM = "www.yourwebsite.com";
byte Ethernet::buffer[700];
static uint32_t timer = 0;
static void response_callback (byte status, word off, word len) {
Serial.print((const char*) Ethernet::buffer + off + HTTP_HEADER_OFFSET);
}
void setup () {
Serial.begin(57600);
if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
{
Serial.println("Failed to access Ethernet controller");
while(1);
}
else
Serial.println("Ethernet controller initialized");
Serial.println();
if (!ether.dhcpSetup())
{
Serial.println("Failed to get configuration from DHCP");
while(1);
}
else
Serial.println("DHCP configuration done");
if (!ether.dnsLookup(website))
{
Serial.println("DNS failed");
while(1);
}
else
Serial.println("DNS resolution done");
ether.printIp("SRV IP:\t", ether.hisip);
Serial.println();
}
void loop() {
ether.packetLoop(ether.packetReceive());
if (millis() > timer) {
timer = millis() + 5000;
ether.browseUrl("/", "yourpage.php", website, response_callback);
}
}
这个草图的输出,在串行控制台上,将是这样的(图片来自我之前提到的教程)
如您所见,在实际页面之前有一个 header。您只需要计算它们有多少个字符并将此值放入 HTTP_HEADER_OFFSET.
如果此 header 不同,另一种方法是在当前消息之前添加一些内容(例如将所有内容包装在 <body>
标记中)并搜索它。
无论如何,在 response_callback
函数中,您将在 Ethernet::buffer + off + header_offset
中拥有所有数据。然后你要解析它并把它放到一个数组中,但我希望你能自己做..
编辑:
要使用静态 IP,您必须这样设置:
static byte myip[] = {192,168,1,10};
static byte gatewayip[] = {192,168,1,1};
//static byte dnsip[] = {8,8,8,8}; // Google DNS; change if you want to use another
static byte dnsip[] = {192,168,1,1}; // The OP said that with google dns something was not working
...
ether.staticSetup(myip, gatewayip, dnsip);
编辑 2:
好吧,既然您已经有了字符串形式的数据,那么将它拆分成块真的很容易。一种可能的解决方案:
#define MAX_STRINGS 10
#define MAX_STRING_LENGTH 10
char test[MAX_STRINGS][MAX_STRING_LENGTH+1];
static void response_callback (byte status, word off, word len) {
for(int i=0;i<MAX_STRINGS;i++)
for(int j=0;j<=MAX_STRING_LENGTH;j++)
test[i][j] = 0;
int i_string = 0;
int i_char = 0;
int i_ethBuff = off + HTTP_HEADER_OFFSET;
char carat;
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (carat == '\n')
{ // New line char = new string
if (i_string < MAX_STRINGS-1)
i_string++;
else
break; // Too many strings; discarding all the other ones
}
else
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
} // otherwise discard the char (max length of string reached
}
}
}
如果其中一个长度小于 255,那么您可以将 int 计数器更改为 uint8_t。
编辑 3:
要将字符串检测为分隔符,有点棘手。例如,要检测 "<br>"
,您可以:
char separator[] = "<br>";
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
if (i_char < MAX_STRING_LENGTH)
{
test[i_string][i_char] = carat;
i_char++;
uint8_t stringDetected = 0;
if (i_char >= sizeof(separator))
{
int i_sep;
stringDetected = 1;
for (i_sep = 0; i_sep < sizeof(separator) && (stringDetected); i_sep++)
{ // You can try to detect it
if (test[i_string][i_char - sizeof(separator) + i_sep] != separator[i_sep]);
stringDetected = 0;
}
}
if (stringDetected)
{
test[i_string][i_char - sizeof(separator)] = '[=13=]';
if (i_string < MAX_STRINGS-1)
i_string++;
else
break; // Too many strings; discarding all the other ones
}
}
}
我希望这可行(也许你必须将计数器校正 +/-1(不知道 sizeof 是否会 return 尾随的 \0)。
请记住为单个字符串增加 space(它们也需要存储分隔符)
编辑 4:
至于测试错误,我想是因为你还没有收到回复。可以等响应回来再测试。
此外,我注意到计时器中的一个小错误:您必须将其设置为 unsigned long 并测试 millis() - timer 而不是 millis() > timer,否则您将在计时器翻转时遇到问题。我在这段代码中修复了它:
// Before the setup
#define REQUEST_EVERY_X_MS 5000
uint8_t receivedResponse;
unsigned long timer;
// At the end of setup
timer = millis() - REQUEST_EVERY_X_MS;
// Inside response callback
for (i_ethBuff = off + HTTP_HEADER_OFFSET; (carat = (char)Ethernet::buffer[i_ethBuff]) != 0; i_ethBuff++)
{
...
}
receivedResponse = 1;
// In the main loop
if (millis() - timer > REQUEST_EVERY_X_MS)
{
timer += REQUEST_EVERY_X_MS;
receivedResponse = 0;
ether.browseUrl(PSTR("/DevicesQuery.php?device="),device , website, response_callback);
while (!receivedResponse);
for(int i=0; i < 20 - 1; i++)
{
comp[i] = test[i];
if(test2.equals(comp[i]))
Serial.println("OK");
else
Serial.println("Wrong");
}
}
至于每天执行一次,如果你想在午夜恰好执行它,你将需要一些方法来跟踪时间(例如 RTC 或使用以太网的 NTP 协议)。这不是很简单,但是您可以找到很多关于如何使用 RTC 的示例。
另一方面,如果您只想每天执行一次(无论何时),只需将定义 REQUEST_EVERY_X_MS
更改为正确的值(24h = 1440 min = 86400s = 86400000ms,所以 #define REQUEST_EVERY_X_MS 86400000
) 它应该在你打开它的那一刻 运行 然后每 24 小时。您最多可以使用 4294967294 毫秒或大约 49 天的周期。
编辑 5:
好的,看看其他人的想法(主要来自OP在下面评论中提供的link)看起来
- browseUrl 不喜欢在完成前一次之前被调用两次
- 回调不存在于中断中,而是存在于主代码中。因此您无法阻止该程序。
所以.. 尝试为后续调用实现此:
volatile uint8_t receivedResponse;
// in the main
for(int i = 0; i < countRegister ; i++)
{
register[i].toCharArray(tempRegister, 80);
receivedResponse = 0;
ether.browserUrl(PTSR("/log.php"), tempRegister , browser_callback);
while (!receivedResponse)
ether.packetLoop(ether.packetReceive());
}
// the callback
static void browser_callback (byte status, word off, word len)
{
Serial.println("Data sent");
receivedResponse = 1;
}
希望这能解决所有问题 ;)