找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 43170|回复: 33
打印 上一主题 下一主题
收起左侧

自制智能型ICL7135四位半表头

  [复制链接]
跳转到指定楼层
楼主
本文作者:Edward

本文已在《无线电》2012年12期发表。转载请注明出处。这里发表的是原文,和杂志上略有不同。

这个制作以前发过一次帖子:《最近完工的智能型ICL7135四位半表头》这次在这里将详细内容发上来,是想在网络上留个印记,方便自己引用,也是希望和大家分享一下。

正文开始:

       最近需要一个精度比较高的电压表头,但网上卖的表头多是三位半的,精度不够,也有一些四位半表头但性价比不高。正好手里有几片ICL7135,以前也有做过四位半表头的尝试,而且去年也学习了单片机,于是就有了做一个智能型ICL7135四位半表头的想法。历经2个月的学习、设计和修改,最终做出了这样一款表头。
       表头使用ICL7135作为ADC,其是一款高精度的单片4½位ADC,拥有多路复用的BCD输出以及与单片机兼容的控制信号接口,可以很容易的与单片机连接,实现智能化。生产其兼容芯片的厂家有很多,我手里是Maxim和TI生产的。ICL7135应用电路由模拟部分和数字部分组成,表头整体设计思路是:模拟部分采用典型电路和推荐元件参数,数字部分采用单片机提供ICL7135所需时钟、采集输出、驱动数码管。后来,考虑到只做一个简单功能的表头实在是无趣,所以就将单片机的部分IO口和串口引出以便实现与上位机通信或自动控制等功能。
       确定好整体思路和预期功能后就开始进行电路设计了。ICL7135模拟部分典型电路如图1所示。


图1 ICL7135电路模拟部分

       模拟部分元件没什么可说的,基本都采用推荐值。其中比较关键的是积分电容的选择和基准电压的提供。积分电容对于ICL7135这类双积分ADC是至关重要的,它直接影响积分非线性、翻转、比例误差,即它的好坏直接决定了表头的准确性。而ICL7135对积分电容的要求尤为严格。积分电容必须具有低的电介质吸收特性(亦称浸润或电介质迟滞)。将基准输入(REF)接至IN HI可以检测积分电容介质吸收(此法一般称为自检),良好的积分电容读数将会是9999,与这个读数之间的任何偏差都可能是由于电介质吸收引起的。一般来说,特氟龙(聚四氟乙烯)、聚苯乙烯和聚丙烯的电介质吸收特性低至0.02%,一般陶瓷和聚碳酸酯电容的典型值为0.2%,银云母和钽电容为1.0%-5.0%,铝电解电容高达10%或以上。ICL7135手册上建议积分电容最好使用特氟龙和聚丙烯电容,要求不高时可以使用聚苯乙烯和聚碳酸酯电容。在实际选择时,优质高耐压的CBB21或CBB22电容效果不错,一般自检读数能够达到9996或以上,但是买到能有9999自检读数的电容是挺不容易的。我挑选了几批电容测试,读数从9994-9996都有,就是没有9997以上的,比较遗憾。
       开始的时候,想使用LM385作为基准,但是LM385本身参数并不很好,不同厂家的温漂从20~150ppm/℃都有,而且买到正品LM385不太容易。后来在网上搜索了一段时间,发现拆机的Linear公司产电压基准LT1009很好。LT1009是具有0.2%初始精度,15ppm典型温漂,25ppm最大温漂的2.5V并联型基准,它有一个调节引脚,可以在±5%范围内调整输出电压。LT1009的性能超过了一般的LM385,而且拆机件能够保证芯片是真品也廉价。基准电压电路如图2所示,Rref1和Rref2将LT1009输出的电压分压,通过调节电位器Rref3将分压之后的电压调整到准确的1.000V。1.000V电压的微调还有另一种比较常见的方式,即只微调分压电阻,由于种种原因我没选择这种方式。调整电位器要使用如3/8寸Square Trimpot.®微调电位器(3296电位器)等这类精密多圈电位器,以保证精确性和稳定性。


图2  基准电压电路

       传统的ICL7135表头很多是使用4MHz晶振经CD4060分频获得125kHz频率,BCD输出用74LS48之类译码,最后再用三极管或达林顿驱动器驱动数码管,电路复杂不说,成本还高。既然要使用单片机,那么就要让其完成所有功能。STC10F04XE是增强型的8051单片机,拥有4kB的ROM,512B的RAM,5kB的EEPROM以及独立波特率发生器, IO口可设置为多种输出模式;可以实现时钟信号、数据读取、数码管驱动、状态指示、按键控制和串口通信等全部功能。其引脚定义如图3所示。

图3  STC10F04XE引脚图

       考虑程序的复杂度,决定采用比较简单的读取BCD方式采集ICL7135数据。以前我也尝试使用Busy信号来采集数据,但并不成功,所以这次并不打算采用这种方式。ICL7135输出数据有5位数字,D5-D1端按顺序分别输出高电平脉冲进行不间断的扫描。B8、B4、B2、B1端输出当前位的BCD值。当一次正常的数据转换结束后,D5-D1重新开始不断扫描(超量程时不是)。每次数据转换后的D5-D1的第一遍扫描过程中的每个脉冲的中间, 端都会有一个很短的低电平脉冲,之后直到下次转换结束前都没有额外的脉冲。该脉冲能帮助及时采集ADC结果,防止重复采集,简化程序。上述过程的时序如图4所示。


