2721浏览
查看: 2721|回复: 0

[ESP8266/ESP32] 利用Beetle ESP32-C3+ADS1115自制数字电压表

[复制链接]
本帖最后由 glwz007 于 2023-5-30 22:20 编辑


    前言
感谢DFRobot提供活动的平台和提供硬件支持,祝DFRobot越办越好,人气越来越旺,祝各位创客老师们学习快乐,作品频出!
下面是活动链接:
一、项目由来

        我是一个物理老师,也是一个喜欢折腾实验的老师,在信息化数字化的浪潮下,一直有一个想法,就是将传统的物理实验信息化、数字化,在这方面我一直处于学习和不断的制作中。
        在中学物理实验中,电学实验也是一个重点,而电学实验,离不开电学三个基本物理量电压、电流、电阻的测量,这次先从电压的测量工具电压表入手进行学习。
        二、对电压表的对比分析
        1. 传统的电压表
        中学物理实验室传统的电压表都是电磁式电表,如下图所示:

      它是基于灵敏电流计G改装得到,下图是灵敏电流计G(俗称表头)的构造图,它的原理是利用通电线圈在磁场中受力转动,通过电流计的电流越大,与线圈相连接的指针转过的角度越大。

        通过串并联电路,可以将表头改装为不同量程的电压表和电流表。
这种传统的电流表,属于模拟式电压表,优点是结构简单,价格便宜,测量频率范围较宽;缺点是精度、分辨力较低,不便于与计算机组成自动测试系统。
        2.数字式电压表
        数字是电压表用A/D转换器和数字显示器代替了模拟电压表的测量显示部分,优缺点基本上正好与模拟式电压表相反。
        在中学实验室,常用的数字式电表,大多是商品化的DIS系统,DIS( Digital Information System) 实验技术,又称“数字化信息系统”,是由“传感器、数据采集器、实验软件包(教材专用软件、通用扩展软件)、计算机”等构成的新型实验系统。该系统成功地克服了传统物理实验仪器的诸多弊端,有力地支持了信息技术与物理教学的全面整合。

        但是这种系统价格相对比较高,于是我萌生了自制数字电压表的想法,下面是初步的实验过程。
         三、基于Beetle ESP32-C3 + ADS1115的数字电压表
         前段时间,DFRobot论坛开展了Beetle ESP32-C3的免费试用活动,于是我申请了两块作为实验用主控板,在此向DFRobot表示衷心的感谢!
        (一)主要硬件
       本次使用的主要元件如下:
       1. 主控板:Beetle ESP32-C3,详细资料不再重复,可以看官网产品资料库信息。https://wiki.dfrobot.com.cn/_SKU_DFR0868_Beetle_ESP32_C3

       2.显示屏采用12864OLED,OLED 屏幕作为一种新型的显示技术,其自身可以发光,亮度,对比度高,功耗低,在当下备受追捧。而在我们正常的显示调整参数过程中,我们越来越多的使用这种屏幕。我们使用的一般是分辨率为 128x64 ,屏幕尺寸为 0.96 寸。

       3.AD转换器采用ADS1115,ADS1115是一种精密16位模数转换器(ADC),能将模拟信号转换为数字信号。它采用I2C接口进行通信,并具有四个单端或两个差分输入通道。由于其高精度和低功耗特性,ADS1115广泛用于温度、压力、湿度等传感器的数据采集与处理。

       (二)编程软件
       在以往的制作中,我大多数情况下采用图形化编程模式,这次转换使用代码编程。采用MicroPython,编辑器为Thonny。Thonny 是一个面向初学者的 Python IDE
Thonny 由爱沙尼亚的 Tartu 大学开发,它采用了不同的方法,因为它的调试器是专为学习和教学编程而设计的。

       (三)制作过程
       1. 硬件搭建
       将Beetle ESP32-C3、12864OLED屏、ADS1115通过连接线连接到面包板上,为了改变测量电压,还接了一个1KΩ的电位器,将电位器可变电压提供给自制电压表和数字万用表测量作为对比。连接示意图如下:

       2. 软件编程
       (1)首先要给Beetle ESP32-C3刷固件,刷固件的烧录工具、固件、方法采用官方资料中方法,参照如下链接:https://wiki.dfrobot.com.cn/_SKU_DFR0868_Beetle_ESP32_C3#target_24
       (2)编程环境配置
