单片机第一季:零基础13——AD和DA转换

1,AD转换基本概念

51 单片机系统内部运算时用的全部是数字量,即0 和1,因此对单片机系统而言,无法直接操作模拟量,必须将模拟量转换成数字量。所谓数字量,就是用一系列0 和1 组成的二进制代码表示某个信号大小的量。用数字量表示同一个模拟量时,数字位数可以多也可以少,位数越多则表示的精度越高,位数越少表示的精度就越低。 

ADC(analog to digital converter)也称为模数转换器,是指一个将模拟信号转变为数字信号。单片机在采集模拟信号时,通常都需要在前端加上A/D 芯片。 

 A(A,analog,模拟的,D,digital,数字的)现实世界是模拟的,连续分布的,无法被分成有限份;计算机世界是数字的,离散分布的,是可以被分成有限份的;AD转换就是把一个物理量从模拟的转换成数字的。

AD转换中的主要概念:
(1)位数,AD转换后转出来的二进制数由几位二进制来表示。位数越多,越细腻;
(2)量程,AD转换器可以接受的模拟量的范围;
(3)精度,简单理解就是转出来到底有多准;
(4)分辨率,AD转换器转出来的二进制数,每一格表示多少;
(5)转换速率(转换时间); 

例:输入电压范围0-5V,AD转换输出位数是10,精度是0.01V,则:量程为0-5V,分辨率为:(5-0)/2exp(10)=0.00488V,譬如一次AD转换后得到的数据是1010101010,则对应的电压值为:3.328V,考虑精度后为3.33V 。

AD转换在系统中存在的方式:
(1)CPU外部扩展专用AD芯片;
(2)CPU内部集成AD模块(内部外设); 

电池单体的电压采集芯片有一种叫AFE的(Anlog Front End),即是一种AD转换模块,采集单体的电压转换为数字量发给MCU。 

2,AD转换原理图和数据手册 

 ET2046 AD转换模块通过AIN0/AIN1/AIN2分别连接滑线变阻器、热敏电阻、光敏电阻。与单片机连接的接口为CS(使能接口,低有效)、CLK(时钟信号)、DI(数据输入,从单片机到AD转换模块)、DO(数据输出、从AD转换模块到单片机)。

X+、Y+、VBAT 和AUX 模拟信号经过片内的控制寄存器选择后进入ADC,ADC 可以配置为单端或差分模式。选择VBAT和AUX 时应该配置为单端模式;作为触摸屏应用时,应该配置为差分模式。

单片机在对AD转换模块进行控制时,控制字节由DIN 输入的控制字命令格式如下所示:

Bit7为开始位,为1表示一个新的控制字节到来,为0则忽略PIN引脚上的数据;

A2-A0为通道选择位,表示选择哪个通道的输入电压进行AD转换;

MODE为12/8位转换分辨率选择位,为1选择8位转换分辨率,为0选择12位分辨率;

SER/DFR:单端输入方式/差分输入方式选择,为1是单端输入方式,为0是差分输入方式;

PD1-PD0为低功耗模式选择位,若为11,器件总处于供电状态,若为00,器件在转换之间处于低功耗模式。

单端模式时采集通道的选择如下表所示(通过上述控制字节的A2-A1进行选择): 

选择X+通道、12位分辨率、单端模式、低功耗模式的控制字节命令:0b1001 0100 = 0x94。 

AD转换模块的时序图如下所示: 

从时序图上可见,转换模块进入工作状态时,CS为低,DCLK为低,DIN和DOUT不用关注;首先通过DIN数据线从单片机发送控制字节到AD转换模块,在DCLK的上升沿AD转换模块读入数据(从高到低进行读入),当8位控制字节命令发送完成后,转换模块进入busy状态,即转换模块开始进行AD转换,此时间可从数据手册获取,一般程序中通过延迟一段时间来进行处理;然后单片机在DOUT数据线读取转换模块发出的数据,每个DCLK的下降沿转换模块会将一位数据发送到DOUT数据线上,仍然是从高到低的顺序。

