嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记11:数字电位器MCP4017

系列文章目录

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记01:赛事介绍与硬件平台

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记02:开发环境安装

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记03:G4时钟结构

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记04:从零开始创建工程模板并开始点灯

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记05:Systick滴答定时器

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记06:按键输入

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记07:ADC模数转换

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记08:LCD液晶屏

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记09:EEPROM

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记10:USART串口通讯

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记11:数字电位器MCP4017


目录

系列文章目录

前言

一、电路原理

二、程序设计

三、ADC采样分压电压


前言

数字电位器MCP4017本质是一个IC器件,也就是说它是一个集成芯片,而板子上的蓝色旋转电位器R37、R38本质是一个电阻。数字电位器本质是一个芯片,但是内部有一个电阻网络,通过很多模拟开关来给电阻网络切换不同的阻值,我们是通过之前介绍过的I2C总线来给芯片发送数据,告诉芯片我要打开哪些模拟开关,从而控制它的阻值。

一、电路原理

首先我们看一下MCP4017,首先1号管脚接3.3V,2号管脚接GND,3、4管脚是I2C的通讯线,最重要的是5、6,数字电位器W、B两个管脚,5脚相当于是一个可变电阻的一端,另一端是悬空的,6脚相当于是可变电阻的滑片。

我们假设W滑到最左边,则5、6之间的电阻R_{WB}就等于AB之间整个电阻的总值R_{AB},如果滑到AB的中点,那么R_{WB}=\frac{1}{2}R_{AB},如果滑到B端,那么R_{WB}就约等于0。需要注意的是,芯片内部并不是这样的结构,而是一堆模拟开关实现了这样的功能。因为模拟开关本身是有阻值的,所以也会存在一些误差。

这个电位器的型号是104ELT(原理图可见),也就是说最多有10*10^4欧姆的电阻可调,即100kΩ

那么我们看电路图,W端接了一个10k的电阻接到3.3V,B端接地,很容易看出这是一个分压电路,那么我们很容易可以算出W端的电位:V=3.3\cdot \frac{R_{WB}}{R_{WB}+10}。而这个分压的电压V是接到了单片机的PB14这个口,PB14在STM32上也是一个ADC的输入口,所以我们可以通过ADC来采集这个电压的分压情况,从而可以知道WB之间的阻值变化。当然我们也可以设置好一个阻值,然后通过ADC来确认它的电压。

通过对这个电路的分析我们可知,我们实际上就是通过一个10k的电阻与一个数字电位器分压来得到PB14口的模拟输入。

那么我们接下来简单了解一下MCP4017这个芯片。可以看到它是一个7bit的支持IIC总线的数字电位器,并且拥有可变内存。SC70是它的封装。401系列还有4018、4019,其中4018一般用于分压器,4017、4019一般用于可变电阻,具体的我们就不去了解了。

 

  • 7bit是指它的电阻网络有7个位可以配置,也就是可以配置一共127个不同的阻值。因为总阻值是100kΩ,那么我们就可以把100k分成127个档
  • 抽头的电阻是100Ω,也就是说如果把WB短接,那也有100Ω的阻值(几乎可忽略)。
  • 低温漂:可变电阻的温漂是50ppm(百万分之50)。
  • 用IIC协议来读写。
  • 掉电时WB的电压不能超过1.5V。
  • 不编任何程序的话,它默认上电就是中间电压(50kΩ)。
  • 低功耗(2.5微安)
  • 电压工作范围:2.7V-5.5V。

还有一点就是芯片的存储形式是RAM,也就是说每次掉电都会清空,这就是为什么要规定默认上电时要中间电压。

除此之外比较重要的就是MCP4017的器件地址:0101111,还有一个R/W位,如果是写入的话,R/W就是0,加上器件地址就是01011110,即0x5e,如果是读就是0x5f

我们再看一下内部的电阻网络是怎么构成的。可以看到电阻网络还是挺简单的,我们甚至可以自己用电阻加模拟开关来构成一个类似的电路,当然,芯片帮我们集成好了用起来更方便。

可以看到每个Rs的电阻上都加了一个开关,每个开关上都有一个数,也就是说我们每往上增加一个数,就会增加一个Rs的电阻。Rs一共有127个,加起来等于100kΩ,这样我们可以算出Rs的值应该是0.7874kΩ。比方说:如果控制字节是0x7F,那么电阻就是100kΩ,如果控制字节是0x3F,就是中间位,即50kΩ,如果控制字节是0x00,那么电阻就是0(实际上是100Ω)。

二、程序设计

