First release
Dependencies: EthernetInterface HTTPServer TextLCD mbed-rpc mbed-rtos mbed
Sample code of section 5 in Oct 2014 issue of the Interface Magazine, published by CQ publishing in Japan. CQ出版社インターフェース誌 2014年10月号5章に掲載のサンプルコードです.
LPC1768にトラ技OV7670モジュールとサーボを接続したうえで,リモート操作可能なネットワーク・カメラにしています.このコードのうちカメラ制御部には,Sadaei Osakabe氏のコードを流用させていただいています.
また,次のHTMLファイルをダウンロードして,LPC1768のフラッシュメモリに置いてください.ネットワーク経由で,このHTMLにアクセスをします(ブラウザで開く). /media/uploads/smorioka/netcam.htm
Diff: main.cpp
- Revision:
- 0:993f719c9352
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Aug 26 16:49:26 2014 +0000 @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2014, Sumio Morioka + * All rights reserved. + * + * This source code was originally written by Dr.Sumio Morioka for use in the Oct 2014 issue of + * "the Interface magazine", published by CQ publishing Co.Ltd in Japan (http://www.cqpub.co.jp). + * The author has no responsibility on any results caused by using this code. + * + * - Distribution date of this code: Aug 26, 2014 + * - Author: Dr.Sumio Morioka (http://www002.upp.so-net.ne.jp/morioka) + * + * + * IMPORTANT NOTICE: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mbed.h" +#include "mbed_rpc.h" + +#include "TextLCD.h" +#include "LocalFileSystem.h" + +#include "EthernetInterface.h" +#include "HTTPServer.h" +#include "FsHandler.h" +#include "RpcHandler.h" + +#include "ov7670.h" + +TextLCD lcd(p24, p26, p27, p28, p29, p30); + + +//#define USE_RPCOUT +#undef USE_RPCOUT + +#ifndef USE_RPCOUT +DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4); +PwmOut sv0(p21), sv1(p22), sv2(p23); +#else +RpcDigitalOut led1(LED1, "led1"); +RpcDigitalOut led2(LED2, "led2"); +RpcDigitalOut led3(LED3, "led3"); +RpcDigitalOut led4(LED4, "led4"); + +RpcPwmOut sv0(p21, "sv0"); +RpcPwmOut sv1(p22, "sv1"); +RpcPwmOut sv2(p23, "sv2"); +#endif + + +LocalFileSystem local("webfs"); + +OV7670 camera( + p9,p10, // SDA,SCL(I2C / SCCB) + p5,p6,p7, // VSYNC,HREF,WEN(FIFO) + p20,p19,p18,p17,p16,p15,p14,p13, // D7-D0 + p8,p11,p12); // RRST,OE,RCLK + +//Timer tmr; + +#define QQVGA +//#define QVGA +//#define VGA34 + +#ifdef QQVGA +#define SIZEX 160 +#define SIZEY 120 +#endif + +#ifdef QVGA +#define SIZEX 320 +#define SIZEY 240 +#endif + +#ifdef VGA34 +#define SIZEX 480 +#define SIZEY 360 +#endif + + +//void cam_cap(void); +void cam_cap(Arguments* input, Reply* output); +RPCFunction rpcFunc(&cam_cap, "cam_cap"); + +#ifndef USE_RPCOUT +float sv0_rpc; +float sv1_rpc; +float sv2_rpc; + +RPCVariable<float> rpc_sv0_val(&sv0_rpc, "sv0"); +RPCVariable<float> rpc_sv1_val(&sv1_rpc, "sv1"); +RPCVariable<float> rpc_sv2_val(&sv2_rpc, "sv2"); +#endif + +int cap_flag; +RPCVariable<int> rpc_cap_flag(&cap_flag, "cap_flag"); + + +int memfree(void) +{ + int ret = 1; + while (1) { + char *p = (char *)malloc(ret); + if (p == NULL) + break; + free(p); + ret++; + } + return (ret); +} + + +float deg_to_pulsewidth(float deg) +{ + // limit range + if (deg < -90.0f) + deg = -90.0f; + else if (deg > 90.0f) + deg = 90.0f; + + // return result + return (0.00145f + 0.001f * (deg / 90.0f)); +} + +int main() +{ + float sv0_val, sv1_val, sv2_val; + +#ifndef USE_RPCOUT + led1 = 0; + led2 = 0; + led3 = 0; + led4 = 0; +#else + led1.write(0); + led2.write(0); + led3.write(0); + led4.write(0); +#endif + +#ifdef USE_RPCOUT + sv0_val = 0.00045f; // unit: sec + sv1_val = 0.00145f; // unit: sec + sv2_val = 0.00245f; // unit: sec + + sv0.period(0.02f); // unit: sec + sv0.pulsewidth(sv0_val); + + sv1.period(0.02f); // unit: sec + sv1.pulsewidth(sv1_val); + + sv2.period(0.02f); // unit: sec + sv2.pulsewidth(sv2_val); + +#else + sv0_val = 0.0f; // unit: deg + sv1_val = 0.0f; // unit: deg + sv2_val = 0.0f; // unit: deg + + sv0.period(0.02f); // unit: sec + sv0.pulsewidth(deg_to_pulsewidth(sv0_val)); + + sv1.period(0.02f); // unit: sec + sv1.pulsewidth(deg_to_pulsewidth(sv1_val)); + + sv2.period(0.02f); // unit: sec + sv2.pulsewidth(deg_to_pulsewidth(sv2_val)); + + sv0_rpc = sv0_val; + sv1_rpc = sv1_val; + sv2_rpc = sv2_val; +#endif + + cap_flag = 0; + + //////////////////////////////////////////////////////////////////////////// + camera.WriteReg(0x12, 0x80); // com7; reset + wait_ms(200); + + camera.InitDefaultReg(); + + // negate vsync + camera.WriteReg(0x15, 0x02); // com10; negative vsync + +#ifdef QQVGA + camera.InitQQVGA(); +#endif +#ifdef QVGA + camera.InitQVGA(); +#endif +#ifdef VGA34 + camera.InitVGA_3_4(); +#endif + + // data format + camera.WriteReg(0x12, 0x04 + 0); // com7 RGB (bit1...test pattern) + camera.WriteReg(0x40, 0xD0); // com15 RGB565 + camera.WriteReg(0x8c, 0x00); // RGB444 + + wait_ms(300); + +//{ +//FILE *f = fopen("/webfs/REG.TXT", "wt"); +//for (int i = 0; i < 256; i++) { +// int val = camera.ReadReg(i); +// fprintf(f, "%02X ", val); +// if ((i % 16) == 15) +// fprintf(f, "\n"); +//} +//fclose(f); +//} + + ////////////////////////////////////////////////// + + // network + EthernetInterface eth; // locate here + +// //Static IP +// char *ip = "192.168.0.20"; +// char *mask = "255.255.255.0"; +// char *gateway = "192.168.0.1"; +// eth.init(ip, mask, gateway); + //DHCP + eth.init(); + + eth.connect(); + + lcd.locate(0, 0); + lcd.printf("IP %s", eth.getIPAddress()); + + // rcp +#ifdef USE_RPCOUT +// RPC::add_rpc_class<RpcDigitalIn>(); // read + RPC::add_rpc_class<RpcDigitalOut>(); // read,write +// RPC::add_rpc_class<RpcDigitalInOut>(); // read,write,input,output + RPC::add_rpc_class<RpcPwmOut>(); // read,write,period,period_ms,pulsewidth,pulsewidth_ms +// RPC::add_rpc_class<RpcAnalogIn>(); // read,read_u16 +// RPC::add_rpc_class<RpcAnalogOut>(); // read,write,write_u16 +// RPC::add_rpc_class<RpcSPI>(); // format,frequency,write +// RPC::add_rpc_class<RpcSerial>(); // baud,readable,writeable(SPELL?),putc,getc,puts +// RPC::add_rpc_class<RpcTimer>(); // start,stop,reset,read,read_ms,read_us +#endif + + // http + HTTPServer svr; // locate here + HTTPFsRequestHandler::mount("/webfs/", "/"); + svr.addHandler<HTTPFsRequestHandler>("/"); + svr.addHandler<HTTPRpcRequestHandler>("/rpc"); + + svr.start(80, ð); + +// lcd.locate(0, 1); +// lcd.printf("mem %d", memfree()); + +#ifndef USE_RPCOUT + led1 = 1; +#else + led1.write(1); +#endif + + while (1) { + svr.poll(); + +#ifndef USE_RPCOUT + if (sv0_val != sv0_rpc) { + sv0_val = sv0_rpc; + // limit + if (sv0_val < -90.0f) + sv0_val = -90.0f; + else if (sv0_val > 90.0f) + sv0_val = 90.0f; + + sv0_rpc = sv0_val; + sv0.pulsewidth(deg_to_pulsewidth(sv0_val)); + + lcd.locate(0, 1); + lcd.printf("0:%f ", sv0_val); + } + + if (sv1_val != sv1_rpc) { + sv1_val = sv1_rpc; + // limit + if (sv1_val < -90.0f) + sv1_val = -90.0f; + else if (sv1_val > 90.0f) + sv1_val = 90.0f; + + sv1_rpc = sv1_val; + sv1.pulsewidth(deg_to_pulsewidth(sv1_val)); + + lcd.locate(0, 1); + lcd.printf("1:%f ", sv1_val); + } + + if (sv2_val != sv2_rpc) { + sv2_val = sv2_rpc; + // limit + if (sv2_val < -90.0f) + sv2_val = -90.0f; + else if (sv2_val > 90.0f) + sv2_val = 90.0f; + + sv2_rpc = sv2_val; + sv2.pulsewidth(deg_to_pulsewidth(sv2_val)); + + lcd.locate(0, 1); + lcd.printf("2:%f ", sv2_val); + } +#endif + + wait_ms(10); + } +} + + +//void cam_capture(char *input, char *output) // compile error +void cam_cap(Arguments* input, Reply* output) +//void cam_cap(void) +{ + FILE *fp_bmp; + unsigned int d1, d2; + unsigned char sort[3]; + +#ifndef USE_RPCOUT + led2 = 1; +#else + led2.write(1); +#endif + + cap_flag = 0; + + fp_bmp = fopen("/webfs/cam.bmp", "wb"); + + ///////////////////////// + // file header + ///////////////////////// + fprintf(fp_bmp, "BM"); + int val = 14 + 40 + SIZEX * SIZEY * 3; // file size + fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000); + fprintf(fp_bmp, "%c%c%c%c%c%c%c%c", 0, 0, 0, 0, 0x36, 0, 0, 0); + + ///////////////////////// + // information header + ///////////////////////// + fprintf(fp_bmp, "%c%c%c%c", 0x28, 0, 0, 0); // header size + fprintf(fp_bmp, "%c%c%c%c", SIZEX % 0x100, SIZEX / 0x100, SIZEX / 0x10000, SIZEX / 0x1000000); + fprintf(fp_bmp, "%c%c%c%c", SIZEY % 0x100, SIZEY / 0x100, SIZEY / 0x10000, SIZEY / 0x1000000); + fprintf(fp_bmp, "%c%c", 1, 0); // # of plane + fprintf(fp_bmp, "%c%c", 24, 0); // bit count + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); // compression + val = SIZEX * SIZEY * 3; // data size + fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); + + camera.CaptureNext(); // sample start! + + while(camera.CaptureDone() == false) + ; + + camera.ReadStart(); // reset pointer + +#ifndef USE_RPCOUT + led3 = 1; +#else + led3.write(1); +#endif + + for (int y = 0;y < SIZEY;y++) { + for (int x = 0;x < SIZEX;x++) { + d1 = camera.ReadOneByte() ; // upper nibble is XXX , lower nibble is B + d2 = camera.ReadOneByte() ; // upper nibble is G , lower nibble is R + + // RGB565 + sort[0] = ((d1 & 0xF8) >> 3) << 3; // R + sort[1] = ( ((d1 & 0x07) << 3) + ((d2 & 0xE0) >> 5) ) << 2; // G + sort[2] = (d2 & 0x1F) << 3; // B + + fprintf(fp_bmp, "%c%c%c", sort[2], sort[1], sort[0]); // B,G,R + } + } + + camera.ReadStop(); + fclose(fp_bmp); + +#ifndef USE_RPCOUT + led2 = 0; + led3 = 0; + led4 = 0; +#else + led2.write(0); + led3.write(0); + led4.write(0); +#endif + + cap_flag = 1; +} + +// end of file