刷好固件后,启动Thonny,选择“运行”菜单,进行如下图配置:

       点击“视图”菜单中“文件”选项,如果前面配置正常,将会显示主控板中文件,一开始应该是空的。
       (3)新建”ssd1306.py”,复制下面代码,保存到“MicroPython设备”作为12864OLED显示屏的库。


  1. #MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit
  2. import time
  3. import framebuf
  4. # register definitions
  5. SET_CONTRAST        = const(0x81)
  6. SET_ENTIRE_ON       = const(0xa4)
  7. SET_NORM_INV        = const(0xa6)
  8. SET_DISP            = const(0xae)
  9. SET_MEM_ADDR        = const(0x20)
  10. SET_COL_ADDR        = const(0x21)
  11. SET_PAGE_ADDR       = const(0x22)
  12. SET_DISP_START_LINE = const(0x40)
  13. SET_SEG_REMAP       = const(0xa0)
  14. SET_MUX_RATIO       = const(0xa8)
  15. SET_COM_OUT_DIR     = const(0xc0)
  16. SET_DISP_OFFSET     = const(0xd3)
  17. SET_COM_PIN_CFG     = const(0xda)
  18. SET_DISP_CLK_DIV    = const(0xd5)
  19. SET_PRECHARGE       = const(0xd9)
  20. SET_VCOM_DESEL      = const(0xdb)
  21. SET_CHARGE_PUMP     = const(0x8d)
  22. class SSD1306:
  23.     def __init__(self, width, height, external_vcc):
  24.         self.width = width
  25.         self.height = height
  26.         self.external_vcc = external_vcc
  27.         self.pages = self.height // 8
  28.         # Note the subclass must initialize self.framebuf to a framebuffer.
  29.         # This is necessary because the underlying data buffer is different
  30.         # between I2C and SPI implementations (I2C needs an extra byte).
  31.         self.poweron()
  32.         self.init_display()
  33.     def init_display(self):
  34.         for cmd in (
  35.             SET_DISP | 0x00, # off
  36.             # address setting
  37.             SET_MEM_ADDR, 0x00, # horizontal
  38.             # resolution and layout
  39.             SET_DISP_START_LINE | 0x00,
  40.             SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
  41.             SET_MUX_RATIO, self.height - 1,
  42.             SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
  43.             SET_DISP_OFFSET, 0x00,
  44.             SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
  45.             # timing and driving scheme
  46.             SET_DISP_CLK_DIV, 0x80,
  47.             SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
  48.             SET_VCOM_DESEL, 0x30, # 0.83*Vcc
  49.             # display
  50.             SET_CONTRAST, 0xff, # maximum
  51.             SET_ENTIRE_ON, # output follows RAM contents
  52.             SET_NORM_INV, # not inverted
  53.             # charge pump
  54.             SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
  55.             SET_DISP | 0x01): # on
  56.             self.write_cmd(cmd)
  57.         self.fill(0)
  58.         self.show()
  59.     def poweroff(self):
  60.         self.write_cmd(SET_DISP | 0x00)
  61.     def contrast(self, contrast):
  62.         self.write_cmd(SET_CONTRAST)
  63.         self.write_cmd(contrast)
  64.     def invert(self, invert):
  65.         self.write_cmd(SET_NORM_INV | (invert & 1))
  66.     def show(self):
  67.         x0 = 0
  68.         x1 = self.width - 1
  69.         if self.width == 64:
  70.             # displays with width of 64 pixels are shifted by 32
  71.             x0 += 32
  72.             x1 += 32
  73.         self.write_cmd(SET_COL_ADDR)
  74.         self.write_cmd(x0)
  75.         self.write_cmd(x1)
  76.         self.write_cmd(SET_PAGE_ADDR)
  77.         self.write_cmd(0)
  78.         self.write_cmd(self.pages - 1)
  79.         self.write_framebuf()
  80.     def fill(self, col):
  81.         self.framebuf.fill(col)
  82.     def pixel(self, x, y, col):
  83.         self.framebuf.pixel(x, y, col)
  84.     def scroll(self, dx, dy):
  85.         self.framebuf.scroll(dx, dy)
  86.     def text(self, string, x, y, col=1):
  87.         self.framebuf.text(string, x, y, col)
  88. class SSD1306_I2C(SSD1306):
  89.     def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
  90.         self.i2c = i2c
  91.         self.addr = addr
  92.         self.temp = bytearray(2)
  93.         # Add an extra byte to the data buffer to hold an I2C data/command byte
  94.         # to use hardware-compatible I2C transactions.  A memoryview of the
  95.         # buffer is used to mask this byte from the framebuffer operations
  96.         # (without a major memory hit as memoryview doesn't copy to a separate
  97.         # buffer).
  98.         self.buffer = bytearray(((height // 8) * width) + 1)
  99.         self.buffer[0] = 0x40  # Set first byte of data buffer to Co=0, D/C=1
  100.         self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
  101.         super().__init__(width, height, external_vcc)
  102.     def write_cmd(self, cmd):
  103.         self.temp[0] = 0x80 # Co=1, D/C#=0
  104.         self.temp[1] = cmd
  105.         self.i2c.writeto(self.addr, self.temp)
  106.     def write_framebuf(self):
  107.         # Blast out the frame buffer using a single I2C transaction to support
  108.         # hardware I2C interfaces.
  109.         self.i2c.writeto(self.addr, self.buffer)
  110.     def poweron(self):
  111.         pass
  112. class SSD1306_SPI(SSD1306):
  113.     def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
  114.         self.rate = 10 * 1024 * 1024
  115.         dc.init(dc.OUT, value=0)
  116.         res.init(res.OUT, value=0)
  117.         cs.init(cs.OUT, value=1)
  118.         self.spi = spi
  119.         self.dc = dc
  120.         self.res = res
  121.         self.cs = cs
  122.         self.buffer = bytearray((height // 8) * width)
  123.         self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
  124.         super().__init__(width, height, external_vcc)
  125.     def write_cmd(self, cmd):
  126.         self.spi.init(baudrate=self.rate, polarity=0, phase=0)
  127.         self.cs.high()
  128.         self.dc.low()
  129.         self.cs.low()
  130.         self.spi.write(bytearray([cmd]))
  131.         self.cs.high()
  132.     def write_framebuf(self):
  133.         self.spi.init(baudrate=self.rate, polarity=0, phase=0)
  134.         self.cs.high()
  135.         self.dc.high()
  136.         self.cs.low()
  137.         self.spi.write(self.buffer)
  138.         self.cs.high()
  139.     def poweron(self):
  140.         self.res.high()
  141.         time.sleep_ms(1)
  142.         self.res.low()
  143.         time.sleep_ms(10)
  144.         self.res.high()
复制代码






       新建”ads1x15.py”,复制下面代码,保存到“MicroPython设备”作为ADS1115的库。


  1. # The MIT License (MIT)
  2. #
  3. # Copyright (c) 2016 Radomir Dopieralski (@deshipu),
  4. #               2017 Robert Hammelrath (@robert-hh)
  5. #
  6. # Permission is hereby granted, free of charge, to any person obtaining a copy
  7. # of this software and associated documentation files (the "Software"), to deal
  8. # in the Software without restriction, including without limitation the rights
  9. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. # copies of the Software, and to permit persons to whom the Software is
  11. # furnished to do so, subject to the following conditions:
  12. #
  13. # The above copyright notice and this permission notice shall be included in
  14. # all copies or substantial portions of the Software.
  15. #
  16. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. # THE SOFTWARE.
  23. #
  24. import utime as time
  25. _REGISTER_MASK = const(0x03)
  26. _REGISTER_CONVERT = const(0x00)
  27. _REGISTER_CONFIG = const(0x01)
  28. _REGISTER_LOWTHRESH = const(0x02)
  29. _REGISTER_HITHRESH = const(0x03)
  30. _OS_MASK = const(0x8000)
  31. _OS_SINGLE = const(0x8000)  # Write: Set to start a single-conversion
  32. _OS_BUSY = const(0x0000)  # Read: Bit=0 when conversion is in progress
  33. _OS_NOTBUSY = const(0x8000)  # Read: Bit=1 when no conversion is in progress
  34. _MUX_MASK = const(0x7000)
  35. _MUX_DIFF_0_1 = const(0x0000)  # Differential P  =  AIN0, N  =  AIN1 (default)
  36. _MUX_DIFF_0_3 = const(0x1000)  # Differential P  =  AIN0, N  =  AIN3
  37. _MUX_DIFF_1_3 = const(0x2000)  # Differential P  =  AIN1, N  =  AIN3
  38. _MUX_DIFF_2_3 = const(0x3000)  # Differential P  =  AIN2, N  =  AIN3
  39. _MUX_SINGLE_0 = const(0x4000)  # Single-ended AIN0
  40. _MUX_SINGLE_1 = const(0x5000)  # Single-ended AIN1
  41. _MUX_SINGLE_2 = const(0x6000)  # Single-ended AIN2
  42. _MUX_SINGLE_3 = const(0x7000)  # Single-ended AIN3
  43. _PGA_MASK = const(0x0E00)
  44. _PGA_6_144V = const(0x0000)  # +/-6.144V range  =  Gain 2/3
  45. _PGA_4_096V = const(0x0200)  # +/-4.096V range  =  Gain 1
  46. _PGA_2_048V = const(0x0400)  # +/-2.048V range  =  Gain 2 (default)
  47. _PGA_1_024V = const(0x0600)  # +/-1.024V range  =  Gain 4
  48. _PGA_0_512V = const(0x0800)  # +/-0.512V range  =  Gain 8
  49. _PGA_0_256V = const(0x0A00)  # +/-0.256V range  =  Gain 16
  50. _MODE_MASK = const(0x0100)
  51. _MODE_CONTIN = const(0x0000)  # Continuous conversion mode
  52. _MODE_SINGLE = const(0x0100)  # Power-down single-shot mode (default)
  53. _DR_MASK = const(0x00E0)     # Values ADS1015/ADS1115
  54. _DR_128SPS = const(0x0000)   # 128 /8 samples per second
  55. _DR_250SPS = const(0x0020)   # 250 /16 samples per second
  56. _DR_490SPS = const(0x0040)   # 490 /32 samples per second
  57. _DR_920SPS = const(0x0060)   # 920 /64 samples per second
  58. _DR_1600SPS = const(0x0080)  # 1600/128 samples per second (default)
  59. _DR_2400SPS = const(0x00A0)  # 2400/250 samples per second
  60. _DR_3300SPS = const(0x00C0)  # 3300/475 samples per second
  61. _DR_860SPS = const(0x00E0)  # -   /860 samples per Second
  62. _CMODE_MASK = const(0x0010)
  63. _CMODE_TRAD = const(0x0000)  # Traditional comparator with hysteresis (default)
  64. _CMODE_WINDOW = const(0x0010)  # Window comparator
  65. _CPOL_MASK = const(0x0008)
  66. _CPOL_ACTVLOW = const(0x0000)  # ALERT/RDY pin is low when active (default)
  67. _CPOL_ACTVHI = const(0x0008)  # ALERT/RDY pin is high when active
  68. _CLAT_MASK = const(0x0004)  # Determines if ALERT/RDY pin latches once asserted
  69. _CLAT_NONLAT = const(0x0000)  # Non-latching comparator (default)
  70. _CLAT_LATCH = const(0x0004)  # Latching comparator
  71. _CQUE_MASK = const(0x0003)
  72. _CQUE_1CONV = const(0x0000)  # Assert ALERT/RDY after one conversions
  73. _CQUE_2CONV = const(0x0001)  # Assert ALERT/RDY after two conversions
  74. _CQUE_4CONV = const(0x0002)  # Assert ALERT/RDY after four conversions
  75. # Disable the comparator and put ALERT/RDY in high state (default)
  76. _CQUE_NONE = const(0x0003)
  77. _GAINS = (
  78.     _PGA_6_144V,  # 2/3x
  79.     _PGA_4_096V,  # 1x
  80.     _PGA_2_048V,  # 2x
  81.     _PGA_1_024V,  # 4x
  82.     _PGA_0_512V,  # 8x
  83.     _PGA_0_256V   # 16x
  84. )
  85. _GAINS_V = (
  86.     6.144,  # 2/3x
  87.     4.096,  # 1x
  88.     2.048,  # 2x
  89.     1.024,  # 4x
  90.     0.512,  # 8x
  91.     0.256  # 16x
  92. )
  93. _CHANNELS = {
  94.     (0, None): _MUX_SINGLE_0,
  95.     (1, None): _MUX_SINGLE_1,
  96.     (2, None): _MUX_SINGLE_2,
  97.     (3, None): _MUX_SINGLE_3,
  98.     (0, 1): _MUX_DIFF_0_1,
  99.     (0, 3): _MUX_DIFF_0_3,
  100.     (1, 3): _MUX_DIFF_1_3,
  101.     (2, 3): _MUX_DIFF_2_3,
  102. }
  103. _RATES = (
  104.     _DR_128SPS,   # 128/8 samples per second
  105.     _DR_250SPS,   # 250/16 samples per second
  106.     _DR_490SPS,   # 490/32 samples per second
  107.     _DR_920SPS,   # 920/64 samples per second
  108.     _DR_1600SPS,  # 1600/128 samples per second (default)
  109.     _DR_2400SPS,  # 2400/250 samples per second
  110.     _DR_3300SPS,  # 3300/475 samples per second
  111.     _DR_860SPS    # - /860 samples per Second
  112. )
  113. class ADS1115:
  114.     def __init__(self, i2c, address=0x48, gain=1):
  115.         self.i2c = i2c
  116.         self.address = address
  117.         self.gain = gain
  118.         self.temp2 = bytearray(2)
  119.     def _write_register(self, register, value):
  120.         self.temp2[0] = value >> 8
  121.         self.temp2[1] = value & 0xff
  122.         self.i2c.writeto_mem(self.address, register, self.temp2)
  123.     def _read_register(self, register):
  124.         self.i2c.readfrom_mem_into(self.address, register, self.temp2)
  125.         return (self.temp2[0] << 8) | self.temp2[1]
  126.     def raw_to_v(self, raw):
  127.         v_p_b = _GAINS_V[self.gain] / 32767
  128.         return raw * v_p_b
  129.     def set_conv(self, rate=4, channel1=0, channel2=None):
  130.         """Set mode for read_rev"""
  131.         self.mode = (_CQUE_NONE | _CLAT_NONLAT |
  132.                      _CPOL_ACTVLOW | _CMODE_TRAD | _RATES[rate] |
  133.                      _MODE_SINGLE | _OS_SINGLE | _GAINS[self.gain] |
  134.                      _CHANNELS[(channel1, channel2)])
  135.     def read(self, rate=4, channel1=0, channel2=None):
  136.         """Read voltage between a channel and GND.
  137.            Time depends on conversion rate."""
  138.         self._write_register(_REGISTER_CONFIG, (_CQUE_NONE | _CLAT_NONLAT |
  139.                              _CPOL_ACTVLOW | _CMODE_TRAD | _RATES[rate] |
  140.                              _MODE_SINGLE | _OS_SINGLE | _GAINS[self.gain] |
  141.                              _CHANNELS[(channel1, channel2)]))
  142.         while not self._read_register(_REGISTER_CONFIG) & _OS_NOTBUSY:
  143.             time.sleep_ms(1)
  144.         res = self._read_register(_REGISTER_CONVERT)
  145.         return res if res < 32768 else res - 65536
  146.     def read_rev(self):
  147.         """Read voltage between a channel and GND. and then start
  148.            the next conversion."""
  149.         res = self._read_register(_REGISTER_CONVERT)
  150.         self._write_register(_REGISTER_CONFIG, self.mode)
  151.         return res if res < 32768 else res - 65536
  152.     def alert_start(self, rate=4, channel1=0, channel2=None,
  153.                     threshold_high=0x4000, threshold_low=0, latched=False) :
  154.         """Start continuous measurement, set ALERT pin on threshold."""
  155.         self._write_register(_REGISTER_LOWTHRESH, threshold_low)
  156.         self._write_register(_REGISTER_HITHRESH, threshold_high)
  157.         self._write_register(_REGISTER_CONFIG, _CQUE_1CONV |
  158.                              _CLAT_LATCH if latched else _CLAT_NONLAT |
  159.                              _CPOL_ACTVLOW | _CMODE_TRAD | _RATES[rate] |
  160.                              _MODE_CONTIN | _GAINS[self.gain] |
  161.                              _CHANNELS[(channel1, channel2)])
  162.     def conversion_start(self, rate=4, channel1=0, channel2=None):
  163.         """Start continuous measurement, trigger on ALERT/RDY pin."""
  164.         self._write_register(_REGISTER_LOWTHRESH, 0)
  165.         self._write_register(_REGISTER_HITHRESH, 0x8000)
  166.         self._write_register(_REGISTER_CONFIG, _CQUE_1CONV | _CLAT_NONLAT |
  167.                              _CPOL_ACTVLOW | _CMODE_TRAD | _RATES[rate] |
  168.                              _MODE_CONTIN | _GAINS[self.gain] |
  169.                              _CHANNELS[(channel1, channel2)])
  170.     def alert_read(self):
  171.         """Get the last reading from the continuous measurement."""
  172.         res = self._read_register(_REGISTER_CONVERT)
  173.         return res if res < 32768 else res - 65536
  174. class ADS1113(ADS1115):
  175.     def __init__(self, i2c, address=0x48):
  176.         super().__init__(i2c, address, 1)
  177.     def raw_to_v(self, raw):
  178.         return super().raw_to_v(raw)
  179.     def read(self, rate=4):
  180.         return super().read(rate, 0, 1)
  181.     def alert_start(self, rate=4, threshold_high=0x4000, threshold_low=0, latched=False):
  182.         return super().alert_start(rate, 0, 1, threshold_high, threshold_low, latched)
  183.     def alert_read(self):
  184.         return super().alert_read()
  185. class ADS1114(ADS1115):
  186.     def __init__(self, i2c, address=0x48, gain=1):
  187.         super().__init__(i2c, address, gain)
  188.     def raw_to_v(self, raw):
  189.         return super().raw_to_v(raw)
  190.     def read(self, rate=4):
  191.         return super().read(rate, 0, 1)
  192.     def alert_start(self, rate=4, threshold_high=0x4000, threshold_low=0, latched=False):
  193.         return super().alert_start(rate, 0, 1, threshold_high,
  194.             threshold_low, latched)
  195.     def alert_read(self):
  196.         return super().alert_read()
  197. class ADS1015(ADS1115):
  198.     def __init__(self, i2c, address=0x48, gain=1):
  199.         super().__init__(i2c, address, gain)
  200.     def raw_to_v(self, raw):
  201.         return super().raw_to_v(raw << 4)
  202.     def read(self, rate=4, channel1=0, channel2=None):
  203.         return super().read(rate, channel1, channel2) >> 4
  204.     def alert_start(self, rate=4, channel1=0, channel2=None, threshold_high=0x400,
  205.         threshold_low=0, latched=False):
  206.         return super().alert_start(rate, channel1, channel2, threshold_high << 4,
  207.             threshold_low << 4, latched)
  208.     def alert_read(self):
  209.         return super().alert_read() >> 4
复制代码






       新建”main.py”,复制下面代码,作为主程序,主控板启动会自动执行这个程序。


  1. # 使用ADS1115测量电压,并用OLED屏幕显示
  2. import ads1x15 ,time
  3. from machine import Pin, SoftI2C
  4. import ssd1306
  5. import time
  6. i2c = SoftI2C(scl=Pin(9), sda=Pin(8),freq=400000)
  7. oled = ssd1306.SSD1306_I2C(128, 64 ,i2c)
  8. adc = ads1x15.ADS1115(i2c)
  9. # 汉字字典
  10. character_dict = {
  11.     '电': [0x01,0x01,0x01,0x3F,0x21,0x21,0x21,0x3F,0x21,0x21,0x21,0x3F,0x21,0x01,0x01,0x00,
  12.         0x00,0x00,0x00,0xF8,0x08,0x08,0x08,0xF8,0x08,0x08,0x08,0xF8,0x0A,0x02,0x02,0xFE],
  13.     '压': [0x00,0x3F,0x20,0x20,0x20,0x20,0x20,0x2F,0x20,0x20,0x20,0x20,0x20,0x40,0x5F,0x80,
  14.         0x00,0xFE,0x00,0x80,0x80,0x80,0x80,0xFC,0x80,0x80,0x90,0x88,0x88,0x80,0xFE,0x00],
  15.     '流': [0x00,0x20,0x17,0x10,0x81,0x42,0x47,0x10,0x10,0x22,0xE2,0x22,0x22,0x22,0x24,0x08,
  16.         0x80,0x40,0xFE,0x80,0x10,0x08,0xFC,0x04,0x00,0x48,0x48,0x48,0x48,0x4A,0x4A,0x46],
  17.     '测': [0x00,0x27,0x14,0x14,0x85,0x45,0x45,0x15,0x15,0x25,0xE5,0x21,0x22,0x22,0x24,0x08,
  18.         0x04,0xC4,0x44,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x04,0x84,0x44,0x14,0x08],
  19.     '量': [0x00,0x1F,0x10,0x1F,0x10,0xFF,0x00,0x1F,0x11,0x1F,0x11,0x1F,0x01,0x1F,0x01,0x7F,
  20.         0x00,0xF0,0x10,0xF0,0x10,0xFE,0x00,0xF0,0x10,0xF0,0x10,0xF0,0x00,0xF0,0x00,0xFC],
  21.     'A': [0x00,0x00,0x00,0x10,0x10,0x18,0x28,0x28,0x24,0x3C,0x44,0x42,0x42,0xE7,0x00,0x00],
  22.     'V': [0x00,0x00,0x00,0xE7,0x42,0x42,0x44,0x24,0x24,0x28,0x28,0x18,0x10,0x10,0x00,0x00],
  23.     ':': [0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00],
  24.     '-': [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
  25.     '.': [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00],
  26.     '0': [0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00],
  27.     '1': [0x00,0x00,0x00,0x08,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00],
  28.     '2': [0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00],
  29.     '3': [0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x18,0x04,0x02,0x42,0x42,0x3C,0x00,0x00],
  30.     '4': [0x00,0x00,0x00,0x04,0x0C,0x0C,0x14,0x24,0x24,0x44,0x7F,0x04,0x04,0x1F,0x00,0x00],
  31.     '5': [0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x78,0x44,0x02,0x02,0x42,0x44,0x38,0x00,0x00],
  32.     '6': [0x00,0x00,0x00,0x18,0x24,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x22,0x1C,0x00,0x00],
  33.     '7': [0x00,0x00,0x00,0x7E,0x42,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x00,0x00],
  34.     '8': [0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00],
  35.     '9': [0x00,0x00,0x00,0x38,0x44,0x42,0x42,0x42,0x46,0x3A,0x02,0x02,0x24,0x18,0x00,0x00]
  36. }
  37. # 显示中文
  38. def display_zh_character(character, x, y):
  39.     num_list = character_dict[character]
  40.     for i in range(16):
  41.         left = bin(num_list[i]).replace('0b', '')
  42.         right = bin(num_list[i + 16]).replace('0b', '')
  43.    
  44.         # 补 0
  45.         while len(left) < 8:
  46.             left = '0' + left
  47.         while len(right) < 8:
  48.             right = '0' + right
  49.         num_binary = left+right
  50.         for j in range(len(num_binary)):
  51.             oled.pixel(x + j, y + i, int(num_binary[j]))
  52. # 显示英文、数字和其他符号
  53. def display_en_character(character, x, y):
  54.     num_list = character_dict[character]
  55.     for i in range(16):
  56.         left = bin(num_list[i]).replace('0b', '')
  57.         # 补 0
  58.         while len(left) < 8:
  59.             left = '0' + left
  60.         num_binary = left
  61.         for j in range(len(num_binary)):
  62.             oled.pixel(x + j, y + i, int(num_binary[j]))
  63.         
  64. def display_zh(text, x, y):
  65.     for i in range(len(text)):
  66.         display_zh_character(text[i], x + i * 16, y)
  67. def display_en(text, x, y):
  68.     for i in range(len(text)):
  69.         display_en_character(text[i], x + i * 8, y)
  70. # 测量电压并显示在oled
  71. while True:
  72.     value = adc.read()
  73.     voltage=str('{:.3f}'.format((value/2**15)*4.096)) #量程为4.096V
  74.     oled.fill(0)
  75.     display_zh('电压电流测量', 16, 3)
  76.     display_zh('电压', 0, 24)
  77.     display_en(":",32,24)
  78.     display_en(voltage,40,24)
  79.     display_en('V',(40+len(voltage)*8),24)
  80.     oled.show()
  81.     time.sleep(0.5)
复制代码






       完成后文件目录如下图所示:


  四、实验结果

       下图是连接成功,运行程序,进行测量电压的照片:

       下表是利用自制电压表和数字万用表测量结果对比,由表中可以看出,自制数字电压表测量结果和数字万用表测量结果基本一致,实验取得基本成功。

       近期学校事务较多,时间紧张,实验进行的比较简略和粗糙,我会在以后继续完善和扩充,请各位批评指正。实验中所用图片、库和部分代码,参考了网络资源,仅作为自己学习之用,如有侵权,请联系我修改删除。



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail