打印

【TI 技术资料分享】+ 基于launchpad的简易数字万用表

[复制链接]
1624|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 dirtwillfly 于 2015-1-23 22:08 编辑

一:本设计基于MSP430G2231为核心控制系统,结合适量的硬件设计,配合12864液晶,制作出一个自动量程的电压,电阻,温度测试仪表。电压量程在0-11V,电阻档量程:0-100kΩ,温度适于室温测量。此表多适用于电子DIY爱好者使用。
二:原理


当被测电压VDD时,由上图可知,我们只需测出V值,即可知道VDD值。VDD=V*(R9+R10)/R10.V的值可用430ADC采集得到。
2. 电阻测量:

原理和电压测量一样当VDD已知,R10已知,V已知时。R9的阻值:R9=(VDD/V-1)*R10
3:温度测量:基于18B20DS1820 数字温度计以9 位数字量的形式反映器件的温度值。
DS1820 通过一个单线接口发送或接收信息,因此在中央微处理器和DS1820 之间仅需一条连
接线(加上地线)。用于读写和温度转换的电源可以从数据线本身获得,无需外部电源。
因为每个 DS1820 都有一个独特的片序列号,所以多只DS1820 可以同时连在一根单线总线上,
这样就可以把温度传感器放在许多不同的地方。这一特性在HVAC 环境控制、探测建筑物、仪
器或机器的温度以及过程监测和控制等方面非常有用。
整体设计思路

三:电路实现

1:电阻与电压测量外围硬件电路图,电压测量时,高电位端接红表笔,低电位端接黑表笔。通过运放的电压跟随,解决了数字万用表仅使用于测量恒压源的窘境,但同时也由于运放的限制,测量电压范围变小。当测量电压低于2V时,ADC0采集的电压值有效,作为测量值,而ADC1采样无效。每次测量都是由大量程开始,通过程序判断,该量程是否合适,如量程太大,进行小量程切换。
2:电阻的测量是本设计的经典,不借助于模拟开关,手动开关选档。而借助于单片机IO口的上拉输出,高阻态输入完成自动选档。如当P12为高电平时,P13为高阻态时,R5与被测电阻形成通路分IO口电压,然后再经358跟随供AD采集。通过切换P12P13的输入输出状态即可实现档位切换。


18B20具有很多优秀的特性,如零待机功耗,独特的单线接口仅需一个端口引脚进行通讯,报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件。
3:电源模块
    因为用的是MSP430LAUNCHPAD开发板,故3,5V供电电压不用单独制作。只需产生运放需要要的12V电压,本设计依赖34063的芯片的升压,由5V升到12V

4:液晶显示模块

此设计也是经典之举,尽管抬高了此作品的造价,因430总共只有10个可操控IO口,而一般的显示模块都得用8个左右,而用12864的串行模式,同时运用MSP430SPI通信,既方便又高效的完成了液晶显示的操作。同时采用5分钟定时息屏操作,从根本上解决了低功耗的问题,环保,节约。关于12864这里不再赘述。
4:按键模块

因为设计温度是一直显示,所以就只需对电阻,电压进行选择。所以运用了两个按键作为人际交互手段,而复位按键由MSP430开发板自身提供。
实物图

源码:

/*
* main.c
*/
#include <msp430.h>
typedef struct REG{
unsigned bit0 : 1;
unsigned bit1 : 1;
unsigned bit2 : 1;
unsigned bit3 : 1;
unsigned bit4 : 1;
unsigned bit5 : 1;
unsigned bit6 : 1;
unsigned bit7 : 1;
}REG;
typedef enum STATE{
WELCOME = 1,
VOLTAGE,
RESISTANCE
}STATE;
#define uchar unsigned char
#define uint  unsigned int
#define jump_ROM 0xCC
#define start 0x44
#define read_EEROM 0xBE
typedef unsigned char byte;
typedef unsigned int word;
#define N_SAMPLE 12
#define P1 ((REG *) 0x0021)
#define RS P1->bit7
#define DQ P1->bit4           //DS18B20数据口
void dispnum(unsigned int a,unsigned char x,unsigned char y) ;
void dispuserset(unsigned int a,unsigned char x,unsigned char y);
volatile STATE state = WELCOME;
word adc_value[N_SAMPLE];
unsigned char TMPH,TMPL;
void Key_Init(void)
{
P2SEL &= ~BIT6 + ~BIT7;
P2REN |= BIT6 + BIT7;
P2OUT |= BIT6 + BIT7;
P2IE |= BIT6 + BIT7;
P2IES |= BIT6 + BIT7;
P2IFG &= ~BIT6 + ~BIT7;
}
void TimerA0_Init(void)
{
TACCR0 = 30000;
TACCR1 = 20000;
TACTL = TASSEL_2 + MC_2 + ID_3;
TACCTL1 = CCIE;
TACTL |= TACLR;
}
void ADC_Init(void)
{
ADC10CTL1 = CONSEQ_2;
ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
ADC10DTC1 = N_SAMPLE;
ADC10SA = (word) adc_value;
}
void ADC_Channel_Select(word channel)
{
ADC10CTL1 &= 0x0fff;
ADC10CTL1 |= channel;
ADC10AE0 &= 0x00;
ADC10AE0 = (1 << (channel >> 12));
}


inline void SPI_Init(void)
{
USICTL0 |= USIPE6 + USIPE5 + USIMST + USIOE;
USICTL1 |= USICKPH + USIIE;
USICKCTL = USIDIV_4 + USISSEL_2;
USICTL0 &= ~USISWRST;
__enable_interrupt();
}
void SPI_Transmit(byte data)
{
USISRL = data;
USICNT = 8;
// while (!(USIIFG & USICTL1));
LPM0;
}
/********************************************************************
* 名称 : delay()
* 功能 : 延时函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay(unsigned int yN)
{
unsigned int i;
for(i=0; i<yN; i++)
      ;
}
/********************************************************************
* 名称 : Reset()
* 功能 : 复位DS18B20
* 输入 : 无
* 输出 : 无
***********************************************************************/
uchar Reset(void)
{
uchar deceive_ready;
DQ = 0;
delay(29);
DQ = 1;
delay(3);
deceive_ready = DQ;
delay(25);
return(deceive_ready);
}
/********************************************************************
* 名称 : read_bit()
* 功能 : 从DS18B20读一个位值
* 输入 : 无
* 输出 : 从DS18B20读出的一个位值
***********************************************************************/
uchar read_bit(void)
{
uchar i;
DQ = 0;
DQ = 1;
for(i=0; i<3; i++);
return(DQ);
}
/********************************************************************
* 名称 : write_bit()
* 功能 : 向DS18B20写一位
* 输入 : bitval(要对DS18B20写入的位值)
* 输出 : 无
***********************************************************************/
void write_bit(uchar bitval)
{
DQ=0;if(bitval==1)
DQ=1;
delay(5);
DQ=1;
}
/********************************************************************
* 名称 : read_byte()
* 功能 : 从DS18B20读一个字节
* 输入 : 无
* 输出 : 从DS18B20读到的值
***********************************************************************/
uchar read_byte(void)
{
uchar i,m,receive_data;
m = 1;
receive_data = 0;
for(i=0; i<8; i++)
{
  if(read_bit())
  {
   receive_data = receive_data + (m << i);
  }
  delay(6);
}
return(receive_data);
}
/********************************************************************
* 名称 : write_byte()
* 功能 : 向DS18B20写一个字节
* 输入 : val(要对DS18B20写入的命令值)
* 输出 : 无
***********************************************************************/
void write_byte(uchar val)
{
uchar i,temp;
for(i=0; i<8; i++)
{
  temp = val >> i;
  temp = temp & 0x01;
  write_bit(temp);
  delay(5);
}
}

/********************************************************************
* 名称 : GETDATA()
* 功能 : 获取数据
* 输入 : 无
* 输出 : 温度值,整数
***********************************************************************/
unsigned int GETDATA()
{
unsigned int temp;
  DQ = 0;
  Reset();
  write_byte(jump_ROM);
  write_byte(start);
  Reset();
  write_byte(jump_ROM);
  write_byte(read_EEROM);
  TMPL = read_byte();
  TMPH = read_byte();
  temp = TMPL>>4 + 4<<TMPH;
  return temp;
}
void LCD_Write_Cmd(byte com)
{
RS = 1;
SPI_Transmit(0xf8);
SPI_Transmit(0xf0 & com);
SPI_Transmit(0xf0 & (com << 4));
RS = 0;
}
void LCD_Write_Dat(byte dat)
{
RS = 1;
SPI_Transmit(0xfa);
SPI_Transmit(0xf0 & dat);
SPI_Transmit(0xf0 & (dat << 4));
RS = 0;
}
void LCD_Pos(byte x, byte y)
{
byte pos;
switch(x)
{
case 0:
  x = 0x80;
  break;
case 1:
  x = 0x90;
  break;
case 2:
  x = 0x88;
  break;
case 3:
  x = 0x98;
  break;
default:
  break;
}
pos = x + y;
LCD_Write_Cmd(pos);
}

void LCD_Init(void)
{
LCD_Write_Cmd(0x30);
LCD_Write_Cmd(0x0c);
LCD_Write_Cmd(0x01);
LCD_Write_Cmd(0x02);
LCD_Write_Cmd(0x80);
}
void LCD_Write_Str(byte x, byte y, char *str)
{
LCD_Pos(x, y);
while (*str)
{
  LCD_Write_Dat(*str++);
}
}
void LCD_Clear_Screen(void)
{
LCD_Write_Cmd(0x34);
LCD_Write_Cmd(0x30);
LCD_Write_Cmd(0x01);
}
void Disp_Welcome_Msg(void)
{
LCD_Write_Str(0, 1, "自动量程仪表");
LCD_Write_Str(1, 0, "温度:   °C");
LCD_Write_Str(2, 0, "1:电阻  2:电压");
LCD_Write_Str(3, 0, "    欢迎使用");
}
word filter(void)
{
word ad_val;
int i;
for (i = 0; i < N_SAMPLE; i++)
{
  ad_val += adc_value[i];
}
ad_val /= N_SAMPLE;
return ad_val;
}
void Measure_Voltage(void)
{
word ad_val = 0;
byte flag=0;
LCD_Write_Str(2, 0, "                ");
LCD_Write_Str(2, 0, "电压:");
LCD_Write_Str(3, 0, "                ");
ADC_Channel_Select(INCH_1);
ADC10CTL0 &= ~ENC;
while (ADC10CTL1 & BUSY); // Wait if ADC core is active
ADC10CTL0 |= ENC + ADC10SC;  // Sampling and conversion start
LPM0;
ad_val = filter();
if (ad_val > 150)
{
  flag=1;
}
else
{
  flag=0;
  ADC_Channel_Select(INCH_2);
  ADC10CTL0 |= ADC10SC;
  LPM0;
  ad_val = filter();
}
if(flag==1)
{
  ad_val=ad_val*1.05;
  dispuserset(ad_val,3,2);
}
else
{
  ad_val=ad_val*3.60;
  dispuserset(ad_val,3,2);
}
LCD_Write_Str(3, 4, "V");
}
inline void Measure_Resistance(void)
{
byte flag=0;
word ad_val,temp_adc;
LCD_Write_Str(2, 0, "                ");
LCD_Write_Str(2, 0, "电阻:");
LCD_Write_Str(3, 0, "                ");
P1DIR |= BIT2;
P1DIR &= ~BIT3;
P1OUT |= BIT2;
ADC_Channel_Select(INCH_0);
ADC10CTL0 |= ENC + ADC10SC;  // Sampling and conversion start
LPM0;
ad_val = filter();
if (ad_val > 150)
  {
   flag=1;
  }
  else
  {
   flag=0;
   P1DIR |= BIT3;
   P1DIR &= ~BIT2;
   P1OUT |= BIT3;
   ADC_Channel_Select(INCH_0);
   ADC10CTL0 |= ENC + ADC10SC;  // Sampling and conversion start
   LPM0;
   ad_val = filter();
  }
if(flag==1)
{
   temp_adc=1024-ad_val;  //(带小数显示)
   temp_adc=ad_val*10/temp_adc;
   temp_adc=50*temp_adc;
   dispuserset(temp_adc,3,2);
   LCD_Write_Str(3, 4, "KOH");
}
else
{
   temp_adc=1024-ad_val;  //(整数显示)
   temp_adc=ad_val*10/temp_adc;
   temp_adc=100*temp_adc;
   dispnum(temp_adc,3,2);
   LCD_Write_Str(3, 4, "OH");
}
}
void main(void) {
WDTCTL = WDTPW + WDTHOLD;
P1DIR |= BIT7 + BIT4;
SPI_Init();
LCD_Init();
ADC_Init();
Key_Init();
TimerA0_Init();
P1DIR |= BIT0;
// Disp_Welcome_Msg();
for(;;)
{
  switch(state)
  {
  case WELCOME:
   Disp_Welcome_Msg();
   //dispnum(GETDATA(),1,2);
   break;
  case RESISTANCE:
   Measure_Resistance();
   break;
  case VOLTAGE:
   Measure_Voltage();
   break;
  }
  LPM0;
}
}
#pragma vector = USI_VECTOR
__interrupt void USI_ISR(void)
{
USICTL1 &= ~USIIFG;
LPM0_EXIT;
}
#pragma vector = TIMERA1_VECTOR
__interrupt void TIMERA1_ISR(void)
{
switch(TAIV)
{
case 2:
  TACCR1 += 20000;
  LPM0_EXIT;
  break;
}
}
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
LPM0_EXIT;
}
#pragma vector = PORT2_VECTOR
__interrupt void PORT2_ISR(void)
{
if (TACCTL0 & CCIFG)
{
  if (P2IFG & BIT6)
  {
   if (state == VOLTAGE)
   {
    state = WELCOME;
   }
   else
   {
    state = VOLTAGE;
   }
  }
  if (P2IFG & BIT7)
  {
   if (state == RESISTANCE)
   {
    state = WELCOME;
   }
   else
   {
    state = RESISTANCE;
   }
  }
  TACCTL0 &= ~CCIFG;
  TACCR0 += 30000;
}
P2IFG &= ~BIT6 + ~BIT7;
}
/********************************************************************************/
void dispnum(unsigned int a,unsigned char x,unsigned char y)    //整数显示(4位数-9999)
{
unsigned char flag,i=0;
unsigned char out[5];
out[0]=' ';
out[1]=48+(a/1000);
a=a%1000;
out[2]=48+(a/100);
a=a%100;
out[3]=48+(a/10);
out[4]=48+(a%10);
flag=0;
for(i=1;(i<4)&&(flag==0);i++)
{
  if(out[i]==48)
  {
   out[i]=32;
  }
  else
  {
   flag=1;
  }
}
LCD_Pos( x, y);
i=0;
while (i<5)
{
  LCD_Write_Dat(out[i]);
  i++;
}
}
void dispuserset(unsigned int a,unsigned char x,unsigned char y)//小数显示(2位数+2位小数-99.99)
{
unsigned char flag,i=0;
unsigned char out[5];
out[0]=48+(a/1000);
a=a%1000;
out[1]=48+(a/1000);
a=a%100;
out[2]='.';
out[3]=48+(a/10);
    a=a%10;
out[4]=48+a;
flag=0;
for(i=0;(i<2)&&(flag==0);i++)
{
  if(out[i]==48)
  {
   out[i]=32;
  }
  else
  {
   flag=1;
  }
}
LCD_Pos( x, y);
i=0;
while (i<5)
{
  LCD_Write_Dat(out[i]);
  i++;
}
}



