**实现功能:**双机都能控制彼此的电位器模块开启与关闭(单片机为普中科技89C51单片机)
**连线:**P31接P30,P30接P31;
实验原理:
1.AD模数转换电路原理图:
2.AD模数转换器的主要技术指标:
①分辨率
ADC的分辨率是指使输出数字量变化一个相邻数码所需输入模拟电压的变化量。常用二进制的位数表示。例如12位ADC的分辨率就是12位,或者说分辨率为满刻度的1/(2^12)。
②量化误差
ADC把模拟量变为数字量,用数字量近似表示模拟量,这个过程称为量化。量化误差是ADC的有限位数对模拟量进行量化而引起的误差。
③偏移误差
偏移误差是指输入信号为零时,输出信号不为零的值,所以有时又称为零值误差。假定ADC没有非线性误差,则其转换特性曲线各阶梯中点的连线必定是直线,这条直线与横轴相交点所对应的输入电压值就是偏移误差。
④满刻度误差
满刻度误差又称为增益误差。ADC的满刻度误差是指满刻度输出数码所对应的实际输入电压与理想输入电压之差。
⑤线性度
线性度有时又称为非线性度,它是指转换器实际的转换特性与理想直线的最大偏差。
⑥绝对精度
在一个转换器中,任何数码所对应的实际模拟量输入与理论模拟输入之差的最大值,称为绝对精度。对于ADC而言,可以在每一个阶梯的水平中点进行测量,它包括了所有的误差。
⑦转换速率
ADC的转换速率是能够重复进行数据转换的速度,即每秒转换的次数。而完成一次A/D转换所需的时间(包括稳定时间),则是转换速率的倒数。
3.控制字描述:
即在本次实验中,我要检测转换电位器模拟信号,控制字命令寄存器值为0X94。
4.时序图:
在时序图中可以看出,我们要先写入再读取,写入前要将时钟信号拉低,并且读取的是12bit的数据;
C语言代码:
①shuangji.c
#include "reg52.h"
#include"XPT2046.h"
#define uchar unsigned char
#define uint unsigned int
sbit LSA=P2^2;//数码管使能
sbit LSB=P2^3;
sbit LSC=P2^4;
sbit K3=P3^2; //独立按键
sbit K4=P3^3;
uchar flag; //存储接受的指令
uchar disp[4];
uchar code smgduan[10]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //数码管显示
void delay(uint i)
{
while(i--);
}
void datapros()
{
uint temp;
static uchar i;
if(i==50)
{
i=0;
temp = Read_AD_Data(0x94); // AIN0 电位器
}
i++;
disp[0]=smgduan[temp/1000];//千位
disp[1]=smgduan[temp%1000/100];//百位
disp[2]=smgduan[temp%1000%100/10];//个位
disp[3]=smgduan[temp%1000%100%10];
}
void DigDisplay()
{
uchar i;
for(i=0;i<4;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=1;LSB=1;LSC=1; break;//显示第0位
case(1):
LSA=0;LSB=1;LSC=1; break;//显示第1位
case(2):
LSA=1;LSB=0;LSC=1; break;//显示第2位
case(3):
LSA=0;LSB=0;LSC=1; break;//显示第3位
}
P0=disp[i];//发送数据
delay(100); //间隔一段时间扫描
P0=0x00;//消隐
}
}
void UART_INIT(){
SCON=0x50;//设定串口工作方式0101 0000
PCON=0x00;//设置了SMOD,波特率不翻倍
TMOD=0x20;//设置定时器1方式二
EA=1;//开中断
ES=1;//允许串口1发起中断
TL1=0xfd;//波特率9600
TH1=0xfd;
TR1=1;//定时器1开始计时
}
void main(){
UART_INIT();
while(1){
uchar i;
if(K3==0){
SBUF=0x00; //发送0x00给单片机2
}else if(K4==0){
SBUF=0x01; //发送0x01给单片机2
}
switch(flag) //接收到0x00开启电位器,0x01关闭电位器
{
case(0x00): //开启电位器
datapros();
DigDisplay();
break;
case(0x01): //关闭电位器
for(i=0;i<4;i++)
{
disp[i]=0;
}
break;
}
}
}
//串口中断
void Interrupt_Receive() interrupt 4
{
if(TI==1) TI=0;
if(RI==1)
{
RI=0;
flag=SBUF;
}
}
②XPT2046.c
#include"XPT2046.h"
void SPI_Write(uchar dat) //写数据
{
uchar i;
CLK = 0;
for(i=0; i<8; i++) //先写高位,再写低位
{
DIN = dat >> 7; //放置最高位
dat <<= 1; //左移一位,从最高位放起
CLK = 0; //上升沿放置数据
CLK = 1;
}
}
uint SPI_Read(void) //读数据
{
uint i, dat=0;
CLK = 0;
for(i=0; i<12; i++) //接收12位数据
{
dat <<= 1; //读取最高位
CLK = 1;
CLK = 0;
dat |= DOUT; //DOUT数据输出管脚
}
return dat;
}
uint Read_AD_Data(uchar cmd)
{
uchar i;
uint AD_Value;
CLK = 0; //拉低时钟信号再开始写入
CS = 0; //拉低片选信号
SPI_Write(cmd); //写一个字节
for(i=6; i>0; i--); //延时一个时钟周期,等待转换结果
CLK = 1; //发送一个时钟周期,清除BUSY
_nop_();
_nop_();
CLK = 0;
_nop_();
_nop_();
AD_Value=SPI_Read(); //返回的是12位的数据,想要显示电压还需要进行处理
CS = 1; //拉高片选信号,停止传输数据
return AD_Value;
}
流程框图:
①主函数:
②延时函数:
③数据接收转换函数(datapros):
④数码管显示函数: