全局变量:该变量在主函数外面定义
局部变量:在函数体内部定义
当子函数内部定义的变量,该变量的变量名和全局变量名相同并且类型相同时,在主函数调用该子函数时,该子函数的该变量有效,将全局变量屏蔽掉
D/A,数字量(Digital):例如直接从5V跳到0V;模拟量(Anolog):例如从5V缓慢变化到0V,有个变化的过程。
例子:1111 1111 对应 5v(或50mA)
1000 0000 对应 2.5v(或25mA)
0000 0000 对应 0v(或0mA)
当都接0时,从最右边的电阻依次并联算起,到最左边的2R电阻处再和右边全部的电阻(并联后也为2R)为R,所以Vref/R= I, Io2=1/2 I,Io1=0
当I7接0,其它接1时,I7处的电流为I7,I7右边的电流也为I7,所以Io2=1/2 I
当I7接1,当I6接1,先不看其它支路,Io1=(1/2 )*Vref/R+(1/2 *1/2 ) *Vref/R
以此类推,到最后全接1时Io1=Vref/R(1/2+1/2*1/2+……+1/2的八次方)
DAC0832,这里用直通方式,一种简单的方式会了其它方式照猫画虎就行
Vref为输入参考电压,这里IOUT2接地,IOUT1作为输出,当需要模拟电压时IOUT1接运算放大器并且连接Rfb(反馈电阻)
类似这样上面有横杠的表示低电平有效;上图中连线上连接与门的圆圈表示取反
CS表示片选信号,Chip Select
下载数据文档:Datasheet即数据文档网站:www.21ic.com-->左边的IC处填写”DAC0832”,“资料”-->下载Datasheet。www.alldatasheet.com
看资料芯片看串并行方式,接口说明,转换位数和转换速率,操作时序
www.maxim-ic.com,如果是并行的一次把数据都读走,但浪费I/O口
见dac0832资料,P5图,ts指不稳定的输出范围,之后稳定
选取DA时,要先知道设计的产品的运行速度,然后选取DA的转换速率,根据产品的精度选取DA的精度即位
串行MAX531的资料:DIN是数据输入端,SCLK是数据时钟,DOUT是输入电压,VDD是电源,VOUT是输出电压,REFIN是参考电压,AGND是接地
时序图中,网格表示无所谓高低电平,两个箭头包起来的数据表示有效数据,MAX531的资料P8中图Figure1:SCLK上升沿读走位(DIN)的数据,八个上升沿就读走八个位数据。
看这种资料主要看各个管脚怎么使用以及时序图
时序图中,阴影表示高低电平都可以;两个箭头包起来的数据表示有效数据,例如DIN
SCLK上升沿读走位(DIN)的数据,八个上升沿就读走八个位数据
DA资料中,看多少位,速度,管脚,时序图,有的接法不同,时序图就不同
找资料,根据资料设计电路,按资料上的器件接法连接,把资料上的电器件(如电阻的阻值,电容的法拉)都表示清楚,然后画Protel图,再做出PCB板子,拿到车间生产焊接再连接单片机就制作出来了。
见dac0832的PDF的P5,图中表示CS和ILE要先给低电平,然后WR给低电平,随后有效数据就传送过去,经过一小段时间稳定一下,IOUT1和IOUT2再进行有效输出
直通连接方式:直接送数据,IOUT1口就输出;结合TX-1C原理图看,赋给相应管脚低电平或高电平,结合DA接口.bmp看,DI0到DI7是数据口连接单片机的P0口,其它的为控制口或电源口,CSDA连接单片机的P3.2口(使用时要给低电平),WR连接单片机的P3.6口(使用时要给低电平);IOUT1口输出的P5的2和3用跳线帽(又叫短路子)短路,IOUT1输出的电流直接穿过发光二极管到地上,输出的数字量变化,那么输出的模拟量就变化,模拟量的变化体现在流过发光二极管上的电流,发光二极管就有明暗的变化可以判断有没有把DA操作起来,1口可以外接运算放大器;DA输出口的器件,当2和3短路后直接通过发光二极管接地
和赋给低电平
输出最高电压,点亮DA的灯,一上电P0口到P3口就输出最大值,所以开始DA的灯就亮:
#include<reg52.h>
sbit csda=P3^2;//注意csda(数模)和csad(模数)相区别
sbit wr=P3^6;
void main()
{
csda=0;
wr=0;
P0=0xff;//输出最高电压,P0=0时,关闭DA灯
while(1);
}
我的随笔程序:证明按照AD的时序图来操作是可以的,可以让片选CSDA高低电平变化,并且WR高低电平的变化:
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit csda=P3^2;//注意csda(数模)和csad(模数)相区别
sbit wr=P3^6;
sbit dula=P2^6;
sbit wela=P2^7;
uchar aa;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
while(1)
{
dula=0;
wela=0;
aa++;
if(aa==256)
aa=0;
csda=0;
wr=0;
P0=aa;//输出最高电压,P0=0时,关闭DA灯
delay(5);
wr=1;
csda=1;
delay(5);
}
}
DA灯由灭到逐渐变到最亮,时间2s,由最亮到逐渐变暗到灭,时间2s
我的程序:
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit csda=P3^2;
sbit wr=P3^6;
sbit wela=P2^7;
uchar flag;
int aa,bb,cc;
void init()
{
csda=0;
wr=0;
P0=0;
TMOD=0x01;
TH0=(65536-7812)/256;
TL0=(65536-7812)%256;
EA=1;
ET0=1;
TR0=1;
wela=1;
P0=0xff;
wela=0;
bb=255;
}
void main()
{
init();
while(1)
{
P0=cc;
}
}
void timer0() interrupt 1
{
if(flag==0)
{
TH0=(65536-7812)/256;
TL0=(65536-7812)%256;
aa++;
if(aa==256)
{
aa=0;
flag=1;
}
cc=aa;
}
if(flag==1)
{
TH0=(65536-7812)/256;
TL0=(65536-7812)%256;
bb--;
if(bb==-1)
{
bb=255;
flag=0;
}
cc=bb;
}
}
DA灯亮灭变化的同时发光二极管做加法变化:
#include<reg51.h>
sbit wela=P2^7;
sbit dula=P2^6;
sbit dawr=P3^6;
sbit csda=P3^2;
unsigned char a,j,k;
void delay(unsigned char i)
{
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
void main()
{
wela=0;
dula=0;//因为下面控制P1口,段选和位选给零,不让数码管干扰
csda=0;
a=0;
dawr=0;
while(1)
{
P0=a;
P1=~a;
delay(50);
a++;
}
}
A/D:例如把0到8V电压分成百位就是全部量化分配到0到255
用的最多的是逐次逼近式和双积分式
见PPT的P16:VIN模拟量的输入端,EOC(End Of Convert)转换结束(输出一个信号,告诉转换结束,可以把数据读走),倒三角是比较器,OE(Output Enable)是使能端,D/A转换器有A/D转换的功能
倒三角是比较器,倒三角上面的线(带圆圈的是上面)输出比下面高输出就是1,上面的线输出比下面低输出就是0;图中最右边,从右向左看,先将作为参考电压,这里将八位D/A转换器的最高位先置1,通过D/A转换器后的对应电压是 = /2,输出电压为 = /2,与 比较,如果大,则置1到N位寄存器最高位并传给D/A转换器,如果小,则置0到N位寄存器最高位并传给D/A转换器和锁存缓存器,再在D/A转换器的第二位置1,进行判断,如此类推,进行八次后,EOC口输出一个信号给单片机,告诉转换结束,单片机收到EOC信号后给OE一个低电平再将数据读走
见dac0832资料P1的典型管脚连线图,11到18管脚是数据口(TX-1C型单片机实验板原理图中的DB1到DB8),用来送数据,接单片机的P1口;INTR是中断口,当芯片转换完给单片机一个中断,要接单片机的外部中断(P3.2口或P3.3口),开发板中AD转换器没;使用中断,就是过段时间去读,肯定能转换完;RD和WR接单片机的RD和WR,即单片机的P3.6口和P3.7口;CS即片选,接锁存器(控制数码管位选的那个锁存器)的CSAD;VCC接5V电压;CLK R和CLK IN接管脚19和4是一个RC振荡电路,作用是提供频率让A/D转换;VIN(+)和VIN(-)采集电压,组成差分电路,输出差分信号,两条电路用来比较,可以采集桥式电路(见下图,可以做电子秤,上面的支路的第一个电阻是滑动电阻,两条并联的支路的两个电阻之间的导线连在VIN(+)和VIN(-)上,得到的压差来得出压力值);A GND表示模拟电压地端,D GND表示数字电压地端,之所以分开是防止它俩有干扰;Processor是处理器,即单片机(51,arm等);AD转换器在开发板中的电源灯下面,ADIN在AD转换器的左侧,即有跳线帽的,为了扩展,可能接模拟输入端,开发板中将其1和2短路,上面的滑动变阻器对应开发板中AD转换器的右边,可以调节上面的旋钮,ADIN的1连接着AD转换器的6管脚,6管脚下面的7管脚接地,所以6管脚就能检测到0到5伏之间的变化,ADIN的1管脚和AD转换器的6管脚之间的10k电阻是限流电阻,保护不被击穿,但电压是不会变的;AD转换器的9管脚是, 即,开发板上用两个1K电阻分成2.5V
见P5的时序图,第一个图是开始转换,CS给低电平,WR在CS低电平期间给个低脉冲,即在CS给低电平之后稍过一段时间WR给个低脉冲,实际内部转换状态(Actual Internal Status Of The Converter)的BUSY表示AD转换过程,转换完INTR给个低电平通知中断,实际内部转换状态和INTR可以不用程序实现,只是表示转换过程;第二个图是读取数据,如果要AD转换器一直工作就让CS一直置0;中断INTR通知后,给RD一个低电平,在RD低电平到高电平变化的瞬间把数据读走,开发板上不用中断,所以不用考虑中断;程序中就让RD为高,变低,再为高,读走数据,即送到P1口;AD转换器的CSAD连接着锁存器,程序中直接控制锁存器就行
开发板中的AD转换器的数据口也连接着发光二极管,设计一个程序,就不停的启动读,数字量变化八个发光二极管就亮灭变化
见ad0804的PDF的P18,是内部工作频率,八个数据全转换完需要八个,R=10K,C=145PF,由公式可得,开发板上的C很大,所以程序启动后要等一会再读数字
利用AD转换器动态显示发光二极管:
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit wr=P3^6;
sbit rd=P3^7;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void init();
void start();
void main()
{
init();
while(1)
{
start();
delay(20);
rd=0;//rd低电平才能读数据,见时序图
delay(10);//一定要延时一会将数据读走再将rd变高电平,见上面的总结
rd=1; //rd高电平为了下次变低电平后读数据
delay(10);
}
}
void init()
{
P0=0;//即将csad赋给0,A/D转换器被选用
}
void start()
{
wr=1;//见0804的资料上的时序图,启动AD转换
wr=0;
wr=1;
}
A/D转换器的数据口接在DB1到DB8上,DB1到DB8连在发光二极管上,所以A/D转换器的数据口有数据输出,发光二极管也会亮
旋转AD转换器右边的电位器的旋钮,发光二极管的亮度会变化。
TX-1C型单片机实验板原理图中单片机和数码管中间的是USB设备开发芯片,右边是USB下载接口,晶振下面是复位电路,复位电路下面是DS18B20是数字温度传感器,DS18B20下面是串口,串口那,电容处的104表示10* PF(皮法),103是10*PF,180是18*;电阻4K7是4.7K,5R8是5.8欧姆;封装(电阻,电容封装方式):0805,还有1206封装,3216封装,0604封装,0302封装(数字越小封装越小);键盘下面的P6到P9是扩展口(下面标明了对应的P0、P1、P2和P3),即开发板上单片机左右的两排针;扩展口的右边是EEPROM,再右边是1602液晶接口,再右边是1280液晶接口;晶振右边是下载程序的指示灯,键盘上面是AD转换器
开发板上,黄色的是电容,黑色的是电阻
课件练习:
将AD模拟数字的模拟量读回来,转换成十进制数显示在数码管的前三位上,0到255:
我的程序:
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar bai,shi,ge,temp;
sbit dula=P2^6;
sbit wela=P2^7;
sbit wr=P3^6;
sbit rd=P3^7;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,
0x76,0x79,0x38,0x3f,0
};
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void start()
{
wela=1;
P0=0;
wr=0;//下面不能加延时程序delay(10),一旦加入延时,wela=1;P0=0;这两句就把数码管//打开,让八个数码管一起显示,而没有延时,刚打开数码管就wela=0关闭就不会出现八个//数码管一起显示
wr=1;
P0=0xff;
delay(10);
wela=0;
}
void display(uchar aa,uchar bb,uchar cc)
{
dula=1;
P0=table[aa];
dula=0;
P0=0xff;
wela=1;
P0=0xfe;
wela=0;
delay(10);
dula=1;
P0=table[bb];
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
delay(10);
dula=1;
P0=table[cc];
dula=0;
P0=0xff;
wela=1;
P0=0xfb;
wela=0;
delay(10);
}
void init()
{
P0=0;
}
void main()
{
init();
while(1)
{
start();
delay(20);
wela=1;//必须有这句,否则会出错,现象是只显示255,因为上次存储器锁存的是//P0=0xff,如果不打开wela,锁存器仍然锁存0xff,而不会把新的P0值存入并显示
P1=0xff;
P0=0;
rd=0;
temp=P1;
rd=1;
P0=0xff;
P1=temp;
delay(20);
display(temp/100,temp%100/10,temp%10);
}
}
课件的程序:
#include<reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit adrd=P3^7; //IO口定义
sbit adwr=P3^6;
sbit diola=P2^5;
sbit dula=P2^6;
sbit wela=P2^7;
unsigned char j,k,adval;
void delay(unsigned char i) //延时程序
{
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, //数码管编码
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void display(uchar bai_c,uchar sh_c,uchar g_c) //显示程序
{
P0=table[bai_c]; //显示百位
dula=1;
dula=0;
P0=0xfe;
wela=1;
wela=0;
delay(5);
dula=0;
P0=table[sh_c]; //显示十位
dula=1;
dula=0;
wela=0;
P0=0xfd;
wela=1;
wela=0;
delay(5);
P0=table[g_c]; //显示个位
dula=1;
dula=0;
P0=0xfb;
wela=1;
wela=0;
delay(5);
}
void main() // 主程序
{
uchar a,A1,A2,A2t,A3;
while(1)
{
wela=1;
P0=0; //选通ADCS
adwr=0; //AD写入(随便写个什么都行,主要是为了启动AD转换)
_nop_();
adwr=1;
P0=0xff; //关闭ADCS
delay(10);
wela=0; //关闭有AD片选信号锁存器的锁存端以防止在操作数
//码管时使AD的片选发生变化
for(a=20;a>0;a--) //需要注意的是ADC0804在写和读之间的时间间隔要足够//长否则无法读出数据
{ //这里把显示部分放这里的原因也是为了增加写读之间//的时间间隔
display(A1,A2,A3);
} //送去显示各位。
wela=1; //重新打开有AD片选信号锁存器的锁存端
P1=0xff; //读取P1口之前先给其写全1
P0=0; //选通ADCS
adrd=0; //AD读使能
adval=P1; //AD数据读取赋给P1口
adrd=1;
P0=0xff; //关闭ADCS
adwr=0;
P1=adval; //同时把AD的值送八个发光二极显示
A1=adval/100; //分出百,十,和个位
A2t=adval%100;
A2=A2t/10;
A3=A2t%10;
};
}
将AD的值读回来,赋给DA,即调节AD的电位器时,DA对应的发光二极管也会发生变化:
我的程序:
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit adwr=P3^6;
sbit adrd=P3^7;
sbit dula=P2^6;
sbit wela=P2^7;
sbit csda=P3^2;
uchar temp;
void delay(uchar z)
{
uchar x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void init()
{
temp=0;
P0=0;
}
void start()
{
P0=0;
adwr=0;
adwr=1;
P0=0xff;
}
void admode()
{
csda=0;
adwr=0;
//temp=P1;
delay(1);//调试的时候,由于我不能确定P0是否被赋值为temp,这里可以添加一句//temp=0xfd,再调试中下面的语句csda=1加断点,看看P0是否等于temp,如果是说明AD
//转换器的输出值temp确实被DA转换器读入,并将此值送给P0来控制DA转换器的发光//二极管
P0=temp;
csda=1;
delay(10);
}
void main()
{
init();
while(1)
{
start();
delay(10);
P1=0xff;
P0=0;
adrd=0;
temp=P1;
adrd=1;
P0=0xff;
delay(20);
P1=temp;//发光二极管亮,可以判断AD转换器是否起作用
admode();
}
}