LoginSignup
0
0

More than 3 years have passed since last update.

PIC18F14K50でのBaudrateの設定の仕方

Last updated at Posted at 2016-05-26

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.参考にしたサイト

参考1; http://www.microchip.com/forums/m924490.aspx
参考2; http://www48.atpages.jp/cent22/Electronics/PIC/Usart_Calc_Baudrate/Usart_Calc_Baudrate.html

5.謝辞

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

6.問い合わせ

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

0
0
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0