# 介面實驗五 ## 工作日誌 10/11 使用MCP4921 IC輸出3V的電壓 10/12 要產生正弦波,卻無法用出來,示波器的波型很奇怪,最後詢問發現我不小心對IC輸出負值,所以才無法產生弦波 10/13 成功用示波器看到弦波 10/14 成功用DAC輸出正弦波的電壓,透過ADC讀取產生圖 ## 程式碼 **DAC介面卡原型試作**-使用MCP4921 DAC輸出3V電壓,電表觀測 C語言 :::spoiler ```c= #include "c4mlib.h" #include "math.h" #include "stdlib.h" #include "stdio.h" #include <avr/io.h> #include "spi.cfg" void SPI_setup(); void pin_setup(); #define PIN_CS 0 #define PIN_F1CS 1 #define PIN_SCK 1 #define PIN_MOSI 2 #define PIN_MISO 3 uint16_t data = 20480+3146;//20480+3072=23552 uint16_t data_1 =3146; int main(void) { C4M_DEVICE_set(); pin_setup(); SPI_setup();// initial SPI REGFPT( &PORTD , 0x03 , 0 , 3 ); while(1) { REGFPT(&PORTD,1,0,0);//set CS low before receive data ASA_SPIM_trm( 4 , 0 , 0 , 2 , &data , 10);//對A通達雙倍參考電壓輸出 REGFPT(&PORTD,1,0,1);//set CS high after receive data REGFPT(&PORTD,2,0,0);//set LDAC low _delay_ms(100); REGFPT(&PORTD,2,0,2);//set LDAC high } return 0; } void SPI_setup() { SPCR=(1<<SPE)|(1<<MSTR);// enable SPI,set master mode,CPHA=0,CPOL=0,DORD=0,SPR0:1=0 REGFPT(&SPSR,0x01,0,1);//set double mode } void pin_setup() { DDRB |= (1<<PIN_SCK)|(1<<PIN_MOSI)|(1<<PIN_CS);//set pin CS,SCK as output DDRB &= ~(1<<PIN_MISO);// set pin MISO as input DDRD |= (1<<PIN_CS)|(1<<PIN_F1CS)|(1<<5)|(1<<6)|(1<<7);//set D0 D1 as input } ``` ::: --- **示波器觀察DAC輸出波型** C語言 :::spoiler ```c= #include "c4mlib.h" #include "math.h" #include "stdlib.h" #include "stdio.h" #include <avr/io.h> #include "spi.cfg" #include "tim.cfg" void SPI_setup(); void pin_setup(); void Time_setup(); void DAC_put(); #define PIN_CS 0 #define PIN_F1CS 1 #define PIN_SCK 1 #define PIN_MOSI 2 #define PIN_MISO 3 int i =0,b=0; uint16_t data = 20480+3146,DATA= 86,xx;//20480+3072 float x[101][1] = {}; float data_1=20480,data_2=1024; int main(void) { C4M_DEVICE_set(); HMI_snget_matrix(8,101,1,x); pin_setup(); SPI_setup();// initial SPI REGFPT( &PORTD , 0x03 , 0 , 3 ); for (int j =0;j<=100;j++) { x[j][0]=x[j][0]*data_2; } HMI_snput_matrix(8,101,1,x);//傳送矩陣給matlab for (int j =0;j<=100;j++) { x[j][0]=data_1+x[j][0]; } Time_setup(); while(1){} return 0; } void SPI_setup() { SPCR=(1<<SPE)|(1<<MSTR);// enable SPI,set master mode,CPHA=0,CPOL=0,DORD=0,SPR0:1=0 REGFPT(&SPSR,0x01,0,1);//set double mode } void pin_setup() { DDRB |= (1<<PIN_SCK)|(1<<PIN_MOSI)|(1<<PIN_CS);//set pin CS,SCK as output DDRB &= ~(1<<PIN_MISO);// set pin MISO as input DDRD |= (1<<PIN_CS)|(1<<PIN_F1CS)|(1<<5)|(1<<6)|(1<<7);//set F0 F1 as input } void Time_setup() { REGFPT( &TCCR2 , 0x48 , 3 , 1 );//波型模式選擇 REGFPT( &TCCR2 , 0x07 , 0 , 4 );//除頻值設定 REGFPT( &TCCR2 , 0x30 , 4 , 1 );//波行輸出選擇 REGFPT( &TIMSK , 0x80 , 7 , 1 );//中斷致能 REGPUT( &OCR2 , 1 , &DATA );//設定週期 sei(); } void DAC_put() { xx=x[i][0]; REGFPT(&PORTD,1,0,0);//set CS low before receive data ASA_SPIM_trm( 4 , 0 , 0x50 , 2 , &xx , 1);//對A通達雙倍參考電壓輸出 REGFPT(&PORTD,1,0,1);//set CS high after receive data REGFPT(&PORTD,2,0,0);//set LDAC low _delay_us(1); REGFPT(&PORTD,2,0,2);//set LDAC high i++; if (i == 100) { i = 0; } } ISR(TIMER2_COMP_vect) { DAC_put(); } ``` ::: MATLAB :::spoiler ```matlab= clear; close all; clc; portnum=5; t=(0:0.01:1)'; p=sin(2*pi*5*t)+1.5; %p(1:101)=3; x=p(1:101); x=single(x); port=remo_open(portnum);%打開com5 [err]=remo_snput_matrix(port,x); [input,err_2] = remo_snget_matrix(port);%得到ASA電腦給的矩陣 remo_close(port);%關閉com5 input=single(input);%轉型 %disp(input_2);%顯示outpute plot(t(1:101),input(1:101),'r'); %legend(input_2) ``` ::: --- **ADC觀察DAC輸出波型** C語言 :::spoiler ```c= #include "c4mlib.h" #include "math.h" #include "stdlib.h" #include "stdio.h" #include <avr/io.h> #include "spi.cfg" #include "tim.cfg" void SPI_setup(); void pin_setup(); void Time_setup(); void DAC_put(); void ADC_setup(); void ADC_save(); #define PIN_CS 0 #define PIN_F1CS 1 #define PIN_SCK 1 #define PIN_MOSI 2 #define PIN_MISO 3 int i =0,msk = 0,num = 0,interupt = 0,j=0; uint8_t value_ADCL,value_ADCH,flag; uint16_t data = 20480+3146,DATA= 86,xx,Code_sing,Code_vbg;//20480+3072 float x[101][1] = {},code[101][1] = {},tmp = 0; float data_1=20480,data_2=1024; int main(void) { C4M_DEVICE_set(); HMI_snget_matrix(8,101,1,x); ADC_setup(); REGFPT( &ADMUX , 0x1F , 0 , 0x00 );//輸入 _delay_ms(2); pin_setup(); SPI_setup();// initial SPI REGFPT( &PORTD , 0x03 , 0 , 3 ); for (int j =0;j<=100;j++) { x[j][0]=x[j][0]*data_2; } //HMI_snput_matrix(8,101,1,x);//傳送矩陣給matlab for (int j =0;j<=100;j++) { x[j][0]=data_1+x[j][0]; } Time_setup(); while(1) { if (msk == 100 && interupt == 0) { HMI_snput_matrix(8,101,1,code);//傳送矩陣給matlab interupt = 1; break; } _delay_us(1); } return 0; } void SPI_setup() { SPCR=(1<<SPE)|(1<<MSTR);// enable SPI,set master mode,CPHA=0,CPOL=0,DORD=0,SPR0:1=0 REGFPT(&SPSR,0x01,0,1);//set double mode } void pin_setup() { DDRB |= (1<<PIN_SCK)|(1<<PIN_MOSI)|(1<<PIN_CS);//set pin CS,SCK as output DDRB &= ~(1<<PIN_MISO);// set pin MISO as input DDRD |= (1<<PIN_CS)|(1<<PIN_F1CS)|(1<<5)|(1<<6)|(1<<7);//set F0 F1 as input } void Time_setup(){ REGFPT( &TCCR2 , 0x48 , 3 , 1 );//波型模式選擇 REGFPT( &TCCR2 , 0x07 , 0 , 3 );//除頻值設定 REGFPT( &TCCR2 , 0x30 , 4 , 1 );//波行輸出選擇 REGFPT( &TIMSK , 0x80 , 7 , 1 );//中斷致能 REGPUT( &OCR2 , 1 , &DATA );//設定週期 sei(); } void ADC_setup() { REGFPT( &ADMUX , 0xC0 , 6 , 3 ); //設定參考電壓來源 REGFPT( &ADMUX , 0x20 , 5 , 0 ); //資料向右靠齊 REGFPT( &ADCSRA , 0x07 , 0 , 3 ); //設定工作時脈除頻 REGFPT( &ADCSRA , 0x20 , 5 , 0 ); //設定非連續轉換 REGFPT( &ADCSRA , 0x80 , 7 , 1 ); //設定ADC致能 REGFPT( &ADCSRA , 0x08 , 3 , 1 ); //設定禁制能中斷 REGFPT( &DDRF , 0x0F , 0 , 0 ); //設定ADC接角為輸入 } void DAC_put() { xx=x[i][0]; REGFPT(&PORTD,1,0,0);//set CS low before receive data ASA_SPIM_trm( 4 , 0 , 0x50 , 2 , &xx , 1);//對A通達雙倍參考電壓輸出 REGFPT(&PORTD,1,0,1);//set CS high after receive data REGFPT(&PORTD,2,0,0);//set LDAC low _delay_us(1); REGFPT(&PORTD,2,0,2);//set LDAC high i++; if (i == 100) { i = 0; } } void ADC_save() { REGFPT( &ADCSRA , 0x40 , 0 , 0x40 ); //觸發單一轉換 while((ADCSRA&(1<<ADIF)) != (1<<ADIF)); //轉換需時 REGGET( &ADCL , 1 , &value_ADCL ); //先讀低BYTE資料 REGGET( &ADCH , 1 , &value_ADCH ); //後讀高BYTE資料,接著暫存器更新 REGFGT( &ADCSRA , 0x10 , 4 , &flag ); //讀取轉換旗標 Code_sing=((value_ADCH<<8)+value_ADCL); //存為10BITS的資料 tmp = Code_sing*0.0025; REGFPT( &ADCSRA , 0x10 , 4 , 1 ); //消除中斷旗標 if (msk < 101) { code[msk][0] = tmp; } } ISR(TIMER2_COMP_vect) { DAC_put(); if (j==10)//取樣頻率100hz { msk++; ADC_save(); j=0; } j++; if (msk == 200) { msk = 199; } } ``` ::: MATLAB :::spoiler ```matlab= clear; close all; clc; portnum=5; t=(0:0.01:1)'; p=sin(2*pi*5*t)+1.5; %p(1:101)=3; x=p(1:101); x=single(x); port=remo_open(portnum);%打開com5 [err]=remo_snput_matrix(port,x); [input,err_2] = remo_snget_matrix(port);%得到ASA電腦給的矩陣 remo_close(port);%關閉com5 input=single(input);%轉型 %disp(input_2);%顯示outpute plot(t(1:101),input(1:101),'r'); %legend(input_2) ``` ::: ## 流程圖 **DAC介面卡原型試作-使用MCP4921 DAC輸出3V電壓,電表、示波器觀測** ![](https://i.imgur.com/hwoM3xN.jpg) **示波器觀察DAC輸出波型** ![](https://i.imgur.com/W2Pbu2h.jpg) **ADC觀察DAC輸出波型** ![](https://i.imgur.com/iOMHypg.jpg) ## 實驗結果 **DAC介面卡原型試作-使用MCP4921 DAC輸出3V電壓,電表、示波器觀測** ![](https://i.imgur.com/nVNi0zt.jpg) ![](https://i.imgur.com/q4fL4gW.jpg) **示波器觀察DAC輸出波型** 5hz弦波 ![](https://i.imgur.com/89VV27A.jpg) 10hz弦波 ![](https://i.imgur.com/kaMXykN.jpg) **ADC觀察DAC輸出波型** 5hz弦波 ![](https://i.imgur.com/LmkK0uE.jpg) 10hz弦波 ![](https://i.imgur.com/sQH7d4q.jpg) ## 遭遇問題 1. **示波器圖形呈階梯狀?** 因為當固定時間輸出類比電壓值時,輸出電壓會在一段時間內保持在恆定值,直到下一個輸出電壓輸出,所以會導致其在示波器看起來是一階一階的樣子,而ADC量測的話是因為DAC輸出一次ADC讀取一次,所以不會跑出階梯狀,而是一個一個不同的點相連而成的弦波。 *matlab 用plot的話不會有階梯狀,因為它會把兩個點連起來,實際上的數值要用stairs才能看吃來喔!!* ## 問題 1. **請問您在這個實驗中您學到了什麼?** 知道如何使用MCP4921 DAC輸出電壓,並且輸出弦波接著透過ADC去讀取。 2. **請問 D/A 輸出是否能夠有斜率的上昇或則下降, 為什麼?** 當頻率為5HZ時可以看到弦波有斜率的上升或下降,而在10HZ時看到的波偏向階梯狀,看不太出來其斜率上升下降,因為波的頻率變高,導致取樣點變少,看起來就會有階梯狀。取樣頻率為100hz *你的取樣率有問題,太低了,可能是tim中斷頻率有問題* ## 驗收 用DAC來做16bitADC,並print出來ADC的結果。 ![](https://i.imgur.com/LjmJwuw.png) ### 驗收結果 $$ {\bf LSB}={工作電壓範圍 \over 幾位元}={3.84V \over 2^{16}}=0.00005859375V $$ $$ {ADC*{V_{ref} \over 2^{16}}}={V_{in}} $$ 1. V input=2.88v 輸出16bitsADC為1011 1111 1011 1100=49084 $$ {49084*{3.84 \over 2^{16}}}={2.876V} $$ 電表量測2.87~2.88 ![](https://i.imgur.com/FRJPNDg.jpg) 結果 ![](https://i.imgur.com/d9bBuXp.jpg) 計算機 ![](https://i.imgur.com/fAcZ4rk.jpg) 2. V input=1.92V 輸出16bitsADC為0111 1111 1110 1111=32751 $$ {32751*{3.84 \over 2^{16}}}={1.919V} $$ 電表量測1.91~1.92 ![](https://i.imgur.com/itW9hVz.jpg) 結果 ![](https://i.imgur.com/rVFPoah.jpg) 計算機 ![](https://i.imgur.com/PbufcqK.jpg)