PIC18F14K50でのBaudrateの設定の仕方

#1.目的
　12MHzの外部オシレータにPLLをかけて、Foscを48MHzにした後UART（PIC18F14K50ではEUSARTという。）の通信を行なうことが目的。

#2.早速つまずいた
　例のごとく早速つまずきました。
　一番初めに書いたコードは以下。

```
/*
 * File: main.c
 * Author: kashiharaakira
 *
 * Created on April 16, 2016, 8:35 PM
 */
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <p18f14k50.h>
#define _XTAL_FREQ 48000000

#pragma config CPUDIV = NOCLKDIV
#pragma config USBDIV = OFF
#pragma config FOSC = HS
#pragma config PLLEN = ON
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRTEN = OFF
#pragma config BOREN = OFF
#pragma config BORV = 30
#pragma config WDTEN = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = OFF
#pragma config HFOFST = OFF
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config XINST = OFF
#pragma config BBSIZ = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CPB = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTRB = OFF

void putch(unsigned char ch) {
    while(!TXIF);
    TXREG = ch;
}

void DelayMs(int dlyms){
    while(dlyms--){
        __delay_ms(1);
    }
}

void main(void) {
    OSCCON = 0b00000000; 
    TRISB = 0xF0;
    RCSTA = 0b10010000; 
    TXSTA = 0b00100100; 
    BAUDCON = 0b00001000; 
    SPBRGH = 0; 
    SPBRG = 1249; 
    __delay_ms(10); 
    while(1){
        printf("Hello World!\n");
        DelayMs(1000);
    }
}
```

　ここで肝になるのはTXSTA、BAUDCON、SPBRGH、SPBRGレジスタ。
　上のコードを動かしてみると、文字化けしてとても読める文字列を返してこない。
　
#3.解決策
##3.1.考えられる原因
・オシレータの精度
・PLLの精度
・Baudrateの何かしらの不具合

#3.3.実験してみた
長くなるので詳細は省きますが、結果一番高いのはBaundrateの何かしらの不具合orPLLの精度でした。
理由としては、オシレータの精度はオシロスコープで見た波形から誤差がほぼ無く綺麗なものでした。PLLの精度に関しては、内部オシレータのPLLは正常に行なえUARTの送受信は正常に行えた。しかし、周波数が高い場合特性が変わることは否定出来ない。最後のBaudrateの設定は、データシートの対応表を元にコードを組んだ。しかし、この設定が根本的におかしいことを否定することは出来ない。

##3.4.データシートをもう一度見る
PIC18F14K50のデータシートは以下。
日本語；　http://ww1.microchip.com/downloads/jp/DeviceDoc/41350D_JP.pdf
英語；　http://ww1.microchip.com/downloads/en/DeviceDoc/40001350F.pdf

PLLは今のところ調査しようがないので、Baudrateを疑う。
Baudrateに関しての基本的な情報は以下。
>baudrate timerはフリーラン動作
>SPBRGH:SPBRGレジスタペアで動作する
>TXSTAレジスタのBRGHビットとBAUDCONレジスタのBRG16ビットによってbaudrate周期の乗数が決まる
>BRGHビットは高baudレート、BRG16ビットは16bitBRGを意味する。それぞれHにすることで、利用が可能。どちらもbaudレートエラーの低減に効果があり、16bitBRGに関してはオシレータの周波数が高い場合でも低速のbaudレートを得ることが出来る。
>SPBRGH:SPBRGレジスタペアに新しい値を書き込むとBRG timerはリセットされる
>->BRG timerオーバフローを待たず、新しいbaudrateを出力できるようになる。

##3.5.今回利用する設定
今回利用する設定内容は、以下
BRG16=1,SYNC=0,BRGH=1
この、設定の場合Desired Baud RateとSPBRGH:SPBRGの関係式は以下

>Desired Baud Rate = Fosc/64([SPBRGH:SPBRG]+1)
これをとりあえず解いていきましょう。目的はSPBRGH:SPBRGを導き出すことです。
SPBRGH:SPBRG = X, Desired Baud Rate = Yと置く。
Y = Fosc/4(X+1)
X+1 = Fosc/4Y
X = (Fosc/4Y)-1
今、Fosc=48MHz, Desired Baud Rate = 9600より
X = {(48*10^6) / 4*9600} - 1
X = 1249

ここでXとはなんぞやというところが、ネックだったわけです。
これまでは、このSPBRGH:SPBRGは「比率」だと思っていたのですが、そうではなくて8bit:8bitの意味だったんです。
つまり

>SPBRGH:SPBRG = 1249[D] = 0000010011100001[B]
SPBRGH = 00000100[B] = 4[D]
SPBRG = 11100001[B] = 225[D]

ということだったんですね。
つまり、さっきのコードのこの部分をきちんと変えてやれば動くはずです。

##3.6.やっと動いた…
今までの過程で、書いた以下のコードでやっと動きました…完成です。

```
/*
 * File:   main.c
 * Author: kashiharaakira
 *
 * Created on April 16, 2016, 8:35 PM
 */
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <p18f14k50.h>
#define _XTAL_FREQ 48000000

#pragma config CPUDIV = NOCLKDIV
#pragma config USBDIV = OFF
#pragma config FOSC   = HS
#pragma config PLLEN  = ON
#pragma config FCMEN  = OFF
#pragma config IESO   = OFF
#pragma config PWRTEN = OFF
#pragma config BOREN  = OFF
#pragma config BORV   = 30
#pragma config WDTEN  = OFF
#pragma config WDTPS  = 32768
#pragma config MCLRE  = OFF
#pragma config HFOFST = OFF
#pragma config STVREN = ON
#pragma config LVP    = OFF
#pragma config XINST  = OFF
#pragma config BBSIZ  = OFF
#pragma config CP0    = OFF
#pragma config CP1    = OFF
#pragma config CPB    = OFF
#pragma config WRT0   = OFF
#pragma config WRT1   = OFF
#pragma config WRTB   = OFF
#pragma config WRTC   = OFF
#pragma config EBTR0  = OFF
#pragma config EBTR1  = OFF
#pragma config EBTRB  = OFF

void putch(unsigned char ch) {
    while(!TXIF);
    TXREG = ch;
}

void DelayMs(int dlyms){
    while(dlyms--){
        __delay_ms(1);
    }
}

void DelayUs(int dlyum){
    while(dlyum--){
        __delay_us(1);
    }
}

void main(void) {
    OSCCON = 0b00000000;       
    TRISB = 0xF0;
    RCSTA   = 0b10010000; 
    TXSTA   = 0b00100100;  
    BAUDCON = 0b00001000;  
    SPBRGH  = 1249 / 256;           
    SPBRG   = 1249 % 256;    
    __delay_ms(10);                
    while(1){
        printf("Hello World!\n");
        DelayMs(1000);
    }
}
```

#4.参考にしたサイト
参考１；　http://www.microchip.com/forums/m924490.aspx
参考２；　http://www48.atpages.jp/cent22/Electronics/PIC/Usart_Calc_Baudrate/Usart_Calc_Baudrate.html

#5.謝辞
参考１のサイトで、本件について質問をさせていただきました。解決の糸口は、答えていただいたMicrochip Forumの利用者の方の助言があったからです。本、情報を書くにあたり御礼申し上げます。

#6.問い合わせ
なんか「ここおかしいんじゃないの？」とか「ここもっと聞きたい！」という所があれば、以下のメールアドレスもしくは本記事にコメントいただけると、嬉しいです。
akira.kashihara@hotmail.com