本帖最后由 dirtwillfly 于 2015-1-23 22:08 编辑
一:本设计基于MSP430G2231为核心控制系统,结合适量的硬件设计,配合12864液晶,制作出一个自动量程的电压,电阻,温度测试仪表。电压量程在0-11V,电阻档量程:0-100kΩ,温度适于室温测量。此表多适用于电子DIY爱好者使用。
二:原理
当被测电压VDD时,由上图可知,我们只需测出V值,即可知道VDD值。VDD=V*(R9+R10)/R10.而V的值可用430的ADC采集得到。
2. 电阻测量:
原理和电压测量一样当VDD已知,R10已知,V已知时。R9的阻值:R9=(VDD/V-1)*R10。 3:温度测量:基于18B20。DS1820 数字温度计以9 位数字量的形式反映器件的温度值。 DS1820 通过一个单线接口发送或接收信息,因此在中央微处理器和DS1820 之间仅需一条连 接线(加上地线)。用于读写和温度转换的电源可以从数据线本身获得,无需外部电源。 因为每个 DS1820 都有一个独特的片序列号,所以多只DS1820 可以同时连在一根单线总线上, 这样就可以把温度传感器放在许多不同的地方。这一特性在HVAC 环境控制、探测建筑物、仪 器或机器的温度以及过程监测和控制等方面非常有用。 整体设计思路
三:电路实现 1:电阻与电压测量外围硬件电路图,电压测量时,高电位端接红表笔,低电位端接黑表笔。通过运放的电压跟随,解决了数字万用表仅使用于测量恒压源的窘境,但同时也由于运放的限制,测量电压范围变小。当测量电压低于2V时,ADC0采集的电压值有效,作为测量值,而ADC1采样无效。每次测量都是由大量程开始,通过程序判断,该量程是否合适,如量程太大,进行小量程切换。 2:电阻的测量是本设计的经典,不借助于模拟开关,手动开关选档。而借助于单片机IO口的上拉输出,高阻态输入完成自动选档。如当P12为高电平时,P13为高阻态时,R5与被测电阻形成通路分IO口电压,然后再经358跟随供AD采集。通过切换P12,P13的输入输出状态即可实现档位切换。 18B20具有很多优秀的特性,如零待机功耗,独特的单线接口仅需一个端口引脚进行通讯,报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件。 3:电源模块 因为用的是MSP430的LAUNCHPAD开发板,故3,5V供电电压不用单独制作。只需产生运放需要要的12V电压,本设计依赖34063的芯片的升压,由5V升到12V。 4:液晶显示模块 此设计也是经典之举,尽管抬高了此作品的造价,因430总共只有10个可操控IO口,而一般的显示模块都得用8个左右,而用12864的串行模式,同时运用MSP430的SPI通信,既方便又高效的完成了液晶显示的操作。同时采用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++;
}
}
|