图4  数字扫描和输出时序

       将BCD输出端和D1-D4按顺序连接在单片机的P0口(D5悬空即可),用于采集ICL7135数据,端接到单片机中断0端(P3.2)。单片机的P1.0口是独立波特率发生器的可编程输出时钟端口,用该端口输出稳定的时钟信号给ICL7135。为了良好的抑制50Hz工频干扰,ICL7135的信号积分阶段周期应是工频周期的整数倍,信号积分阶段周期为10000个时钟周期,则最佳时钟频率=50×10000/N,N为整数。所以可选的时钟频率可为100kHz、125kHz等。STC10F04XE是1T单片机,所以可以选择4MHz、6Mhz等较低频率的晶振以减小功耗和干扰,但选择晶振频率要注意保证P1.0口能输出所需的时钟频率。使用6MHz的晶振能产生100kHz、120kHz、125kHz等多种频率,但4MHz晶振无法产生120kHz等频率。本来我是想选择4MHz晶振的,但是考虑到程序中要能设定多种时钟频率,所以最终使用了6MHz晶振。为了能够直接驱动数码管和8个LED,所以选择了这种IO口可设为推挽输出的单片机。数码管各段需要用电阻限流,以防烧坏数码管和单片机。ICL7135的其余端口根据PCB布线的方便性接在单片机的不同IO口上,在P4.0口设置一轻触开关,同时单片机引出串口、中断1、部分IO口以供通信、控制之用。
       ICL7135通常需要±5V供电,提供双电源实在是不方便,所以采用手册推荐的ICL7660电荷泵负压电路,简单稳定。供电电路还额外增加了AMS1117-5.0稳压芯片,除使用5V外还可以使用6V-15V电压供电,扩展了供电范围,同时还设计了超压保护和反接保护电路,以保护芯片安全。不要小看这个超压保护和反接保护,在平时做一些实验调试时,各种线会很多很乱,各种电压也会有很多,接错线是很正常的事,如果没有这些保护,接错的后果往往很严重。我在修改测试这个表头的过程中,就有过将13V电源误接入5V供电输入上,幸好当时没偷懒,保护电路也焊上了,不然芯片肯定不保了。


图5  整机电路(清晰大图请下载本贴附件)

       整机电路图见图5。将电路画好检查无误之后就开始进行电路板布线了。布线主要看个人的学习和经验了。各元件优先选择贴片元件以减小体积和成本,为了便于更换积分电容,我特意制作了能兼容多种脚距的封装。布线时要注意元件的合理布局,数字模拟要分开,模拟地和数字地要单点接地。如果想使用洞洞板搭建电路,那就要注意不要使用纸基的洞洞板,纸基的洞洞板很容易受潮,漏电大,会严重影响ICL7135模拟电路的工作。我曾经使用过纸基板搭电路,工作很不稳定。这也是我选择PCB打样的原因之一。经历两次打样和修改后,最终的PCB如下:



图6  PCB空板

       焊接元件时要注意首先将所有贴片元件焊接好,仔细检查已焊接元件有无错误,LED、1N4148和稳压二极管的极性不能接反。然后将除数码管、ICL7135和排针以外的直插元件焊接好,再次检查已焊接元件有无错误。最后依次焊接ICL7135、数码管和排针,数码管和ICL7135方向一定不要装反。如果想日后能够更换积分电容,可使用28Pin的IC插座来安装ICL7135。元件焊接好后,可以通电试一下机,如果没有下载过程序,LED1-8会不断闪烁。将元件焊接好之后是这样的:



图7  焊接好元件之后

       设计工作的最后一步自然是程序设计了。其实程序设计、测试和电路板打样、修改是交互进行的。第一次打样出的PCB很可能有很多问题,如设计不合理等等。在写程序和测试时发现问题就要修改电路板,然后再编程再打样再测试,如此反复,最后设计出成品。可以说,程序是整个作品的灵魂,因为表头的全部功能都体现在程序上,程序的好坏直接决定了作品的成败。我花了很长时间来设计这个程序,也尝试使用了一些以前未曾用过的程序结构,得到了比较好的效果。整个程序最关键的自然是ADC数据的读取和显示。最初我没有使用信号和中断,结果数据读取不及时,有时还会丢字或者是重复读取,而且还不好与显示函数协调。经过反复尝试和研读ICL7135手册,最后利用的电平脉冲信号产生中断来读取和更新数据。读取ADC数据后结束中断返回正常运行,由于读取数据过程很短,能够不影响显示正常的显示、通信和控制,同时也节省了单片机资源,简化了程序。把主要的做好,其他的功能逐步添加就可以了。由于单片机的功能很强,同时也有EEPROM,可以方便的存储数据,所以我设计了一个菜单来方便功能的设置,设置数据存储在EEPROM中实现掉电不丢失。现在功能菜单也有了,就可以完全任凭自己的想象力来发挥了,因为MCU无限可能。我目前实现的功能有数据保持、串口发送测量值设定、工作频率设定、小数点位置设定、菜单超时退出和还原出厂设置等。未来要实现的功能有:开关短按功能设置,电压超阈值报警,平均值计算,差值计算,软件校准,自动控制等等。板子上只设计了一个轻触开关,基本够用了。长按按键进入设置菜单,短按按键数据保持。以后要增加短按功能设置,可以更改短按的功能。这个程序也是我第一次使用定时器来进行按键按检测。我没有使用常用的软件延时和中断检测法。因为单片机要不断扫描数码管,不能打断扫描太长时间,不然数字显示会闪烁或中断。不使用中断的原因是单片机外部中断资源比较有限,我想把中断1端口预留给以后控制使用;另外程序编写得循环很快,每次循环只扫描一个数码管,这样一次循环的时间就很短,不会影响到按键的判断。程序也有向上位机发送测量结果的功能如果设置打开了串口发送数据,那么每次测量结束就会将测量结果以BCD码通过串口发送出去。多参考单片机的数据手册,再开动脑筋就可以做出很多很有意思的功能。编写程序的时候要注意IO口的工作模式,数据接收要设为开漏,数据发送和发送接收口要设为准双向口,数码管段驱动口要根据选取的数码管类型(共阴或共阳)设为推挽或开漏,数码管位驱动口同样,要设为开漏或推挽。
       当程序编写调试完成后,在投入使用前最后一个重要工作就是对表头进行校准,以保证测量的准确性。原则上应该使用4½及以上位数的数字电压表或万用表,将其输入端与表头输入端并联,并输入一个1V左右稳定的电压,调节电位器使二者显示一致的方式来调整。但是考虑可能没有4½或以上位数的仪表,也可以用精度良好的3½或3¾位万用表来简单调整。方法是使用万用表200.0mV或400.0mV量程电压档,将其输入端与本机输入端并联,并输入一个100-200mV稳定的电压,调节电位器,调整使二者显示一致即可。
       最后就可以将表头投入使用了。由于我没有更好的积分电容,所以表头精度略差,实际满量程误差是正负十几个字左右。整机耗电在30mA左右。目前工作正常,与上位机通信也很稳定。



