---
# System prepended metadata

title: 介面實驗五

---

# 介面實驗五
## 工作日誌 
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)



