【单片机】15-AD和DA转换
1.AD转换及其相关背景知识
1.基本概念
1.什么是AD转换?
A(A,analog,模拟的,D,digital,数字的)
现实世界是模拟的,连续分布的,无法被分成有限份;
计算机世界是数字的,离散分布的,可以被分成有限份的
AD转换就是把一个物理量从模拟的转换成数字的。
2.AD转换的意义
想要计算机来实现现实世界
3.什么情况下需要AD转换
CPU是数字的【要准确的0V或者5V】
2.AD转换的原理
1.比较器
将差一点的电压转换为准确的二进制
所有的AD转换芯片内部都是用比较器来实现的。
2.和十进制转二进制有点像
使用除法
3.AD转换中的主要概念
1.位数
AD转换后转出来的二进制数由几位二进制来表示。【实际结果是一样大】
位数越多,越细腻。【精度越高】
2.量程
AD转换器可以接受的模拟量的范围
3.精度
精度==准确度
简单理解就是转出来有多准
【精度越小可靠率越高】
4.分辨率
AD转换器转出来的二进制数,每一格表示多少
5.转换速率(转换时间)
时间越短,速率越大
6.例子
输入电压范围:0-5V,AD转换输出位数是10,精度是0.01V
量程:0-5V
分辨率:(5-0)/2exp(10)=0.00488V
比如一次AD转换后得到数据为:【1010101010】,对应电压值:1010101010-->十进制:682,电压=682*0.00488=3.328V,考虑精度后为=3.33V
4.AD转换在系统中存在的方式
1.CPU外部扩展专用AD芯片
2.CPU内部集成AD模块(内部外设)
2.原理图和数据手册
https://www.semiee.com/file/ETEK/ETEK-ET2046.pdf
1.原理图
2.数据手册
AIN0-AIN3:不能同时采集,同一时间只能采集一路
3.SPI接线
CLK接P1.0
CS接P1.1
DI接P1.2
DO接P1.3
4.3种模拟电压变化原理
AIN0靠滑动变阻器控制电压变化
AIN1靠热敏电阻NTC
AIN2靠光敏电阻
5.ET2046控制字
bit7:起始位【高表示开始传输】:1
bit6-bit4:决定采样哪一路(AIN1,AIN0,AINT2,AINT3):
AIN0:001/011 X+
AIN1:101 Y+
AIN2:010 VBAT
AIN3:110 VBAT
bit3:设置ADC精度:【1:使用bit8位】【0:使用bit12位--一般使用这个】:0
bit2:【1:表示用单端模式】【0:表示差分模式(触摸屏)】:1
bit1:power down模式使能,00表示使能
读AIN0:0b 1001 0100=0x94
读AIN1:0b 1101 0100=0xd4
读AIN2;0b 1010 0100=0xa4
读AIN3:0b 1110 0100=0xe4
AIN0:001/011 X+
AIN1:101 Y+
AIN2:010 VBAT
AIN3:110 VBAT
3.分析时序
1.时序图
1.SPI变种
回顾SPI知识点:【单片机】13-实时时钟DS1302-CSDN博客
有CS,DCLK,I/O
2.上升沿写入下降沿读出
之前DS1302(SPI)的时候也是这样
上升沿写入:当CLK为上升沿的时候,数据通过DI从SPI主设备写入到SPI从设备
下降沿读出:当CLK为下降沿的时候,数据通过DO从SPI从设备读入到SPI主设备
3.读写都是高位在前
之前DS1302(SPI)的时候是低位在前
4.注意写和读的交界点
2.官方例程分析
1.ET2046写数据
/*******************************************************************************
* 函 数 名 : xpt2046_wirte_data
* 函数功能 : XPT2046写数据
* 输 入 : dat:写入的数据
* 输 出 : 无
*******************************************************************************/
void xpt2046_wirte_data(u8 dat)
{u8 i;CLK = 0;//可以忽略的_nop_();for(i=0;i<8;i++)//循环8次,每次传输一位,共一个字节{//先准备好数据,在置CLK=0DIN = dat >> 7;//先传高位再传低位dat <<= 1;//将低位移到高位CLK = 0;//CLK由低到高产生一个上升沿,从而写入数据_nop_(); CLK = 1;_nop_();}
}
2.ET2046读数据
/*******************************************************************************
* 函 数 名 : xpt2046_read_data
* 函数功能 : XPT2046读数据
* 输 入 : 无
* 输 出 : XPT2046返回12位数据
*******************************************************************************/
u16 xpt2046_read_data(void)
{u8 i;u16 dat=0;CLK = 0;_nop_();for(i=0;i<12;i++)//循环12次,每次读取一位,大于一个字节数,所以返回值类型是u16{dat <<= 1;CLK = 1;_nop_();CLK = 0; //CLK由高到低产生一个下降沿,从而读取数据_nop_();dat |= DOUT;//先读取高位,再读取低位。 }return dat;
}
3.ET2046返回AD值
/*******************************************************************************
* 函 数 名 : xpt2046_read_adc_value
* 函数功能 : XPT2046读AD数据
* 输 入 : cmd:指令
* 输 出 : XPT2046返回AD值
*******************************************************************************/
u16 xpt2046_read_adc_value(u8 cmd)
{u8 i;u16 adc_value=0;CLK = 0;//先拉低时钟CS = 0;//使能XPT2046xpt2046_wirte_data(cmd);//发送命令字for(i=6; i>0; i--);//延时等待转换结果,这个时候进行AD转换CLK = 1;//发送应该_nop_();CLK = 0;//发送一个时钟,清除BUSY_nop_();adc_value=xpt2046_read_data();CS = 1;//关闭XPT2046return adc_value;
}
4.main函数
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{ u16 adc_value=0;float adc_vol;//ADC电压值u8 adc_buf[3];while(1){ //0x94:对应AINT0--0b 1001 1100 adc_value=xpt2046_read_adc_value(0x94);//测量电位器adc_vol=5.0*adc_value/4096;//将读取的AD值转换为电压adc_value=adc_vol*10;//放大10倍,即保留小数点后一位adc_buf[0]=gsmg_code[adc_value/10]|0x80;adc_buf[1]=gsmg_code[adc_value%10];adc_buf[2]=0x3e;//显示单位Vsmg_display(adc_buf,6); }
}
4.代码实践【AD转换】
1.将12bit位的数值分2次输出
//AD value是12bit的,分2波出去【因为一次只能输出8位】
void uart_send_advalue(u16 val){uart_send_byte((val>>8)&0xff); //高8位uart_send_byte(val&0xff); //低8位uart_send_byte(0);//分割符
}
2. 计算电压值
3.读取AD数值:
ET2046.c
#include"ET2046.h"/*******************************************************************************
* 函 数 名 : xpt2046_read_adc_value
* 函数功能 : XPT2046读AD数据
* 输 入 : cmd:指令
* 输 出 : XPT2046返回AD值
*******************************************************************************/
u16 xpt2046_read_adc_value(u8 cmd)
{u8 i;u16 adc_value=0; //局部变量的初始化非常重要CLK = 0;//先拉低时钟CS = 0;//使能XPT2046//写入数据for(i=0;i<8;i++)//循环8次,每次传输一位,共一个字节{//先准备好数据,在置CLK=0DIN = cmd >> 7;//先传高位再传低位cmd <<= 1;//将低位移到高位CLK = 0;//CLK由低到高产生一个上升沿,从而写入数据_nop_(); CLK = 1;_nop_();}for(i=6; i>0; i--);//延时等待转换结果,这个时候进行AD转换CLK = 1;//发送应该_nop_();CLK = 0;//发送一个时钟,清除BUSY_nop_();for(i=0;i<12;i++)//循环12次,每次读取一位,大于一个字节数,所以返回值类型是u16{adc_value <<= 1;CLK = 1;_nop_();CLK = 0; //CLK由高到低产生一个下降沿,从而读取数据_nop_();adc_value |= DOUT;//先读取高位,再读取低位。 }CS = 1;//关闭ET2046return adc_value;
}
ET2046.h
#ifndef _xpt2046_H
#define _xpt2046_H#include "reg51.h"
#include "intrins.h" typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
typedef unsigned long u32;//管脚定义
sbit DOUT = P1^3; //输出
sbit CLK = P1^0; //时钟
sbit DIN = P1^2; //输入
sbit CS = P1^1; //片选//函数声明
u16 xpt2046_read_adc_value(u8 cmd);#endif
main.c
#include"ET2046.h"
#include"uart.h"#define CMD_READ_AIN0 0x94 //滑动变阻器
#define CMD_READ_AIN1 0xD4 //NTC--热敏电阻
#define CMD_READ_AIN2 0xA4 //GR1--光敏电阻
#define CMD_READ_AIN3 0xE4 //外部输入的电压值void Delay400000us() //@11.0592MHz
{unsigned char i, j, k;_nop_();_nop_();i = 17;j = 208;k = 27;do{do{while (--k);} while (--j);} while (--i);
}//AD value是12bit的,分2波出去【因为一次只能输出8位】
void uart_send_advalue(u16 val){uart_send_byte((val>>8)&0xff); //高8位uart_send_byte(val&0xff); //低8位uart_send_byte(0);//分割符
}void main(){//注意:定义一个变量要记得初始化,要不然后面可能出现问题u16 val=0;//12bit数值uart_init();while(1){val=xpt2046_read_adc_value(CMD_READ_AIN0);uart_send_advalue(val);Delay400000us();}
}
4.串口直接显示电压值
1.关键点
(1)直接显示电压值,而不是采样AD值
(2)以文本方式显示,而不是十六进制方式
2.将数值转换为十进制
//以文本方式发送c过去,意思就是要串口助手用文本方式来查看,看到的是
//这个数字本身
void uart_send_text(unsigned char c){//思路就是把c以十进制方式显示的几个数字,挨个变成文本发出去unsigned char i;//因为c是unsigned char 范围是0-255//先计算得出c的最高位,然后发出去i=c/100;uart_send_byte(i+48);//+48是对应ASCII//计算次高位c=c%100;i=c/10;uart_send_byte(i+48);//计算个位c=c%10;i=c;uart_send_byte(i+48);//发送一个换行uart_send_byte('\r');uart_send_byte('\n');
}
因为我们这里的电压是5V,对应5000mV,明显上面的0-255不在范围内,所以我们要求传入的是unsigned int c,【0-2的16次方】才足够
//因为这个函数的范围是unsigned char---->是2的8次方
//但是我们最大电压值为:5V----5000mV,所以我们这里要使用unsigned int
//以文本方式发送c过去,意思就是要串口助手用文本方式来查看,看到的是
//这个数字本身
void uart_send_text2(unsigned int c){//思路就是把c以十进制方式显示的几个数字,挨个变成文本发出去unsigned char i;//因为c是unsigned char 范围是0-255//因为我们知道电压值不会超过5000mV,所以只考虑显示1万以内的数据//先计算得出c的最高位,然后发出去i=c/1000;uart_send_byte(i+48);//+48是对应ASCIIc=c%1000;i=c/100;uart_send_byte(i+48);//+48是对应ASCII//计算次高位c=c%100;i=c/10;uart_send_byte(i+48);//计算个位c=c%10;i=c;uart_send_byte(i+48);//发送一个换行uart_send_byte('\r');uart_send_byte('\n');
}
5.DA转换
将数字转换为模拟的
1.DA转换的原理
为了让数字量转换成模拟量,必须将每一位代码按其权重的大小转换为相应的模拟量,然后再把这些模拟量相加。
2.原理图和案例分析
1.运算放大器(LM358)
放大作用:将数字信号-----》模拟信号
隔离作用:防止输出信号影响输入信号
2.PWM数字信号
当输入的PWM数字信号一直为1,则输出的模拟信号一直为高电压
如果输入的PWM数字信号一直为0,则输出的模拟信号一直为低电压
关键点:取决于输入的PWM信号的高低电平所占的时间。【连续变化的模拟量】
3.LM358
其实不接LM358,直接用IO口连接LED实现现象也一样。(说明灯的亮度只与PWM输入的电压值的大小有关)
4.注意点
真正的DA一般是专用芯片或者CPU内置模块,给数字值输出平滑模拟量
相关文章:

