×

Raspberry Pi Pico和WizFi360无线热成像仪

消耗积分:0 | 格式:zip | 大小:0.08 MB | 2023-02-01

王秀兰

分享资料个

描述

1.在Arduino IDE中安装库文件和板卡支持

为 Arduino IDE 添加“WIZnet WizFi360-EVB-PICO”支持

打开 Arduino IDE 并转到“文件”->“首选项”。

在弹出的对话框中,在“Additional Boards Manager URLs”字段中输入以下 URL:

https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

pYYBAGPXbwGAN8DlAAC1qv4tDf4781.png
 

通过“Board Manager”搜索“WizFi360”并安装 Board 支持

poYBAGPXbwOALkWuAADNRYL8VNQ245.png
 

“工具->开发板:”***”-> Raspberry Pi RP2040 Boards(2.6.1)”选择“WIZnet WizFi360-EVB-PICO”。

poYBAGPXbweAZ4LLAAK8pEcuKo0132.png
 

添加“GFX Library for rduino”,该库支持圆屏GC9A01。

pYYBAGPXbwuAVheYAACvMlk2KbQ071.png
 

2. Thermography Carmera和协处理器初始化和数据处理

poYBAGPXbw2ATx-OAACUmNpVFks116.png
 

热成像相机和协处理器接口和功能引脚初始化

#include                      // i2c library (standard Arduino library)                     
#include                       // SPI library (standard Arduino library)

const int THERMAL_DATA_READY_PIN   = 21;  //Pin connected to DATA_READY
const int THERMAL_CS_PIN           = 17;  //Pin Connected to CS
const int THERMAL_nRESET_PIN       = 20;  //pin Connected to nRESET 
const int THERMAL_ADDR_PIN         = 3;   //The Thermography i2c address
uint16_t  THERMAL_Addr = 0x40;                 
/*i2c address for Thermography (0x40 if Thermography_ADDR_PIN =0 or 0x41 if Thermography_ADDR_PIN = 1 )*/

热像注册地址

// Now the addresses for each of the registers within the device
const uint16_t THERMAL_FRAME_MODE      = 0xB1; // Frame Mode register address
const uint16_t THERMAL_SW_VERSION      = 0xB2; // swVersion register address
const uint16_t THERMAL_BUILD           = 0xB3; // swVersion build register address
const uint16_t THERMAL_FRAME_RATE      = 0xB4; // Frame Rate register addres 
const uint16_t THERMAL_POWER_DOWN      = 0xB5; // Power down register address 
const uint16_t THERMAL_STATUS_ERROR    = 0xB6; // Status Error register address
const uint16_t THERMAL_SENSOR_TYPE     = 0xBA; // SenXor type register address  
const uint16_t THERMAL_EMISSIVITY      = 0xCA; // emissivity register address
const uint16_t THERMAL_FILTER_CONTROL  = 0xD0; // filter control (bits 0-2 R_W)
const uint16_t THERMAL_FILTER_SETTINGS_LSB = 0xD1; // filter setting LSB (0x32 default, 0x80 rec)
const uint16_t THERMAL_FILTER_SETTINGS_MSB = 0xD2; // filter setting MSB (0x00 default)
const uint16_t THERMAL_ROLLING_AVG_SETTING = 0xD3; // rolling average setting (0x04 default)

I2C读写Thermography寄存器地址

// =========================================================================
//  Function to write i2c register
// =========================================================================
void WriteI2c(int RegAddr, unsigned char RegData)
{
  Wire.beginTransmission(Addr);       // Begin transmission to the Sensor
  Wire.write (RegAddr);                     // Set the address for the requested register
  Wire.write (RegData);                     // Write the data for that register
  Wire.endTransmission(true);               // Release i2c bus - so others can use it (can have multiple slaves & masters connected
  return;
}
 
// =========================================================================
//  Function to read i2c register
// =========================================================================
unsigned char ReadI2c(int RegAddr)
{
  unsigned char Result;
  Wire.beginTransmission(Addr);       // Begin transmission to the Sensor
  Wire.write (RegAddr);                     // Set the address for the requested register
  Wire.endTransmission();                   // End tranmission We should have set the address of the register
  Wire.requestFrom(Addr, 1);          // Tell slave we need to read 1 byte from the current register
  Result = Wire.read();                     // read that Serial Number byte (register will auto increment)
  Wire.endTransmission(true);               // Release i2c bus - so others can use it 
  return Result;
}

在“void setup()”中通过I2C BUS获取和设置参数

THERMAL_FILTER_CONTROL :将此位设置为 1 指示在连续捕获模式下运行,从而连续从相机模块获取数据并更新可通过 SPI 接口访问的读出缓冲区。将此位重置为 0 指示停止连续数据采集。这也会将 DATA_READY 引脚和 STATUS 寄存器的相应位 4 重置为 0。

THERMAL_FRAME_RATE :这些位的值确定主机控制器可以通过 SPI 接口从输出帧缓冲区读取热数据帧的速率。该值必须是一个无符号整数,表示所连接相机模块的最大帧速率 FPS_MAX 的帧速率除数:FPS = FPS_MAX / FRAME_RATE_DIVIDER。例外情况是 FRAME_RATE = 0,这会产生 FPS_MAX = 24FPS。

THERMAL_FRAME_MODE :将此位设置为 1 会消除通过 SPI 接口传输的热数据帧中的标头。将此位重置为 0 包括热数据帧中的 HEADER,

Wire.begin();                               // Initialise and configure the i2C//
  Wire.setClock(400000);                      // use 400 kHz I2C//
  
  pinMode(THERMAL_DATA_READY_PIN, INPUT_PULLUP);
  pinMode (nRESET_PIN, OUTPUT);               
  digitalWrite (nRESET_PIN, LOW);              // First put the THERMAL in reset - THIS NEEDS TO BE TIMED//
  pinMode (THERMAL_ADDR_PIN, OUTPUT);          
  digitalWrite (THERMAL_ADDR_PIN, LOW);        // Set the THERMAL i2c addrees LOW = 0x40 HIGH = 0x41//
  pinMode(THERMAL_CS_PIN, OUTPUT);             // Configure CS pin for THERMAL
  digitalWrite (THERMAL_CS_PIN, HIGH);         
  delay(200);                      // Wait 0.2 seconds //
  digitalWrite (nRESET_PIN, HIGH); // remove reset to the THERMAL - allow it to boot//
  delay(1000);                     // Wait 1 seconds for the THERMAL to boot 
  SPI.begin();                     // Initialise the SPI 

  // =========================================================================
  //  Read all the individual i2c registers
  //  Uses ReadI2c() routine
  // =========================================================================
  frameMode = ReadI2c(THERMAL_FRAME_MODE);     
  swVersion = ReadI2c(THERMAL_SW_VERSION);     
  build     = ReadI2c(THERMAL_BUILD);             
  frameRate = ReadI2c(THERMAL_FRAME_RATE);     
  powerDown = ReadI2c(THERMAL_POWER_DOWN);     
  statusError = ReadI2c(THERMAL_STATUS_ERROR); 
  senxorType = ReadI2c(THERMAL_SENSOR_TYPE);   
  emissivity = ReadI2c(THERMAL_EMISSIVITY); 

  // =========================================================================
  // Write any registers required beofre starting exitig setup
  // and starting Data aquisition
  // =========================================================================
  WriteI2c(THERMAL_FILTER_SETTINGS_LSB, 0x80);
  WriteI2c(THERMAL_FILTER_SETTINGS_MSB, 0x00);  
  WriteI2c(THERMAL_FILTER_CONTROL, 0x02);  
  delay(100);         // currently required after modifying filter values//
  WriteI2c(THERMAL_FRAME_RATE, 0x3);           // Write the Frame_rate register 0x1 = as fast as possible (24FPS)//
  WriteI2c(THERMAL_FRAME_MODE, 0x3);           // Write the Frame_mode register 0x3 = capture continuous with header)//

在“void loop()”中通过SPI BUS获取camera Header和data

SPI 时钟设置为 40MHz,来自传感器的数据相对于屏幕翻转,因此我们必须向后绘制行。

void Get_sensor_data()
{
  dataReady = digitalRead(THERMAL_DATA_READY_PIN);     
  // Read the state on THERMAL_DATA_READY_PIN line
  if ( digitalRead (THERMAL_DATA_READY_PIN) == HIGH) { 
  // Wait for THERMAL_DATA_READY_PIN to assert
  Serial.println ("Data ready!!");
  //THERMAL_DATA_READY_PIN has been asserted so data is now available on SPI bus
  SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));  
  digitalWrite (THERMAL_CS_PIN, LOW);                                
  for (int i = 0; i < THERMAL_WIDTH; i++) 
  {                          
    header_buffer[i] = SPI.transfer16(0x0);                          
    // write data to the header buffer
  }
  for (int j = 0; j < THERMAL_HEIGHT; j++) 
  {         
    for (int i = 0; i < THERMAL_WIDTH; i++) 
    {        
       THERMAL_SpiData = SPI.transfer16(0x0);         
       // The data from the sensor is flipped with respect to the screen so we have to draw the rows backwards
       draw_buffer[((THERMAL_WIDTH - 1) - i) + (j * THERMAL_WIDTH)] = THERMAL_SpiData;
      }        // (finished a row)
    }          
    // We have now read the entire frame of data
    digitalWrite (THERMAL_CS_PIN, HIGH);                                
    SPI.endTransaction();
  }
}

3. 在屏幕上显示热数据(GC9A01)。

#include 
Arduino_GFX *tft = create_default_Arduino_GFX();

在“libraries\GFX_Library_for_Arduino\src\Arduino_GFX_Library.h”中定义 GC9A01 使用的引脚

pYYBAGPXbw-AQHmgAACoDGzo2-o317.png
 
#elif defined(ARDUINO_RASPBERRY_PI_PICO)||defined(ARDUINO_WIZNET_WIZFI360_EVB_PICO)||defined(ARDUINO_WIZNET_5100S_EVB_PICO)
#define DF_GFX_SCK 26
#define DF_GFX_MOSI 27
#define DF_GFX_MISO GFX_NOT_DEFINED
#define DF_GFX_CS 25
#define DF_GFX_DC 23
#define DF_GFX_RST 28
#define DF_GFX_BL 22

在“void setup()”中初始化屏幕并打开屏幕的背光

tft->begin();
  tft->fillScreen(BLACK);
  pinMode(22, OUTPUT); 
  digitalWrite(22, HIGH);
  Display_Begin();

将热数据的每一个像素点转化为颜色(RGB565),通过根据minmax中温度值的相对位置(thermal Header中识别范围内的温度差)在colormap中找到对应的颜色信息。

通过“DISPLAY_buffer”函数显示所有温度颜色信息。由于摄像头分辨率只有80*62,而GC9A01的屏幕分辨率为240*240,所以每个温度点扩展为3*3显示。

// =========================================================================
    // Colour conversion - one pixel at a time
    // The draw_buffer starts as 16 bit sensor data
    // At the end it is 16 bit RGB (5-6-5)
    // =========================================================================
    for (int j = 0; j < THERMAL_HEIGHT; j++) {                              
      for (int i = 0; i < THERMAL_WIDTH; i++) {                            
        pixelVal = draw_buffer[(i) + (j * THERMAL_WIDTH)];                  
        if (pixelVal <= THERMAL_MinVal) {
          lutIndex = 0;                                                     
        }
        else if (pixelVal >= THERMAL_MaxVal) {
          lutIndex = 255;                                                   
        }
        else {
          lutIndex = map (pixelVal, THERMAL_MinVal, THERMAL_MaxVal , 0, 0xff); 
        }
        for(int m = 0; m<3; m++)
        {
            DISPLAY_buffer[(i*3)+m + (j*3) * DISPLAY_WIDTH]= palette[lutIndex];
            DISPLAY_buffer[(i*3)+m + ((j*3)+1) * DISPLAY_WIDTH]= palette[lutIndex];
            DISPLAY_buffer[(i*3)+m + ((j*3)+2) * DISPLAY_WIDTH]= palette[lutIndex];
        }
      }                                                                     
    }

然后我们得到了这个项目中的第一张热水热成像图。

poYBAGPXbxmAPmfMABBHpF97GY8063.jpg
 

4. WizFi360通过WiFi与热查看器软件通信。

Thermal Viewer 软件作为 TCP 客户端使用端口 5051。

#include "WizFi360.h"

// Wi-Fi info //
char ssid[] = "WIZNET_test";       // your network SSID (name)//
char pass[] = "********";          // your network password//
int status = WL_IDLE_STATUS;       // the Wifi radio's status//
WiFiServer server(5051);
pYYBAGPXbxuAKTdbAAB-Z7Nxexw001.png
 

初始化WizFi360模块的串口,修改波特率为2000000bps(wizfi360的最大波特率)。

第一次初始化为115200,然后在WiZfi360库的初始化部分加入设置波特率(2000000),第二次改为2000000bps。

// initialize serial port for WizFi360 module//
#if defined(ARDUINO_WIZNET_WIZFI360_EVB_PICO)
  Serial2.begin(2000000);
  WiFi.init(&Serial2);
  Serial2.begin(2000000); 
#endif

在“void setup()”中查看wifi的wizfi360 Link状态

// check for the presence of the shield//
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue//
    while (true);
  }
  // attempt to connect to WiFi network//
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network//
    status = WiFi.begin(ssid, pass);
  }
  Serial.println("You're connected to the network");

热查看器软件连接到此服务器(WizFi360)时,RP2040 读取热数据“Get_sensor_data()”并将数据发布到 TCP 客户端(热查看器软件)。

先传热像头,再传热像素数据(80*62 16bits)。

WiFiClient client;
if (client) {
      Serial.println("Connected");
      socket_status = client.connected();
      socket_status_cnt = 0;
      delay(1000);
      uint8_t i;
      while (socket_status&&!buttonState)
      {                      
          switch(socket_send_status)
          {
            case 0:
            {
              Get_sensor_data();
              socket_send_result = client.write((uint8_t*)header_buffer,160);
              socket_send_status = 1;
            }break; 
            case 1:
            {
              if(socket_send_result == 160 ){
                  socket_sendnum = 9920; //80*62*2//
                  socket_send_status = 2;
                  i=0;
              }else if(socket_send_result == 0){
                  socket_send_status = 4;
              }
            }break; 
            case 2:
            {
              if(socket_sendnum >=2048)
              {
                socket_send_result = client.write((uint8_t*)(draw_buffer+(i*1024)),2048);
              }
              else
              {
                socket_send_result = client.write((uint8_t*)(draw_buffer+(i*1024)),socket_sendnum);
              }
              socket_send_status = 3;
            }break; 
            case 3:
            { 
               if(socket_sendnum >= 2048)
               {  
                  if(socket_send_result == 2048)
                  {
                    socket_sendnum -= 2048;
                    i++;
                    socket_send_status = 2;
                  }else if(socket_send_result == 0){                    
                    socket_send_status = 4;
                  }
               }
               else
               {
                  if(socket_send_result == socket_sendnum)
                  {
                    socket_sendnum = 0;
                    socket_send_status = 4;
                   }
               }                
            }break;
            case 4:
            {   
                socket_status_cnt ++;
                if(socket_status_cnt == 20)
                {
                  socket_status = client.connected();
                  if(socket_status == 0)
                  {
                    client.stop();
                  }
                  socket_status_cnt = 0;
                }
                socket_send_status = 0;
            }break; 
          } 
     }   
    }

Thermal viewer 软件接收像素数据,它可以显示和显示这些像素的最高温度。

poYBAGPXbx6ARMqnAACukestJ34456.png
 

硬件如下图

poYBAGPXby6AJV0VAA8iejPWgp4025.jpg
 

结束。

注意:由于签署了保密协议,一些细节不能公开。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.lene-v.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'Raspberry Pi Pico和WizFi360无线热成像仪',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.lene-v.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);