我们都知道微控制器只能处理数字值,但在现实世界中我们必须处理模拟信号。这就是为什么 ADC(模数转换器) 可以将现实世界的模拟值转换为数字形式,以便微控制器可以处理信号。但是,如果我们需要来自数字值的模拟信号怎么办,那么就来了 DAC(数模转换器)。
数模转换器的一个简单示例 是在录音室录制歌曲,艺术家歌手正在使用麦克风唱歌。这些模拟声波被转换为数字形式,然后存储在数字格式文件中,当使用存储的数字文件播放歌曲时,这些数字值被转换为模拟信号用于扬声器输出。所以在这个系统中使用了 DAC。
DAC 可用于许多应用 ,例如电机控制、控制 LED 灯的亮度、 音频放大器、视频编码器、数据采集系统等。
我们已经将 MCP4725 DAC 模块与 Arduino连接起来。今天我们将使用相同的 MCP4725 DAC IC 来设计一个使用 STM32F103C8 微控制器的数模转换器。
所需组件
STM32F103C8
MCP4725 DAC集成电路
10k 电位器
16x2 液晶显示器
面包板
连接电线
MCP4725 DAC 模块(数模转换器)
MCP4725 IC 是一款 12 位数模转换器模块 ,用于生成(0 至 5V)的输出模拟电压,并通过 I2C 通信进行控制。它还带有板载非易失性存储器 EEPROM。
该 IC 具有 12 位分辨率。这意味着我们使用(0 到 4096)作为输入来提供相对于参考电压的电压输出。最大参考电压为 5V。
计算输出电压的公式
O/P 电压 = (参考电压/分辨率) x 数字值
例如 ,如果我们使用 5V 作为参考电压,假设数字值为 2048。因此要计算 DAC 输出。
O/P 电压 = (5/ 4096) x 2048 = 2.5V
MCP4725的引脚排列
下面是 MCP4725 的图像,清楚地标明了引脚名称。
MCP4725 中的 I2C 通信
该 DAC IC 可通过 I2C 通信与任何微控制器连接。I2C 通信只需要两条线 SCL 和 SDA。默认情况下,MCP4725 的 I2C 地址为 0x60。点击链接了解更多关于STM32F103C8 中 I2C 通信的信息。
STM32F103C8 中的 I2C 引脚:
SDA: PB7 或 PB9、PB11。
SCL : PB6 或 PB8, PB10。
电路图及说明
STM32F103C8 和 16x2 LCD 之间的连接
MCP4725 DAC IC和STM32F103C8之间的连接
还连接了一个电位器,中心引脚连接到 STM32F10C8 的 PA1 模拟输入 (ADC),左侧引脚连接到 GND,最右侧引脚连接到 STM32F103C8 的 3.3V。
在本教程中,我们将MCP4725 DAC IC 与 STM32 连接,并使用 10k 电位器为 STM32 ADC 引脚 PA0 提供模拟输入值。然后使用ADC将模拟值转换为数字形式。之后通过 I2C 总线将这些数字值发送到 MCP4725。然后使用 DAC MCP4725 IC 将这些数字值转换为模拟值,然后使用 STM32 的另一个 ADC 引脚 PA1 从引脚 OUT 检查 MCP4725 的模拟输出。最后在16x2 LCD 显示屏上显示ADC 和 DAC 的电压值。
对 STM32F103C8 进行数模转换编程
现在不需要 FTDI 程序员将代码上传到 STM32F103C8。只需通过 STM32 的 USB 端口将其连接到 PC 并开始使用ARDUINO IDE进行编程。访问此链接以了解有关在 Arduino IDE 中对 STM32 进行编程的更多信息。 最后给出了这个STM32 DAC教程的完整程序。
首先使用wire.h、SoftWire.h和liquidcrystal.h库包含I2C 和LCD库。在此处了解有关STM32 微控制器中 I2C 的更多信息。
#include
#include
#include
接下来根据与STM32F103C8连接的LCD引脚定义并初始化LCD引脚
const int rs = PB11, en = PB10, d4 = PB0, d5 = PB1, d6 = PC13, d7 = PC14;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
然后定义 MCP4725 DAC IC 的 I2C 地址。MCP4725 DAC 默认 I2C 地址为 0x60
#define MCP4725 0x60
在 void setup()
首先在 STM32F103C8 的引脚 PB7 (SDA) 和 PB6 (SCL) 处开始 I2C 通信。
Wire.begin(); //开始I2C通信
接下来将 LCD 显示屏设置为 16x2 模式并显示欢迎信息。
lcd.开始(16,2);
lcd.print("电路文摘");
延迟(1000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("STM32F103C8");
lcd.setCursor(0,1);
lcd.print("带有 MCP4725 的 DAC");
延迟(2000);
lcd.clear();
在无效循环()
1.首先在缓冲区[0]中放入控制字节值(0b01000000)。
(010-将 MCP4725 设置为写模式)
缓冲区[0] = 0b01000000;
2. 以下语句从引脚 PA0 读取模拟值并将其转换为 0 到 4096 范围内的数字值,因为 ADC 是 12 位分辨率并存储在变量adc中。
adc = 模拟读取(PA0);
3. 以下语句是用于计算 ADC 输入值(0 到 4096)的电压的公式,参考电压为 3.3V。
浮动 ipvolt = (3.3/4096.0)* adc;
4. 通过在 ADC 变量中右移 4 位将最高有效位值放入缓冲区[1],通过在adc变量中左移 4 位将最低有效位值放入缓冲区[2]。
缓冲区[1] = adc >> 4;
缓冲区[2] = adc << 4;
5. 以下语句从 STM32 的 ADC 引脚 PA1 读取模拟值,即 DAC 输出(MCP4725 DAC IC 的 OUTPUT 引脚)。该引脚也可以连接到万用表以检查输出电压。
无符号整数模拟读取 = 模拟读取(PA1);
6. 此外,来自变量analogread的电压值使用带有以下语句的公式计算。
浮动 opvolt = (3.3/4096.0)* 模拟读数;
7. 在同一个void loop()中还有一些其他语句,下面解释
使用 MCP4725 开始传输:
Wire.beginTransmission(MCP4725);
将控制字节发送到 I2C
Wire.write(buffer[0]);
将 MSB 发送到 I2C
Wire.write(buffer[1]);
将 LSB 发送到 I2C
Wire.write(buffer[2]);
结束传输
Wire.endTransmission();
现在使用 lcd.print() 在 LCD 16x2 显示器中显示这些结果
lcd.setCursor(0,0);
lcd.print("A IP:");
lcd.print(adc);
lcd.setCursor(10,0);
lcd.print("V:");
lcd.print(ipvolt);
lcd.setCursor(0,1);
lcd.print("D OP:");
lcd.print(模拟读取);
lcd.setCursor(10,1);
lcd.print("V:");
lcd.print(opvolt);
延迟(500);
lcd.clear();
使用 STM32 测试 DAC
当我们通过旋转电位器改变输入 ADC 值和电压时,输出 DAC 值和电压也会发生变化。此处输入值显示在液晶显示屏的第一行,输出值显示在第二行。万用表也连接到 MCP4725 输出引脚以验证模拟电压。
#include //包含用于使用 I2C 功能的 Wire 库
#include
#include //包含用于使用 LCD 显示功能的 LCD 库
#define MCP4725 0x60 //MCP4725 地址为 0x60 相应地改变你的
const int rs = PB11, en = PB10, d4 = PB0, d5 = PB1, d6 = PC13, d7 = PC14;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
无符号整数 adc;
字节缓冲区[3];
void setup()
{
Wire.begin(); //开始 I2C 通信
lcd.begin(16,2); //将 LCD 设置为 16X2 模式
lcd.print("CIRCUIT DIGEST");
延迟(1000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("STM32F103C8");
lcd.setCursor(0,1);
lcd.print("带有 MCP4725 的 DAC");
延迟(2000);
lcd.clear();
}
无效循环()
{
缓冲区[0] = 0b01000000;//使用控制字节设置缓冲区0(010-设置为写入模式)
adc = analogRead(PA0); //从引脚 PA0 读取模拟值
float ipvolt = (3.3/4096.0)* adc; //求电压公式
buffer[1] = adc >> 4; //放置最高有效位值
buffer[2] = adc << 4; //输入最低有效位值
unsigned int analogread = analogRead(PA1) ; //从 PA1 读取模拟值
float opvolt = (3.3/4096.0)* analogread; //寻找电压公式
Wire.beginTransmission(MCP4725); //通过地址为0x60的MCP4725加入I2C总线
Wire.write(buffer[0]); //发送控制字节到I2C
Wire.write(buffer[1]); //将 MSB 发送到 I2C
Wire.write(buffer[2]); //发送LSB到I2C
Wire.endTransmission(); //结束传输
lcd.setCursor(0,0);
lcd.print("A IP:");
lcd.print(adc); //打印来自 PA0 的 ADC 值
lcd.setCursor(10,0);
lcd.print("V:"); //在 PA0 打印输入电压
lcd.print(ipvolt);
lcd.setCursor(0,1);
lcd.print("D OP:");
lcd.print(模拟读取);//打印来自 PA1 (From DAC) 的 ADC 值
lcd.setCursor(10,1);
lcd.print("V:");
lcd.print(opvolt);
//在 PA1(来自 DAC)延迟(500)处打印输入电压;
lcd.clear();
}