main.lua 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. --[[
  2. 1. 本demo可直接在Air8000整机开发板上运行
  3. 2. 演示摄像头拍照扫码功能,通过TEST_MODE宏来选择演示的内容。
  4. 摄像头使用了如下管脚
  5. [85, "AGPIO4", " PIN85脚, PA供电使能"],
  6. [67, "CAM_SPI_CLK", " PIN67脚, 用作摄像头时钟"],
  7. [66, "CAM_SPI_CS", " PIN66脚, 用作摄像头片选", "可选,开发板未用到"],
  8. [98, "CAM_MCLK", " PIN98脚, 用于摄像头时钟"],
  9. [52, "GPIO153", " PIN52脚, 控制摄像头开启/关闭"],
  10. [53, "GPIO147", " PIN53脚, 控制摄像头电源"],
  11. [80, "I2C0_SCL", " PIN80脚, 用作摄像头复用"],
  12. [81, "I2C0_SDA", " PIN81脚, 用作摄像头复用"],
  13. [1, "USB_BOOT", " PIN1脚, 用作功能键"],
  14. [16, "UART1_TX", " PIN16脚,初始化串口1"],
  15. [17, "UART1_RX", " PIN17脚,用作输出拍摄的照片"]
  16. 3.注意:在air8000整机开发版上,因为es8311/gsensor/lcd_tp触摸/camera 用的都是I2C0(80/81脚),所以使用此demo时不能同时使用es8311/gsensor/lcd_tp触摸功能
  17. 4. 本程序使用逻辑:
  18. 4.1 如果TEST_MODE 设置为1 ,程序运行后,点击boot 键,将进行扫码测试,如果解析二维码或者条形码成功,将会打印在luatools 中。
  19. 4.2 如果TEST_MODE 设置为0,程序运行后,点击boot 键,将进行拍照测试,并且保存在本地。
  20. ]]
  21. PROJECT = "spi_camera_demo"
  22. VERSION = "1.0.0"
  23. -- 实际使用时选1个就行
  24. -- require "bf30a2"
  25. -- require "gc0310"
  26. require "gc032a"
  27. sys = require("sys")
  28. sysplus = require("sysplus")
  29. local taskName = "SPI_CAMERA"
  30. local TEST_MODE = 0 -- 写1 演示扫码(使用摄像头对二维码、条形码或其他类型的图案进行扫描和识别),0 演示拍照
  31. local scan_pause = true -- 扫码启动与停止标志位
  32. local done_with_close = false -- true 结束后关闭摄像头
  33. local uartid = 1 -- 根据实际设备选取不同的uartid
  34. local cspiId = 1 -- 摄像头使用SPI1、I2C0
  35. local i2cId = 0
  36. local camera_id
  37. -- 初始化UART
  38. local result = uart.setup(uartid, -- 串口id
  39. 115200, -- 波特率
  40. 8, -- 数据位
  41. 1 -- 停止位
  42. )
  43. -- 注册摄像头事件回调
  44. camera.on(0, "scanned", function(id, str)
  45. if type(str) == 'string' then
  46. log.info("扫码结果", str)
  47. elseif str == false then
  48. log.error("摄像头没有数据")
  49. else
  50. log.info("摄像头数据", str)
  51. sys.publish("capture done", true)
  52. end
  53. end)
  54. -- 初始化按键,这里选取boot键作为功能键
  55. local function press_key()
  56. log.info("boot press")
  57. sys.publish("PRESS", true)
  58. end
  59. gpio.setup(0, press_key, gpio.PULLDOWN, gpio.RISING)
  60. gpio.debounce(0, 100, 1)
  61. -- 初始化摄像头
  62. local rawbuff, err = zbuff.create(60 * 1024, 0, zbuff.HEAP_AUTO) -- gc032a
  63. if rawbuff == nil then
  64. log.info(err)
  65. end
  66. local function device_init()
  67. i2c.setup(i2cId, i2c.FAST)
  68. gpio.setup(153, 0) -- PD拉低
  69. sys.wait(500)
  70. -- return bf30a2Init(cspiId,i2cId,25500000,TEST_MODE,TEST_MODE)
  71. -- return gc0310Init(cspiId, i2cId, 25500000, TEST_MODE, TEST_MODE)
  72. return gc032aInit(cspiId, i2cId, 24000000, TEST_MODE, TEST_MODE)
  73. end
  74. local function main_task()
  75. sys.wait(500)
  76. gpio.setup(147, 1, gpio.PULLUP) -- camera的供电使能脚
  77. gpio.setup(153, 1, gpio.PULLUP) -- 控制camera电源的pd脚
  78. gpio.setup(24, 1, gpio.PULLUP) -- 打开内部公用的gsensor,所以需要先打开供电
  79. gpio.setup(164, 1, gpio.PULLUP) -- 因为整机开发板的音频i2c 共用,不打开会导致I2C 对地,所以需要打开音频的codec
  80. sys.wait(4000)
  81. log.info("摄像头启动")
  82. local camera_id = device_init()
  83. if done_with_close then
  84. camera.close(camera_id)
  85. else
  86. camera.stop(camera_id)
  87. end
  88. log.info("按下boot开始测试")
  89. log.info(rtos.meminfo("sys"))
  90. log.info(rtos.meminfo("psram"))
  91. while 1 do
  92. result, data = sys.waitUntil("PRESS", 30000)
  93. if result == true and data == true then
  94. if TEST_MODE == 1 then
  95. if scan_pause then
  96. log.info("启动扫码")
  97. if done_with_close then
  98. camera_id = device_init()
  99. end
  100. camera.start(camera_id)
  101. scan_pause = false
  102. sys.wait(1000)
  103. log.info(rtos.meminfo("sys"))
  104. log.info(rtos.meminfo("psram"))
  105. else
  106. log.info("停止扫码")
  107. if done_with_close then
  108. camera.close(camera_id)
  109. else
  110. camera.stop(camera_id)
  111. end
  112. scan_pause = true
  113. sys.wait(1000)
  114. log.info(rtos.meminfo("sys"))
  115. log.info(rtos.meminfo("psram"))
  116. end
  117. else
  118. log.debug("摄像头拍照")
  119. if done_with_close then
  120. camera_id = device_init()
  121. end
  122. -- 先保存到文件,再上传
  123. local save_path = "/ram/capture.jpg"
  124. camera.capture(camera_id, save_path, 95)
  125. result, data = sys.waitUntil("capture done", 30000)
  126. if done_with_close then
  127. camera.close(camera_id)
  128. else
  129. camera.stop(camera_id)
  130. end
  131. -- 上传服务器
  132. local httpplus = require("httpplus")
  133. local opts = {
  134. url = "http://upload.air32.cn/api/upload/jpg", -- 必选, 目标URL
  135. method = "POST", -- 可选,默认GET, 如果有body,files,forms参数,会设置成POST
  136. headers = {}, -- 可选,自定义的额外header
  137. body = io.readFile("/ram/capture.jpg"), -- 将原始缓冲区中已使用的数据转换为字符串,作为HTTP请求的body内容
  138. forms = {}, -- 可选,表单参数,若存在本参数,如果不存在files,按application/x-www-form-urlencoded上传
  139. debug = false, -- 可选,打开调试日志,默认false
  140. try_ipv6 = false, -- 可选,是否优先尝试ipv6地址,默认是false
  141. adapter = nil, -- 可选,网络适配器编号, 默认是自动选
  142. timeout = 30, -- 可选,读取服务器响应的超时时间,单位秒,默认30
  143. }
  144. local code, resp = httpplus.request(opts)
  145. if code >= 200 and code < 300 then
  146. -- headers, 是个table
  147. log.info("http", "headers", json.encode(resp.headers))
  148. -- body, 是个zbuff
  149. -- 通过query函数可以转为lua的string
  150. log.info("http", "headers", resp.body:query())
  151. log.info("发送完毕,图片在: https://www.air32.cn/upload/data/jpg/ 中查看")
  152. else
  153. log.error("上传失败,http code:", code)
  154. end
  155. rawbuff:resize(60 * 1024)
  156. log.info(rtos.meminfo("sys"))
  157. log.info(rtos.meminfo("psram"))
  158. end
  159. end
  160. end
  161. end
  162. -- 启动任务时传入依赖
  163. sysplus.taskInitEx(main_task,taskName)
  164. -- 用户代码已结束---------------------------------------------
  165. -- 结尾总是这一句
  166. sys.run()
  167. -- sys.run()之后后面不要加任何语句!!!!!