| 作为一个创客,其中最大的一件好事就是能够制造属于自己的工具。在前几篇文章中,我们介绍了从电压表到电池测试仪等几种电子工具的开发。今天,在本篇文章中,我们将介绍danielrp @ www.instructables.com制造的一款毫欧表工具。 
  
 毫欧表是一种用于确定小型电阻、PCB迹线、电机线圈、电感线圈和变压器线圈的电阻或计算诸如电线长度之类的设备。它提供的分辨率并不是常规的万用表内置的,因此可以轻松获得毫欧范围内的精确读数。 互联网上有很多自制毫欧表的教程,但在本文中,我们将主要介绍Daniel制作的毫欧表。它基于精密电流吸收器和由Arduino Nano控制的高分辨率ADC。电流吸收器基于LT3092精密电流源/吸收器,该电流源/吸收器使用电阻器和晶体管网络设置为吸收器。对于ADC,使用了高分辨率的MCP3422A0。仅使用ADC的一个通道,并且将其差分连接到被测电阻“ S + S-”。 MCP3422配置为18位,但由于S +总是大于S-,因此有效分辨率为17位。 为减少测试引线电阻对测量的影响,设备使用开尔文连接器作为引线连接被测电阻到测量点。 
  该设备的测量范围包括: ●    分辨率0.1mOhm:0.1mOhm至12.9999欧姆。 ●    分辨率1m0:1mOhm至129.999欧姆。 ●    分辨率10m:10mOhm至1299.99欧姆。 用户可以使用设备上两个按钮的其中一个在上述测量范围之间进行选择。通过1602 LCD显示屏向用户提供有关选择和仪表读数的视觉反馈,整个项目都装在橙色的Hammond 1590B铝制盒子中,方便使用和展示。 
 所需的组件 使用的一些关键组件包括: ●    Arduino Nano开发板 ●    1602 LCD显示屏 ●    ULN2003A ●    LT3092EST ●    MCP3422A0 ●    Kelvin连接器 
 原理图 由于项目的复杂性,在试验板上进行实施不仅耗时,而且会使项目容易出错。为防止这种情况,该项目在由Eagle设计的PCB上实施。下面提供了显示组件如何在PCB上连接的示意图: 
  根据原理图开发的PCB如下图所示: 
  下图显示了制造后的实际电路板。 
  
 外壳和组件 DanielrP为该项目开发了一种外壳,并采用PCB方法使该项目具有代表性和实用性,并使用Inkscape设计了对铝制外壳盒的修改。请按照以下步骤制作外壳。 
  1.    用油漆胶带盖住铝盒的顶部。然后切割前盖的模板并将其粘贴到铝盒的胶带上。 2.    接下来,标记孔和钻孔的位置,以使钢丝锯或顶盖锯片进入内部切口 3.    剪切所有形状。 
  4.    修剪文件,然后取下模具和胶带。 
  5.    使用双面胶带或热胶将按钮和屏幕一起安装。 6.    盖好盖子后,在盒子上标记出(螺钉)孔的位置。中心打孔。 
  7.    在安装完所有组件之后,盖子应如下图所示。在将外壳耦合在一起之前,先将PCB的某些组件安装到位可能是明智的。由于用于PCB的大多数组件都是SMT类型的,因此将它们安装到PCB上将需要使用热风枪或使用常规烙铁以及细尖镊子、一些焊芯和0.02英寸焊料。下图提供了一些组件在PCB上的放置位置。 
  由于开尔文(Kelvin)连接器和开关仅在外壳的外部有用,因此它们将通过跨接线连接到PCB,如上图所示。在准备好PCB和包装盒之后,将PCB安装在包装盒中并连接按钮和开尔文连接器。 
  
 为了方便在完成后将代码上传到设置中,您可以在Nano的USB端口附近打开一个小孔,以便可以轻松地将USB线连接到此。完成后,我们现在就可以编写该项目的代码。 
 代码 该项目代码背后的算法非常复杂。我们通过驱动连接到ULN2003的设置引脚来设置项目的分辨率。然后考虑分辨率和模式(由按钮的状态决定),并读取MCP3422以获取电阻值并将其显示在LCD上。由于草图已经很复杂了,因此稍微降低了复杂性,使用了许多库,包括: Wire.h库、LiquidCrystal_I2C库和EEPROM库。Wire库用于Arduino与项目的两个I2C组件LCD和MCP3422之间的I2C通信。另一方面,LiquidCrystal_I2C库有助于与LCD进行接口连接,而EEPROM库用于访问Arduino上的EEPROM以存储有关模式和仪表刻度的信息。 Arduino IDE已预装了 Wire和EEPROM库,LiquidCrystal_I2C库可以通过附加的链接安装,也可以通过Arduino库管理器安装。我们将快速讲解并解释一些Sketch /片段。代码相当庞大,可能难以覆盖全部内容,但幸运的是,Daniel在每一行代码上都做了注释,因此应该很容易理解。 接下来,我们指定显示的尺寸并为分辨率创建宏。基本上,这将设置与分辨率有关的引脚状态。 复制代码//LCD display parameters
