数字和模拟是电子学的一个组成部分。大多数设备同时具有ADC和 DAC,当需要将信号从模拟转换为数字或从数字转换为模拟时使用它们。此外,声音和光等现实世界的信号本质上是模拟的,因此无论何时必须使用这些现实世界的信号,都必须将数字信号转换为模拟信号,例如使用扬声器产生声音或控制光源。
另一种类型的 DAC 是脉冲宽度调制器 (PWM)。PWM 接收一个数字字并生成一个具有可变脉冲宽度的数字脉冲。当这个信号通过一个滤波器时,结果将是纯模拟的。一个模拟信号在一个信号中可以有多种类型的数据。
在本教程中,我们将DAC MCP4921 与 Microchip PIC16F877A 接口以进行数模转换。
在本教程中,我们将数字信号转换为模拟信号,并在16x2 LCD上显示输入数字值和输出模拟值。它将提供 1V、2V、3V、4V 和 5V 作为最终的模拟输出,这在最后给出的视频中进行了演示。
DAC 可用于许多应用 ,例如电机控制、LED 灯的控制亮度、 音频放大器、视频编码器、数据采集系统等。在直接跳转到接口部分之前,了解 MCP4921 的概述非常重要。
MCP4921 DAC(数模转换器)
MCP4921 是 12 位 DAC,因此 MCP4921 将提供 12 位输出分辨率。DAC 分辨率是指可以转换为模拟信号的数字位数。我们可以从中获得多少价值是基于公式的。对于 12 位,它 = 4096。这意味着 12 位分辨率 DAC 可以产生 4096 个不同的输出。
通过使用该值,可以轻松计算单个模拟阶跃电压。为了计算步数,需要参考电压。由于该器件的逻辑电压为 5V,因此步进电压为 5/4095(4096-1,因为数字的起点不是 1,而是 0),即 0.00122100122 毫伏。因此,更改 1 位将使模拟输出更改为 0.00122100122。
所以,这就是转换部分。MCP4921是一个 8 引脚 IC。引脚图和说明可以在下面找到。
MCP4921 IC通过SPI 协议与微控制器通信。对于 SPI 通信,设备必须是主设备,它向作为从设备连接的外部设备提交数据或命令。在 SPI 通信系统中,单个主设备可以连接多个从设备。
要提交数据和命令,了解命令寄存器很重要。
在下图中,显示了命令寄存器,
命令寄存器是一个16 位寄存器。bit-15 到 bit-12 用于配置命令。上图清楚地显示了数据输入和配置。在本项目中,MCP4921 将用作以下配置 -
所以二进制是 0011 以及由寄存器的 D11 到 D0 位确定的数据。需要提交16位数据0011 xxxx xxxx xxxx,其中MSB的前4位为配置,其余为LSB。看写命令时序图会更清楚。
根据时序图和数据表,在向 MCP4921 的整个命令写入周期内,CS 引脚为低电平。
现在是时候将设备与硬件连接并编写代码了。
所需组件
对于这个项目,需要以下组件 -
MCP4921
20兆赫晶体
显示 16x2 字符 LCD。
2k电阻-1个
33pF 电容器 - 2 个
4.7k 电阻器 - 1 个
万用表测量输出电压
面包板
5V供电,一个手机充电器即可工作。
很多连接线或 berg 线。
带有 Programmer 套件和带有编译器的 IDE 的 Microchip 编程环境
示意图
将DAC4921 与 PIC 微控制器连接的电路图 如下所示:
该电路是在面包板中构建的-
代码说明
文章末尾给出了使用 PIC16F877A 将数字信号转换为模拟信号 的完整代码。与往常一样,我们首先需要 设置 PIC 单片机中的配置位。
// PIC16F877A 配置位设置 // 'C' 源代码行配置语句 // CONFIG #pragma config FOSC = HS // 振荡器选择位(HS 振荡器) #pragma config WDTE = OFF // 看门狗定时器使能位(WDT 禁用) #pragma config PWRTE = OFF // 上电定时器使能位(PWRT 禁用) # pragma config BOREN = ON // 欠压复位使能位(BOR 使能) #pragma config LVP = OFF // 低电压(单电源)在线串行编程使能位(RB3/PGM 引脚具有 PGM 功能;低-电压编程启用) #pragma config CPD = OFF // 数据 EEPROM 存储器代码保护位(数据 EEPROM 代码保护关闭) #pragma config WRT = OFF // 闪存程序存储器写使能位(写保护关闭;所有程序存储器都可以由 EECON 控制写入) #pragma config CP = OFF // Flash 程序存储器代码保护位(代码保护关闭)
以下代码行用于集成 LCD 和 SPI 头文件,还声明了 XTAL 频率和 DAC 的 CS 引脚连接。
PIC SPI 教程和库可以在给定的链接中找到。
#include#include #include "supporing_cfile\lcd.h" #include "supporing_cfile\PIC16F877a_SPI.h" /* 硬件相关定义 */ #define _XTAL_FREQ 200000000 //晶体频率,用于延迟 #define DAC_CS PORTCbits.RC0 //声明DAC CS引脚
SPI_IniTIalize_Master ()功能针对该项目所需的不同配置稍作修改。在这种情况下,SSPSTAT 寄存器的配置方式是,在数据输出时间结束时采样输入数据以及配置为发送的 SPI 时钟发生在从活动时钟状态模式转换到空闲时钟状态模式时。其他也一样。
无效 SPI_IniTIalize_Master() { TRISC5 = 0; // 设置为输出 SSPSTAT = 0b11000000; //pg 74/234 SSPCON = 0b00100000; //pg 75/234 TRISC3 = 0; //设置为从模式的输出 }
此外,对于以下函数,SPI_Write() 稍作修改。数据传输将在缓冲区清空后进行,以确保通过 SPI 进行完美的数据传输。
无效 SPI_Write(char 传入) { SSPBUF = 传入; //将用户给定的数据写入缓冲区 while (!SSPSTATbits.BF); }
该程序的重要部分是 MCP4921 驱动程序。这是一个有点棘手的部分,因为命令和数字数据被打孔在一起以通过 SPI 提供完整的 16 位数据。但是,该逻辑清楚地显示在代码注释中。
/* 此函数用于将数字值转换为模拟值。 */ void convert_DAC(unsigned int value) { /*步长 = 2^n, 因此 12bit 2^12 = 4096 对于 5V 参考,步长将为 5/4095 = 0.0012210012210012V 或 1mV(大约)*/ unsigned int 容器; 无符号整数 MSB; 无符号整数 LSB; /*步骤:1、将12位数据存入容器 假设数据为4095,二进制1111 1111 1111*/ container = value; /*步骤:2 创建虚拟 8 位。因此,通过除以 256,在 LSB 中捕获高 4 位 LSB = 0000 1111*/ LSB = container/256; /*Step: 3 发送配置打孔4位数据。 LSB = 0011 0000 或 0000 1111。结果为 0011 1111 */ LSB = (0x30) | 低位; /*Step:4 容器仍然有 21bit 的值。提取低 8 位。 1111 1111 和 1111 1111 1111。结果是 1111 1111,即 MSB*/ MSB = 0xFF & 容器; /*Step:4 将16bits的数据分成两个字节发送。*/ DAC_CS = 0; // 数据传输期间 CS 为低电平。根据数据表,需要 SPI_Write(LSB); SPI_Write(MSB); DAC_CS = 1; }
在主函数中,使用“for 循环”来创建用于创建 1V、2V、3V、4V 和 5V 输出的数字数据。数字值是根据输出电压 / 0.0012210012210012 毫伏计算得出的。
无效 main() { system_init(); 介绍屏幕(); 整数=0; 国际伏特=0; 而 (1) { for (volt=1; volt<=MAX_VOLT; volt++){ number = volt / 0.0012210012210012; 清除屏幕(); lcd_com(FIRST_LINE); lcd_puts("数据发送:-"); lcd_print_number(数字); lcd_com(第二行); lcd_puts("输出:-"); lcd_print_number(伏特); lcd_puts("V"); 转换_DAC(数字); __delay_ms(300); } } }
使用 PIC 测试数模转换
使用万用表测试构建的电路。在下图中,输出电压和数字数据显示在 LCD 上。万用表显示接近读数。
/*
* 文件:main.c
* 作者:苏拉夫·古普塔 *<|:-]
* 创建于:circuitdigest.com
* 项目:mcp4921 接口
* 创建于 2019 年 3 月 21 日晚上 7:05
*/
// PIC16F877A 配置位设置
// 'C' 源代码行配置语句
// 配置
#pragma config FOSC = HS // 振荡器选择位(HS 振荡器)
#pragma config WDTE = OFF // 看门狗定时器启用位(WDT 禁用)
#pragma config PWRTE = OFF // 上电定时器使能位(PWRT 禁用)
#pragma config BOREN = ON // 欠压复位使能位(BOR 使能)
#pragma config LVP = OFF // 低压(单电源)在线串行编程使能位(RB3/PGM 引脚具有 PGM 功能;低压编程使能)
#pragma config CPD = OFF // 数据 EEPROM 存储器代码保护位(数据 EEPROM 代码保护关闭)
#pragma config WRT = OFF // Flash 程序存储器写使能位(写保护关闭;EECON 控制可以写入所有程序存储器)
#pragma config CP = OFF // Flash 程序存储器代码保护位(代码保护关闭)
#include
#include
#include "supporTIng_cfile\lcd.h"
#include "supporTIng_cfile\PIC16F877a_SPI.h"
/*
硬件相关定义
*/
#define _XTAL_FREQ 200000000 //晶体频率,用于延迟
#define DAC_CS PORTCbits.RC0 //声明DAC CS引脚
/*
程序流相关定义
*/
#define MAX_VOLT 5
#define FIRST_LINE 0x80
#define SECOND_LINE 0xC0
/*
其他具体功能定义
*/
无效系统初始化(无效);
无效 sw_delayms(无符号整数 d);
无效转换_DAC(无符号整数数字值);
无效清除屏幕(无效);
无效介绍屏幕(无效);
无效的主要(){
系统初始化();
介绍屏幕();
整数=0;
国际伏特=0;
而(1){
对于(伏特=1;伏特<=MAX_VOLT;伏特++){
数字 = 伏特 / 0.0012210012210012;
清除屏幕();
lcd_com(FIRST_LINE);
lcd_puts("数据发送:-");
lcd_print_number(数字);
lcd_com(第二行);
lcd_puts("输出:-");
lcd_print_number(伏特);
lcd_puts("V");
转换_DAC(数字);
__delay_ms(300);
}
}
}
/*
此功能用于软件延迟。
*/
无效 sw_delayms(无符号整数 d){
整数 x, y;
for(x=0;x
for(y=0;y<=1275;y++);
}
/*
该函数用于系统初始化。
*/
无效系统初始化(无效){
TRISB = 0x00;// LCD 引脚作为输出
TRISCbits.TRISC0=0;// CS 引脚声明为输出
液晶初始化();//这将初始化lcd
SPI_Initialize_Master();
}
/*
此功能用于在没有命令的情况下清除屏幕。
*/
无效清除屏幕(无效){
lcd_com(FIRST_LINE);
lcd_puts("");
lcd_com(第二行);
lcd_puts("");
}
/*
此功能用于播放介绍。
*/
无效介绍屏幕(无效){
lcd_com(FIRST_LINE);
lcd_puts("欢迎来到");
lcd_com(第二行);
lcd_puts("电路文摘");
__delay_ms(500);
清除屏幕();
lcd_com(FIRST_LINE);
lcd_puts("mcp4921 with");
lcd_com(第二行);
lcd_puts("PIC16F877A");
__delay_ms(350);
}
/*
此功能用于将数字值转换为模拟值。
*/
无效转换_DAC(无符号整数值)
{
/*步长 = 2^n,因此 12bit 2^12 = 4096
对于 5V 参考,步长为 5/4095 = 0.0012210012210012V 或 1mV(大约)*/
无符号整数容器;
无符号整数 MSB;
无符号整数 LSB;
/*Step: 1、将12位数据存入容器
假设数据为4095,二进制1111 1111 1111*/
容器=价值;
/*步骤:2 创建虚拟 8 位。因此,通过除以 256,在 LSB 中捕获高 4 位
LSB = 0000 1111*/
LSB = 容器/256;
/*Step: 3 发送配置打孔4位数据。
LSB = 0011 0000 或 0000 1111。结果为 0011 1111 */
LSB = (0x30) | 低位;
/*Step:4 容器仍然有 21bit 的值。提取低 8 位。
1111 1111 AND 1111 1111 1111。结果为 1111 1111,即 MSB*/
MSB = 0xFF & 容器;
/*Step:4 将16bits的数据分成两个字节发送。*/
DAC_CS = 0;// 数据传输期间 CS 为低电平。根据数据表,它是必需的
SPI_Write(LSB);
SPI_Write(MSB);
DAC_CS = 1;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)