图8  工作中的表头

电路图大图下载:

单片机的源程序:
4.5Digital Voltmeter MCU Program V1.0.rar (5.91 KB, 下载次数: 403)

另外再补充一段工作时的视频:(数据保持忘了拍了,是短按按键,蓝色LED会亮。为了方便拍摄,是使用串口控制的表头,如果按键,正常显示时短按就是数据保持,长按就是进入菜单,长按生效时,全部LED都会亮起。)

单片机源程序如下:
  1. /**************************************************
  2. 4 1/2 Digital Voltmeter MCU Program

  3. Using MCU STC10F04XE with 6.000MHz Crystal
  4. With PCB v1.01

  5. UART Command
  6. 0xF1 Key Long
  7. 0xF2 Ket Short
  8. 0xF3 Erase EEPROM 0x0800
  9. 0xF4 Reboot(choosen)
  10. 0x00 Reboot

  11. Created By Edward
  12. Creation Date  14-Apr-2012
  13. Latest Version 27-May-2012

  14. Copyright 2012 Edward All rights reserved.
  15. **************************************************/

  16. #include
  17. #include
  18. /*Declare SFR associated*/
  19. sfr CLK_DIV = 0x97;//System clock divide
  20. sfr P4                = 0xC0;//P4 Port
  21. sfr P4SW    = 0xBB;//P4SW Register
  22. sfr P0M0    = 0x94;//IO Port Type Register
  23. sfr P0M1    = 0x93;
  24. sfr P1M0    = 0x92;
  25. sfr P1M1    = 0x91;
  26. sfr P2M0    = 0x96;
  27. sfr P2M1    = 0x95;
  28. sfr P3M0    = 0xB2;
  29. sfr P3M1    = 0xB1;
  30. sfr P4M0    = 0xB4;
  31. sfr P4M1    = 0xB3;
  32. sfr AUXR    = 0x8E;//Auxiliary register
  33. sfr BRT                = 0x9C;//Baud-Rate Timer register
  34. sfr WAKE_CLKO=0x8F;//Clock output and Power-down Wakeup Control register
  35. sfr IAP_CTRL = 0xC7;//ISP/IAP Control register
  36. /*Declare SFR associated with the IAP */
  37. sfr IAP_DATA = 0xC2; //Flash data register
  38. sfr IAP_ADDRH= 0xC3; //Flash address HIGH
  39. sfr IAP_ADDRL= 0xC4; //Flash address LOW
  40. sfr IAP_CMD  = 0xC5; //Flash command register
  41. sfr IAP_TRIG = 0xC6; //Flash command trigger
  42. sfr IAP_CONTR= 0xC7; //Flash control register

  43. /*Define ISP/IAP/EEPROM command*/
  44. #define CMD_IDLE 0 //Stand-By
  45. #define CMD_READ 1 //unsigned char-Read
  46. #define CMD_PROGRAM 2 //unsigned char-Program
  47. #define CMD_ERASE 3 //Sector-Erase
  48. /*Define ISP/IAP/EEPROM operation const for IAP_CONTR*/
  49. #define ENABLE_IAP 0x84 //SYSCLK<6MHz

  50. /*Define Which Command that Received to Reboot System*/
  51. #define REBOOT_CMD 0xF4
  52. //#define REBOOT_CMD 0x00 //STC-ISP Default Download Command
  53. /*Define if the Sysytem will Reboot after Sent Command*/
  54. #define REBOOT_CTRL 1        //Rebot
  55. //#define REBOOT_CTRL 0        //not reboot
  56. /*Define the Different ways to reboot*/
  57. #define REBOOT_WAY 0x60          //From ISP
  58. //#define REBOOT_WAY 0x20 //

  59. sbit S1  = P4^0;//Key1
  60. sbit CLK = P1^0;//ICL7135 Clock
  61. sbit BSY = P1^1;//ICL7135 BUSY signal
  62. sbit POL = P1^2;//ICL7135 Polarity output
  63. sbit RH  = P1^3;//ICL7135 Run/Hold
  64. sbit STB = P3^2;//ICL7135 STROBE signal
  65. sbit OVR = P1^4;//ICL7135 Over Range signal
  66. sbit UNR = P1^5;//ICL7135 Under Range signal
  67. sbit LED = P1^6;//LEDs
  68. sbit D1  = P3^6;//Seven-Segment LED, the right the first
  69. sbit D2  = P3^7;
  70. sbit D3  = P3^5;
  71. sbit D4  = P3^4;
  72. sbit D5  = P1^7;

  73. /*For Seven segment LED display*/
  74. unsigned char code Led_Dsp[]={
  75. 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,//0-7
  76. 0x7F,0x6F,0x77,0x7C,0x58,0x5E,0x79,0x71,//8-F
  77. 0x39,0x3D,0x74,0x76,0x30,//0x39-C,0x3D-G,0x74-h,0x76-H,0x30-I
  78. //20
  79. 0x0E,0x38,0x54,0x5C,0x73,//0x0E-J,0x38-L,0x54-n,0x5C-o,0x73-P
  80. 0x67,0x50,0x6D,0x78,0x1C,//0x67-q,0x50-r,0x6D-S,0x78-t,0x1C-u
  81. //30
  82. 0x3E,0x6E,0x00,0x40,0x0C},//0x3E-U,0x6E-y,0x00-,0x40--,0x0C-
  83. /*Menu Display data*/
  84. MenuDat[][6]={
  85. 0x00,27,14,11,24,29,//rEbot LEDx                0
  86. 0x01,28,14,23,13,33,//SEnd        LED1                1
  87. 0x03,28, 1,28,14,29,//S1SEt LED1-2                2
  88. 0x07,13,25,28,14,29,//dpSEt LED1-3                3
  89. 0x0F,15,26,28,14,29,//FqSEt LED1-4                4
  90. 0x1F,28,34,28,14,29,//S-SEt LED1-5                5
  91. 0x3F,26,31,20,29,33,//qUIt  LED1-6                6
  92. 0x7F,27,14,28,14,29,//rESEt LED1-7                 7
  93. 0xAA,33, 0,15,15,33,// OFF        LED2,4,6,8        8
  94. 0x55,33, 0,23,33,33,// On        LED1,3,5,7  9
  95. 0x10,0x20,0x40,0x80,0,0x01,//For LED        10
  96. 0x11,15,33,33,33, 4,//F   4 LED1,5                11
  97. 0x22,15,33,33, 1, 0,//F  10 LED2,6
  98. 0x33,15,33,33, 5, 0,//F  50 LED
  99. 0x44,15,33, 1, 0, 0,//F 100 LED
  100. 0x55,15,33, 1, 2, 0,
  101. 0x66,15,33, 1, 2, 5,
  102. 0x77,15,33, 1, 5, 0,
  103. 0x88,15,33, 2, 5, 0,
  104. 0x99,15,33, 3, 0, 0,
  105. 0xAA,15,33, 5, 0, 0,
  106. 0xBB,15,33, 6, 0, 0,
  107. 0xCC,15, 1, 0, 0, 0,
  108. 0xDD,15, 1, 5, 0, 0,//F1500 LED                        23
  109. 0xFF,28,30,12,12,14,//SuccE LED1-8                24
  110. 0xA5,14,27,27,24,27 //Error LED1,3,6,8        25
  111. };

  112. unsigned char
  113. Dat[]={0,1,2,3,4,5,0},//ICL7135 Digital output with Polatity
  114. //Data formate: POL MSD ... LSD LED
  115. DatSend[]={0xFF,0xEE,0xEE,0xEE,0x00,0xAA},//Data for send
  116. //Data format:0xff H=POL/OVR L-MSB+0x0E ... L-LSB CRC8 0xAA
  117. DatRom[]={0,0,0},//Data for EEPROM
  118. //Data format H-Send,L-S1;H-Dp,L-CLK;CRC
  119. Dp,//Decimal point setting,0 is the left
  120. ADCLK,//ICL7135 Clock Settings
  121. i,
  122. countdwn0,//Use for timing or countdown
  123. sendjud,//Send Data        judgment and countdown
  124. Keyjud,//For key and menu
  125. dispmod,//Display Mode
  126. dispcnt,//For display
  127. S1Func;//S1 Func

  128. bit
  129. readjud,//Read ICL7135 data judgment
  130. KeyScanjud,//Key scan judgment
  131. KeyLong, //Key
  132. KeyShort,
  133. sendctrl,//Send data control
  134. sndctldsp,//Send data control for display
  135. readadctrl;//Read AD Status        control

  136. /*---------------------------------------------
  137. Software Delay Function

  138. Input  char        for different delay time
  139. Output void
  140. ---------------------------------------------*/
  141. void Delay(char xx)
  142. {
  143.         unsigned int y;
  144.         switch (xx)
  145.         {
  146.                 case 0:         //For Init Function and Key scan
  147.                         {
  148.                                 for(xx=0;xx++;xx<255)
  149.                                         for(y=0;y++;y<255);
  150.                         }break;
  151.                 case 1:          //For LED Display
  152.                         {
  153.                                 xx=1;
  154.                                 while(xx--)
  155.                                 {
  156.                                         y=65500;
  157.                                         while(++y);
  158.                                 }
  159.                         }break;
  160.                 case 2:         //For Reboot
  161.                         {
  162.                                 xx=8;
  163.                                 while(xx--)
  164.                                 {
  165.                                         y=0;
  166.                                         while(++y);
  167.                                 }
  168.                         }break;
  169.         }
  170. }

  171. /*----------------------------
  172. Disable ISP/IAP/EEPROM function

  173. Make MCU in a safe state
  174. ----------------------------*/
  175. void IapIdle()
  176. {
  177.         IAP_CONTR = 0; //Close IAP function
  178.         IAP_CMD = 0; //Clear command to standby
  179.         IAP_TRIG = 0; //Clear trigger register
  180.         IAP_ADDRH = 0x80; //Data ptr point to non-EEPROM area
  181.         IAP_ADDRL = 0; //Clear IAP address to prevent misuse
  182. }

  183. /*----------------------------
  184. Read one unsigned char from ISP/IAP/EEPROM area

  185. Input: addr (ISP/IAP/EEPROM address)
  186. Output:Flash data
  187. ----------------------------*/
  188. unsigned char IapReadByte(unsigned int addr)
  189. {
  190.         unsigned int dat1; //Data buffer
  191.         IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
  192.         IAP_CMD = CMD_READ; //Set ISP/IAP/EEPROM READ command
  193.         IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
  194.         IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
  195.         IAP_TRIG = 0x5a; //Send trigger command1 (0x5a)
  196.         IAP_TRIG = 0xa5; //Send trigger command2 (0xa5)
  197.         _nop_(); //MCU will hold here until ISP/IAP/EEPROM
  198.         //operation complete
  199.         dat1 = IAP_DATA; //Read ISP/IAP/EEPROM data
  200.         IapIdle(); //Close ISP/IAP/EEPROM function
  201.         return dat1; //Return Flash data
  202. }

  203. /*----------------------------
  204. Program one unsigned char to ISP/IAP/EEPROM area

  205. Input:  addr (ISP/IAP/EEPROM address)
  206.                 dat (ISP/IAP/EEPROM data)
  207. Output: void
  208. ----------------------------*/
  209. void IapProgramByte(unsigned int addr, unsigned char dat2)
  210. {
  211.         IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
  212.         IAP_CMD = CMD_PROGRAM; //Set ISP/IAP/EEPROM PROGRAM command
  213.         IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
  214.         IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
  215.         IAP_DATA = dat2; //Write ISP/IAP/EEPROM data
  216.         IAP_TRIG = 0x5a; //Send trigger command1 (0x5a)
  217.         IAP_TRIG = 0xa5; //Send trigger command2 (0xa5)
  218.         _nop_(); //MCU will hold here until ISP/IAP/EEPROM
  219.         //operation complete
  220.         IapIdle();
  221. }

  222. /*----------------------------
  223. Erase one sector area

  224. Input: addr (ISP/IAP/EEPROM address)
  225. Output:void
  226. ----------------------------*/
  227. void IapEraseSector(unsigned int addr)
  228. {
  229.         IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
  230.         IAP_CMD = CMD_ERASE; //Set ISP/IAP/EEPROM ERASE command
  231.         IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
  232.         IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
  233.         IAP_TRIG = 0x5a; //Send trigger command1 (0x5a)
  234.         IAP_TRIG = 0xa5; //Send trigger command2 (0xa5)
  235.         _nop_(); //MCU will hold here until ISP/IAP/EEPROM
  236.         //operation complete
  237.         IapIdle();
  238. }

  239. /*----------------------------
  240. CRC sector area

  241. Input: *p len
  242. Output:CRC
  243. ----------------------------*/
  244. unsigned char CRC8(unsigned char *ptr,unsigned char len)  
  245. {
  246.         unsigned char crc=0;
  247.         while(len--!=0)
  248.         {
  249.                 for(i=0x80;i!=0;i=i>>1)
  250.                 {
  251.                         if((crc&0x80)!=0)
  252.                         {
  253.                                 crc=crc<<1;
  254.                                 crc^=0x5E;
  255.                         } /* 余式CRC 乘以2 再求CRC */
  256.                         else crc=crc<<1;
  257.                         if((*ptr&i)!=0)crc^=0x5E; /* 再加上本位的CRC */
  258.                 }
  259.                 ptr++;
  260.         }
  261.         return crc;
  262. }
  263. /*---------------------------------------------
  264. Reboot Function

  265. Reboot the system

  266. Input  void
  267. Output void
  268. ---------------------------------------------*/
  269. void Reboot(void)
  270. {
  271.         P2=0x40;
  272.         D1=D3=D5=D2=D4=0;
  273.         Delay(2);
  274.         IAP_CTRL=REBOOT_WAY;        
  275. }
  276. /*---------------------------------------------
  277. Read AD Status Function

  278. Read Status for ICL7135, then write to Dat[]

  279. Input  unsigned char
  280. Output void
  281. ---------------------------------------------*/
  282. void ReadAD(bit yy)
  283. {
  284.         if (yy)
  285.         {
  286.                 Dat[0]=POL;
  287.                 if(BSY)Dat[6]=Dat[6]|0x01;
  288.                         else Dat[6]=Dat[6]&0xFE;
  289.                 if(OVR)                                                 //Over Range
  290.                 {
  291.                         Dat[6]=Dat[6]|0x10;
  292.                         DatSend[1]|=0xE0;
  293.                         dispmod=2;
  294.                 }
  295.                 else
  296.                 {
  297.                         Dat[6]=Dat[6]&0xEF;
  298.                         DatSend[1]&=0x0F;
  299.                         dispmod=0;
  300.                 }
  301.                 if(UNR)Dat[6]=Dat[6]|0x20;         //Under Range
  302.                         else Dat[6]=Dat[6]&0xDF;
  303.                 if(!RH)Dat[6]=Dat[6]|0x02;         //Run/Hold
  304.                         else Dat[6]=Dat[6]&0xFD;
  305.         }
  306. }

  307. /*---------------------------------------------
  308. Data Convert Function

  309. Convert ICL7135 output to an int number
  310. Directly use Dat[]

  311. Input  void
  312. Output int
  313. ---------------------------------------------*/
  314. void DataConvt(void)
  315. {
  316.         DatSend[1]=Dat[0]<<4;
  317.         DatSend[1]=DatSend[1]+Dat[1]+0x0E;
  318.         if(OVR)DatSend[1]|=0xE0; //Over Range
  319.         DatSend[2]=Dat[2]<<4;
  320.         DatSend[2]=DatSend[2]+Dat[3];
  321.         DatSend[3]=Dat[4]<<4;
  322.         DatSend[3]=DatSend[3]+Dat[5];
  323.         DatSend[4]=CRC8(&DatSend[0],4);
  324. }

  325. /*---------------------------------------------
  326. ICL7135 Clock Set Function

  327. MCU should run at 6MHz

  328. Input  unsigned char
  329. Output void
  330. ---------------------------------------------*/
  331. void AD_Clock(unsigned char clk)
  332. {
  333.         AUXR&=0xEF;//Stop the Independent Baud Rate Generator
  334.         AUXR|=0x04;//SysCLK divide by 1
  335.         switch (clk)
  336.         {
  337.                 case 1://4kHz
  338.                 {
  339.                         AUXR&=0xF3;//SysCLK divide by 12
  340.                         BRT=0xFA;//250
  341.                 }break;
  342.                 case 2://10kHz
  343.                 {
  344.                         AUXR&=0xFB;//SysCLK divide by 12
  345.                         BRT=0xE7;//231
  346.                 }break;
  347.                 case  3:BRT=0xC4;break;//   50kHz 196
  348.                 case  4:BRT=0xE2;break;//  100kHz 226
  349.                 case  5:BRT=0xE7;break;//  120kHz 231
  350.                 case  6:BRT=0xE8;break;//  125kHz 232
  351.                 case  7:BRT=0xEC;break;//  150kHz 236
  352.                 case  8:BRT=0xF4;break;//  250kHz 244
  353.                 case  9:BRT=0xF6;break;//  300kHz 246
  354.                 case 10:BRT=0xFA;break;//  500kHz 250
  355.                 case 11:BRT=0xFB;break;//  600kHz 251
  356.                 case 12:BRT=0xFD;break;//1,000kHz 253
  357.                 case 13:BRT=0xFE;break;//1,500kHz 254
  358.         }
  359.         AUXR|=0x10;//Run the Independent Baud Rate Generator
  360. }

  361. /*---------------------------------------------
  362. Display Function

  363. Dynamic scanning of the digital

  364. Input  char display mode
  365. Output void
  366. ---------------------------------------------*/
  367. void Display(char k)
  368. {
  369.         D5=D4=D3=D2=D1=LED=1;
  370.         switch (k)
  371.         {
  372.                 case 0://Normal display
  373.                 {
  374.                         P2=Led_Dsp[Dat[dispcnt]];
  375.                         switch (dispcnt)
  376.                         {
  377.                         case 0:
  378.                         {
  379.                                 P2=Dat[6];//LED
  380.                                 LED=0;
  381.                         }break;
  382.                         case 1:
  383.                         {
  384.                                 if(!Dat[1])P2=0x00;//The Left Digit
  385.                                 if(!Dat[0])P2=P2+0x40;
  386.                                 D5=0;
  387.                         }break;
  388.                         case 2:D4=0;break;
  389.                         case 3:D3=0;break;
  390.                         case 4:D2=0;break;
  391.                         case 5:D1=0;break;
  392.                         case 6:
  393.                         {
  394.                                 P2=0x80;                           //Decimal point
  395.                                 switch (Dp)
  396.                                 {
  397.                                         case 0:D5=0;break;
  398.                                         case 1:D4=0;break;
  399.                                         case 2:D3=0;break;
  400.                                         case 3:D2=0;break;
  401.                                         case 4:D1=0;break;
  402.                                 }
  403.                         }break;
  404.                         }
  405.                 }break;
  406.                 case 1://Menu display
  407.                 {
  408.                         if(countdwn0>80)Reboot();//Quite Menu if timeout
  409.                         P2=Led_Dsp[Dat[dispcnt]];
  410.                         if(!dispcnt)P2=Dat[0];
  411.                         switch (dispcnt)
  412.                         {
  413.                         case 0:LED=0;break;
  414.                         case 1:D5=0;break;
  415.                         case 2:D4=0;break;
  416.                         case 3:D3=0;break;
  417.                         case 4:D2=0;break;
  418.                         case 5:D1=0;break;
  419.                         case 6:
  420.                         {
  421.                                 P2=0x80;                           //Decimal point
  422.                                 switch (Keyjud)
  423.                                 {
  424.                                         case 1:D2=0;break;
  425.                                         case 2:D4=0;break;
  426.                                         case 3:D4=0;break;
  427.                                         case 4:D4=0;break;
  428.                                         case 5:D5=0;break;
  429.                                         case 6:D2=0;break;
  430.                                         case 7:D1=0;break;
  431.                                         case 0xF3:
  432.                                         {
  433.                                                 switch (Dp)
  434.                                                 {
  435.                                                         case 0:D5=0;break;
  436.                                                         case 1:D4=0;break;
  437.                                                         case 2:D3=0;break;
  438.                                                         case 3:D2=0;break;
  439.                                                         case 4:D1=0;break;
  440.                                                 }
  441.                                         }break;
  442.                                         case 0xF4:D5=0;break;
  443.                                 }
  444.                         }break;
  445.                         }
  446.                 }break;
  447.                 case 2://O.L. display
  448.                 {
  449.                         switch(dispcnt)
  450.                         {
  451.                                 case 1:
  452.                                 {
  453.                                         P2=Dat[6];
  454.                                         LED=0;
  455.                                 }break;
  456.                                 case 2:
  457.                                 {
  458.                                         P2=Led_Dsp[0]+0x80;
  459.                                         D2=0;
  460.                                 }break;
  461.                                 case 3:
  462.                                 {
  463.                                         P2=Led_Dsp[22]+0x80;
  464.                                         D1=0;
  465.                                         dispcnt=0;
  466.                                 }break;
  467.                         }
  468.                 }break;
  469.         }
  470.         Delay(1);
  471.         dispcnt++;
  472.         if(dispcnt>6)dispcnt=0;
  473. }

  474. /*---------------------------------------------
  475. Display Menu Function

  476. Write Menu display data to Dat[]

  477. Input  void
  478. Output void
  479. ---------------------------------------------*/
  480. void DispMenu(void)
  481. {
  482.         if(Keyjud>0&&Keyjud<0x10)for(i=0;i<7;i++)Dat[i]=MenuDat[Keyjud][i];//For Display
  483.         else
  484.         {
  485.                 switch (Keyjud)
  486.                 {
  487.                 case 0xF1://Send or not
  488.                         {
  489.                                 for(i=0;i<7;i++)
  490.                                 {
  491.                                         if(sndctldsp)Dat[i]=MenuDat[9][i];
  492.                                                 else Dat[i]=MenuDat[8][i];
  493.                                 }
  494.                         }break;
  495.                 case 0xF2:;break;//S1.Set Func is reserved for future use
  496.                 case 0xF3://Dp position
  497.                         {
  498.                                 for(i=0;i<7;i++)Dat[i]=33;
  499.                                 Dat[Dp+1]=35;
  500.                                 Dat[0]=MenuDat[10][Dp];
  501.                         }break;
  502.                 case 0xF4:for(i=0;i<7;i++)Dat[i]=MenuDat[ADCLK+10][i];break;//CLK
  503.                 }
  504.         }
  505. }
  506. /*---------------------------------------------
  507. Serial communication Function

  508. Send One Byte Data using UART

  509. Input  unsigned char
  510. Output void
  511. ---------------------------------------------*/
  512. void SendOneByte(unsigned char xx)
  513. {
  514.         SBUF=xx;
  515.         while(!TI);
  516.         TI=0;
  517. }

  518. /*---------------------------------------------
  519. Data Send Function

  520. Send AD Data using UART

  521. Input  void
  522. Output void
  523. ---------------------------------------------*/
  524. void SendData(bit y)
  525. {
  526.         if(y)
  527.         {
  528.                 if(!BSY&&sendjud)
  529.                 {
  530.                         DataConvt();
  531.                         SendOneByte(DatSend[sendjud-1]);
  532.                         sendjud++;        //send only one byte per scan
  533.                         if(sendjud>6)sendjud=0;
  534.                 }
  535.                 if(BSY)sendjud=1;
  536.                 if(!RH&&!dispcnt)SendOneByte(0xF0);
  537.         }
  538. }

  539. /*---------------------------------------------
  540. Reset Settings Function

  541. Just reset the settings in EEPROM

  542. Input  unsigned char MenuDat[?][]
  543. Output void
  544. ---------------------------------------------*/
  545. void Reset(unsigned char y)
  546. {
  547.         countdwn0=0;
  548.         IapEraseSector(0x0800);
  549.         DatRom[0]=0x01;//Default not Send data, S1Func reserved for future use
  550.         DatRom[1]=0x04;//Default decimal point at the most significant digit
  551.                                    //ICL7135 default run at 100kHz
  552.         DatRom[2]=CRC8(&DatRom[0],2);
  553.         for(i=0;i<4;i++)IapProgramByte(0x0800+i,DatRom[i]);
  554.         for(i=0;i<7;i++)Dat[i]=MenuDat[y][i];
  555.         Keyjud=7;
  556.         while(countdwn0<20)
  557.         {
  558.                 Display(1);
  559.         }
  560.         Reboot();
  561. }
  562. /*---------------------------------------------
  563. Settings Function

  564. Read, check, Save or reset settings
  565. or reboot(Quit Menu) the System

  566. Input  unsigned char
  567. Output void
  568. ---------------------------------------------*/
  569. void Settings(unsigned char yy)
  570. {
  571.         switch (yy)
  572.         {
  573.                 case 0://Check settings while Init
  574.                 {
  575.                         for(i=0;i<3;i++)DatRom[i]=IapReadByte(0x0800+i);
  576.                         if(DatRom[2]!=CRC8(&DatRom[0],2))
  577.                         {
  578.                                 Reset(25);
  579.                         }
  580.                         else
  581.                         {
  582.                                 S1Func=DatRom[0]&0x0F;
  583.                                 sendctrl=DatRom[0]>>4;
  584.                                 ADCLK=DatRom[1]&0x0F;
  585.                                 Dp=DatRom[1]>>4;
  586.                         }
  587.                 }break;
  588.                 case 1://Save settings
  589.                 {
  590.                         countdwn0=0;
  591.                         IapEraseSector(0x0800);
  592.                         if(sndctldsp)DatRom[0]=0x10;
  593.                                 else DatRom[0]=0x00;
  594.                         DatRom[0]|=S1Func;
  595.                         DatRom[1]=Dp<<4;
  596.                         DatRom[1]|=ADCLK;
  597.                         DatRom[2]=CRC8(&DatRom[0],2);
  598.                         for(i=0;i<4;i++)IapProgramByte(0x0800+i,DatRom[i]);
  599.                         for(i=0;i<7;i++)Dat[i]=MenuDat[24][i];
  600.                         Keyjud=7;
  601.                         while(countdwn0<20)
  602.                         {
  603.                                 Display(1);
  604.                         }
  605.                         Reboot();
  606.                 }break;
  607.                 case 2://Quit(Reboot Sysytem)
  608.                 {
  609.                         Reboot();
  610.                 }break;
  611.                 case 3://Reset settings
  612.                 {
  613.                         Reset(24);
  614.                 }break;
  615.         }
  616. }
  617. /*---------------------------------------------
  618. Key Scan Function

  619. Input  void
  620. Output void
  621. ---------------------------------------------*/
  622. void KeyScan(void)
  623. {
  624.         if(!S1)
  625.         {
  626.                 Delay(0);
  627.                 if(!S1)                   //>2s Long time
  628.                 {
  629.                         if(!KeyScanjud)
  630.                         {
  631.                                 countdwn0=0;
  632.                                 KeyScanjud=1;
  633.                         }
  634.                 }
  635.                 if(countdwn0>12)  //Light a LED
  636.                 {
  637.                         switch (dispmod)
  638.                         {
  639.                         case 0:Dat[6]=0xFF;break;
  640.                         case 1:Dat[0]=0xFF;break;
  641.                         }
  642.                 }
  643.         }
  644.         else                   //<2S Short time
  645.         {
  646.                 if(KeyScanjud)
  647.                 {
  648.                         if(countdwn0>12)KeyLong=1;
  649.                                 else KeyShort=1;
  650.                         KeyScanjud=0;
  651.                 }
  652.         }
  653. }

  654. /*---------------------------------------------
  655. Key Function

  656. Input  void
  657. Output void
  658. ---------------------------------------------*/
  659. void KeyFunc(void)
  660. {
  661.         if(KeyLong)                        //For Long Key
  662.         {
  663.                 if(!Keyjud)
  664.                 {
  665.                         Keyjud=1;
  666.                         EX0=0;//STOP read data from AD
  667.                         readadctrl=0;//Stop read status from AD
  668.                         dispmod=1;//Change Display Mode to Menu
  669.                         sndctldsp=sendctrl;
  670.                         sendctrl=0;
  671.                 }
  672.                 else
  673.                 {
  674.                         if(Keyjud<5)Keyjud|=0xF0;
  675.                         else if(Keyjud>0xF0){if(Keyjud<0xF5)Keyjud&=0x0F;}
  676.                         else if(Keyjud<0x10)Settings(Keyjud-4);
  677.                         if(Keyjud==0xF2)Keyjud=0x02;//S1.Set Func is reserved for future use
  678.                 }
  679.                 DispMenu();
  680.                 KeyLong=0;
  681.         }
  682.         
  683.         if(KeyShort)                   //For Short Key
  684.         {
  685.                 if(!Keyjud)RH=!RH;
  686.                 else if(Keyjud<0x10)
  687.                 {
  688.                         Keyjud++;
  689.                         if(Keyjud>7)Keyjud=1;
  690.                 }
  691.                 else if(Keyjud>0xF0)
  692.                 {
  693.                         switch (Keyjud)
  694.                         {
  695.                         case 0xF1:sndctldsp=!sndctldsp;break;//Send dat or not
  696.                         case 0xF2:;break;//S1.Set Func is reserved for future use
  697.                         case 0xF3:{Dp++;if(Dp>4)Dp=0;}break;//Dp position
  698.                         case 0xF4:{ADCLK++;if(ADCLK>13)ADCLK=1;}break;//AD CLK
  699.                         }
  700.                 }
  701.                 DispMenu();
  702.                 KeyShort=0;
  703.         }
  704. }

  705. /*---------------------------------------------
  706. Initialization Function

  707. Input  void
  708. Output void
  709. ---------------------------------------------*/
  710. void Init(void)
  711. {
  712.         CLK_DIV=0x00;//System run at 6MHz
  713.         WAKE_CLKO=0x04;//Set the P1.0 pin as the independent Baud Rate Generator clock output
  714.         P4SW =0x70;//Set P4.4 P4.5 P4.6 to IO Prot
  715.         P0M1 =0xFF;//Set P0 Prot to HZ input
  716.         P0M0 =0x00;
  717.         P1M1 =0XF6;//Set P1.0 P1.3 to IO, P1.6-P1.7 to Open Drain, others to HZ
  718.         P1M0 =0XC0;
  719.         P2M1 =0x00;//Set P2 Port to Pull Push Output
  720.         P2M0 =0xFF;
  721.         P3M1 =0xF4;//Set P3.4-P3.7 to Open Drain, P3.2 to HZ, others to IO
  722.         P3M0 =0xF0;
  723.         P4M1 =0xE6;//Set P1.0 P4.3 P4.4 Prot to IO, others to HZ
  724. ……………………

  725. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏41 分享淘帖 顶5 踩
回复

使用道具 举报

沙发
ID:47634 发表于 2017-8-3 07:06 | 只看该作者
很好很好,学习学习
回复

使用道具 举报

板凳
ID:249545 发表于 2017-11-26 22:09 | 只看该作者
用英特希尔的ICL7135制做4位电压电流表,比ICL7107的3位高端了10倍!
回复

使用道具 举报

地板
ID:249545 发表于 2017-11-26 22:10 | 只看该作者
感谢楼主老师分享ICL7135 4位表制做资料!
回复

使用道具 举报

5#
ID:283207 发表于 2018-2-9 13:01 | 只看该作者
感谢楼主分享ICL7135 4位表制做资料,程序已下载,仔细学习。
回复

使用道具 举报

6#
ID:289512 发表于 2018-3-9 09:32 | 只看该作者
很好的方案,谢谢楼主分享。
回复

使用道具 举报

7#
ID:320325 发表于 2018-5-17 17:45 | 只看该作者
好东西,已收藏;
回复

使用道具 举报

8#
ID:52915 发表于 2018-7-6 11:58 | 只看该作者
太好了,谢谢分享!
回复

使用道具 举报

9#
ID:61493 发表于 2018-11-19 08:09 | 只看该作者
感谢楼主分享ICL7135 4位表制做资料,学习学习。
回复

使用道具 举报

10#
ID:428400 发表于 2018-11-24 19:46 | 只看该作者
有去做PCB吗?
回复

使用道具 举报

11#
ID:74143 发表于 2018-12-10 21:49 | 只看该作者
谢谢楼主分享。
回复

使用道具 举报

12#
ID:162957 发表于 2018-12-11 17:33 | 只看该作者

谢谢楼主分享。
回复

使用道具 举报

13#
ID:103151 发表于 2018-12-25 22:06 | 只看该作者
非常好的资料
回复

使用道具 举报

14#
ID:205532 发表于 2019-1-18 09:41 | 只看该作者
好资料,感谢楼主分享啊
回复

使用道具 举报

15#
ID:73762 发表于 2019-1-29 09:49 | 只看该作者
能分享PCB文件吗,手头有7135,向做一个
回复

使用道具 举报

16#
ID:474288 发表于 2019-1-31 10:36 | 只看该作者
多谢楼主分享  辛苦
回复

使用道具 举报

17#
ID:467275 发表于 2019-3-28 15:09 | 只看该作者
很好很好,学习学习
回复

使用道具 举报

18#
ID:168038 发表于 2019-4-11 08:38 | 只看该作者
如果能分享PCB文件就好了,刚好手头有7135
回复

使用道具 举报

19#
ID:42468 发表于 2019-9-12 17:04 | 只看该作者
学习了,单独用TCL7135可以做数显4位半电压电流表吗
回复

使用道具 举报

20#
ID:618416 发表于 2019-10-5 06:25 | 只看该作者
非常感谢学习
回复

使用道具 举报

21#
ID:149799 发表于 2019-10-8 13:41 | 只看该作者
学习了,程序好复杂啊
回复

使用道具 举报

22#
ID:491577 发表于 2019-10-11 17:59 | 只看该作者
楼主的数码管都是单片机IO直接驱动,8个LED全亮时电流大于50mA,楼主不担心单片机会挂掉吗?
回复

使用道具 举报

23#
ID:491577 发表于 2019-10-11 18:06 | 只看该作者
楼主的电源用料差了点吧,模拟、数字部分公用一个电源想要达到4位半的精度有点难,起码用两块稳压芯片分开供电。
回复

使用道具 举报

24#
ID:11393 发表于 2019-11-15 20:22 | 只看该作者
很好很好,学习学习
回复

使用道具 举报

25#
ID:106489 发表于 2019-12-24 10:11 | 只看该作者
谢谢分享!正好需要学习这个芯片!
回复

使用道具 举报

26#
ID:671776 发表于 2019-12-30 15:14 | 只看该作者
多谢楼主分享,学习学习
回复

使用道具 举报

27#
ID:60026 发表于 2020-1-22 16:23 | 只看该作者
看看学习下!谢谢分享!
回复

使用道具 举报

28#
ID:361863 发表于 2020-4-18 20:17 | 只看该作者
好好学习研究一下
回复

使用道具 举报

29#
ID:507641 发表于 2020-7-1 22:03 | 只看该作者
做电子需要高精度电压表,谢谢分享!学习又可以有工具。强!
回复

使用道具 举报

30#
ID:413201 发表于 2021-6-9 00:31 | 只看该作者
没有图纸提供下载吗?
回复

使用道具 举报

31#
ID:97023 发表于 2021-6-29 10:59 | 只看该作者
hhh402 发表于 2019-10-11 17:59
楼主的数码管都是单片机IO直接驱动,8个LED全亮时电流大于50mA,楼主不担心单片机会挂掉吗?

动态扫描LED,任意时刻只有一个在工作。
回复

使用道具 举报

32#
ID:1013588 发表于 2022-9-23 20:40 | 只看该作者
要做一个电压实时显示,做一个试试,楼主牛
回复

使用道具 举报

33#
ID:1052903 发表于 2022-12-29 12:00 | 只看该作者
感谢楼主分享ICL7135 4位表
回复

使用道具 举报

34#
ID:1083475 发表于 2023-6-12 08:30 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表