luat_lib_mlx90640.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. @module mlx90640
  3. @summary 红外测温(MLX90640)
  4. @version 1.0
  5. @date 2022.1.20
  6. */
  7. #include "luat_base.h"
  8. #include <MLX90640_I2C_Driver.h>
  9. #include <MLX90640_API.h>
  10. #include <math.h>
  11. #include "luat_lcd.h"
  12. #define LUAT_LOG_TAG "mlx90640"
  13. #include "luat_log.h"
  14. static luat_lcd_conf_t* lcd_conf;
  15. #define FPS1HZ 0x01
  16. #define FPS2HZ 0x02
  17. #define FPS4HZ 0x04
  18. #define FPS8HZ 0x08
  19. #define FPS16HZ 0x10
  20. #define FPS32HZ 0x20
  21. #define FPS64HZ 0x40
  22. #define MLX90640_ADDR 0x33
  23. #define TA_SHIFT 8 //Default shift for MLX90640 in open air
  24. static uint16_t eeMLX90640[832];
  25. static float mlx90640To[768];
  26. static uint16_t frame[834];
  27. static float emissivity=0.95;
  28. static int status;
  29. static float vdd;
  30. static float Ta;
  31. const uint16_t camColors[] = {0x480F,
  32. 0x400F,0x400F,0x400F,0x4010,0x3810,0x3810,0x3810,0x3810,0x3010,0x3010,
  33. 0x3010,0x2810,0x2810,0x2810,0x2810,0x2010,0x2010,0x2010,0x1810,0x1810,
  34. 0x1811,0x1811,0x1011,0x1011,0x1011,0x0811,0x0811,0x0811,0x0011,0x0011,
  35. 0x0011,0x0011,0x0011,0x0031,0x0031,0x0051,0x0072,0x0072,0x0092,0x00B2,
  36. 0x00B2,0x00D2,0x00F2,0x00F2,0x0112,0x0132,0x0152,0x0152,0x0172,0x0192,
  37. 0x0192,0x01B2,0x01D2,0x01F3,0x01F3,0x0213,0x0233,0x0253,0x0253,0x0273,
  38. 0x0293,0x02B3,0x02D3,0x02D3,0x02F3,0x0313,0x0333,0x0333,0x0353,0x0373,
  39. 0x0394,0x03B4,0x03D4,0x03D4,0x03F4,0x0414,0x0434,0x0454,0x0474,0x0474,
  40. 0x0494,0x04B4,0x04D4,0x04F4,0x0514,0x0534,0x0534,0x0554,0x0554,0x0574,
  41. 0x0574,0x0573,0x0573,0x0573,0x0572,0x0572,0x0572,0x0571,0x0591,0x0591,
  42. 0x0590,0x0590,0x058F,0x058F,0x058F,0x058E,0x05AE,0x05AE,0x05AD,0x05AD,
  43. 0x05AD,0x05AC,0x05AC,0x05AB,0x05CB,0x05CB,0x05CA,0x05CA,0x05CA,0x05C9,
  44. 0x05C9,0x05C8,0x05E8,0x05E8,0x05E7,0x05E7,0x05E6,0x05E6,0x05E6,0x05E5,
  45. 0x05E5,0x0604,0x0604,0x0604,0x0603,0x0603,0x0602,0x0602,0x0601,0x0621,
  46. 0x0621,0x0620,0x0620,0x0620,0x0620,0x0E20,0x0E20,0x0E40,0x1640,0x1640,
  47. 0x1E40,0x1E40,0x2640,0x2640,0x2E40,0x2E60,0x3660,0x3660,0x3E60,0x3E60,
  48. 0x3E60,0x4660,0x4660,0x4E60,0x4E80,0x5680,0x5680,0x5E80,0x5E80,0x6680,
  49. 0x6680,0x6E80,0x6EA0,0x76A0,0x76A0,0x7EA0,0x7EA0,0x86A0,0x86A0,0x8EA0,
  50. 0x8EC0,0x96C0,0x96C0,0x9EC0,0x9EC0,0xA6C0,0xAEC0,0xAEC0,0xB6E0,0xB6E0,
  51. 0xBEE0,0xBEE0,0xC6E0,0xC6E0,0xCEE0,0xCEE0,0xD6E0,0xD700,0xDF00,0xDEE0,
  52. 0xDEC0,0xDEA0,0xDE80,0xDE80,0xE660,0xE640,0xE620,0xE600,0xE5E0,0xE5C0,
  53. 0xE5A0,0xE580,0xE560,0xE540,0xE520,0xE500,0xE4E0,0xE4C0,0xE4A0,0xE480,
  54. 0xE460,0xEC40,0xEC20,0xEC00,0xEBE0,0xEBC0,0xEBA0,0xEB80,0xEB60,0xEB40,
  55. 0xEB20,0xEB00,0xEAE0,0xEAC0,0xEAA0,0xEA80,0xEA60,0xEA40,0xF220,0xF200,
  56. 0xF1E0,0xF1C0,0xF1A0,0xF180,0xF160,0xF140,0xF100,0xF0E0,0xF0C0,0xF0A0,
  57. 0xF080,0xF060,0xF040,0xF020,0xF800,};
  58. uint8_t tempto255(float temp){
  59. return (uint8_t)round((temp+40)*255/340);
  60. }
  61. static paramsMLX90640 mlx90640;
  62. uint8_t mlx90640_i2c_id;
  63. uint8_t mlx90640_i2c_speed;
  64. static uint8_t mlx90640_refresh_rate;
  65. /*
  66. 初始化MLX90640传感器
  67. @api mlx90640.init(i2c_id,i2c_speed,refresh_rate)
  68. @int 传感器所在的i2c总线id,默认为0
  69. @int 传感器所在的i2c总线速度,默认为i2c.FAST
  70. @int 传感器的测量速率,默认为4Hz
  71. @return bool 成功返回true, 否则返回nil或者false
  72. @usage
  73. if mlx90640.init(0,i2c.FAST,mlx90640.FPS4HZ) then
  74. log.info("mlx90640", "init ok")
  75. sys.wait(500) -- 稍等片刻
  76. while 1 do
  77. mlx90640.feed() -- 取一帧数据
  78. mlx90640.draw2lcd(0, 0 ,32 ,24)-- 需提前把lcd初始化好
  79. sys.wait(250) -- 默认是4HZ
  80. end
  81. else
  82. log.info("mlx90640", "init fail")
  83. end
  84. */
  85. static int l_mlx90640_init(lua_State *L){
  86. mlx90640_i2c_id = luaL_optinteger(L, 1 , 0);
  87. mlx90640_i2c_speed = luaL_optinteger(L, 2 , 1);
  88. mlx90640_refresh_rate = luaL_optinteger(L, 3 , 3);
  89. lcd_conf = luat_lcd_get_default();
  90. MLX90640_I2CInit();
  91. // luat_timer_mdelay(50);
  92. MLX90640_SetRefreshRate(MLX90640_ADDR, mlx90640_refresh_rate);
  93. MLX90640_SetChessMode(MLX90640_ADDR);
  94. status = MLX90640_DumpEE(MLX90640_ADDR, eeMLX90640);
  95. if (status != 0){
  96. LLOGW("load system parameters error with code:%d",status);
  97. return 0;
  98. }
  99. status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640);
  100. if (status != 0) {
  101. LLOGW("Parameter extraction failed with error code:%d",status);
  102. return 0;
  103. }
  104. //初始化后此处先读两帧,去掉初始化后一些错误数据
  105. for (size_t i = 0; i < 2; i++){
  106. int status = MLX90640_GetFrameData(MLX90640_ADDR, frame);
  107. if (status < 0){
  108. LLOGD("GetFrame Error: %d",status);
  109. return 0;
  110. }
  111. vdd = MLX90640_GetVdd(frame, &mlx90640);
  112. Ta = MLX90640_GetTa(frame, &mlx90640);
  113. MLX90640_CalculateTo(frame, &mlx90640, emissivity , Ta - TA_SHIFT, mlx90640To);
  114. MLX90640_BadPixelsCorrection(mlx90640.brokenPixels, mlx90640To, 1, &mlx90640);
  115. MLX90640_BadPixelsCorrection(mlx90640.outlierPixels, mlx90640To, 1, &mlx90640);
  116. lua_pushboolean(L, 1);
  117. }
  118. return 1;
  119. // while (1){
  120. // luat_timer_mdelay(10);
  121. // int x,y = 0;
  122. // // uint8_t mul = 3;
  123. // for(int i = 0; i < 768; i++){
  124. // if(i%32 == 0 && i != 0){
  125. // x = 0;
  126. // // y+=mul;
  127. // y++;
  128. // // printf("\n");
  129. // }
  130. // // uint8_t mul_size = mul*mul;
  131. // // uint16_t draw_data[mul_size];
  132. // // for (size_t m = 0; m < mul_size; m++){
  133. // // draw_data[m] = camColors[tempto255(mlx90640To[i])];
  134. // // }
  135. // // luat_lcd_draw(lcd_conf,x, y, x+mul-1, y+mul-1, draw_data);
  136. // // x+=mul;
  137. // luat_lcd_draw(lcd_conf,x, y, x, y, &(camColors[tempto255(mlx90640To[i])]));
  138. // x++;
  139. // }
  140. // }
  141. }
  142. /*
  143. 取一帧数据
  144. @api mlx90640.feed()
  145. @return nil
  146. */
  147. static int l_mlx90640_feed(lua_State *L) {
  148. int status = MLX90640_GetFrameData(MLX90640_ADDR, frame);
  149. if (status < 0){
  150. LLOGD("GetFrame Error: %d",status);
  151. return 0;
  152. }
  153. vdd = MLX90640_GetVdd(frame, &mlx90640);
  154. Ta = MLX90640_GetTa(frame, &mlx90640);
  155. MLX90640_CalculateTo(frame, &mlx90640, emissivity , Ta - TA_SHIFT, mlx90640To);
  156. MLX90640_BadPixelsCorrection(mlx90640.brokenPixels, mlx90640To, 1, &mlx90640);
  157. MLX90640_BadPixelsCorrection(mlx90640.outlierPixels, mlx90640To, 1, &mlx90640);
  158. lua_pushboolean(L, 1);
  159. return 0;
  160. }
  161. /*
  162. 获取底层裸数据,浮点数矩阵
  163. @api mlx90640.raw_data()
  164. @return table 浮点数数据,768个像素对应的温度值
  165. */
  166. static int l_mlx90640_raw_data(lua_State *L) {
  167. lua_createtable(L, 768, 0);
  168. for (size_t i = 0; i < 768; i++)
  169. {
  170. lua_pushnumber(L, mlx90640To[i]);
  171. lua_seti(L, -2, i + 1);
  172. }
  173. return 1;
  174. }
  175. /*
  176. 获取单一点数据
  177. @api mlx90640.raw_point(index)
  178. @int 索引值(0-767)
  179. @return number 单点温度值
  180. */
  181. static int l_mlx90640_raw_point(lua_State *L) {
  182. lua_pushnumber(L, mlx90640To[luaL_checkinteger(L, 1)]);
  183. return 1;
  184. }
  185. /*
  186. 获取外壳温度
  187. @api mlx90640.get_temp()
  188. @return number 外壳温度
  189. */
  190. static int l_mlx90640_get_temp(lua_State *L) {
  191. lua_pushnumber(L, Ta);
  192. return 1;
  193. }
  194. /*
  195. 获取vdd
  196. @api mlx90640.get_vdd()
  197. @return number vdd
  198. */
  199. static int l_mlx90640_get_vdd(lua_State *L) {
  200. lua_pushnumber(L, vdd);
  201. return 1;
  202. }
  203. // 实验性插值
  204. #if defined(AIR101) || defined(AIR103)
  205. #include "csky_math.h"
  206. // src[32][24]
  207. // dst[160][120] , 即放大25倍
  208. int luat_interpolation(float *src, float *dst) {
  209. csky_bilinear_interp_instance_f32 fif;
  210. fif.pData = src;
  211. fif.numRows = 24;
  212. fif.numCols = 32;
  213. for (size_t i = 0; i < 120; i++)
  214. {
  215. for (size_t j = 0; j < 160; j++)
  216. {
  217. dst[i*160 + j] = csky_bilinear_interp_f32(&fif, (160.0 -j)/160*32, (120 - i)/120*24);
  218. }
  219. }
  220. return 0;
  221. }
  222. #endif
  223. /*
  224. 绘制到lcd
  225. @api mlx90640.draw2lcd(x, y, w, h)
  226. @int 左上角x坐标
  227. @int 左上角y坐标
  228. @int 显示尺寸的宽,需要是32的倍数, 若大于32会进行插值
  229. @int 显示尺寸的高,需要是24的倍数, 若大于24会进行插值
  230. @return bool 成功返回true,否则返回false
  231. */
  232. static int l_mlx90640_draw2lcd(lua_State *L) {
  233. luat_color_t line[32];
  234. // TODO 还得插值
  235. if (lcd_conf == NULL) {
  236. LLOGW("init lcd first!!!");
  237. return 0;
  238. }
  239. uint16_t lcd_x = luaL_optinteger(L, 1 , 0);
  240. uint16_t lcd_y = luaL_optinteger(L, 2 , 0);
  241. uint16_t lcd_w = luaL_optinteger(L, 3 , 32);
  242. uint16_t lcd_h = luaL_optinteger(L, 4 , 24);
  243. if (lcd_w%32||lcd_h%24){
  244. LLOGW("lcd_w or lcd_h set error !!!");
  245. return 0;
  246. }
  247. // #if defined(AIR101) || defined(AIR103)
  248. #if 0
  249. float *dst = lua_newuserdata(L, 160*120*sizeof(float));
  250. // 插值, 试试air101的dsp函数
  251. luat_interpolation(mlx90640To, dst);
  252. for (size_t y = 0; y < 120; y++)
  253. {
  254. for (size_t x = 0; x < 160; x++)
  255. {
  256. int i = y*120 + x;
  257. line[x] = camColors[tempto255(dst[i])];
  258. }
  259. luat_lcd_draw(lcd_conf, 0, y, 159, y, line);
  260. }
  261. #else
  262. for (size_t y = 0; y < 768/32; y++)
  263. {
  264. for (size_t x = 0; x < 32; x++)
  265. {
  266. int i = y*32 + x;
  267. line[x] = camColors[tempto255(mlx90640To[i])];
  268. }
  269. luat_lcd_draw(lcd_conf, 0, y, 31, y, line);
  270. }
  271. #endif
  272. return 0;
  273. }
  274. #include "rotable.h"
  275. static const rotable_Reg reg_mlx90640[] =
  276. {
  277. {"init", l_mlx90640_init, 0},
  278. {"feed", l_mlx90640_feed, 0},
  279. {"raw_data", l_mlx90640_raw_data, 0},
  280. {"raw_point", l_mlx90640_raw_point, 0},
  281. {"draw2lcd", l_mlx90640_draw2lcd, 0},
  282. {"get_temp", l_mlx90640_get_temp, 0},
  283. {"get_vdd", l_mlx90640_get_vdd, 0},
  284. { "FPS1HZ", NULL, FPS1HZ},
  285. { "FPS2HZ", NULL, FPS2HZ},
  286. { "FPS4HZ", NULL, FPS4HZ},
  287. { "FPS8HZ", NULL, FPS8HZ},
  288. { "FPS16HZ", NULL, FPS16HZ},
  289. { "FPS32HZ", NULL, FPS32HZ},
  290. { "FPS64HZ", NULL, FPS64HZ},
  291. { NULL, NULL , 0}
  292. };
  293. LUAMOD_API int luaopen_mlx90640( lua_State *L ) {
  294. luat_newlib(L, reg_mlx90640);
  295. return 1;
  296. }