首页 > 编程知识 正文

51单片机adc0809模数转换(单片机 ADC0809模数转换实验)

时间:2023-05-04 12:26:02 阅读:121993 作者:1045

电路图如下。

1、简单描述ADC0809工作过程

ADC0809工作流程:

)1)通道地址发送到ADDA~ADDC,选择一个模拟输入端子。

)2)在信道地址信号有效的同时,ALE上的上升沿将该地址锁存在内部地址锁存器中。

)3)在START引脚的下降沿开始A/D转换。

)4)转换开始后,EOC引脚变为低电平,EOC再次变为高电平时,表示转换结束。

)5) OE信号打开输出锁存器的三态门,发送转换结果。

http://www.Sina.com/http://www.Sina.com /

1、首先程序开头:头文件twdqc、宏定义、端口定义、函数twdqc、变量定义

2、然后是主程序。 在main ()函数中,首先初始化LCD1602显示器和计时器0,然后在while循环中输入转换通道数,开始转换并显示转换结果。

3、子函数的定义

3.1输入转换通道编号的函数ADC_channel(bitac、bit ab、bit aa ) ——对ADDC~ADDA分配值,选择模拟输入端子。

3.2 ADC转换函数在ADC_change(void ) ——START下降沿开始转换,如果查询EOC为1,则表示ADC0809的输出数据连接到P0端口。

所以在OE信号被设置为1之后,开始读取P0端口,将读取的数据分配给adc_data,最后OE被设置为0。

3.3定时器0控制ADC的CLK信号——采用定时器0的初始化time_init (:方式1,周期为200,启动定时器0,接通中断分开关和中断主开关; 计时器0中断函数——采用方式1,因此手动提供初始值,然后反转clk信号输出方波。

3.4 LCD显示信息函数display_data(ucharinput )——显示器的第一行显示转换数据的一百个、十个比特,其中每一个比特通过使用dis_char函数被显示。 第2行表示输入电压值,用公式Vin=D500/256将转换数据转换为电压值。 **请注意,此时将Voltage的数据类型定义为long型。 因为int类型计算D500可能会溢出超过65536。 *最后,使用dis_char函数显示电压的整数位和小数点后两位。

3.5之后的延迟函数delay(uintj )、忙函数check _ busy (void )、写控制命令函数write _ command (uchar com )、写数据命令函数write _ data (uccccom ) 请不要说uchar *s )、输出字符函数dis_char ) ucharad、uchar input )是LCD1602显示器上的一系列函数。

2、在LCD1602上实现采样电压值的显示,输出参考下图(可自定义显示格式,但必须显示实际电压,精确到0.01V),修改程序。

/**功能描述:程序运行后,实现ADC通道的数据采样,并将采样结果发送到液晶屏,* */# includereg 52.h # includeintrins.h # include stdio 显示defineuintunsignedint#的efineADC_data_portP0/********端口定义* * * * * * * * * * * * * * * * * * * * *。 sbit e=P2^2; sbit ADCCLK=P2^6; sbit START=P2^3; sbit EOC=P2^4; sbit OE=P2^5; sbit ADDA=P3^0; sbit ADDB=P3^1; sbit ADDC=P3^2; /******函数twd QC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */void check _ busy voidwrite_data(uchardat; voidLCD_initial(void; 语音字符串(uchar *s,uchar *s ); voiddis_char(ucharad,uchar input; void display _ data (uchar输入; voidLCD_test(void; 语音延迟(uint; voidADC_change(void; voidADC_Channel(bitAC、bit ab、bit aa ); void time_init (; uchar adc_data=0;//存储ADC转换结果的/* * * * * * * * * * * * * * * * * * * * * * * * * */void main (void ) { LCD_initial ); //LCD1602初始化time_init (; while(1) ADC _ channel (0,0,1 );

adc_change(); display_data(adc_data); delay(500); }}//输入转换通道号void adc_channel(bit ac,bit ab,bit aa){ ADDC=ac; ADDB=ab; ADDA=aa;}//开始转换void adc_change(void){ OE=0; START=0; START=1; START=0; while(EOC==0); adc_data_port=0x0ff; OE=1; adc_data=adc_data_port; OE=0;}//定时器0控制ADC的CLK信号void time_init(){TMOD=0x01;TH0=(65536-200)/256;TL0=(65536-200)%256;ET0=1;EA=1;TR0=1;}void timer0()interrupt 1{TH0=(65535-200)/256; TL0=(65535-200)%256; ADCCLK=~ADCCLK;}//LCD显示信息void display_data(uchar input){ long voltage;dis_char(0x0d,input/100+0x30);dis_char(0x0e,input/10%10+0x30);dis_char(0x0f,input%10+0x30);voltage = input;voltage = voltage*500/255;dis_char(0x4a,voltage/100+0x30);dis_char(0x4b,'.');dis_char(0x4c,voltage/10%10+0x30);dis_char(0x4d,voltage%10+0x30);dis_char(0x4e,'V');}//1ms延时程序void delay(uint j){uchar i=250;for(;j>0;j--){while(--i);i=249;}}//查忙程序void check_busy(void){uchar dt;do{dt=0xff;e=0;rs=0;rw=1;e=1;dt=lcd_out;}while(dt&0x80);e=0;}//写控制指令void write_command(uchar com){check_busy();e=0;rs=0;rw=0;lcd_out=com;e=1;_nop_();e=0;delay(1);}//写数据指令void write_data(uchar dat){check_busy();e=0;rs=1;rw=0;lcd_out=dat;e=1;_nop_();e=0;delay(1);}//液晶屏初始化void LCD_initial(void){write_command(0x38);//8位总线,双行显示,5X7的点阵字符write_command(0x0C);//开整体显示,光标关,无黑块write_command(0x06);//光标右移write_command(0x01);//清屏delay(1);string(0x00,"ADC0809 ch1="); //显示字符串string(0x40,"Voltage = "); //显示字符串}//输出字符串void string(uchar ad,uchar *s){write_command(ad+0x80); //ad是显示位置信息while(*s>0){write_data(*s++);delay(100);}}// 输出字符void dis_char(uchar ad, uchar input){write_command(ad+0x80);write_data(input);delay(10);}

3、利用定时器1的定时中断,实现ADC通道3每隔1s转换一次,并将模拟电压值送LCD1602显示。

编程思路:
大体思路和第二问差不多。所以这里只说不同点。

这里增加了一个定时器1控制通道3转换时间为1s。

1、首先对定时计数器1进行初始化,因为要控制通道3的转换时间为1s=200us*5000。
所以利用定时器1的方式2,这时一定要注意!!! 因为Timer1工作在方式2,Timer0工作在方式1,所以在选择模式的时候一定要一起配置,即TMOD=0x21(如果分开在各自的子函数里面初始化TMOD=0x20,TMOD=0x01就会出错)。溢出周期为200,设置初值TH1=0-200,TL1=0-200。然后PT1=0(低级),这是因为定时器0中断控制ADC的CLK信号,所以PT0=1(高级)。程序里面有两个中断,最好分下高低级。最后启动定时器1,打开中断分开关和中断总开关。

2、定时器1中断函数里面来进行counter的软件计数,中断一次counter++。转换在主程序里面做,避免中断耗时太长。

3、主函数main() 先配置T0,T1的模式,TMOD=0x21,然后对LCD1602、T0和T1进行初始化。在while循环里面,先输入通道数,然后对中断函数中counter进判断,如果counter==5000,就开始AD转换,并把counter清零,同时也把数字和电压清屏,在显示器上给人一种1s变化一次的感觉。最后调用显示函数 将数字和电压显示出来。

代码如下:

/** 功能描述: 程序运行后,实现ADC一个通道的数据采样,并将采样结果送LCD显示 **/#include <reg52.h>#include <intrins.h>#include <stdio.h>#define uchar unsigned char#define uint unsigned int#define lcd_out P1#define adc_data_port P0/***********端口定义********************************/sbit rs=P2^0;sbit rw=P2^1;sbit e=P2^2;sbit ADCCLK=P2^6;sbit START=P2^3;sbit EOC=P2^4;sbit OE=P2^5;sbit ADDA=P3^0;sbit ADDB=P3^1;sbit ADDC=P3^2;/***********函数twdqc***********************************/void check_busy(void);void write_command(uchar com);void write_data(uchar dat);void LCD_initial(void);void string(uchar ad ,uchar *s);void dis_char(uchar ad, uchar input);void display_data(uchar input);void delay(uint);void adc_change(void);void adc_channel(uchar ch);void time0_init();void time1_init(); uchar adc_data=0; //存放ADC转换结果 uint counter=0;//软件计数timer1中断次数 uchar channel_num=0;//通道数/***********主程序***********************/void main(void){ TMOD=0x21; LCD_initial(); //LCD1602 初始化time0_init();time1_init();while(1){ channel_num=3; adc_channel(channel_num); if(counter>=5000){ counter=0; string(0x0d," ");//数字清屏 string(0x4a," ");//电压清屏 adc_change(); //开始转换 } display_data(adc_data); }}//输入转换通道号// set ADC channelvoid adc_channel(uchar ch){ch = ch%0x07;ADDA=0;if(ch&0x01)ADDA=1;ADDB=0;if(ch&0x02)ADDB=1;ADDC=0;if(ch&0x04)ADDC=1;}//开始转换void adc_change(void){ OE=0; START=0; START=1; START=0; while(EOC==0); adc_data_port=0x0ff; OE=1; adc_data=adc_data_port; OE=0;}//定时器1控制通道3转换时间void time1_init(){ TH1=0-200; TL1=0-200; PT1=0; ET1=1; EA=1; TR1=1;}void timer1() interrupt 3{ counter++; }//定时器0控制ADC的CLK信号void time0_init(){TH0=(65536-200)/256;TL0=(65536-200)%256;PT0=1;//设为高级ET0=1;EA=1;TR0=1;}void timer0()interrupt 1{TH0=(65535-200)/256; TL0=(65535-200)%256; ADCCLK=~ADCCLK;}//LCD显示信息void display_data(uchar input){ long voltage; dis_char(0x0a,channel_num+0x30);//显示通道数string(0x0b,"= "); //显示数字dis_char(0x0d,input/100+0x30);dis_char(0x0e,input/10%10+0x30);dis_char(0x0f,input%10+0x30);voltage = input;voltage = voltage*500/255; //显示电压dis_char(0x4a,voltage/100+0x30);dis_char(0x4b,'.');dis_char(0x4c,voltage/10%10+0x30);dis_char(0x4d,voltage%10+0x30);dis_char(0x4e,'V');}//1ms延时程序void delay(uint j){uchar i=250;for(;j>0;j--){while(--i);i=249;}}//查忙程序void check_busy(void){uchar dt;do{dt=0xff;e=0;rs=0;rw=1;e=1;dt=lcd_out;}while(dt&0x80);e=0;}//写控制指令void write_command(uchar com){check_busy();e=0;rs=0;rw=0;lcd_out=com;e=1;_nop_();e=0;delay(1);}//写数据指令void write_data(uchar dat){check_busy();e=0;rs=1;rw=0;lcd_out=dat;e=1;_nop_();e=0;delay(1);}//液晶屏初始化void LCD_initial(void){write_command(0x38);//8位总线,双行显示,5X7的点阵字符write_command(0x0C);//开整体显示,光标关,无黑块write_command(0x06);//光标右移write_command(0x01);//清屏delay(1);string(0x00,"ADC0809 ch"); //显示字符串string(0x40,"Voltage = "); //显示字符串}//输出字符串void string(uchar ad,uchar *s){write_command(ad+0x80); //ad是显示位置信息while(*s>0){write_data(*s++);delay(100);}}// 输出字符void dis_char(uchar ad, uchar input){write_command(ad+0x80);//ad是显示位置信息write_data(input);delay(10);}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。