我们可以利用I2C总线控制数字电位器芯片的电阻值,与R17的10kΩ形成分压,这样PB14的电位就会发生相应的变化,再用ADC来进行读取。

这里我们先看一下怎么编程STM32来改变MCP4017的阻值。

程序流程:

  • 复制i2c的底层驱动文件到“编程工程”并改名
  • 在main.c调用i2c的IO初始化代码并包含头文件
  • 在i2c.c文件里编程:读写MCP4017函数,并在i2c.h中声明
  • 在main.c调用MCP4017_Write和MCP4017_Read完成程序

其中重点是MCP4017读写函数的编写,其他的部分我们在EEPROM里面已经做过了就不赘述了。我们这里主要看一下怎么编写MCP4017读写函数。下图是厂商芯片资料给的如何写一个字节数据的示例。

主器件就是我们的STM32,首先要发一个Start起始命令,然后发送从器件的地址+一个R/W位,因为是写数据,所以R/W位是0,所以是0x5E。然后等待应答。完成后,我们要送一个数据给MCP4017,送的数据就是我们要控制它的电阻的大小,它是一个7bit的控制字,就是0-0x7F的控制范围。主设备把这个字节发送过去,第一位用不到所以丢弃。然后等待应答。最后主器件再发一个终止命令STOP。

根据这个图我们很容易就可以写出MCP4017_Write()函数:

void MCP4018_Write(u8 val)
{I2CStart();I2CSendByte(0x5E);I2CWaitAck();I2CSendByte(val);I2CWaitAck();I2CStop();
}

读取函数我们一般用不到,因为我们只需要写入控制它的阻值就行了,并不需要读取现在阻值多少。比赛的时候也几乎很少遇到,但是最好还是学一下,也可以通过读取函数来判断是否成功写入,防止数据干扰。比方说可以写完之后读取一下,判断写的对不对,如果不对就再写一次。但是比赛中不需要这样。

u8 MCP4017_Read(void)
{u8 val;I2CStart();I2CSendByte(0x5F);I2CWaitAck();val=I2CReceiveByte();I2CSendNotAck();I2CStop();return val;
}

 还有一点就是,MCP4017两次写入之间是不需要延时的,不同于EEPROM。

三、ADC采样分压电压

MCP4017的W端接了一个PB14的管脚,并接在了ADC1的输入口上,所以我们可以用PB14来采样分压电压。

进入CubeMX开始配置引脚。可以看到PB14可以设置为ADC1的5通道,与PB12共用一个ADC,但是通道不同。我们把它设置为单端模式直接采集电压就行了。如果这部分内容还不清楚的话可以翻到之前的内容看一下ADC的讲解。

我们需要注意的是,ADC1现在有两个通道,那我们怎么告诉STM32现在要采集哪个通道呢?这边就有一个内容要在CubeMX上配置的,在ADC1的Configuration中有一个Number of Conversion也就是ADC转换的数量,这里要改成2。改完后下面有个Rank就自动变成2个了,并自动打开Scan conversion mode扫描转换模式,它会先转换一个通道的输入后再去转换另一个通道,转化的顺序就是由Rank决定,Rank1就是第一个被转换的通道,我们可以在Rank里面选择,并且这里我们可以调整它的采样速度Sampling Time(采样时间)。注意,多通道采集的时候,采样速度最好不要太快,否则会容易出错,所以我们可以把采样速度调的慢一点,这里我们调640.5个周期。

再把Rank1设置为通道5,Rank2设置为通道11。

生成代码,我们可以看到ADC1的初始化定义里面已经有了要转换的通道数量为2,和不同Rank对应的通道。

我们已经有了之前的ADC的程序,现在在此基础上增加ADC1通道5的内容。(如果没有的话就自己写一下,配置ADC的教程在前面有,写完记得初始化一下,有的时候程序写完了发现运行不对有可能就是忘了初始化)

我们定义一个变量volt_mcp来表示通过mcp采集到的电压值。

因为我们定义的Rank1是采集mcp,也就是先采集mcp再采集R37,所以我们是在采集R37的程序前面添加采集mcp的程序。

u16 adc1_val,adc2_val;
float volt_r37,volt_r38,volt_mcp;
void ADC_Process(void)
{//rank1HAL_ADC_Start(&hadc1);volt_mcp = HAL_ADC_GetValue(&hadc1)/4095.0f*3.3f;//rank2HAL_ADC_Start(&hadc1);adc1_val = HAL_ADC_GetValue(&hadc1);volt_r37 = adc2_val/4095.0f*3.3f;HAL_ADC_Start(&hadc2);adc2_val = HAL_ADC_GetValue(&hadc2);volt_r38 = adc1_val/4095.0f*3.3f;
}

