本帖最后由 xinxincaijq 于 2013-3-14 08:44 编辑
方案说明:此方案系本人去年冬天即兴做的一个高精度表头,预期精度能够达到6位半表的水平,由于手上没有6位半到8位半的高精度万用表进行对比测试,所以实际精度暂时值得怀疑,有待进一步验证改进!整个电路板的设计制作均由本人独立完成,电路板采用手工单面板制作工艺,主控芯片ATmega16(本人比较擅长和喜欢使用AVR芯片)。废话不多说了,直接上系统实际测试运行图片。
这张是系统整体照,还没有上电的情形,手机拍的效果一般。系统总共设4个功能控制按键,分别是液晶显示/串口传输切换按键,该按键实现数据在液晶屏上显示和经过串口上传至PC上位机的切换;自校准按键,由于没有制作用于校准的电压源,所以该按键的功能暂时没有启用;液晶开关按键,顾名思义就是实现液晶屏显示的开与关;高速/低速切换按键,实现测量速度的切换,低速测量时,大约6次/s,高速测量时约2K次/s。使用的ADC芯片是凌特公司生产的高精度ADC芯片LTC2440,该表被广泛用于5位半的万用表中,但是该芯片的手册中明确指出可以用于6位半的万用表设计中,基准源使用的是maxim公司的max6175芯片,精度和噪声性能都比较优异。
这张是新旧表头对比照,之前曾经做过一板简单的,性能也很优异,但是只能液晶屏显示,实用性很低于是就有了重新设计第2版的想法。想到了就要做,说动手就动手,花了大约一星期把第二版做出来了,并用LabVIEW设计了一个上位机软件,可用性和可操作性大大提升。图中测试使用一节三洋爱乐普镍氢充电电池,实测发现只有最后一位数字在跳动,说明本表头的稳定性特别好,同时也说明小日本的充电电池放电性能特别稳定。
这张是液晶屏背光打开的测量工作照,手机拍照效果一般,凑合着看吧!
这张是板子背部照,纯手工打造感光法制作,焊接的松香残渣由于没有洗板水就没有洗了,不影响性能。至于为何有飞线后面会有说明的,稍安勿躁。
这张是将测量数据上传至计算机上的,软件界面一看就知道是LabVIEW开发的,不多解释。从LabVIEW上的值也可以看出测量结果很稳定、准确。
两版工作对比照,从测量显示的数值可以看出略有差异,可能是因为两片芯片之间有一点点工艺上的差异吧!程序和电路基本没变,排除硬件设计上的原因,当然有待进一步核查。
附上测试程序代码(编译环境CVAVR,简单易用,原先使用的是IAR) #include <mega16.h> #include <delay.h> // Alphanumeric LCD Module functions #include <alcd.h> // Specify that a new putchar function will be used instead of the one from stdio.h #define _ALTERNATE_PUTCHAR_ #include <stdio.h> // Declare your global variables here #define LCD_ON_OFF PORTA.0 #define LTC2440_CS PORTC.0 #define LTC2440_SCK PORTC.6 #define LTC2440_SDO PINC.1 #define LTC2440_BUSY PINC.7 #define LTC2440_HI PORTD.7 #define DATA_REGISTER_EMPTY (1<<UDRE) unsigned char int_flag; // 按键中断标志 unsigned char lcd_flag; // 液晶屏开关标志 unsigned char uart_flag; // 串口标志 // Define the new putchar function void putchar(char c) { // the output will be directed to the LCD lcd_putchar(c); } void main(void) { // Declare your local variables here unsigned char i,key,sign_flag; unsigned char adc0,adc1,adc2,adc3; unsigned long adc_vltg = 0; unsigned long adc_result = 0; // 32 bits float adc_voltage = 0;
int_flag = 0; lcd_flag = 0; uart_flag = 0; LTC2440_CS = 0; // 片选一直有效 LTC2440_SCK = 0; PORTA=0x00; DDRA=0xFF; PORTB=0x00; DDRB=0x00; PORTC=0x82; DDRC=0x41; PORTD=0xFD; DDRD=0x82; LTC2440_HI = 1;
// USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: Off // USART Transmitter: On // USART Mode: Asynchronous // USART Baud Rate: 9600 UCSRA=0x00; UCSRB=0x08; UCSRC=0x86; UBRRH=0x00; UBRRL=0x33;
// External Interrupt(s) initialization // INT0: On // INT0 Mode: Falling Edge // INT1: Off // INT2: Off GICR|=0x40; MCUCR=0x02; MCUCSR=0x00; GIFR=0x40;
LCD_ON_OFF = 1; // 开启液晶显示
// Alphanumeric LCD initialization // Connections specified in the // Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu: // RS - PORTA Bit 1 // RD - PORTA Bit 2 // EN - PORTA Bit 3 // D4 - PORTA Bit 4 // D5 - PORTA Bit 5 // D6 - PORTA Bit 6 // D7 - PORTA Bit 7 // Characters/line: 16 lcd_init(16); printf("DVM 6 1/2"); lcd_gotoxy(10,1); lcd_putchar('V');
// Global enable interrupts #asm("sei") while (1) { if(int_flag==1) { int_flag = 0; key = (PIND & 0x78); if (key == 0x38) // S4 { lcd_flag = ~lcd_flag; if(lcd_flag) { LCD_ON_OFF = 0; // 关闭液晶显示 DDRA &= 0x01; } else { LCD_ON_OFF = 1; // 开启液晶显示 DDRA |= 0xFE; lcd_init(16); printf("DVM 6 1/2"); lcd_gotoxy(10,1); lcd_putchar('V'); } } else if (key == 0x58) // S3 { LTC2440_HI = ~LTC2440_HI; // 切换测量速度 } else if (key == 0x68) // S2 {
} else if (key == 0x70) // S1 { uart_flag = ~uart_flag; // 串口传输标志 } }
if(LTC2440_BUSY == 0) // 转换完成 { for(i=0; i<32; i++) // { LTC2440_SCK = 1; adc_result <<= 1; LTC2440_SCK = 0; if(LTC2440_SDO) adc_result += 1; }
if(uart_flag) // 采样结果经串口发送 { adc3 = (adc_result & 0xFF000000)>>24; adc2 = (adc_result & 0x00FF0000)>>16; adc1 = (adc_result & 0x0000FF00)>>8; adc0 = (unsigned char)adc_result; while ((UCSRA & DATA_REGISTER_EMPTY)==0); UDR = 0xA5; while ((UCSRA & DATA_REGISTER_EMPTY)==0); UDR = adc3; while ((UCSRA & DATA_REGISTER_EMPTY)==0); UDR = adc2; while ((UCSRA & DATA_REGISTER_EMPTY)==0); UDR = adc1; while ((UCSRA & DATA_REGISTER_EMPTY)==0); UDR = adc0; } else { sign_flag = (adc_result & 0x20000000)>>29;
lcd_gotoxy(0,1);
if(sign_flag == 1) { lcd_putchar('+'); adc_result = ((adc_result & 0x1FFFFFE0) >> 5); adc_voltage = (float)adc_result * 5.0 / 16777216.0; adc_voltage *= 10000000; adc_vltg = adc_voltage;
lcd_putchar((adc_vltg/10000000+0x30)); lcd_putchar('.'); lcd_putchar((adc_vltg%10000000/1000000+0x30)); lcd_putchar((adc_vltg%1000000/100000+0x30)); lcd_putchar((adc_vltg%100000/10000+0x30)); lcd_putchar((adc_vltg%10000/1000+0x30)); lcd_putchar((adc_vltg%1000/100+0x30)); lcd_putchar((adc_vltg%100/10+0x30)); lcd_putchar((adc_vltg%10+0x30)); } else { lcd_putchar('-'); adc_result = ((adc_result & 0x1FFFFFE0) >> 5); adc_result = ~adc_result; adc_result &= 0x0FFFFFF; adc_result += 1;
adc_voltage = (float)adc_result * 5.0 / 16777216.0; adc_voltage *= 10000000; adc_vltg = adc_voltage;
lcd_putchar((adc_vltg/10000000+0x30)); lcd_putchar('.'); lcd_putchar((adc_vltg%10000000/1000000+0x30)); lcd_putchar((adc_vltg%1000000/100000+0x30)); lcd_putchar((adc_vltg%100000/10000+0x30)); lcd_putchar((adc_vltg%10000/1000+0x30)); lcd_putchar((adc_vltg%1000/100+0x30)); lcd_putchar((adc_vltg%100/10+0x30)); lcd_putchar((adc_vltg%10+0x30)); } } } } } // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { // Place your code here int_flag = 1; } 总结经验教训:系统比较简单,但是第二版在设计电路时ADC输入引脚没有接上对地的去噪电容,到指初期测试时发现测量结果偏差很大,所以后来手工焊上两个0805封装的贴片电容,遂有了上面照片显示的那样(背部看到一根明显的飞线)。
由于个人时间和水平有限,本表头暂时就做到这种程度,欢迎各位高手指点和共同参与完善之!
|