2023年10月5日 星期四

Arduino 多台 網頁互控紅外線 固定IP 多webserver

實現控制多個發射遙控器訊號的初版

以WiFiManualWebServer範例當基底,融合紅外線發射

因為找不到比網頁更方便的範例來開發

畢竟UI部分,也很難找到比網頁更方便的方式


#include <ESP8266WiFi.h>


#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>

const uint16_t kIrLed = 4;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.

#ifndef STASSID
#define STASSID "你的WIFI名稱"
#define STAPSK "你的WIFI密碼"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
  Serial.begin(115200);

  irsend.begin();

  // prepare LED
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, 0);

  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print(F("Connecting to "));
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(F("."));
  }
  Serial.println();
  Serial.println(F("WiFi connected"));

  // Start the server
  server.begin();
  Serial.println(F("Server started"));

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.accept();
  if (!client) { return; }
  Serial.println(F("new client"));

  client.setTimeout(5000);  // default is 1000

  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(F("request: "));
  Serial.println(req);

  // Match the request
  int val,IR;
  if (req.indexOf(F("/gpio/0")) != -1) {
    val = 0;
  } else if (req.indexOf(F("/gpio/1")) != -1) {
    val = 1;}
    else if (req.indexOf(F("/IRon")) != -1)
    {IR = 0;
    Serial.println("NEC");
    irsend.sendNEC(0xCF20D);
    }
    else if (req.indexOf(F("/IRclose")) != -1)
    {IR = 1;}
    else {
    Serial.println(F("invalid request"));
    val = digitalRead(LED_BUILTIN);
  }

  // Set LED according to the request
  digitalWrite(LED_BUILTIN, val);

  // read/ignore the rest of the request
  // do not client.flush(): it is for output only, see below
  while (client.available()) {
    // byte by byte is not very efficient
    client.read();
  }

  // Send the response to the client
  // it is OK for multiple small client.print/write,
  // because nagle algorithm will group them into one single packet
  client.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n"));
  client.print(WiFi.localIP());
  client.print(F("This hostname:\n"));//读取当前的hostname并输出
  client.print(WiFi.hostname());
  client.print(F("&nbsp;"));
  client.print(F("GPIO is now "));
  client.print((val) ? F("high") : F("low"));

  client.print(F("&nbsp;"));
  client.print(F("Click <a href='http://"));
  client.print(WiFi.localIP());
  client.print(F("/gpio/0'>here</a> to switch LED GPIO on, or <a href='http://"));
  client.print(WiFi.localIP());
  client.print(F("/gpio/1'>here</a> to switch LED GPIO off. Or <a href='http://"));
  client.print(WiFi.localIP());
  client.print(F("/IRon'>here</a> to send IR on."));

  client.print(F("<br><br>"));
  client.print(F("192.168.179.146"));
  client.print(F("&nbsp;"));
  client.print(F("Click <a href='http://"));
  client.print(F("192.168.179.146"));
  client.print(F("/gpio/0'>here</a> to switch LED GPIO on, or <a href='http://"));
  client.print(F("192.168.179.146"));
  client.print(F("/gpio/1'>here</a> to switch LED GPIO off. Or <a href='http://"));
  client.print(F("192.168.179.146"));
  client.print(F("/IRon'>here</a> to send IR on."));

  client.print(F("<br><br>"));
  client.print(F("192.168.179.246"));
  client.print(F("&nbsp;"));
  client.print(F("Click <a href='http://"));
  client.print(F("192.168.179.246"));
  client.print(F("/gpio/0'>here</a> to switch LED GPIO on, or <a href='http://"));
  client.print(F("192.168.179.246"));
  client.print(F("/gpio/1'>here</a> to switch LED GPIO off. Or <a href='http://"));
  client.print(F("192.168.179.246"));
  client.print(F("/IRon'>here</a> to send IR on.</html>"));


  // The client will actually be *flushed* then disconnected
  // when the function returns and 'client' object is destroyed (out-of-scope)
  // flush = ensure written data are received by the other side
  Serial.println(F("Disconnecting from client"));
}

2023年9月23日 星期六

Arduino 簡易訊號偵測,紅外線拼接

 void setup() {

  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(5,INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(100); //延遲毫秒
  if(digitalRead(5)==0) //0=LOW
  // If no signal print collision detected
  Serial.println("Balls");
  if(digitalRead(5)==1) //1=HIGH
  //else
  // 11 If signal detected print collision detected
  Serial.println("No Balls.");
}

2023年9月17日 星期日

Arduino WeMos D1 R3 [入門] 開發板上控制製造呼吸燈

選板子

選板子前要先安裝ESP8266

打開 Arduino IDE,菜單 / 偏好設定,額外的開發板管理員網址打上:https://arduino.esp8266.com/stable/package_esp8266com_index.json
  1. https://ithelp.ithome.com.tw/upload/images/20190928/20120058J9MrrmsjkR.jpg

安裝ESP8266的方法






void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);    //必要
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(LED_BUILTIN, 1);
  delay(1000);
  digitalWrite(LED_BUILTIN, 0);
  delay(1000);    //必要不然迴圈會導致看不到效果
}


2023年9月13日 星期三

印加寶藏 機率自動化進行

本來想自稱AI

不過實際上只有加點機率

實現單人可以遊玩

機率電腦是固定數量的

https://scratch.mit.edu/projects/879030558/

2023年7月24日 星期一

Arduino WeMos R2 [入門] 兩個按鈕控制

參考
ESP8266作为arduino D1 wifi模块应用时引脚序号说明(与UNO对比异同)2.5.0版本开发板库



const int BUTTON_PIN1 = 16;  // 按鍵的接腳
const int BUTTON_PIN2 = 5;  // 按鍵的接腳

int buttonState1 = 0;   // 按鈕的狀態
int buttonState2 = 0;   // 按鈕的狀態

void setup() {
  Serial.begin(9600);
  pinMode(BUTTON_PIN1, INPUT_PULLUP);
  pinMode(BUTTON_PIN2, INPUT_PULLUP); //設定按鈕的接腳為輸入,因為我們要讀取它的狀態
}

void loop() {
  buttonState1 = digitalRead(BUTTON_PIN1);  //讀取按鍵的狀態
  buttonState2 = digitalRead(BUTTON_PIN2);
  /*
  if(buttonState1 == LOW){          //如果按鍵按了
    Serial.println("16BUTTON");
  }
  if(buttonState2 == LOW){          //如果按鍵按了
    Serial.println("5BUTTON");
  }
  */
  if(buttonState1 == HIGH){          //如果按鍵按了
    Serial.println("16BUTTON");
  }
  if(buttonState2 == HIGH){          //如果按鍵按了
    Serial.println("5BUTTON");
  }
 
}

2023年7月23日 星期日

Arduino WeMos R2 遙控器複製拷貝自造 紅外線發射接收復刻 無線網頁控制

目前功能,

連上WiFi後,用網頁控制Arduino發射紅外線,

WiFi無線控制有紅外線接收器的設備。



無線功能由WiFi傳輸,

所以需要一個WiFi基地台,

試驗時可用手機分享基地台熱點當作WiFi主機(基地台)。


Arduino連上WiFi後,

創建一個WiFiWebServer,

這WebServer可用網址後綴來接收控制。


主要 WiFiManualWebServer

接收 IRrecvDump

發射 IRremoteESP8266: IRsendDemo

------------------------

主要 WiFiManualWebServer

接收 IRrecvDump

發射 IRremoteESP8266: IRsendDemo











/*
    This sketch demonstrates how to set up a simple HTTP-like server.
    The server will set a GPIO pin depending on the request
      http://server_ip/gpio/0 will set the GPIO2 low,
      http://server_ip/gpio/1 will set the GPIO2 high
    server_ip is the IP address of the ESP8266 module, will be
    printed to Serial when the module is connected.
*/

#include <ESP8266WiFi.h>

#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>

const uint16_t kIrLed = 4;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.

#ifndef STASSID
#define STASSID "你的WIFI SSID"
#define STAPSK "你的WIFI密碼"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
 

  irsend.begin();
#if ESP8266
  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
#else  // ESP8266
  Serial.begin(115200, SERIAL_8N1);
#endif  // ESP8266


  // prepare LED
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, 0);

  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print(F("Connecting to "));
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(F("."));
  }
  Serial.println();
  Serial.println(F("WiFi connected"));

  // Start the server
  server.begin();
  Serial.println(F("Server started"));

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.accept();
  if (!client) { return; }
  Serial.println(F("new client"));

  client.setTimeout(5000);  // default is 1000

  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(F("request: "));
  Serial.println(req);

  // Match the request
  int val,IR;
  if (req.indexOf(F("/gpio/0")) != -1)
    {val = 0;}
  else if (req.indexOf(F("/gpio/1")) != -1)
    {val = 1;}
  else if (req.indexOf(F("/IRsend")) != -1)
    {IR = 0;
    Serial.println("NEC");
    irsend.sendNEC(0xCF20D);
    }
  else if (req.indexOf(F("/IRclose")) != -1)
    {IR = 1;}  
  else {
    Serial.println(F("invalid request"));
    val = digitalRead(LED_BUILTIN);
  }

  // Set LED according to the request
  digitalWrite(LED_BUILTIN, val);

  // read/ignore the rest of the request
  // do not client.flush(): it is for output only, see below
  while (client.available()) {
    // byte by byte is not very efficient
    client.read();
  }

  // Send the response to the client
  // it is OK for multiple small client.print/write,
  // because nagle algorithm will group them into one single packet
  client.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now "));
  client.print((val) ? F("high") : F("low"));
  client.print(F("<br><br>Click <a href='http://"));
  client.print(WiFi.localIP());
  client.print(F("/gpio/1'>here</a> to switch LED GPIO on, or <a href='http://"));
  client.print(WiFi.localIP());
  client.print(F("/gpio/0'>here</a> to switch LED GPIO off.<a href='http://"));
  client.print(WiFi.localIP());
  client.print(F("/IRsend'>here</a> to send IR.</html>"));

  // The client will actually be *flushed* then disconnected
  // when the function returns and 'client' object is destroyed (out-of-scope)
  // flush = ensure written data are received by the other side
  Serial.println(F("Disconnecting from client"));
}