这样就完成了ADC1先采集通道5,再采集通道11的过程,需要注意的是,我们并不需要手动切换采集通道,只需要再调用一次HAL_ADC_Start()函数就可以自动切换通道了,这是因为我们之前配置了扫描转换,正因如此,我们在编写程序的时候一定要注意采样的顺序!

我们可以调用一下前面写好的MCP4017_Write(),然后写入0x3F,也就是中位点。设置好电阻后在主循环中调用ADC采样函数就可以看一下现在的分压电压了。

int main()
{MCP4017_Write(0x3F);while(1);{ADC_Process();}
}

我们可以写个LCD显示函数来看一下此时volt_mcp的值,这里就跳过了。显示出来的值应该是2.7左右。如果输入0x7F的话,输出应该是2.95左右。

如果之前没有现成的ADC程序的话,我们总结一下利用ADC1双通道采集的程序设计步骤:

  • 用给的“模版”生成代码
  • 设置ADC相关的GPIO为输入模式,并设置成单端模式。(PB15、PB12、PB14)
  • 设置ADC1的转换的通道数(number of conversion)为2,并设置Rank和采集速度。
  • 添加ADC相关的HAL库驱动文件
  • 包含ADC的头文件,并初始化ADC(如果是移植代码的话要初始化外设时钟)
  • 利用HAL_ADC_Start和HAL_ADC_GetValue编写程序(双通道要调用两次Start)

总结

这节课主要是学习如何使用MCP4017数字电位器,它需要通过I2C总线进行通信,利用I2C向其内部写入数据从而控制它的内部电阻大小,并且外部接了一个分压电路,并把分压电压作为ADC的输入采样,从而转化成数字量被我们读取。所以这一节的内容需要结合I2C总线和ADC这两部分内容一起来学习的。其中最重要的内容是MCP4017读写函数的编写ADC的双通道采集这两部分内容,比赛时是需要自己编写的,需要牢记。此外,还需要记得ADC的采样Rank和采样速度。

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

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

相关文章

【Linux】详细分析/dev/loop的基本知识 | 空间满了的解决方法

目录 前言1. 基本知识2. 内存满了2.1 清空2.2 扩增 3. 彩蛋 前言 服务器一直down机,翻找日志文件一直找不到缘由,最终发现是挂载的内存满了,那本身这个文件就什么用呢? 1. 基本知识 /dev/loop是一种特殊的设备文件,…

005 Math类中的常用方法

