# 微算機期末上機
避免 picket 接線掉下來

pic18f 腳位

## Lab6 基本設置、輸入輸出
設定 digital I/O
```c=
movlw 0x0f
movwf ADCON1 //所有與analog multiplexed的腳位都設為 digital I/O
```
記得設定 ==TRISx== , 來設定對應的 pin 腳的資料流向。
輸出電位時使用 ==LATx== , 讀取資料時使用 ==PORTx== 。
如果有使用到按鈕,記得加一點 delay , 避免 bouncing problem。
:::warning
組語的指令集記得下載,記得複習自己的程式碼,
而 C 與組語寫起來會有一些不同,
如:
>BCF LATB, 0, 0 ; 設定 RB0 為 0
與
>LATBbits.RB0 = 0;
:::
## Lab7 interrupt
### interrupt vector
- high-priority interrupt 在 0008h
- the low-priority interrupt vector 在 0018h
寫組語時 :
```asm=
; 以 INT0 為 external interrupt 來源
; 注意 INT0 永遠是 high-priority , 因此 org 要設在 0x0008
ISR:
org 0x0008
; some instructions handling interrupt
bcf INTCON, INT0IF ;clear interrupt flag
RETFIE
```
寫C時 :
```c=
void __interrupt(high_priority) ISR(void) {
if(INTCONbits.INT0IF)
{
INTCONbits.INT0IF = 0; // clear interrupt flag
// some some instructions handling interrupt
}
}
```
### interrupt 相關 register
可從 datasheet page ==93== 開始找到與 interrupt register 有關的敘述。
如果忘記到底要設定什麼 interrupt 設定,可以去瀏覽一下。
以下列出較常用的 register bit,基本上許多與 interrupt 有關的設定都與它們脫不了關係。
此次lab使用的 INT0 的 enable 與 flag bit 也有補充在下方。
若想找的是 peripheral device 相關的 interrupt 設定 (如 ADC、UART、CCP、TMR 等),
可以參考 page ==98== 開始的 ==PIR Registers==
:::info
通常 interrupt 都會有一個 enable bit 、 flag bit 、 priority bit 跟 edge select bit 等,
但很多時候它們是分散在不同 register 的,
記得要去找它們在哪些 register 裡,並且 enable interrupt、清空 flag bit 等。
:::
:::warning
flag 不會自動清空,記得自己在程式裡要把他清掉
:::
- INTCON :
- GIE/GIEH
- When IPEN = 0:
1 = Enables all unmasked interrupts
0 = Disables all interrupts
- When IPEN = 1:
1 = Enables all high-priority interrupts
0 = Disables all interrupts
- PEIE/GIEL
- When IPEN = 0:
1 = Enables all unmasked peripheral interrupts
0 = Disables all peripheral interrupts
- When IPEN = 1:
1 = Enables all low-priority peripheral interrupts
0 = Disables all low-priority peripheral interrupts
- INT0IE
- INT0 enable bit
1 = Enables the INT0 external interrupt
0 = Disables the INT0 external interrupt
- INT0IF
- INT0 flag bit
1 = The INT0 external interrupt occurred (==must be cleared in software==)
0 = The INT0 external interrupt did not occur
- INTCON2 :
- INTEDG0: External Interrupt 0 Edge Select bit
1 = Interrupt on rising edge
0 = Interrupt on falling edge
- RCON : 控制要不要有 priority
- IPEN: Interrupt Priority Enable bit
1 = Enable priority levels on interrupts
0 = Disable priority levels on interrupts (PIC16CXXX Compatibility mode
## Lab8 Timer
4 個 Timer 中, Timer2 最特別,也是此次 lab 使用的 timer 。
從 data sheet page ==123== 開始會從 Timer0 介紹。
如果想要知道 Timer2 的設定方式,則從 page ==133== 開始看。
### Timer2 運作方式
會有兩個 8-bit 暫存器, TMR2 跟 PR2 ,
TMR2 會在經由 prescaler 與 postscaler 運作以後的每個 instruction cycle 加 1,
當 TMR2 的值 與 PR2 的值 match 到時,就會產生 interrupt,並清空 TMR2 的值。
### 計算方式
若 $Fosc = 250kHz$ , 則$Tosc = 1 / 250k = 4 us$。
在 pic18f 裡,要把 $Tosc * 4$ 才會是 instruction cycle,
且假設今天 prescaler 與 postscaler 皆為 $1:16$
則 TMR2 的值,會在每 $(4us * 4 * 16 * 16 = 4096 us)$ 過後加 1 。
因此假如今天需要讓 Timer2 計算 1 秒,
則需要讓 TMR2 的值加到 $1/(4096*10{^{-6}}) = 244$時產生 interrupt,
因此 PR2 的值要設定成 244。
## 設定方式
首先要先設定震盪器頻率,預設是 ==1MHZ==。
- OSCCON:
- IRCF<2:0>: Internal Oscillator Frequency Select bits
111 = 8 MHz (INTOSC drives clock directly)
110 = 4 MHz
101 = 2 MHz
100 = 1 MHz(3)
011 = 500 kHz
010 = 250 kHz
001 = 125 kHz
000 = 31 kHz (from either INTOSC/256 or INTRC directly)
再來,如果要使用的是 Timer2 , 要去 ==T2CON==設定 。
- T2CON:
- T2OUTPS<3:0>: Timer2 Output Postscale Select bits
0000 = 1:1 Postscale
0001 = 1:2 Postscale
•
•
•
1111 = 1:16 Postscale
- TMR2ON: Timer2 On bit
1 = Timer2 is on
0 = Timer2 is off
- T2CKPS<1:0>: Timer2 Clock Prescale Select bits
00 = Prescaler is 1
01 = Prescaler is 4
1x = Prescaler is 16
:::warning
T2CONbits.TMR2ON 記得在做前置設定的時候先關起來,
等到真正要計時時再打開。
:::
最後是 interrupt 的設定。
- INTCON :
- GIE/GIEH
- When IPEN = 0:
1 = Enables all unmasked interrupts
0 = Disables all interrupts
- When IPEN = 1:
1 = Enables all high-priority interrupts
0 = Disables all interrupts
- PEIE/GIEL
- When IPEN = 0:
1 = Enables all unmasked peripheral interrupts
0 = Disables all peripheral interrupts
- When IPEN = 1:
1 = Enables all low-priority peripheral interrupts
0 = Disables all low-priority peripheral interrupts
- PIR1:
- TMR2IF: TMR2 to PR2 Match Interrupt Flag bit
1 = TMR2 to PR2 match occurred (must be cleared in software)
0 = No TMR2 to PR2 match occurred
- PIE1:
- TMR2IE: TMR2 to PR2 Match Interrupt Enable bit
1 = Enables the TMR2 to PR2 match interrupt
0 = Disables the TMR2 to PR2 match interrupt
- IPR1:
- TMR2IP: TMR2 to PR2 Match Interrupt Priority bit
1 = High priority
0 = Low priority
## Lab9 伺服馬達 (PWM)
Timer 與 CCP module 的對應關係:

此次 Lab 主要使用 PWM 來控制伺服馬達的轉動,
因此要使用 TMR2,TMR2的一些設定、計算方式與原理可以參考 ==Lab8==
### CCP1 設定
CCPx 的設定可以從 page ==139== 開始查看。
- CCPxCON
- CCPxM<3:0>: CCPx Module Mode Select bits
0000 = Capture/Compare/PWM disabled (resets CCPx module)
0001 = Reserved
0010 = Compare mode, toggle output on match (CCPxIF bit is set)
0011 = Reserved
0100 = Capture mode, every falling edge
0101 = Capture mode, every rising edge
0110 = Capture mode, every 4th rising edge
0111 = Capture mode, every 16th rising edge
1000 = Compare mode, initialize CCPx pin low; on compare match, force CCPx pin high (CCPxIF bit is set)
1001 = Compare mode, initialize CCPx pin high; on compare match, force CCPx pin low (CCPxIF bit is set)
1010 = Compare mode, generate software interrupt on compare match (CCPxIF bit is set, CCPx pin
reflects I/O state)
1011 = Compare mode, trigger special event; reset timer; CCP2 match starts A/D conversion (CCPxIF
bit is set)
==11xx = PWM mode==
因為此次 Lab 要使用 PWM mode,因此設定為
```c=
CCP1CONbits.CCP1M = 0b1100; //11xx , x 為 don't care
// 因為是 PWM Mode , 因此 CCP1/RC2 -> Output
TRISC = 0;
LATC = 0;
```
### PWM
#### 計算公式
$PWM\ Period =[(PR2) + 1]*4*Tosc * (TMR2\ Prescale\ Value)$
$PWM\ Duty\ Cycle = (CCPRXL:CCPXCON<5:4>)\ *\ Tosc\ *\ (TMR2\ Prescale\ Value)$
:::warning
注意 postscaler 沒有被用到!
且計算 duty cycle 時沒有再多乘以4。
:::
:::info
若使用 CCP1,則
CCP1CON<5:4> 在C裡面可以直接用 CCP1CONbits.DC1B 來操作。
:::
當 TMR2 與 PR2 相等時,會發生以下三件事:
- TMR2 is cleared
- The CCPx pin is set (exception: if PWM duty cycle = 0%, the CCPx pin will not be set)
- The PWM duty cycle is latched from CCPRxL into CCPRxH
小小注意事項:
CCPRxL and CCPxCON<5:4> can be written to at anytime, but ==the duty cycle value is not latched into CCPRxH until after a match between PR2 and TMR2 occurs== (i.e., the period is complete).
In PWM mode, CCPRxH is a read-only register.
### 伺服馬達

根據此伺服馬達的 spec,
- PWM period = 20ms
- duty cycle = 500 us -> $-90^{^o}$
- PR2 設為 0x9b
- duty cycle = 2400 us -> $90^{^o}$
可以將目標 duty cycle 代入公式反推 ==CCPRXL:CCPXCON<5:4>== 的值應為多少,
基本上沒有辦法算到很剛好,差不多就好。
## Lab 10 ADC
此次 Lab 將 可變電阻輸入的電壓轉成數值形式。
ADC 的設定可以在 page ==223== 開始找到。
### ADC 設定
- ADCON0:
- CHS<3:0>: Analog Channel Select bits ==(選擇要從哪個 port 接收 analog訊號)==
0000 = Channel 0 (AN0)
0001 = Channel 1 (AN1)
0010 = Channel 2 (AN2)
0011 = Channel 3 (AN3)
0100 = Channel 4 (AN4)
0101 = Channel 5 (AN5)
0110 = Channel 6 (AN6)
0111 = Channel 7 (AN7)
1000 = Channel 8 (AN8)
1001 = Channel 9 (AN9)
1010 = Channel 10 (AN10)
1011 = Channel 11 (AN11)
1100 = Channel 12 (AN12)
1101 = (Unimplemented)
1110 = (Unimplemented)
1111 = (Unimplemented)
- GO/DONE: A/D Conversion Status bit ==設定為1時開始做 A/D convert,變為0時做好==
When ADON = 1:
1 = A/D conversion in progress
0 = A/D Idle
- ADON: A/D On bit
1 = A/D Converter module is enabled
0 = A/D Converter module is disabled
- ADCON1:
- VCFG1: Voltage Reference Configuration bit (VREF- source)
1 = VREF- (AN2)
0 = VSS
- VCFG0: Voltage Reference Configuration bit (VREF+ source)
1 = VREF+ (AN3)
0 = VDD
- PCFG<3:0>: A/D Port Configuration Control bits

- ADCON2:
- ADFM: A/D Result Format Select bit
1 = Right justified ==(10bits,將 ADRESH 前兩bits與 ADRESL 結合)==
0 = Left justified ==(8 bits,取 ADRESH )==
- ACQT<2:0>: A/D Acquisition Time Select bits
111 = 20 TAD
110 = 16 TAD
101 = 12 TAD
100 = 8 TAD
011 = 6 TAD
010 = 4 TAD
001 = 2 TAD
000 = 0 TAD(1)
- ADCS<2:0>: A/D Conversion Clock Select bits
111 = FRC (clock derived from A/D RC oscillator
110 = FOSC/64
101 = FOSC/16
100 = FOSC/4
011 = FRC (clock derived from A/D RC oscillator)
010 = FOSC/32
001 = FOSC/8
000 = FOSC/2
:::info
注意 $T_{AD}$ 的值是根據 $T_{osc}$ 來設定的,不要用 instruction cycle ($T_{osc}*4$) 去計算。
:::
題目可能會指定 Fosc 應為多少或大於等於多少,
而因為有以下限制:
- $T_{AD} \geq 0.7 us$
- $T_{ACQ} \geq 2.4 us$
因此我們需要根據 Fosc 去查表,並設定 ADCON2 的 ADCS。
設定完 $T_{AD}$ 以後,要設定 ACQT ,
自己要算一下 $T_{ACQ}$ 應為幾倍的 $T_{AD}$,才會 大於等於 2.4 us。

例:題目要求要 Fosc = 4MHZ
則查表可知 ADCS = 0b100 (Fosc/4) 時間才夠
且我們可以得知 $T_{AD} = (0.25 us) * 4 = 1us$
為了滿足 $T_{ACQ} \geq 2.4 us$ 的條件,
ACQT = 010 (4*$T_{AD}$ = 4 us) 才夠。
### 其他小設定
記得將輸入 analog 訊號的 port設為 input。
若要用 interrupt 去偵測 ADC 做好了沒,
記得去設定:
```c=
RCONbits.IPEN = 1; //Interrupt Priority Enable bit
INTCONbits.GIE = 1; //Enables all high-priority interrupts
INTCONbits.PEIE = 1;
PIE1bits.ADIE = 1; // enable ADC interrupt
PIR1bits.ADIF = 0;
```
當ISR要做的處理做完後,記得要清空 flag ,
並且等待至少 $2T_{AD}$的時間才再將 GO 設起來,進行下一輪轉換。
## Lab11 UART
從 datasheet page 201 開始
### 前置設定
- Connect PIC18F’s RC6(TX) to the white wire of the UART.
- Connect PIC18F’s RC7(RX) to the green wire of the UART.
- TX 跟 RX 都要設定成 input
- async mode
- 查表設定 baud rate
接著設定 serial port,這部分可以參考:
```c=
// Serial enable
RCSTAbits.SPEN = 1; // Serial port enabled
PIR1bits.TXIF = 1; // TXREG empty
PIR1bits.RCIF = 0; // reception is not completed
TXSTAbits.TXEN = 1; // Transmit enabled
RCSTAbits.CREN = 1;// Enables receiver
PIE1bits.TXIE = 0; // disable transmit interrupt
IPR1bits.TXIP = 0;
PIE1bits.RCIE = 1; // enable receive interrupt
IPR1bits.RCIP = 0; // low priority
```
### 從 TTL 線抓取鍵盤輸入的資料
先觸發 interrupt , 再來讀。
```c=
void __interrupt(low_priority) Lo_ISR(void)
{
if(RCIF)
{
if(RCSTAbits.OERR)
{
CREN = 0;
Nop();
CREN = 1;
}
MyusartRead();
}
// process other interrupt sources here, if required
return;
}
```
```c=
void MyusartRead()
{
/* TODObasic: try to use UART_Write to finish this function */
// read RCREG when reception is completed
mystring[lenStr] = RCREG;
UART_Write(mystring[lenStr]); // 此行為把讀到的資料寫到 terminal 上
lenStr++;
lenStr %= 10;
return ;
}
```
### 寫資料到terminal上
```c=
void UART_Write(unsigned char data) // Output on Terminal
{
// TRMT shows the status of TSR
// TRMT is read only
// if TRMT is set => TSR is empty => we can transmit data!
while(!TXSTAbits.TRMT);
TXREG = data; //write to TXREG will send data
}
```
Lab11 有結合 ADC , 記得去查看一下怎麼設定。