#define N_ROWS 2u
#define N_COLS 16u
//General parameters
#define DEBOUNCEHARDNESS 10u 
//Macros
//Scale
//0.0001ohm - 156mA
#define SCALE_01    digitalWrite(10, LOW); \
  digitalWrite(11, HIGH); \
  digitalWrite(12, HIGH); \
  pinMode(10, OUTPUT); \
  pinMode(11, OUTPUT); \
  pinMode(12, OUTPUT)
//0.001ohm - 15.6mA
#define SCALE_1    digitalWrite(11, LOW); \
  digitalWrite(10, HIGH); \
  digitalWrite(12, HIGH); \
  pinMode(10, OUTPUT); \
  pinMode(11, OUTPUT); \
  pinMode(12, OUTPUT)
//0.01ohm - 1.56mA
#define SCALE_10    digitalWrite(12, LOW); \
  digitalWrite(11, HIGH); \
  digitalWrite(10, HIGH); \
  pinMode(10, OUTPUT); \
  pinMode(11, OUTPUT); \
  pinMode(12, OUTPUT)
 接下来,为Arduino内置led创建宏,该宏将用于提供有关状态的视觉反馈。我们在此之后配置了按钮。一个打开或关闭它,另一个使它进入和退出校准模式。接下来,我们声明一些将用于MCP3422相关数据的变量。 我们指定变量来保存通道、从站地址和其他内容。 复制代码//MCP3422
#define MCP3422_CH1 0x00
#define MCP3422_CH2 0x01
#define MCP3422_SR 0x03 //3.75 SPS (18bit)
#define MCP3422_GAIN 0x00 //x1
#define MCP3422_CR_STARTONESHOT 0x80 // /RDY bit = 1, /O/C bit = 0
#define MCP3422_CR_READY 0x80        // /RDY bit mask
#define MCP3422_NCH 2u    //Number of channels available
#define MCP3422_ADD 0x68  //Slave address
 接下来,我们创建将显示的消息字符串。 复制代码//Messages
const char strHOLD[5] = "HOLD";
const char strRUN[5] = " RUN";
const char strScale0m1[6] = "(0m1)";
const char strScale1m0[6] = "(1m0)";
const char strScale10m[6] = "(10m)";
const char strScaleAuto[7] = "(Auto)";
const char strFullScale[9] = "--------";
 然后是存储不同类型数据的EEPROM地址规范。 复制代码//EEPROM Addresses
#define EE_U8MODE       0x0000
#define EE_U8SCALERUN   0x0002
#define EE_U8SCALEHOLD  0x0004
#define EE_U32MEASHOLD  0x0006
 接下来,我们创建某种类型的变量。 复制代码//MCP3422 machine states
enum eMCP3422ReadStates_t
{
  eMS_WaitCurrent = 0,
  eMS_WaitVoltage = 1
};
 创建LiquidCrystal_I2C库的实例,并创建其他一些常规变量。 复制代码LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Addr, En, Rw, Rs, d4, d5, d6, d7, backlighpin, polarity (As descrived in the ebay link but with 0x3F address instead of 0x20)