相关帖子

沙发
xyz549040622| | 2015-1-23 22:10 | 只看该作者
给灰板顶起

使用特权

评论回复
板凳
dirtwillfly|  楼主 | 2015-1-23 22:13 | 只看该作者
xyz549040622 发表于 2015-1-23 22:10
给灰板顶起

:handshake

使用特权

评论回复
地板
youluo235| | 2015-1-25 10:04 | 只看该作者
顶起。哈哈

使用特权

评论回复
5
acer4736| | 2015-1-26 07:49 | 只看该作者
没想到自己都可以做万用表

使用特权

评论回复
6
jinpaidianzi| | 2015-1-26 07:53 | 只看该作者
学习一下 争取自己做一个

使用特权

评论回复
7
teabottle| | 2015-1-26 07:58 | 只看该作者
钥匙能有配套的机械设计就好了

使用特权

评论回复
8
wangjinlili| | 2015-1-26 08:02 | 只看该作者
先要完整的电路图

使用特权

评论回复
9
meishizhaoshi| | 2015-1-26 08:08 | 只看该作者
这么点代码就可以了?

使用特权

评论回复
10
shibalihuandao| | 2015-1-26 08:12 | 只看该作者
很实用 不错不错

使用特权

评论回复
11
zndz410| | 2015-1-26 11:12 | 只看该作者
要是设计成电压/电流表就好了。

使用特权

评论回复
12
smilingangel| | 2015-1-26 21:16 | 只看该作者
按照楼上的方案的,,其选取的电阻的必须是精密的电阻啊。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:欢迎进入TI MCU论坛      21ic TI技术交流1群:61549143(已满),  21ic TI技术交流2群:311421422 我的博客:http://blog.timcu.com/

1180

主题

34752

帖子

1116

粉丝