數字和模擬是電子學的一個組成部分。大多數設備同時具有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
PIC16F877A
20兆赫晶體
顯示 16x2 字符 LCD。
2k電阻-1個
33pF 電容器 - 2 個
4.7k 電阻器 - 1 個
萬用表測量輸出電壓
面包板
很多連接線或 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;
}
評論
查看更多