资源描述
数字式直流电压表
一、整体说明
在电子技术中,往往离不开对电压的测量,作为一种测量电压的仪器——电压表是近代电子技术领域的常用工具之一,在许多领域得到广泛应用。本设计是基于TI单片机设计的数字式直流电压表,它主要由MSP430G2553、LCD12864和分压电路三部分组成。分压电路先将输入的电压信号衰减一定的倍数,后通过控制双路选择开关设定测量的量程,分别有0~3V和0~15V两个档,以便实现精确读数;分压处理后的电压信号由MSP430G2553内部的ADC10模块转换成数字信号;再通过LCD12864液晶屏进行串行显示。经多次测量实验得出误差范围在2%以内。
二、原理图
基于MSP430G2553单片机设计的数字式直流电压表的电路图如图1所示。由于MSP430开发板已具备单片机最小系统结构,只需添加显示电路和分压电路。LCD12864通过串口方式显示,只需占用单片机2个I/O口;分压电路可以通过开关S1选择量程档位,只占用1个I/O口。
图1 直流电压表电路图
三、接口定义
MSP430G2553的接口说明如表1所示。图1中的复位和晶振部分是MSP430开发板固有的部分,故不再说明。P1.0接液晶屏的SID脚,作为串行的数据口用;P1.1则接液晶屏的SCLK脚,控制串行的同步时钟;P1.4接分压电路的输出端。LCD12864的接口说明如表2所示。当PSB脚接低电平时,串口模式被选择。在该模式下,只用2根线(SID与SCLK)来完成数据传输。RS接高电平,不使用片选功能。注意:信号源与单片机之间要共地。
表1 MSP430G2553的接口说明
引脚号
引脚名
接口说明
备注
2
P1.0
接12864的5脚(R/W)
3
P1.1
接12864的6脚(E)
6
P1.4
接分压电路的输出端
表2 LCD12864的接口说明
引脚号
引脚名
接口说明
备注
1
VSS
电源地
2
VDD
电源正端
4
RS(CS)
电源正端
5
R/W(SID)
P1.0
6
E(CLK)
P1.1
15
PSB
电源地
19
LED_A
电源正端
20
LED_K
电源地
四、程序流程图
图1 主函数流程图
系统初始化
开启ADC转换
开始
(一)主函数
主函数的流程框图如图1所示。主函数主要是调用系统初始化函数和循环开启ADC转换,这是由于ADC10采用单通道单次转换模式,每次采样后需要重新开启ADC,才会进行下一次信号采样转换。另外,信号的采样与处理以及电压值的显示都是通过中断来完成。
(二)系统初始化函数
系统初始化的流程框图如图2所示。该函数对看门狗的工作模式、所需的I/O口以及ADC10和12864进行定义或初始化配置。
(三)ADC初始化函数
ADC初始化的流程框图如图3所示。该函数的任务是对转换控制寄存器ADC10CTL0和ADC10CTL1的初始化配置。其中,ADC10CTL0 需要配置的是ADC10的开关、采样周期、参考电压、ADC10中断使能;而ADC10CTL1则只需要对外部采样通道和ADC的工作模式进行选择。
(四)液晶屏初始化
液晶屏初始化的流程框图如图4所示。该函数需要写指令控制:清屏指令、功能设定为基本指令集操作、地址归0、开显示且关闭光标及其反白显示。
结束
系统初始化开始
设看门狗为定时器模式
图2 系统初始化流程图
使能看门狗中断
设P1.0~P1.1口为输出
设P1.4作A4通道
选择电压量程
ADC初始化
液晶屏初始化
结束
ADC初始化开始
ADC10CTL0&=~ENC
图3 ADC初始化流程图
ADC10CTL0|=ADC10ON
ADC10CTL0|=SREF_0
ADC10CTL0|=ADC10IE
ADC10CTL1|=INCH_4+CONSEQ_0
_EINT( )
结束
液晶屏初始化开始
写指令0x01
图4 液晶屏初始化流程图
写指令0x30
写指令0x02
写指令0x0c
(五)中断函数
结束
看门狗中断开始
LCD显示
图6 看门狗中断流程图
流程图
结束
ADC中断开始
读取采样数据
图5 ADC中断流程图
处理数据
中断函数用到了ADC中断函数和看门狗中断函数。ADC中断函数的流程框图如图5所示,每4个ADC10CLKS周期会产生一次中断,ADC10会将采集到的电压值自动保存在转换存储寄存器ADC10MEM中,直接读取该寄存器就可以取出数据,再通过固定的转换公式转换成测得的电压值。看门狗中断函数的流程框图如图6所示,每隔1s会产生一次中断,更新液晶屏显示的电压值。
五、程序代码
/******************************************************************/
/* 程序说明:直流电压表(串行LCD显示) */
/* P1.0控制RW,并行的读/写选择信号,串行的数据口 */
/* P1.1控制E,并行的使能信号,串行的同步时钟 */
/* P1.4接被测电压信号源,信号源与单片机要共地 */
/* PSB低电平是串行,直接接地;RS接高电平 */
/* 注:程序运行前先选择量程Voltage_Range,并将P1.4口接上对应通 */
/* 道,若选Range_3V接①道,若选Range_15V接②道,否则烧坏芯片 */
/******************************************************************/
#include<msp430g2452.h>
#define uint unsigned int
#define uchar unsigned char
#define BIT(x) (1<<(x))
#define Range_3V 0 //量程为0~3V
#define Range_15V 1 //量程为0~15V
/*********************************************************
函数声明
*********************************************************/
void System_Init(void);
void ADC_Init(void);
void LCD_Init();
void LCD_Send(uchar type,uchar transdata);
void Delay_nms(uint n);
void LCD_Pos(uchar x,uchar y);
void LCD_Display_String(const uchar *pt,uchar num);
void LCD_Display(long int Data);
void LCD_Display_Digit(long int num);
uchar LCD_Table[]={'0','1','2','3','4','5','6','7','8','9','.','V'};
long int Voltage; //全局变量Voltage
uint Voltage_Range;
/*********************************************************
函数功能:系统初始化
入口参数:无
出口参数:无
函数说明:无
*********************************************************/
void System_Init(void)
{
WDTCTL = WDT_ADLY_1000; //看门狗工作在定时器模式,1s中断一次
IE1 |= WDTIE; //使能看门狗中断
P1DIR |= BIT0 + BIT1; //相应的位端口设置为输出
P1SEL |= BIT4; //P1.4为A4通道
Voltage_Range = Range_15V; //Range_3V即量程为3V,Range_15V即量程为15V
ADC_Init(); //ADC初始化;
LCD_Init(); //液晶初始化
}
/*********************************************************
函数功能:ADC初始化
入口参数:无
出口参数:无
函数说明:无
*********************************************************/
void ADC_Init (void)
{
ADC10CTL0 &= ~ENC; //复位转换允许位
ADC10CTL0 |= ADC10ON + ADC10SHT_0 + SREF_0 + ADC10IE ;
//设置转换控制寄存器ADC10CTL0,ADC10ON=0x010,使ADC10内核工作
//ADC10SHT_0=0*0x800u,确定采样周期为4xADC10CLKs
//SREF_0=0*0x2000u,选择参考电压为VR+=AVCC,VR-=AVSS
//ADC10IE=0x00使对应通道转换后产生中断
ADC10CTL1 |= INCH_4 + CONSEQ_0;
//设置AD转换控制寄存器ADC10CTL1,INCH_0=0*0x1000u,选择通道A4
//CONSEQ_1=1*2u,设置工作模式为单通道、单次转换模式
ADC10CTL0 |= ENC + ADC10SC;
//设置转换控制寄存器ADC12CTL0,ENC=0x002使转换允许位为1
//ADC12SC=0x001使采样/转换控制位为1
_EINT(); //总中断使能
}
/***************************ADC中断函数****************************/
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_Interrupt(void)
{
uint data;
data = ADC10MEM; //将AD采样值存入data
if(Voltage_Range == Range_3V) //V(实际)=(VR+ - VR-)*data/1023 + VR-
Voltage = (uint)(35.4*data/10.23); //Voltage是实际电压值的1000倍
else
Voltage = (uint)(35.4*data/10.23*5.38);
}
/***************************WDT中断函数****************************/
#pragma vector = WDT_VECTOR
__interrupt void watchdog_timer(void)
{
LCD_Display(Voltage); //显示电压值
}
/*********************************************************
函数名称:LCD初始化函数
入口参数:无
出口参数:无
函数说明:无
*********************************************************/
void LCD_Init()
{
Delay_nms(5);
LCD_Send(0,0x01); //清屏指令
Delay_nms(5); //延时等待液晶完成复位
LCD_Send(0,0x30); //功能设定:基本指令集操作
Delay_nms(5);
LCD_Send(0,0x02); //地址归0
Delay_nms(5);
LCD_Send(0,0x0c); //开显示,且关闭光标及其反白显示
Delay_nms(5);
}
/*********************************************************
函数功能:写指令或数据
入口参数:type,transdata
出口参数:无
函数说明:无
*********************************************************/
void LCD_Send(uchar type,uchar transdata)
{
uchar firstbyte = 0xf8;
uchar temp,i,j;
if(type)
firstbyte |= 0x02;
P1OUT &= ~BIT1;
for(j=3;j>0;j--)
{
switch(j)
{
case 3:temp=firstbyte;break;
case 2:temp=transdata&0xf0;break;
case 1:temp=(transdata<<4)&0xf0;break;
}
for(i=8;i>0;i--)
{
if(temp&0x80)
P1OUT |= BIT0;
else
P1OUT &= ~BIT0;
P1OUT |= BIT1;
temp <<= 1;
P1OUT &= ~BIT1;
}
Delay_nms(1);
}
P1OUT &= ~BIT0;
}
/**********************定位函数************************/
void LCD_Pos(uchar x,uchar y)
{
int pos;
switch(x)
{
case 1:pos=0x80;break;
case 2:pos=0x90;break;
case 3:pos=0x88;break;
case 4:pos=0x98;break;
default:pos=0x80;
}
pos += y;
LCD_Send(0,pos);
}
/*********************************************************
函数功能:字符串显示函数
入口参数:*pt ,num
出口参数:无
函数说明:无
*********************************************************/
void LCD_Display_String(const uchar *pt,uchar num)
{
uchar i;
for(i = 0;i < (num*2);i++)
LCD_Send(1,*(pt++));
}
/*********************************************************
函数功能:数字显示函数
入口参数:num
出口参数:无
函数说明:无
*********************************************************/
void LCD_Display_Digit(long int num)
{
uint SHOW[7],i=0;
SHOW[0]=(num/10000)%10; //十位
SHOW[1]=(num/1000)%10; //个位
SHOW[2]=10; //.
SHOW[3]=(num/100)%10; //十分位
SHOW[4]=num/10%10; //百分位
SHOW[5]=num%10; //千分位
SHOW[6]=11; //V
switch(Voltage_Range)
{
case Range_3V: for(i=1;i<7;i++)
LCD_Send(1,LCD_Table[SHOW[i]]); break;
case Range_15V:for(i=0;i<7;i++)
{
if(i==5)++i;
LCD_Send(1,LCD_Table[SHOW[i]]);
} break;
default:break;
}
}
/***********************延时函数*************************/
void Delay_nms(uint n)
{
uchar i;
while(n--)
for(i=0;i<115;i++);
}
/*************************************************************
函数名称:显示函数
入口参数:Data
出口参数:无
函数说明:每行最多8个字,2个字母或数字相当于1个字的长度,注意
汉字没法跨格显示。
*************************************************************/
void LCD_Display(long int Data)
{
//LCD_Pos(1,0); //第一行
//LCD_Display_String("",0);
LCD_Pos(2,0); //第二行
LCD_Display_String(" 数字式电压表",7);
LCD_Pos(3,0); //第三行
LCD_Display_String("当前电压:",5);
LCD_Display_Digit(Data);
//LCD_Pos(4,0); //第四行
//LCD_Display_String(12.13);
}
/*********************************************************
函数名称:主函数
入口参数:无
出口参数:无
函数说明:请看完最上面程序说明再运行程序
*********************************************************/
void main()
{
System_Init();
while(1)
{
ADC10CTL0 |= ENC + ADC10SC; //开启ADC转换
}
}
展开阅读全文