【单片机】15-AD和DA转换
1.AD转换及其相关背景知识 1.基本概念 1.什么是AD转换? A(A,analog,模拟的,D,digital,数字的) 现实世界是模拟的,连续分布的,无法被分成有限份;…...

基于FPGA的I2C读写EEPROM
文章目录 前言一、I2C协议1.1 I2C协议简介1.2 物理层1.3 协议层 二、EEPROM2.1 型号及硬件规格2.2 各种读写时序 三、状态机设计四、项目源码:五、实现效果参考资料 前言 本次项目所用开发板FPGA芯片型号为:EP4CE6F17C8 EEPROM芯片型号为:24L…...
Viva Employee Communications Communities部署方案
目录 Viva Employee Communications & Communities产品介绍 1. 沟通中心(Communications Center) 2. 新闻和公告(News and Announcements)...

WPF向Avalonia迁移(三、项目结构)
前提: Avalonia版本11.0.0 1.配置文件 1.1 添加配置文件 1.2 读取配置文件 添加System.Configuration.ConfigurationManager using Avalonia.Controls; using System.Configuration;namespace AvaloniaApplication7.Views {public partial class MainWindow : W…...

cvpr24写作模板pdfLaTex编译器注意点小结
文章目录 1 更改作者显示 Anonymous CVPR submission2 \label标签3 换行符// 与换列符&4 \medskip5 首行缩进6 插入图片6.1 单幅图片6.2 并排显示\hfill Reference https://cvpr.thecvf.com/Conferences/2024 1 更改作者显示 Anonymous CVPR submission 这一行开头加上% …...
windows版php扩展包下载
php8有些扩展需自己下载,像redis 看下phpinfo中的PHP Extension Build,确定自己的php版本 windows.php.net - /downloads/pecl/releases/...

计算机竞赛 题目:基于深度学习的中文汉字识别 - 深度学习 卷积神经网络 机器视觉 OCR
文章目录 0 简介1 数据集合2 网络构建3 模型训练4 模型性能评估5 文字预测6 最后 0 简介 🔥 优质竞赛项目系列,今天要分享的是 基于深度学习的中文汉字识别 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! &a…...
Django跨域访问 nginx转发 开源浏览器
Django跨域访问 https://blog.csdn.net/lonelysnowman/article/details/128086205 nginx转发 https://blog.csdn.net/faye0412/article/details/75200607/ 开源浏览器 https://www.oschina.net/p/chromiumengine 浏览器油猴开发 https://blog.csdn.net/mukes/article/detail…...

Docker Alist 在线网盘部署
文章目录 拉取镜像创建并运行查看容器自动生成的密码在浏览器中进行访问 挂载本地磁盘 拉取镜像 docker pull xhofe/alist-aria2创建并运行 # -v /data/alist:/opt/alist/data 挂载本地目录 docker run -d --restartalways -v /data/alist:/opt/alist/data -p 5244:5244 -e P…...

Jmeter吞吐量控制器使用小结
吞吐量控制器(Throughput Controller)场景: 在同一个线程组里, 有10个并发, 7个做A业务, 3个做B业务,要模拟这种场景,可以通过吞吐量模拟器来实现.。 添加吞吐量控制器 用法1: Percent Executions 在一个线程组内分别建立两个吞吐量控制器, 分别放业务A和业务B 吞吐量控制器采…...

3分钟轻松实现网关网口连接罗克韦尔AB CompactLogix系列PLC
目录 EG网关网口连接罗克韦尔AB CompactLogix系列PLC 一. 准备工作 1.1 在对接前我们需准备如下物品 1.2 EG20网关准备工作 1.3 PLC准备工作 二. EMCP平台设置 2.1 新增EG设备 2.2 远程配置网关 2.3 网关绑定 2.4 通讯参数设置 2.5 创建设备驱动 2.5.1 添加变量 2.…...

vscode刷leetcode使用Cookie登录
1、打开vscode,选择扩展,搜索leetcode,选择第一个,带有中文力扣字样,安装后重启 2、选择这个小球,切换中文版本,切换后,会显示一个打勾 3、选择小球旁边的有箭头的小门࿰…...
每次启动Docker容器指定IP、hosts和端口
每次启动Docker容器指定IP、hosts和端口 1问题描述1解决办法1.1启动容器指定好IP、hostname、端口等信息1.2通过docker-compose启动容器,可以配置extra_hosts属性1.3通过k8s来管理容器,则在可以在创建pod的yaml文件通过hostAliases添加域名IP映射 2问题描…...
PL/SQL增量同步
PL/SQL全量同步_枯河垂钓的博客-CSDN博客 目录 增量同步 增量同步存储过程 ORACEL 独有的 增量更新 merge into 增量同步 逻辑: 用源表的数据更新目标表,数据存在则更新,数据不存在,则插入 实现的逻辑: 1. 首先判断目标表是否有源表的数据 2. 如果有,则用源表的数据更新…...

C++——多态底层原理
虚函数表 先来看这个问题: class Base { public: virtual void Func1() { cout << "Func1()" << endl; } private: int _b 1; }; sizeof(Base)是多少? 答案是:8 因为Base中除了成员变量_b,还有一个虚函数表_vfp…...
asdTools-ReID热力图可视化
文章首发见博客:https://mwhls.top/4869.html。 无图/格式错误/后续更新请见首发页。 更多更新请到mwhls.top查看 欢迎留言提问或批评建议,私信不回。 Github - 开源代码及Readme Blog - 工具介绍 摘要:基于TorchCam实现ReID的热力图可视化的…...

CSS学习笔记
目录 1.CSS简介1.什么是CSS2.为什么使用CSS3.CSS作用 2.基本用法1.CSS语法2.CSS应用方式1. 内部样式2.行内样式3.外部样式1.使用 link标签 链接外部样式文件2.import 指令 导入外部样式文件3.使用举例 3.选择器1.基础选择器1.标签选择器2.类选择器3.ID选择器4.使用举例 2.复杂选…...
linux操作命令
VMware版本: 17.0 ubantu版本:22.04.3 命令: # 查看当前目录文件 ls# 切换路径 []内是路径 cd [snap/] cd ../ #返回上一层# 创建文件 []内是文件名 touch [test.txt]# 创建文件夹 []内是文件夹名 mkdir [myself]# 测试一下网络 ping www.b…...
猜数字游戏(Python)
一、猜数字游戏是一个古老的密码破译类、益智类小游戏,通常由两个人参与,一个人设置一个数字,一个人猜数字,当猜数字的人说出一个数字,由出数字的人告知是否猜中:若猜测的数字大于设置的数字,出…...
可视化模块
目录 可视化送入网络的图片可视化网络层的热力图 可视化送入网络的图片 送入的数据为imgs,其大小为(8,3,256,256),并以2行8列进行展示 import matplotlib.pyplot as plt import numpy as np# 假设你的张量名为 tensor,形状为 (8, 3, 256, 2…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...