单片机ADDA模块应用.docx
《单片机ADDA模块应用.docx》由会员分享,可在线阅读,更多相关《单片机ADDA模块应用.docx(18页珍藏版)》请在冰豆网上搜索。
单片机ADDA模块应用
单片微型计算机与接口技术
姓名:
王义鹏
班级:
15电气2班
学号:
123220150058
第一题:
ADDA
1.系统方案论证及方案选择
1.1总体设计方案
题目要求使用AD转换模块,将模拟信号的值转换为数值并通过液晶屏显示;使用矩阵键盘为输入,使其能够设置报警电压,并能够与AD转换值进行比较;使用DA模块通过矩阵键盘能够产生方波,并且能够调节占空比;
1.2方案论证与选择
1.2.1设计要求及思路
题目要求使用ADDA模块,将数字模拟量互相转换。
我们的设计主要控制是用单片机,它将测得模拟量通过AD模块的转换,在用ASCIl换算成数据显示在液晶屏上。
加入矩阵键盘可以设置报警电压,一旦检测AD模块转换的电压高于报警电压,蜂鸣器发出警报,液晶屏显示“warning”。
使用DA模块与矩阵键盘连接可以调试产生方波,且可以用按键设计占空比。
1.2.2方案论证与选择
芯片选择论证
方案一:
PCF8591T
PCF8591是一种具有I2C总线接口的8位A/D,D/A转换芯片,在与CPU的信息传输过程中仅靠时钟线SCL与数据线SDA就可以实现。
I2C总线是飞利浦公司推出的串行总线,它与传统的通信方式相比具有读写方便,结构简单,可维护性好,易实现系统扩展,易实现模块化标准化设计,可靠性高等优点;
在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。
PCF8591的功能包括多路模拟输入、内置跟踪保持、8-bit模数转换和8-bit数模转换。
PCF8591的最大转化速率由I2C总线的最大速率决定。
方案二:
ADC0809
ADC0809 是8位逐次逼近型A/D转换器。
它由一个8路模拟开关、一个地址锁存译码器、一个A/D 转换器和一个三态输出锁存器组成。
多路开关可选通8个模拟通道,允许8路模拟量分时输入,共用A/D转换器进行转换。
三态输出锁存器用于锁存A/D转换完的数字量,当OE端为高电平时,才可以从三态输出锁存器取走转换完的数据。
由于ADC0809芯片需要用到的引脚过多,单片机的接口不允许它占用这么多端口,而PCF8591芯片需要的端口较少并可长时间待机,所以我们选择方案一。
2.系统的软硬件
2.1主控制芯片STC89c51
STC89C51RC是采用8051核的ISP(InSystemProgramming)在系统可编程芯片,最高工作时钟频率为80MHz,片内含4KBytes的可反复擦写1000次的Flash只读程序存储器,器件兼容标准MCS-51指令系统及80C51引脚结构,芯片内集成了通用8位中央处理器和ISPFlash存储单元,具有在系统可编程(ISP)特性,配合PC端的控制程序即可将用户的程序代码下载进单片机内部,省去了购买通用编程器,而且速度更快。
STC89C51RC系列单片机是单时钟/机器周期(1T)的兼容8051内核单片机,是高速/低功耗的新一代8051单片机,全新的流水线/精简指令集结构,内部集成MAX810专用复位电路。
2.2矩阵键盘
矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组。
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。
在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。
由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。
2.3液晶显示
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。
它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。
在本次设计中使用液晶屏双行显示报警电压与实测电压,也显示方波的占空比。
2.4蜂鸣器
本次实验设计使用蜂鸣器作为报警器,蜂鸣器端口默认为高电平(即为1),不发出警报;当蜂鸣器端口为低电平(即为0)时,蜂鸣器即发出警报;
2.5数模转换模块
数模转换就是将离散的数字量转换为连接变化的模拟量。
与数模转换相对应的就是模数转换,模数转换是数模转换的逆过程。
D/A转换:
发送给PCF8591的第三个字节被存储到DAC数据寄存器,并使用片上D/A转换器转换成对应的模拟电压。
这个D/A转换器由连接至外部参考电压的具有256个接头的电阻分压电路和选择开关组成。
模拟输出电压由自动清零单位增益放大器缓冲。
这个缓冲放大器可通过设置控制寄存器的模拟输出允许标志来开户或关闭。
在激活状态,输出电压保持到新的数据字节被发送。
A/D转换:
A/D转换器采用逐次逼近转换技术。
在A/D转换周期将来临时片上D/A抓换器和高增益比较器。
一个A/D转换周期总是开始于发送一个有效读模式地址给PCF8591之后。
A/D转换周期在应答时钟脉冲的后沿被触发,并在传输前一次转换结果时执行。
一旦一个转换周期被触发,所选通道的输入电压采样将保存到芯片被转换为对应的8为二进制码。
3.系统操作显示流程图
开始
进入功能选择
进入DA模块
按下矩阵键盘的S21
按下矩阵键盘的S20
液晶屏显示方波占空比
进入AD模块
输入报警电压
被测电压大于报警电压
蜂鸣器发出警报,液晶屏显示被测电压+“warning”
液晶屏显示被测电压+“save”
结束
按下S18,占空比增加;按下S19占空比减少
结束
YES
NO
ADDA流程图
附件1说明书
按键布局
0
1
2
3
4
5
6
7
8
9
.
占空比+
占空比-
进入DA模块
进入AD模块
按键
功能
0~9.
设置最大电压值
占空比+
方波占空比高电平占有率+10%
占空比-
方波占空比低电平占有率+10%
进入DA模块
进入输出方波占空比设置
进入AD模块
进入AD模块比较电压值
使用说明:
1.上电显示
2.
3.7
按键按下可以测量的最大值如
3.7
x.xvsafe
3.按键按下“进入AD模块”屏幕显示
3.7
4.5vwarning
4.如果超出则显示,并且蜂鸣器发出警报。
3.7
2.5vsafe
5.如果未超出则显示
3.750
2.5vsafe
3.740
2.5vsafe
6.如果按下“进入DA模块”则显示
7.当按下“占空比+”显示
3.760
2.5vsafe
8.如果按下“占空比-”显示
附件2程序
#include
#include
#include
#defineOP_WRITE0x90//PCF8591地址
#defineOP_READ0x91
#defineucharunsignedchar
#defineuintunsignedint
sbitBEEP=P2^3;//蜂鸣器
sbitSDA=P2^0;//I2C串行数据
sbitSCL=P2^1;//I2C串行时钟
sbitRS=P1^0;
sbitRW=P1^1;
sbitEN=P1^2;
ucharK,Key;
charb[10]="vsafe";
doubleaa;
charpd,n,xsd,d=50,l=50;
chara[]="0123456789.";
uchartable1[10]="vwarning";
voiddelayNOP()
{
_nop_();_nop_();_nop_();_nop_();
}
voiddelay(unsignedchart)
{
chari;
while(t--)
for(i=0;i<125;i++);
}
voidstart()
{
SDA=1;
SCL=1;
delayNOP();
SDA=0;
delayNOP();
SCL=0;
}
voidstop()
{
SDA=0;
delayNOP();
SCL=1;
delayNOP();
SDA=1;
}
ucharshin()
//从AT24C02移出数据到MCU
{
uchari,read_data;
for(i=0;i<8;i++)
{
SCL=1;
read_data<<=1;
read_data|=SDA;
SCL=0;
}
return(read_data);
}
bitshout(ucharwrite_data)
//从MCU移出数据到AT24C02
{
uchari;
bitack_bit;
for(i=0;i<8;i++)//循环移入8个位
{
SDA=(bit)(write_data&0x80);//写数据,将R/W置1
_nop_();
SCL=1;
delayNOP();
SCL=0;
write_data<<=1;//左移1位,高位移出
}
SDA=1;//读取应答
delayNOP();
SCL=1;
delayNOP();
ack_bit=SDA;
SCL=0;
returnack_bit;//返回AT24C02应答位
}
voidwrite_byte(ucharaddr,ucharwrite_data)
//在指定地址addr处写入数据write_data
{
start();
shout(OP_WRITE);//发出写命令
shout(addr);//先输出地址
shout(write_data);//后写数据
stop();
delay(10);
//写入周期
}
ucharread_current()
//在当前地址读取
{
ucharread_data;
start();
shout(OP_READ);
read_data=shin();
stop();
returnread_data;
}
ucharread_random(ucharrandom_addr)
//在指定地址读取
{
start();
shout(OP_WRITE);
shout(random_addr);
return(read_current());
}
voidwcmd(ucharcmd)
{
RS=0;
RW=0;
P0=cmd;
delay(5);
EN=1;
delay(5);
EN=0;
delay(5);
}
voidwdat(uchardat)
{
RS=1;
RW=0;
P0=dat;
delay(5);
EN=1;
delay(5);
EN=0;
delay(5);
}
voidinit()
{
EN=0;
wcmd(0x01);
delay(5);
wcmd(0x06);
delay(5);
wcmd(0x0c);
delay(5);
wcmd(0x38);
delay(5);
}
unsignedchardata1_conve(unsignedchardat_temp)
{
unsignedchardata1;
data1=(unsignedchar)(((float)dat_temp/255)*5);//换算为电压值的个位值
data1=data1+48;//转换为对应的ASCII码,因为0对应ASCII码的48,以此类推
returndata1;
}
unsignedchardata0_convert(unsignedchardat_temp)
{
unsignedchardata0,data1;
data1=(unsignedchar)(((float)dat_temp/255)*5);//换算为电压值的个位值
data0=(unsignedchar)((((float)dat_temp/255)*5-data1)*10);//换算为为电压值的小数点后第一位的那个值
data0=data0+48;
returndata0;//转换为对应的ASCII码
}
unsignedcharKeycan(void)//按键扫描程序P3.0--P3.3为行线P3.4--P3.7为列线
{
unsignedcharrcode,ccode;
P3=0xF0;//发全0行扫描码,列线输入
if((P3&0xF0)!
=0xF0)//若有键按下
{
delay(3);//延时去抖动
if((P3&0xF0)!
=0xF0)
{rcode=0xFE;//逐行扫描初值
while((rcode&0x10)!
=0)
{
P3=rcode;//输出行扫描码
if((P3&0xF0)!
=0xF0)//本行有键按下
{
ccode=(P3&0xF0)|0x0F;
while((P3&0xF0)!
=0xF0);//等待键释放
return((~rcode)+(~ccode));//返回键编码
}
else
rcode=(rcode<<1)|0x01;//行扫描码左移一位
}
}
}
return0;//无键按下,返回值为0
}
voidKeyDeal(unsignedcharKey)
{
if(Key!
=0)
{
switch(Key)
{
case0x11:
K=0;break;
case0x21:
K=1;break;
case0x41:
K=2;break;
case0x81:
K=3;break;
case0x12:
K=4;break;
case0x22:
K=5;break;
case0x42:
K=6;break;
case0x82:
K=7;break;
case0x14:
K=8;break;
case0x24:
K=9;break;
case0x44:
K=10;xsd=1;break;
case0x84:
K=11;break;
case0x18:
K=12;if(l>10||l<100){d=d+10;l=l-10;}break;
case0x28:
K=13;if(d>10||d<100){l=l+10;d=d-10;}break;
case0x48:
K=14;pd=2;break;
case0x88:
K=15;pd=1;break;
default:
break;
}
if(K<10)
{
if(xsd==0)
aa=aa*10+K;
else
{
n++;
aa=aa+pow(0.1,n)*K;
}
}
if(K<=10)
{
wdat(a[K]);
}
}
}
voidmain()
{
ucharll,dd,i,j;
init();
wcmd(0x80);
SDA=1;
SCL=1;
while
(1)
{
Key=Keycan();
KeyDeal(Key);
//单端输入,读出通道0的值
if(pd==1)
{
wcmd(0xc0);
wdat(data1_conve(read_random(0x02)));
wcmd(0xc1);
wdat('.');
wcmd(0xc2);
wdat(data0_convert(read_random(0x02)));
if(((float)read_random(0x02)/255)*5>aa)
{
BEEP=0;
for(i=0;i<9;i++)
wdat(table1[i]);
}
else
{
BEEP=1;
for(j=0;j<9;j++)
wdat(b[j]);
}
delay(5);
}
if(pd==2)
{
ll=l;
dd=d;
wcmd(0x85);
wdat(ll/10);
wcmd(0x86);
wdat(ll%10)
while(l--)
write_byte(0x40,255);
while(d--)
write_byte(0x40,0);
}
}