秋月でPICマイコン(AE-USBPIC44, PIC18F4553)を買ったので、UARTでPCとシリアル通信させてみました。
はまった点として、PICkit3でVDDが5.0V出なくて4.75Vになり、エラー表示で書き込みできないというのがありました。
PICkit 3 is trying to supply 5.000000 volts from the USB port, but the target VDD is measured to be 4.750000 volts. This could be due to the USB port power capabilities or the target circuitry affecting the measured VDD.
The target circuit may require more power than the debug tool can provide. An external power supply might be necessary.
Connection Failed.
そこで、プロジェクトのプロパティ→PICkit3→Powerを選び、Voltage Levelを4.5Vに設定すると、うまく書き込めました。(参考サイト)
UARTの送信は putch() で行います。この関数名にしておくことで、printf() が利用できます。
UARTの受信は getch() で行います。この関数名にしておくことで、gets() が利用できますが、gets() にはバッファオーバーランのバグがあるので決して使ってはいけません。そこで、今回は、UARTに接続されたターミナルで1行入力する(バックスペースで編集できる)関数 read_line() を用意しました。コンパクトで便利なのでよかったら使ってください。きちんとバッファオーバーランのないように作ってます。
さて、このプログラムの使い方は、まず、5VのUSBシリアル変換器を用意して、AE-USBPIC44ボード上のGND, TX, RXをクロス結線します。次にターミナルで9600bps 8bit ストップビット1で繋ぐと、PIC>
というプロンプトが表示されますので、help
などと入力してリターンキーを押してください。プロンプトが表示されないときはリターンキーを押してみてください。
/*
* UART example
* PIC18F4553 (AE-USBPIC44) + MPLAB X IDE + XC8
*/
#include <xc.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define _XTAL_FREQ 48000000L
#pragma config PLLDIV = 5
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 2
#pragma config FOSC = HSPLL_HS
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = ON
#pragma config BORV = 3
#pragma config VREGEN = ON
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = ON
#pragma config LPT1OSC = OFF
#pragma config PBADEN = OFF
#pragma config CCP2MX = OFF
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config ICPRT = OFF
#pragma config XINST = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF
#pragma config WRT3 = OFF
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF
#pragma config EBTRB = OFF
#define BAUD_RATE 9600L
#define SW1 PORTEbits.RE0
#define SW2 PORTEbits.RE1
#define LED PORTEbits.RE2
void pic_init(void);
void uart_init(unsigned long baud);
void putch(unsigned char c);
unsigned char getch(void);
void read_line(char *buf, int buf_size);
void main(void)
{
pic_init();
uart_init(BAUD_RATE);
while (1) {
char s[16];
/* Show prompt. */
printf("PIC> ");
/* Read command. */
read_line(s, sizeof(s));
/* Run command. */
if (strcmp(s, "") == 0)
continue;
else if (strcmp(s, "help") == 0)
printf("hello led switch\r\n");
else if (strcmp(s, "hello") == 0)
printf("Hello, world!\r\n");
else if (strcmp(s, "led") == 0)
LED = (unsigned char)~LED;
else if (strcmp(s, "switch") == 0)
printf("Switch is %s.\r\n", SW1 == 0 ? "ON" : "OFF");
else
printf("Command not found.\r\n");
__delay_ms(10);
}
}
void pic_init(void)
{
ADCON1 = 0b00001111;
TRISA = 0b00000000;
TRISB = 0b00000000;
TRISC = 0b00110000; /* D-, D+ */
TRISD = 0b00000000;
TRISE = 0b00000011; /* SW1, SW2, LED */
LATA = 0b00000000;
LATB = 0b00000000;
LATC = 0b00000000;
LATD = 0b00000000;
LATE = 0b00000000;
}
void uart_init(unsigned long baud)
{
/* Set baud rate generator */
if (_XTAL_FREQ / (baud * 16L) <= 255) {
BRGH = 1;
SPBRG = (unsigned char)(_XTAL_FREQ / (baud * 16L));
} else {
BRGH = 0;
SPBRG = (unsigned char)(_XTAL_FREQ / (baud * 64L));
}
SYNC = 0; /* Asynchronous mode (UART) */
SPEN = 1; /* Enable serial port */
TRISC6 = 1; /* Use TX */
TRISC7 = 1; /* Use RX */
CREN = 1; /* Enable continuous reception */
TXEN = 1; /* Enable transmission */
}
void putch(unsigned char c)
{
while(!TRMT)
;
TXREG = c;
}
unsigned char getch(void)
{
while(!RCIF)
;
return (char)RCREG;
}
void read_line(char *buf, int buf_size)
{
int pos = 0;
while (1) {
char c = getch();
if (isprint(c) && pos <= buf_size - 2) {
buf[pos++] = c;
putch(c);
} else if (c == 0x08 && pos > 0) {
pos--;
printf("\x08 \x08");
} else if (c == '\r') {
buf[pos] = '\0';
printf("\r\n");
break;
}
}
}