# 微算機期末上機 避免 picket 接線掉下來 ![](https://i.imgur.com/2Vp2be9.png) pic18f 腳位 ![](https://i.imgur.com/OgGoLyX.png) ## 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 的對應關係: ![](https://i.imgur.com/TaFF2vy.png) 此次 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. ### 伺服馬達 ![](https://i.imgur.com/yiNaQBH.png) 根據此伺服馬達的 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 ![](https://i.imgur.com/TAYKGgz.png) - 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。 ![](https://i.imgur.com/lFMg8Jh.png) 例:題目要求要 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 , 記得去查看一下怎麼設定。