2023年6月22日 星期四

Arduino UNO Rev3 遙控器複製拷貝自造 紅外線接收發射復刻

重點參考 :

Arduino-透過IRremote函式庫(Ver3.5.3)實現紅外線模組接收及發送Jan 25-2022

https://karta146831.pixnet.net/blog/post/335687582-arduino-%E9%80%8F%E9%81%8Eirremote%28ver3.x%29%E8%AA%9E%E6%B3%95%E5%AF%A6%E7%8F%BE%E7%B4%85%E5%A4%96%E7%B7%9A%E6%A8%A1%E7%B5%84%E6%8E%A5

更新的IRremote库实例2023-1-23 https://www.arduino.cn/thread-342990-1-1.html



[接收]

#include <IRremote.hpp>


void setup()

{

  Serial.begin(115200);

  IrReceiver.begin(7, ENABLE_LED_FEEDBACK); // PIN7收IR

}


void loop() {

  if (IrReceiver.decode()) {

      Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);

      IrReceiver.printIRResultShort(&Serial); // optional use new print version

      IrReceiver.resume(); // Enable receiving of the next value

  }

}


原出處用PIN3收IR,但我用7。

我收到的是

B04F3000

Protocol=NEC Address=0x3000 Command=0x4F Raw-Data=0xB04F3000 32 bits LSB first



[發射]

#include <IRremote.hpp>

void setup()
{
  Serial.begin(9600);
  IrSender.begin(7, ENABLE_LED_FEEDBACK);//PIN3發射紅外線
}

void loop() {
  //IrSender.sendNEC(0xB04F3000, 0x1, true, 0);     //將剛剛記錄下來的資訊代入,ture跟0請先不要改
  IrSender.sendNECRaw(0xB04F3000, 1);
  delay(1000);
}

在出處只有IrSender.sendNEC(0xDAE1, 0x1, true, 0);但試了不知道為什麼不成功
我參考另一篇使用
第二种:直接发送原始值,例如0xCB340102,则必须使用sendNECRaw()IrSender.sendNECRaw(0xCB340102, sRepeats);
第一種sendNEC有NEC感覺有協定問題而且也搞不懂sCommand是什麼,


-----------

前期失敗過程

用ESP32系列的NodeMCU-32S,其實也不確定是不是真得是NodeMCU-32S

但IDE選NodeMCU-32S可以正常燒錄,沒有報錯說選錯板子型號

紅外線接收得到,但很怪,

每次收到的不一定一樣,而且也不會一直都能收到

常常五分鐘內只能收到十幾個次,

於是懷疑是接收器的問題,頻率28KHz沒有錯,

但可能有其他不一樣的地方,

但事後證明不是接收器的問題,

只能說既然換官方的 UNO Rev3 就馬上正常解決,

也就是ESP32雖然是相容,

但有太多可能的問題需要克服,

UNO也不貴,

如果單純開發簡單功能如本篇,只是要紅外線收發,

那還是先直接從較單純的Arduino官方版本開始會比較經濟。

2023年3月26日 星期日

[chatgpt] 給貪食蛇遊戲PYTHON代碼

 

vincent Jiang
給貪食蛇遊戲PYTHON代碼

以下是一個簡單的貪食蛇遊戲的 Python 代碼:

python
import pygame import random # 初始化 Pygame pygame.init() # 定義常數 SCREEN_WIDTH = 600 SCREEN_HEIGHT = 600 SNAKE_SIZE = 10 SNAKE_SPEED = 15 SNAKE_COLOR = (0, 255, 0) FOOD_COLOR = (255, 0, 0) # 創建視窗 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) # 設置標題 pygame.display.set_caption('貪食蛇') # 創建蛇 snake = [[200, 200], [210, 200], [220, 200]] snake_direction = 'RIGHT' # 創建食物 food_position = [random.randrange(1, (SCREEN_WIDTH//10)) * 10, random.randrange(1, (SCREEN_HEIGHT//10)) * 10] # 定義函數 def draw_snake(snake): for pos in snake: pygame.draw.rect(screen, SNAKE_COLOR, pygame.Rect(pos[0], pos[1], SNAKE_SIZE, SNAKE_SIZE)) def move_snake(snake, snake_direction): if snake_direction == 'RIGHT': new_pos = [snake[0][0] + SNAKE_SIZE, snake[0][1]] elif snake_direction == 'LEFT': new_pos = [snake[0][0] - SNAKE_SIZE, snake[0][1]] elif snake_direction == 'UP': new_pos = [snake[0][0], snake[0][1] - SNAKE_SIZE] elif snake_direction == 'DOWN': new_pos = [snake[0][0], snake[0][1] + SNAKE_SIZE] snake.insert(0, new_pos) snake.pop() def draw_food(food_position): pygame.draw.rect(screen, FOOD_COLOR, pygame.Rect(food_position[0], food_position[1], SNAKE_SIZE, SNAKE_SIZE)) def check_collision(snake, food_position): if snake[0] == food_position: return True return False def check_game_over(snake): if snake[0][0] < 0 or snake[0][0] > SCREEN_WIDTH-SNAKE_SIZE: return True elif snake[0][1] < 0 or snake[0][1] > SCREEN_HEIGHT-SNAKE_SIZE: return True for block in snake[1:]: if snake[0] == block: return True return False # 遊戲迴圈 while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT and snake_direction != 'LEFT': snake_direction = 'RIGHT' elif event.key == pygame.K_LEFT and snake_direction != 'RIGHT': snake_direction = 'LEFT' elif event.key == pygame.K_UP and snake_direction != 'DOWN': snake_direction = 'UP' elif event.key == pygame.K_DOWN and snake_direction != 'UP': snake_direction = 'DOWN' screen.fill((0, 0, 0)) # 移動蛇 move_snake(snake, snake_direction)

import pygame
import random

# 初始化 Pygame
pygame.init()

# 定義常數
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
SNAKE_SIZE = 10
SNAKE_SPEED = 15
SNAKE_COLOR = (0, 255, 0)
FOOD_COLOR = (255, 0, 0)

# 創建視窗
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

# 設置標題
pygame.display.set_caption('貪食蛇')

# 創建蛇
snake = [[200, 200], [210, 200], [220, 200]]
snake_direction = 'RIGHT'

# 創建食物
food_position = [random.randrange(1, (SCREEN_WIDTH//10)) * 10, 
                 random.randrange(1, (SCREEN_HEIGHT//10)) * 10]

# 定義函數
def draw_snake(snake):
    for pos in snake:
        pygame.draw.rect(screen, SNAKE_COLOR, pygame.Rect(pos[0], pos[1], SNAKE_SIZE, SNAKE_SIZE))

def move_snake(snake, snake_direction):
    if snake_direction == 'RIGHT':
        new_pos = [snake[0][0] + SNAKE_SIZE, snake[0][1]]
    elif snake_direction == 'LEFT':
        new_pos = [snake[0][0] - SNAKE_SIZE, snake[0][1]]
    elif snake_direction == 'UP':
        new_pos = [snake[0][0], snake[0][1] - SNAKE_SIZE]
    elif snake_direction == 'DOWN':
        new_pos = [snake[0][0], snake[0][1] + SNAKE_SIZE]
    snake.insert(0, new_pos)
    snake.pop()

def draw_food(food_position):
    pygame.draw.rect(screen, FOOD_COLOR, pygame.Rect(food_position[0], 
                                                     food_position[1], 
                                                     SNAKE_SIZE, 
                                                     SNAKE_SIZE))

def check_collision(snake, food_position):
    if snake[0] == food_position:
        return True
    return False

def check_game_over(snake):
    if snake[0][0] < 0 or snake[0][0] > SCREEN_WIDTH-SNAKE_SIZE:
        return True
    elif snake[0][1] < 0 or snake[0][1] > SCREEN_HEIGHT-SNAKE_SIZE:
        return True
    for block in snake[1:]:
        if snake[0] == block:
            return True
    return False

# 遊戲迴圈
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT and snake_direction != 'LEFT':
                snake_direction = 'RIGHT'
            elif event.key == pygame.K_LEFT and snake_direction != 'RIGHT':
                snake_direction = 'LEFT'
            elif event.key == pygame.K_UP and snake_direction != 'DOWN':
                snake_direction = 'UP'
            elif event.key == pygame.K_DOWN and snake_direction != 'UP':
                snake_direction = 'DOWN'

    screen.fill((0, 0, 0))

    # 移動蛇
    move_snake(snake, snake_direction)

   


GOOGLE不小心按了改成韓文,改變語言設定

  好奇點了上面的其他語言版本,結果搞了一會才改回中文,提供修改流程給需要的人