因为这学期的课程设计我做了这个测量放大器,并且给他加上了单片机的功能以及串行通信的功能,可以说是非常全面的。
刚开始的时候是放大1000倍,然后放大1000倍的数值可以在单片机中显示。然后我们通过第一模块对他进行筛检,并且通过五个按键实现零到1000倍的衰减衰减后再通过D A C输出。整个过程,我们在测量放大器的基础上做了很多的改进单片机程序相对复杂,然后再试相比来说我们用了七天的时间。还是挺成功的
总体电路图
对应的单片机部分程序:
#include<reg51.h>
#include "lcd.h"
#include<absacc.h>
#define DAC1208 XBYTE[0X7FFF]
#define uint unsigned int
#define uchar unsigned char
#define ulong unsigned long
sbit k2 = P3^2;
sbit k3 = P3^3;
sbit k4 = P3^4;
sbit k5 = P3^5;
sbit relay=P2^4;
sbit relayAD=P3^7;
char temp=-1;
int cent;
ulong volt;//测量的电压值
ulong sum;
uchar mode,a,b,y=0,t=0,y1=0,t1=0,y2=0,t2=0,abs=5;
uchar KEY_Scan(uchar mode);
uchar timebit[5],multiplebit[5];
uchar vol_buf[7],multiple_buf[5],out_buf[7];
uint multiple=500;
char time=-1;
void delay1us(uint i);
void communication();
void kai_display();
void kai_display1();
void count();
void display1();
void display();
uint vtime; // 用来控制测量地址位的改变
uchar addr;//测量地址位,指示测量的是哪一个模拟值 (其实就是TLC2543的控制字)
sbit CLK=P2^3;//定义时钟信号口
sbit DIN=P2^1;//定义2543数据写入口
sbit DOUT=P2^0;//定义2543数据读取口
sbit CS=P2^2;//定义2543片选信号口
void delay1us(uint i)
{
while(i--);
}
/**********************************************************/
//函数名:read2543(uchar addr)
//功能:2543驱动程序
//调用函数:
//输入参数:addr
//输出参数:
//说明:进行ad转换将结果存于volt变量中 addr为测量位地址
/**********************************************************/
void read2543(uchar addr) //读取数值volt是被缩小两倍的电压
{
uint ad=0;
uchar i;
CLK=0;
CS=0;//片选段,启动2543
addr<<=4;//对地址位预处理
for(i=0;i<12;i++) //12个时钟走完,完成一次读取测量
{
if(DOUT==1)
ad=ad|0x01;//单片机读取ad数据
DIN=addr&0x80;//2543读取测量地址位
CLK=1;
;;;//很短的延时
CLK=0;//产生下降沿,产生时钟信号
;;;
addr<<=1;
ad<<=1;//将数据移位准备下一位的读写
}
CS=1;//关2543
ad>>=1;
volt=ad;//取走转换结果
volt=volt*1221*2;//例子的满量程为5V,转换分辩率为12位(2的12次方=4096) 。即最大值是255,5/4096=1221mV,即例子中的1V代表实际1221mV
}
void communication()
{
if(RI != 0)
{
RI = 0; //接收收据后进行清0
temp = SBUF; //读取数据存入temp中
}
if(temp==0)
{
time=0;//选择相应的指令
abs=0;
temp=-1;
}
else if(temp==1)
{
time=1;
abs=1;
temp=-1;
}
else if(temp==2)
{
time=2;
abs=2;
temp=-1;
}
else if(temp==3)
{
time=3;
temp=-1;
}
else if(temp==4)
{
time=4;
temp=-1;
}
}
#define K0 0
#define K1_MODE 1
#define K2_ADD 2
#define K3_DEC 3
#define K4 4
uchar KEY_Scan(uchar mode)
{
uchar key=1;
if(key&&(time>=0&&time<=4))
{
key=0;
if(time==0)
{
return K0;
}
else if(time==1)
{
return K1_MODE;
}
else if(time==2)
{
return K2_ADD;
}
else if(time==3)
{
return K3_DEC;
}
else if(time==4)
{
return K4;
}
}
else if(time>=5&&time<=-1)
{
key=1;
}
if(a)
{
key=1;
}
return 5;
}
void kai_display()
{
LCD_Dispstring(0,0,"WangZheng And");
LCD_Dispstring(0,1,"GuoXuKang's Work");
}
void kai_display1()
{
uchar key;
key=KEY_Scan(0);
if(key==K4||b==K4) //模式选择 直流
{
relay=1;
relayAD=1;
display();
b=K4; //便于按一次直流,之后一直是直流
LCD_Dispstring(2,0,"DIR: V");
LCD_Dispstring(0,1,"M: O: V");
}
if(key==K3_DEC||b==K3_DEC) //交流档位
{
relay=0;
relayAD=0;
display1();
b=K3_DEC;
LCD_Dispstring(2,0,"ALT: V");
LCD_Dispstring(0,1,"M: O: V");
}
}
void display()//直流显示
{
ulong invol;
float ivol;
count();
ivol=(volt*1.000*multiple)/1000;
invol=(long)ivol;
vol_buf[0]=volt/10000000+0x30;
vol_buf[1]=volt/1000000+0x30;
vol_buf[2]='.';
vol_buf[3]=(volt/100000)%10+0x30;
vol_buf[4]=(volt/10000)%10+0x30;
vol_buf[5]=(volt/1000)%10+0x30;
vol_buf[6]='\0';
multiple_buf[0]=multiple/1000+0x30;
multiple_buf[1]=multiple/100%10+0x30;
multiple_buf[2]=multiple/10%10+0x30;
multiple_buf[3]=multiple%10+0x30;
multiple_buf[4]='\0';
out_buf[0]=invol/10000000+0x30;
out_buf[1]=invol/1000000+0x30;
out_buf[2]='.';
out_buf[3]=(invol/100000)%10+0x30;
out_buf[4]=(invol/10000)%10+0x30;
out_buf[5]=(invol/1000)%10+0x30;
out_buf[6]='\0';
LCD_Dispstring(6,0,vol_buf);
LCD_Dispstring(2,1,multiple_buf);
LCD_Dispstring(8,1,out_buf);
}
void display1()//交流显示
{
ulong invol,trans;
float ivol;
count();
trans=volt*0.825;
ivol=(volt*0.825*multiple)/1000;
invol=(long)ivol;
vol_buf[0]=trans/10000000+0x30;
vol_buf[1]=trans/1000000+0x30;
vol_buf[2]='.';
vol_buf[3]=(trans/100000)%10+0x30;
vol_buf[4]=(trans/10000)%10+0x30;
vol_buf[5]=(trans/1000)%10+0x30;
vol_buf[6]='\0';
multiple_buf[0]=multiple/1000+0x30;
multiple_buf[1]=multiple/100%10+0x30;
multiple_buf[2]=multiple/10%10+0x30;
multiple_buf[3]=multiple%10+0x30;
multiple_buf[4]='\0';
out_buf[0]=invol/10000000+0x30;
out_buf[1]=invol/1000000+0x30;
out_buf[2]='.';
out_buf[3]=(invol/100000)%10+0x30;
out_buf[4]=(invol/10000)%10+0x30;
out_buf[5]=(invol/1000)%10+0x30;
out_buf[6]='\0';
LCD_Dispstring(6,0,vol_buf);
LCD_Dispstring(2,1,multiple_buf);
LCD_Dispstring(8,1,out_buf);
}
void count()
{
if(multiple<=999&&multiple>=0)
{
if(abs==0)
{
multiple++;
if(multiple%10==9||t==1)
{
y++;
t=1; //到9后下一次变为0
if(y==2)
{
t=0;
multiple=multiple-10;
y=0;
}
}
abs=5;
}
if(abs==1)
{
multiple=multiple+10;
if((multiple/10%10==9)||t1==1)
{
y1++;
t1=1;
if(y1==2)
{
t1=0;
multiple=multiple-100;
y1=0;
}
}
abs=5;
}
if(abs==2)
{
multiple=multiple+100;
if((multiple/100==9)||t2==1)
{
y2++;
t2=1;
if(y2==2)
{
t2=0;
multiple=multiple-1000;
y2=0;
}
}
abs=5;
}
}
if(multiple<0)//y用来监视从1减小,然后维持,最小为0
{
multiple=0;
}
if(multiple>999)//y用来监视从1减小,然后维持,最小为0
{
multiple=999;
}
}
void main(void)
{
LCD_Init(); //LCD初始化
kai_display();//最初显示
delay1us(50);
LCD_Clear();//清除
TMOD = 0x22; //设置定时器T1为方式2
TH1 = 0xfd;
TL1 = 0xfd;
TH0=0x06;
TL0=0x06;
EA=1;
ET0=1;
TR0=1;
SCON = 0x50; //设置串口为方式1接收,REN = 1
PCON = 0x00; //SMOD = 0;,波特率不加倍
TR1 = 1; //开启定时器T1
TI = 1;
relay=0;
relayAD=0;
while(1)
{
read2543(addr);//调用2543驱动程序测量地址为0
communication();
kai_display1();
}
}
void DA_OUT(int i)
{
int num,num1,num2;
num=i*4.099*8;
num=num>>3;
num1=num>>8;
num2=num&0xff;
DAC1208=num2;
k2=num1&0x01;
k3=num1&0x02;
k4=num1&0x04;
k5=num1&0x08;
}
void f1 () interrupt 1
{
cent++;
if(cent==5000)
{
cent=0;
DA_OUT(multiple);
}
}