Math类中包含一些用于执行基本数字运算的方法。 算术运算 方法描述abs(double a)返回 double值的绝对值。sqrt(double a) 返回 double值的正确舍入正平方根。 cbrt(double a)返回 double值的立方根。max(double a, double b)返回两个 double值中较大的 double 。min(double a…

I2C系列(三):软件模拟I2C读写24C02

一.目标 PC 端的串口调试软件通过 RS-485 与单片机通信,控制单片机利用软件模拟 I2C 总线对 EEPROM(24C02) 进行任意读写。 二.硬件简述 2.1 24C02硬件参数 24C02器件地址为0x50,存储容量为256字节,存储单元地址位数…

【SpringBoot】java.lang.Exception: No tests found matching Method

目录 问题解决 问题 在运行SpringBootMaven工程时,创建了一个新的Test单元测试,在运行时遇到的问题如下: java.lang.Exception: No tests found matching Method test_chatGPT(cn.bugstack.chatbot.api.test.ApiTest) from org.junit.inter…

使用 Docker Swarm(集群) 和Docker Stack(堆栈)部署容器化应用

1、Docker Swarm简介 说到集群,第一个想到的就是k8s,但docker官方也提供了集群和编排解决方案,它允许你将多个 Docker 主机连接在一起,形成一个“群集”(Swarm),并可以在这个 Swarm 上运行和管…

题目:输入三个整数x,y,z,请把这三个数由小到大输出。

题目:输入三个整数x,y,z,请把这三个数由小到大输出。 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worri…

Python与供应链-2预测误差及指数平滑需求预测模型

主要介绍预测误差和指数平滑模型的相关理论,然后再通过Python的statsmodels封装的指数平滑函数预测需求。 1预测误差 预测误差是指预测结果与预测对象发展变化的真实结果之间的差距。这种误差分为绝对误差和相对误差。绝对误差是预测值与实际观测值的绝对差距,而相对误差则…

分期乐(乐信)与银行机构合伙放贷,谁是真正的受益者?

分期乐(乐信)与银行机构的合作放贷模式,无疑在金融领域引起了广泛关注。这种合作模式似乎为各方都带来了不小的利益,但究竟谁是真正的受益者呢? 银行受益:对于银行机构而言,与分期乐&#xff0…

C是用什么语言写出来的?

C是用什么语言写出来的? C语言的起源和发展是一个迭代过程: 1. 最初的C语言编译器的开发始于对B语言的改进。B语言是由Ken Thompson设计的,它是基于BCPL语言简化而来的。在开始前我有一些资料,是我根据网友给的问题精心整理了一份「 C语言的…

RocketMQ学习笔记:分布式事务

这是本人学习的总结,主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、分布式事务的难题2、解决方式2.1、半事务消息和事务回查2.2、代码样例2.2.1、TransactionListener2.2.2、TransactionMQProducer2.2.3、MessageListenerConcurrently2.2.4、流程图 1、分布…

C++判断点是否在三角形内部

1.问题 判断点是否在三角形内部。 2.思路 计算向量AB和AP的叉积、向量BC和BP的叉积、向量CA和CP的叉积&#xff0c;如果所有的叉积符号相同&#xff0c;则点在三角形内部。 3.代码实现和注释 #include <iostream> #include <vector>// 计算两个二维向量的叉积 …

数据结构-队列-005

1链式队列 运行结果如下&#xff1a; 1.1链式队列结点定义 /*自定义一个数据类型*/ typedef struct student {char name[32];char sex;int age; }DATA_TYPE;/*定义一个链式队列结点*/ typedef struct link_queue_node {DATA_TYPE data;//数据域struct link_queue_node *pne…

图像识别中的特征提取技术

图像识别是计算机视觉领域的一个重要分支&#xff0c;它的基本任务是从图像中提取出有助于分类或识别的信息&#xff0c;这些信息通常称为“特征”。特征提取是图像识别中的关键技术之一&#xff0c;它决定了识别系统性能的好坏。以下是几种常见的特征提取技术&#xff1a; 边…

什么是甲状腺相关眼病,四川眼科医院院长孙丰源教授这么说!

近年来&#xff0c;随着人们健康意识的逐渐增强&#xff0c;越来越多人开始关注甲状腺疾病。甲状腺是人体最大的内分泌腺&#xff0c;是维护人体健康的关键&#xff0c;它一旦发生异常&#xff0c;则会危害到多个器官和组织。不同的甲状腺疾病会呈现不同的症状&#xff0c;比如…

C# 快速将数据写入 Excel 单元格

目录 性能问题 Excel元素结构及写入原理 范例运行环境 配置Office DCOM 实现代码 组件库引入 核心代码 WriteArrayToExcel 神奇的 911 事件 小结 性能问题 将生成或查询到的数据&#xff0c;导出到 Excel 是应用中常用的一项功能。其中一些标准的写入单元格的方法如…

数据库学习案例20240326-mysql主从复制对trigger,event是否会导致数据重复测试

1 MASTER -SLAVE TRRGER测试 binlog_formatROW 测试环境为master-master双主模式&#xff0c;配置的双向复制。 11:25: [(none)]> show variables like %binlog_format%; ---------------------- | Variable_name | Value | ---------------------- | binlog_format | RO…

智慧公厕,让数据和技术更好服务社会生活

智慧公厕&#xff0c;作为智慧城市建设中不可忽视的一部分&#xff0c;正逐渐受到越来越多人的关注。随着科技的不断进步&#xff0c;智能化公厕已经成为一种趋势&#xff0c;通过数据的流转和技术的整合&#xff0c;为社会生活带来了更好的服务。本文以智慧公厕源头实力厂家广…

基于51单片机的酒精检测警报系统Proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1gddplAxS_ZKyrHaWE93dog 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52简介&#xff1a; AT89C52是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectronics&#xff09;公…

最新的Flutter3.x版本获取应用包名的方法

以前的flutter项目可以在 AndroidManifest.xml 中获取应用包名&#xff0c; 最新的Flutter3.x版本要获取应用包名可以找到build.gradle 更多内容参考&#xff1a;最新的Flutter3.x版本如何获取应用包名

Linux:Jenkins全自动持续集成持续部署(4)

在上一章部署好了之后&#xff0c;还需要点击一下才能进行部署&#xff0c;本章的效果是&#xff1a;当gitlab上的代码发生了变化后&#xff0c;我们不需要做任何事情不需要去点击构建按钮&#xff0c;Jenkins直接自动检测变化&#xff0c;然后自动去集成部署Linux&#xff1a;…