今天,你几乎不会让任何人感到惊讶,因为你的手机配备了摄像头、无线小工具和其他技术进步。多亏了 Arduino 平台,数百万人发现了电子和编程的美妙世界。关于如何通过蓝牙在手机和 Arduino 之间交换数据的 100、500 条指令被写...我在说什么?是的。我想通过蓝牙在 Android 上的手机和 Arduino UNO 之间交换数据 100、501 次。但我想传输的不仅仅是一组字符和数字,而是图片。
有人会说这是不可能的,Arduino 速度太慢,无法快速处理大量数据。他将是绝对正确的。如果对 Arduino 有一点帮助 - 将所有“艰苦”的工作转移到其他设备的肩上呢?并且有这样的设备!
这是 Arduino 独特的 TFT 屏蔽。有关此徽标的信息在以下文章中:文章 1 ,文章 2在本教程中,我将演示如何通过蓝牙连接 Arduino 和 Android 手机,从 Arduino UNO 上的 OV7670 摄像头获取照片并将其传输到 Android 手机。然后,相反,将图片(来自相机的图像)从 Android 手机传输到 Arduino UNO 并显示在独特的 TFT 屏蔽的屏幕上。
为 Android 手机编写了一个特殊的应用程序。
TFT屏蔽的简要特点:
硬件:
注意:必须(!)使用 6-12 伏电源适配器来操作 TFT 屏蔽,因为 USB 的 500 mA 的最大电流不足以正常操作。
软件:
软件
所有演示草图都是在 Arduino IDE 环境中编写的,因此一开始需要安装 Arduino IDE - https://www.arduino.cc/en/main/software。然后你需要为 TFT shield 安装一个库 - github.com/YATFT/YATFT (下载该库并解压到 Arduino IDE 目录下的“libraries”文件夹中)。
安装 Arduino IDE 后,您必须对 Arduino UNO 板进行编程。为简单起见,我建议单独刷机,不带 TFT 屏蔽。为了这:
如果 Arduino UNO 板编程成功,您可以继续下一步。
ArduinoBluetoothCamera.ino草图:
/**********************************************************************
* SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL AUTHOR OR ITS LICENSORS BE
* LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY,
* CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY
* DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO
* ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES,
* LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS,
* TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT
* NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
***********************************************************************/
#include
#include
#include
#include
#include "ov7670_regs.h"
JPEG_DECODE jpeg_decode;
YATFT tft(0);
INTRFC ifc;
CAM cam;
CODEC codec;
SRL srl;
#define IMG_SizeX 320
#define IMG_SizeY 240
uint8_t mode = 0;
uint8_t last_mode = 0;
uint8_t start_capt = 0;
uint16_t err;
void setup()
{
// initialize the serial port
Serial.begin(115200);
// initialize the display
tft.begin();
tft.SetColor(BRIGHTRED);
tft.ClearDevice();
}
void loop()
{
// put your main code here, to run repeatedly:
if (Serial.available())
{
uint8_t temp = Serial.read();
switch (temp)
{
case 0x10: // Send single Photo
mode = 1;
start_capt = 1;
if (last_mode != mode && last_mode != 2) {
tft.begin();
tft.SetRGB(); // Switch to RGB mode
cam.CamInit(&OV7670_QVGA[0][0]);
cam.CamVideoPreview(0, 0, 1, true);
codec.JPEGInit();
codec.JPEGSetRegs(IMG_SizeX, IMG_SizeY);
delay(1000);
}
break;
case 0x20: // Continuous send Photo
mode = 2;
start_capt = 2;
if (last_mode != mode && last_mode != 1) {
tft.begin();
tft.SetRGB(); // Switch to RGB mode
cam.CamInit(&OV7670_QVGA[0][0]);
cam.CamVideoPreview(0, 0, 1, true);
codec.JPEGInit();
codec.JPEGSetRegs(IMG_SizeX, IMG_SizeY);
}
break;
case 0x30: // Receive single Photo
mode = 3;
start_capt = 3;
if (last_mode != mode && last_mode != 4) {
tft.begin();
tft.SetYUV(); // Switch to YUV mode
}
break;
case 0x40: // Continuous receive Photo
mode = 4;
start_capt = 4;
if (last_mode != mode && last_mode != 3) {
tft.begin();
tft.SetYUV(); // Switch to YUV mode
}
break;
default:
break;
}
}
if (mode == 1) // Send single Photo
{
if (start_capt == 1)
{
start_capt = 0;
last_mode = mode;
mode = 0;
CamCapture();
}
}
else if (mode == 2) // Continuous send Photo
{
while (1)
{
uint8_t temp = Serial.read();
if (start_capt == 2)
{
start_capt = 0;
}
if (temp == 0x21) // Stop ?
{
start_capt = 0;
last_mode = mode;
mode = 0;
break;
}
if (CamCapture()) continue;
}
}
else if (mode == 3) // Receive single Photo
{
if (start_capt == 3)
{
//Start capture
start_capt = 0;
last_mode = mode;
mode = 0;
Serial.print("!");
srl.JPEGReadFromSerial(&jpeg_decode, // jpeg decode structure
0, // x0 (left)
0, // y0 (top)
GetMaxX()+1, // x1 (right)
GetMaxY()+1, // y1 (bottom)
32000); // max image size
}
}
else if (mode == 4) // Continuous receive Photo
{
uint8_t temp = Serial.read();
while (1)
{
if (start_capt == 4)
{
//Start capture
start_capt = 0;
}
if (temp == 0x41) // Stop ?
{
start_capt = 0;
last_mode = mode;
mode = 0;
break;
}
Serial.print("!");
srl.JPEGReadFromSerial(&jpeg_decode, // jpeg decode structure
0, // x0 (left)
0, // y0 (top)
GetMaxX()+1, // x1 (right)
GetMaxY()+1, // y1 (bottom)
32000); // max image size
}
}
}
uint8_t CamCapture(void)
{
uint8_t temp = 0xff, temp_last = 0;
bool is_header = false;
uint32_t length = 0;
length = codec.JPEGStart();
uint32_t en_jpeg_address = ifc.rdReg32(0x414)<<2;
int k = 0;
if ((length >= 0x5FFFF) | (length == 0))
{
start_capt = 2;
return 1;
}
temp = ifc.GetMem(en_jpeg_address+k);
k++;
length --;
while ( length-- )
{
temp_last = temp;
temp = ifc.GetMem(en_jpeg_address+k);
k++;
if (is_header == true)
{
Serial.write(temp);
}
else if ((temp == 0xD8) & (temp_last == 0xFF))
{
is_header = true;
Serial.write(temp_last);
Serial.write(temp);
}
if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
break;
}
is_header = false;
return 0;
}
OV7670_regs.h:
#ifndef OV7670_REGS_H
#define OV7670_REGS_H
const uint8_t OV7670_VGA[][2] PROGMEM =
{
{ 1, 0x42}, // Size of byte, Address (ID)
{ 640/16, 480/16}, // Size X, Size Y
{0b01000010, 0b00000100}, // Reset_Enable_N, 7|6|5|4|3|Vsync Invert|Hsync Invert|0
{0x3a, 0x0C}, {0x40, 0xC0}, {0x12, 0x00}, {0x0c, 0x00},
{0x3e, 0x00}, {0x70, 0x3A}, {0x71, 0x35}, {0x72, 0x11},
{0x73, 0xF0}, {0xa2, 0x02}, {0x11, 0x80}, {0x7a, 0x18},
{0x7b, 0x02}, {0x7c, 0x07}, {0x7d, 0x1F}, {0x7e, 0x49},
{0x7f, 0x5A}, {0x80, 0x6A}, {0x81, 0x79}, {0x82, 0x87},
{0x83, 0x94}, {0x84, 0x9F}, {0x85, 0xAF}, {0x86, 0xBB},
{0x87, 0xCF}, {0x88, 0xEE}, {0x89, 0xEE}, {0x13, 0xE0},
{0x00, 0x00}, {0x10, 0x00}, {0x0d, 0x00}, {0x24, 0x98},
{0x25, 0x63}, {0x26, 0xD3}, {0x2a, 0x00}, {0x2b, 0x00},
{0x2d, 0x00}, {0x13, 0xe5}, {0x13, 0xe7}, {0x1e, 0x30},
{0x74, 0x60}, {0x01, 0x80}, {0x02, 0x80}, {0x15, 0x10},
{0x4f, 0x40}, {0x50, 0x34}, {0x51, 0x0C}, {0x52, 0x17},
{0x53, 0x29}, {0x54, 0x40}, {0x57, 0x80}, {0x58, 0x1e},
{0x41, 0x10}, {0x75, 0x60}, {0x76, 0x50}, {0x77, 0x48},
{0x3d, 0x92}, {0x3b, 0x00}, {0x04, 0x00}, {0xff, 0xff},
};
const uint8_t OV7670_QVGA[][2] PROGMEM =
{
{ 1, 0x42}, // Size of byte, Address (ID)
{ 320/16, 240/16}, // Size X, Size Y
{0b01000010, 0b00000100}, // Reset_Enable_N, 7|6|5|4|3|Vsync Invert|Hsync Invert|0
{0x3a, 0x0C}, {0x40, 0xC0}, {0x12, 0x10}, {0x0c, 0x00},
{0x3e, 0x00}, {0x70, 0x3A}, {0x71, 0x35}, {0x72, 0x11},
{0x73, 0xF0}, {0xa2, 0x02}, {0x11, 0x80}, {0x7a, 0x18},
{0x7b, 0x02}, {0x7c, 0x07}, {0x7d, 0x1F}, {0x7e, 0x49},
{0x7f, 0x5A}, {0x80, 0x6A}, {0x81, 0x79}, {0x82, 0x87},
{0x83, 0x94}, {0x84, 0x9F}, {0x85, 0xAF}, {0x86, 0xBB},
{0x87, 0xCF}, {0x88, 0xEE}, {0x89, 0xEE}, {0x13, 0xE0},
{0x00, 0x00}, {0x10, 0x00}, {0x0d, 0x00}, {0x24, 0x98},
{0x25, 0x63}, {0x26, 0xD3}, {0x2a, 0x00}, {0x2b, 0x00},
{0x2d, 0x00}, {0x13, 0xe5}, {0x13, 0xe7}, {0x1e, 0x30},
{0x74, 0x60}, {0x01, 0x80}, {0x02, 0x80}, {0x15, 0x10},
{0x4f, 0x40}, {0x50, 0x34}, {0x51, 0x0C}, {0x52, 0x17},
{0x53, 0x29}, {0x54, 0x40}, {0x57, 0x80}, {0x58, 0x1e},
{0x41, 0x10}, {0x75, 0x60}, {0x76, 0x50}, {0x77, 0x48},
{0x3d, 0x92}, {0x3b, 0x00}, {0x04, 0x00}, {0xff, 0xff},
};
#endif
安卓
在 Android 手机上,您需要安装ArduinoTFT.apk。允许应用使用蓝牙和相机。
2020 年 5 月 26 日更新!
我添加了 ArduinoTFT.apk 的源代码。原样!下载ArduinoTFT.zip.h
,重命名为ArduinoTFT.zip 并解压。享受!
2020 年 7 月 25 日更新!
“嗨,我遇到了同样的问题,Android 应用程序无法正常工作。授权应用程序访问智能手机相机后解决。就是这样。再见”(c)
蓝牙模块
需要在蓝牙模块中设置汇率为115200(命令“AT+UART=115200, 0, 0”)。这是 Arduino UNO 管理接收和处理数据的最佳速度。(理论上可以提高速度,优化数据接收和处理,但这需要更大的RAM)。关于如何设置汇率的更详细说明可以在网上找到,例如,这里:https:/ /www.instructables.com/id/Communication-Bluetooth-Module-With-HC-05-HC-06/ 。
(!)请注意蓝牙模块连接到 Arduino UNO 的调试端口。因此,在使用蓝牙时,调试端口不可用。并且在对 Arduino UNO(配有蓝牙模块)进行编程之前,必须断开蓝牙模块。编程后,将其重新设置(!)
该设备的组装非常简单:
打开电源后,TFT shield 的屏幕应变为红色。这意味着愿意从 Android 手机接收命令。
在安卓手机上执行以下操作:
屏幕上应出现两个窗口和四个按钮:
按钮功能:
图像大小为 320x240 像素 (2-5 kB)。本章有一个演示视频。
再一次问好!有一个用于一系列屏幕的更新库,目前由两个屏蔽和两个分线板组成。草图的编译取决于所选版本(从 1 到 4)和微控制器类型(MegaAVR 或 ESP-32)。添加了照片,示例。更多信息可以在https://github.com/Ekaburg/EkaTFT中找到。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !