用AD以1HZ的频率采集模拟信号,然后转换成数字量,再将其以1200bps发送到计算机,在计算机上显示(郭天祥老师第七讲课后习题第四题,加了一个数字量在数码管上显示的功能)

 前言

在学完第七讲《串口通信》之后,做练习题用到了前面所学的A/D转换器的知识,将模数转换器与串口通信结合起来实现题目功能。

难度:中等偏上。


一、A/D是什么?

首先A(anolog)是模拟量,D(digital)是数字量。对于TTL电平的取值范围来说,模拟量的取值范围在0~5V之间,是连续的,而对于数字量,则使用二进制数表示的。

二、A/D之间是如何转换的呢?

模拟量通常是在自然界中表示的电信号,可以在一定范围内连续变化。数字量则用1、0来表示电平的两个值,且只能表示两个值,通常应用于数字电路当中,例如在TTL标准中0代表低电平0V,1代表高电平+5V。

那么如何将连续的量转换成离散的量呢?

这就需要用到微分的思想将一段连续的量,切分成离散的数据。例如,0~5V如果用二位二进制数表示,则00代表0V,01代表1.67V,10代表3.34V,11代表5.01V。同理可以用8位的二进制数进行表示,二进制数加1,十进制电压则加5/255≈0.0196V。

三、A/D转换的原理

四、时序图 

 

五、代码实现

1.引入库,初始化全局变量以及引脚

代码如下(示例):

#include<reg52.h>
#include<intrins.h>
#define AD_CH2 0xa4   //电位器端口,从此口可以获取电位器的阻值

typedef unsigned int uint;
typedef unsigned char uchar;

sbit CS=P3^7;     //片选信号
sbit DCLK=P2^1;   //时钟信号
sbit DIN=P2^0;    //输入控制信号
sbit DOUT=P2^5;   //输出数字量
sbit dula=P2^6;   //段选信号
sbit wela=P2^7;   //位选信号
//sbit beef=P2^3;   //蜂鸣器

uchar temp1,temp2;
uint voltage;   //电压值
uchar code du[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
uchar code we[] = {0xfe, 0xfd, 0xfb, 0xf7};

void delay(uchar z);  //延时函数
void init();          //初始化函数
void display(uint);   //位数计算函数
void show_number(uchar,uchar);   //数码管显示函数
uint read_ad(uchar);    //读取二进制电压值

2.延时函数(传入参数为1则延时1毫秒)

void delay(uchar z)
{
		uchar x,y;
		for(x=z;x>0;x--)
			for(y=110;y>0;y--)
			;
}

3.初始化函数

void init()
{
        //将数码管全部初始化为0
		dula=1;
		P0=du[0];
		dula=0;
		P0=0xff;
		wela=1;
		P0=0x00;
		wela=0;
	
        //初始化串口中断
		TMOD=0x20;     //设置定时器1的中断模式为串口中断
		TH1=0xe8;      //1200bps对应的高八位为0xe8
		TL1=0xe8;        
		SM0=0;       //10位异步收发器,可收发八位数据
		SM1=1;
		REN=1;       //允许串口接收数据
		EA=1;        //开启中断开关
		ES=1;        //开启终端开关
		TR1=1;       //启动定时器1
		
}

4.数码管显示函数,位数计算函数

void display(uint number)
{
		uchar qian,bai,shi,ge;
		qian=number/1000;
		bai=number/100%10;
		shi=number/10%10;
		ge=number%10;
	
		show_number(qian,0);
		show_number(bai,1);
		show_number(shi,2);
		show_number(ge,3);
}

void show_number(uchar x,uchar y)
{
		dula=1;
		P0=du[x];
		dula=0;
		P0=0xff;
		wela=1;
		P0=we[y];
		wela=0;
		delay(5);
}

5.A/D转换函数(传入参数为)

uint read_ad(uchar channel)
{
		
		uint date=0;
		uchar i;
		CS=0;
		for(i=0;i<8;i++)   //分别写8次,每次写1位
		{
				DCLK=0;    //拉低时钟总线,允许DIN变化
				if(channel&0x80)    //先写数据的最高位
						DIN=1;      //写1
				else
						DIN=0;      //写0
				DCLK=1;             //拉高时钟,让从机读取DIN
				channel<<=1;         //将次高位移动到最高位
		}
		DCLK=0;      //拉低时钟总线
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		
		for(i=0;i<12;i++)   //分别读12次,每次读1位
		{
				date<<=1;   //数据左移1位,准备接收一位
				DCLK=1;     //拉高时钟总线,读取SDA上的数据
				DCLK=0;     //拉低时钟总线,允许从机控制SDA变化
				if(DOUT)
					date|=0x01;   //为1则写1,否则不执行写1,通过下一次循环的左移补0
		}
		CS=1;    //拉高片选,为下一次拉低片选做准备
		temp2=date;   //获取低八位
		temp1=date>>8;   //获取高八位
        return date;
}

6、主函数 

代码如下(示例):

void main()
{
		init();
		while(1)
		{
				voltage=read_ad(AD_CH2);
				ES=0;        //关闭定时器
				SBUF=temp1;  //获取高八位
				while(!TI);
				
				SBUF=temp2;  //获取低八位
				while(!TI);
				ES=1;        //开启中断定时器
				voltage*=1.2207;  // (5/4096)
				display(voltage);
		}
}

单片机不断的给计算机发送数字量电压

串口数据​​​​​

 当转动电位器时,数码管上显示电位器的电压

数码管显示


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值