将MCP4921与PIC16F877A接口进行数模转换的方法

模拟技术

2414人已加入

描述

  数字和模拟是电子学的一个组成部分。大多数设备同时具有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。引脚图和说明可以在下面找到。

PIC16F877A

  MCP4921 IC通过SPI 协议与微控制器通信。对于 SPI 通信,设备必须是主设备,它向作为从设备连接的外部设备提交数据或命令。在 SPI 通信系统中,单个主设备可以连接多个从设备。

  要提交数据和命令,了解命令寄存器很重要。

  在下图中,显示了命令寄存器,

PIC16F877A

  命令寄存器是一个16 位寄存器。bit-15 到 bit-12 用于配置命令。上图清楚地显示了数据输入和配置。在本项目中,MCP4921 将用作以下配置 -

PIC16F877A

  所以二进制是 0011 以及由寄存器的 D11 到 D0 位确定的数据。需要提交16位数据0011 xxxx xxxx xxxx,其中MSB的前4位为配置,其余为LSB。看写命令时序图会更清楚。

PIC16F877A

  根据时序图和数据表,在向 MCP4921 的整个命令写入周期内,CS 引脚为低电平。

  现在是时候将设备与硬件连接并编写代码了。

  所需组件

  对于这个项目,需要以下组件 -

  MCP4921

  PIC16F877A

  20兆赫晶体

  显示 16x2 字符 LCD。

  2k电阻-1个

  33pF 电容器 - 2 个

  4.7k 电阻器 - 1 个

  万用表测量输出电压

  面包板

  5V供电,一个手机充电器即可工作。

  很多连接线或 berg 线。

  带有 Programmer 套件和带有编译器的 IDE 的 Microchip 编程环境

  示意图

  将DAC4921 与 PIC 微控制器连接的电路图 如下所示:

PIC16F877A

  该电路是在面包板中构建的-

PIC16F877A

代码说明

文章末尾给出了使用 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 上。万用表显示接近读数。

PIC16F877A

/*

* 文件: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;

}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分