可见AD转换和单片机的通讯方式类似于SPI通讯。 

3,AD转换代码 

AD采样转换代码包括单片机和AD转换模块写入命令和读取数据的底层时序代码,通过串口显示采样数据代码,以及main文件。

ET2046.c底层时序代码: 

#include "ET2046.h"
#include <intrins.h>void delay10us(void)   //误差 0us
{unsigned char a,b;for(b=1;b>0;b--)for(a=2;a>0;a--);
}unsigned int read_AD_value(unsigned char cmd)
{unsigned char i = 0;unsigned int AD_Value = 0;CS = 0;SCLK = 0;for(i = 0;i < 8;i++){DIN = cmd >> 7;cmd <<= 1;   //注意将一个数据移位后再赋给本身的运算符位 <<=SCLK = 1;_nop_();SCLK = 0;_nop_();}delay10us();SCLK = 1;	  			//发送一个时钟周期,清除BUSY_nop_();_nop_();SCLK = 0;_nop_();_nop_();for(i = 0;i<12;i++){AD_Value <<= 1;SCLK = 1;_nop_();SCLK = 0;_nop_();AD_Value |= DOUT;}CS = 1;return AD_Value;}

ET2046.h 


#ifndef __ET2046_H__
#define __ET2046_H__#include <reg51.h>sbit SCLK = P1^0;
sbit CS = P1^1;sbit DIN = P1^2;
sbit DOUT = P1^3;unsigned int read_AD_value(unsigned char cmd);#endif

串口调试代码: 

#include "uart.h"// 串口设置为: 波特率9600、数据位8、停止位1、奇偶校验无
// 使用的晶振是11.0592MHz的,注意12MHz和24MHz的不行
void uart_init(void)
{// 波特率9600SCON = 0x50;   	// 串口工作在模式1(8位串口)、允许接收PCON = 0x00;	// 波特率不加倍// 通信波特率相关的设置TMOD = 0x20;	// 设置T1为模式2TH1 = 253;TL1 = 253;	   	// 8位自动重装,意思就是TH1用完了之后下一个周期TL1会// 自动重装到TH1去TR1 = 1;		// 开启T1让它开始工作
//	ES = 1;
//	EA = 1;
}// 通过串口发送1个字节出去
void uart_send_byte(unsigned char c)
{// 第1步,发送一个字节SBUF = c;// 第2步,先确认串口发送部分没有在忙while (!TI);// 第3步,软件复位TI标志位TI = 0;
}void uart_send_adVal(unsigned int val)
{uart_send_byte(val>>8);   //AD采样的数据为12位的,首先左移8位串口输出高4位uart_send_byte(val);	   //再输出低8位
}

注意:因为AD采样的数据是12位的数据,串口每次只能发送8位数据,需要分两次将12位数据进行发送; 

#ifndef __UART_H__
#define __UART_H__#include <reg51.h>void uart_init(void);
void uart_send_byte(unsigned char c);
void uart_send_adVal(unsigned int val);#endif

main.c函数 

#include "ET2046.h"
#include "uart.h"#define AIN0 0x94	  //滑动变阻器
#define AIN1 0xd4	  //热敏电阻
#define AIN2 0xa4	  //光敏电阻void delay1s(void)   //误差 0us
{unsigned char a,b,c;for(c=167;c>0;c--)for(b=171;b>0;b--)for(a=16;a>0;a--);
}void main()
{unsigned int ad_val = 0;uart_init();//uart_send_adVal(0xabc);	  //测试代码//uart_send_byte(0x0d);//uart_send_byte(0x0a);//while(1);while(1){ad_val= read_AD_value(AIN2);uart_send_adVal(ad_val);uart_send_byte(0);      	//发送数据0区分每次采样数值delay1s();				  //如何实现在串口调试助手中发送一次采样数据后换行?}}

思考:上述代码中,main函数是通过while()不断采样和发送AD转换的数据,如何通过中断来采样和发送AD转换数据? 

4,AD转换代码-直接在串口显示电压值 

串口助手中看到的数据以16进制显示或以对应字符形式来显示,因此在显示AD转换的电压时不直观,为了直观显示采集到的电压值,通过对采集到的电压值根据ASCii表对每一个十进制数转化为对应的数字符号,如下图所示,入药显示电压值中的数字5,只需要发送5+48的十进制数,在串口助手中就可以看到对应的符号5。

代码如下: 

5,DA转换 

待完善 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/40009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux -- 进阶 Autofs自动挂载服务 实验详解

服务端创建共享目录&#xff0c; 客户端实现自动挂载 第一步 &#xff1a; 客户端&#xff0c;服务端 均关闭安全软件 [rootserver ~]# setenforce 0 [rootserver ~]# systemctl stop firewalld [rootnode1 ~]# setenforce 0 [rootnode1 ~]# systemctl stop firewalld 第二…

在K8s上处理nginx

基本说明 创建一个名为ssl的TLS类型的Secret对象&#xff0c;用于存储证书和密钥信息。 kubectl create secret tls ssl --certserver.crt --keyserver.key配置Nginx的events块&#xff0c;设置worker连接数为1024。 events {worker_connections 1024; }配置Nginx的http块&a…

MyBaits(单独使用,与整合无关)小白版

文章目录 概述比较配置写xml加载上面配置并执行加载配置的方法方式一 执行方法方式一方式二(MyBatis映射器) 写配置文件的映射文件设置对象的别名&#xff08;简写&#xff09;获取自动生成的主键 查询结果和java的映射规则基本类型映射&#xff1a;简单对象映射&#xff1a;嵌…

加盐加密算法

MD5加密加盐加密项目密码升级 MD5加密 MD5一系列公式进行复杂数学运算&#xff1b;特点&#xff1a;&#xff08;用途校验和、计算hash值方式、加密&#xff09; 1&#xff1a;定长&#xff1b;无论原始数据多长&#xff1b;算出的结果都是4或者8字节的版本。 2&#xff1a;冲…

Java多线程实战

Java多线程实战 java多线程&#xff08;超详细&#xff09; java自定义线程池总结 Java创建线程方式 方法1&#xff0c;继承Thread类 方法2&#xff0c;实现Runable接口 方法2-2&#xff0c;匿名内部类形式lambda表达式 方法3&#xff0c;实现Callable接口&#xff0c;允许…

【深入理解Linux内核锁】三、原子操作

我的圈子: 高级工程师聚集地 我是董哥,高级嵌入式软件开发工程师,从事嵌入式Linux驱动开发和系统开发,曾就职于世界500强企业! 创作理念:专注分享高质量嵌入式文章,让大家读有所得! 文章目录 1、原子操作思想2、整型变量原子操作2.1 API接口2.2 API实现2.2.1 原子变量结…

Shell 函数

Shell 函数 linux shell 可以用户定义函数&#xff0c;然后在shell脚本中可以随便调用。 shell中函数的定义格式如下&#xff1a; [ function ] funname [()] { action; [return int;] } 说明&#xff1a; 1、可以带function fun() 定义&#xff0c;也可以直接fun…

log4j:WARN No appenders could be found for logger问题

本文将idea场景下的使用。 IDEA中&#xff0c;将配置文件命名为log4j.properties&#xff08;该命名才会被自动加载&#xff09;&#xff0c; 并放到某个目录下&#xff08;通常放到resources目录&#xff09;&#xff0c;并在resources上右键&#xff0c;找到Mark Directory a…

微信程序 自定义遮罩层遮不住底部tabbar解决

一、先上效果 二 方法 1、自定义底部tabbar 实现&#xff1a; https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html 官网去抄 简单写下&#xff1a;在代码根目录下添加入口文件 除了js 文件的list 需要调整 其他原封不动 代码&#xf…

Hadoop数据迁移distcp

Hadoop数据迁移distcp 准备工作 确认源集群&#xff08;a&#xff09;,目标集群&#xff08;b&#xff09;确认a集群的主节点和b集群的主节点确认两个集群的网络相通确认迁移模式&#xff08;全量迁移还是增量迁移&#xff09;&#xff0c;这里选择全量迁移 迁移文件 迁移t…

【路由协议】使用按需路由协议和数据包注入的即时网络模拟传递率(PDR)、总消耗能量和节点消耗能量以及延迟研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

斯坦福「小镇」开源AI智能体;小米应用商店将要求AI应用符合资质标准

&#x1f989; AI新闻 &#x1f680; 斯坦福「小镇」开源AI智能体 摘要:斯坦福研究人员开源了一个类似《西部世界》的数字化「小镇」,里面有25个AI智能体可以生活、工作、社交。这项研究被视为AGI的重要开端,可能会改变游戏、企业应用领域。网友期待这项技术改善游戏NPC的交互…

PyMuPDF`库实现PDF旋转功能

本文介绍了一个简单的Python应用程序&#xff0c;用于将PDF文件转换为旋转90度的PDF文件。主要用于csdn网站中导出的博客pdf是横向的&#xff0c;看起来不是很方便&#xff0c;才想到用python编制一个将pdf从横向转为纵向的功能。 功能 该PDF转换工具具有以下功能&#xff1a…

信息安全:防火墙技术原理与应用.

信息安全&#xff1a;防火墙技术原理与应用. 防火墙是网络安全区域边界保护的重要技术。为了应对网络威胁&#xff0c;联网的机构或公司将自己的网络与公共的不可信任的网络进行隔离&#xff0c;其方法是根据网络的安全信任程度和需要保护的对象&#xff0c;人为地划分若干安全…

C#工程建立后修改工程文件名与命名空间

使用之前的项目做二次开发&#xff0c;项目快结束的时候&#xff0c;需要把主项目的名称修改成我们想要的。 之前从来没有这么干过&#xff0c;记录一下。 步骤如下&#xff1a; 1&#xff1a;打开vs2010项目解决方案&#xff0c;重命名&#xff0c;如下图所示&#xff1a; …

SDP协议是什么,详解SDP协议

一、SDP协议简介 SDP&#xff08;Session Description Protocol&#xff09;是一种会话描述协议&#xff0c;用于描述多媒体会话的参数。它是一种文本协议&#xff0c;通常用于VoIP&#xff08;Voice over Internet Protocol&#xff09;和视频会议等应用中。SDP协议定义了一种…

Vue项目(购物车)

目录 购物车效果展示&#xff1a; 购物车代码&#xff1a; 购物车效果展示&#xff1a; 此项目添加、修改、删除数据的地方都写了浏览器都会把它存储起来 下次运行项目时会把浏览器数据拿出来并在页面展示 Video_20230816145047 购物车代码&#xff1a; 复制完代码&#xff0…

leetcode每日一题_2682.找出转圈游戏输家

2682.找出转圈游戏输家 题目: n 个朋友在玩游戏。这些朋友坐成一个圈&#xff0c;按 顺时针方向 从 1 到 n 编号。从第 i 个朋友的位置开始顺时针移动 1 步会到达第 (i 1) 个朋友的位置&#xff08;1 < i < n&#xff09;&#xff0c;而从第 n 个朋友的位置开始顺时针移…

设计模式之原型模式Prototype的C++实现

1、原型模式提出 在软件功能设计中&#xff0c;经常面临着“某些结构复杂的对象”的创建工作&#xff0c;且创建的对象想拥有其他对象在某一刻的状态&#xff0c;则可以使用原型模型。原型模型是通过拷贝构造函数来创建对象&#xff0c;并且该对象拥有其他对象在某一刻的状态。…

Docker基础入门:镜像、容器导入导出与私有仓库搭建

Docker基础入门&#xff1a;镜像导入导出与私有仓库搭建 一、 Docker镜像、容器的导入和导出1.1、Docker镜像的导出1.2、Docker镜像的载入1.3、Docker容器的导出1.4、Docker容器的导入 二、 镜像和容器导出和导入的区别:三、commit操作_本地镜像发布到阿里云3.1、commit操作有关…