单片机 ADC0809模数转换实验

电路图如下:
在这里插入图片描述

1、简单描述ADC0809工作过程
ADC0809工作过程:
(1)把通道地址送到ADDA~ADDC上,选择一个模拟输入端。
(2)在通道地址信号有效期间,ALE上的上升沿把该地址锁存到内部地址锁存器。
(3)START引脚上的下降沿启动A/D转换。
(4)变换开始后EOC引脚呈现低电平,EOC重新变成高电平时表示转换结束。
(5)OE信号打开输出锁存器的三态门并送出转换结果。

2、在LCD1602上实现采样电压值的显示,输出参考下图(可自定义显示格式,但必须显示实际电压,精确到0.01V),修改程序。
在这里插入图片描述
编程思路:
1、首先程序开头:头文件申明,宏定义,端口定义,函数申明,变量定义

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

3、子函数的定义

3.1 输入转换通道号的函数adc_channel(bit ac,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(uchar input)——显示器第一行利用dis_char函数分别显示转换数据的百、十、个位。第二行显示输入电压值,利用公式Vin=D500/256 将转换数据换成电压值,**这时一定要注意将Voltage的数据类型定义为long型 ,因为int型在计算D500可能会超过65536而溢出!!!**最后也利用dis_char函数分别显示电压的整数位和小数点后两位。

3.5 后面的延时函数delay(uint j),查忙函数check_busy(void),写控制指令函数 write_command(uchar com),写数据指令函数write_data(uchar dat),液晶屏初始化函数LCD_initial(void),输出字符串函数string(uchar ad,uchar *s),输出字符函数dis_char(uchar ad, uchar input) 因为是LCD1602显示器的一系列函数,所以就不说啦!!

代码如下:

/** 功能描述:  程序运行后,实现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;
/***********函数申明***********************************/
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 lcd_test(void);
void delay(uint);

void adc_change(void);
void adc_channel(bit ac,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;
/***********函数申明***********************************/
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 channel
void 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);

}
  • 43
    点赞
  • 295
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值