//General variables
bool bIsHoldMode = false;
uint8_t u8HoldScale = 0;
uint32_t u32HoldValue = 0;          
uint8_t u8CurrentScale = 0;         //Current Scale
uint32_t u32CurrentMeasurement = 0;       //Last conversion value from MCP3422
bool bMCP3422ValIsPositive = true;  //Last conversion sign, in this circuit it's always positive
bool bSCALEPressed = false;      //State of On push button
bool bLastSCALEPressed = false;  //Last state of On push button, used for flange detection
bool bCALPressed = false;     //State of Off push button
bool bLastCALPressed = false; //Last state of Off push button, used for flange detection
uint8_t u8SCALEDebounce = 0;     //Debounce counter for On push button
uint8_t u8CALDebounce = 0;    //Debounce counter for Off push button
 接下来是void setup()函数。我们首先检查当前的分辨率,然后将分辨率设置为该值。 复制代码void setup()
{
  if(!eeReadU8(EE_U8SCALERUN , u8CurrentScale))
  {
    eeStoreU8(EE_U8SCALERUN, 0);
    u8CurrentScale = 0;
  }
  changeScale(u8CurrentScale);
 接下来,我们调用setupDisplay()函数来初始化LCD并显示初始界面初始屏幕。 
 接下来设置I2C通讯速度,将LCD的背光调高,然后初始化串口通讯,以便将串口监视器用于调试目的。 复制代码  Wire.setClock(400000);  //Speed for both display and MCP3422
  lcd.setBacklight(HIGH);
  Serial.begin(9600);
}
 接下来是void loop()函数。该函数从一行代码开始,以获得有关按钮状态、模式和分辨率等的更新。 复制代码void loop()
{
  updateInputs(); //Read  pushbuttons, update modes and change scale
 其后是一条if语句,该语句检查设备是否处于保持模式。如果设备处于保持模式,则获得刻度和测量值,但如果不是(运行模式),则使用“ RUN”文本更新bufferA,读取RUN刻度,在当前接收器中设置RUN刻度,检查是否有数据可从MCP3422获得,并在通道上开始新的数据转换。 复制代码if(true == eeIsHoldMode())
  {//Hold Mode
    writeString(1u, 12u, strHOLD);                    //Update bufferA with the "HOLD" text  
    eeReadU8(EE_U8SCALEHOLD, u8CurrentScale);         //Read the HOLD scale
    eeReadU32(EE_U32MEASHOLD, u32CurrentMeasurement); //Read the HOLD measurement
  }
  else
  {//Run Mode
    writeString(1u, 12u, strRUN);                     //Update bufferA with the "RUN" text
    eeReadU8(EE_U8SCALERUN, u8CurrentScale);          //Read the RUN scale
    changeScale(u8CurrentScale);                      //Set the RUN scale in the current sink
    //Read the ADC if a new measurement is available. 
    if(MCP3422_IsDataAndRead(u32CurrentMeasurement, bMCP3422ValIsPositive))
    {//New conversion available
      if(false == bMCP3422ValIsPositive)
      {
        u32CurrentMeasurement = 0;
      }
      MCP3422_StartConversion(MCP3422_CH1);   //Restart conversion
    } 
  }
 最后,显示缓冲区被更新,并且使用loop()的updateDisplay()函数在LCD上显示该值。 复制代码  updateDisplayBuffer();                              //Update the rest of BufferA
  updateDisplay();                                    //Write the necessary chars in the display
}
 上面讨论的void loop()和void setup()包含很少的代码行,因为大部分工作是在其他几个函数中完成的。从在MCP3422 ADC上处理数据转换的函数到用于设置比例尺的函数到用于更新显示的函数,所有这些函数都起着重要的作用,尽管有点难以一一遍解。由于它将使本教程体积很大,但Danielrp会正确注释实现这些代码的代码,因此应该易于遵循。完整的草图随附在以下下载部分的zip文件中。 
 演示 完成代码并安装好硬件后,将设备连接到计算机并将代码上传到计算机上,一段时间后,您将看到如下图所示的显示屏。 
  在将毫欧电阻器连接到导线上时,您应该看到该电阻器的值显示。 
  以上就是制作的毫欧表。本文使用的代码如下:
 Milliohmeter.zip
(384.71 KB, 下载次数: 31) |