PICでリアルタイムクロック
概要
PIC18F27J53は、リアルタイムクロック&カレンダー(RTCC)モジュールをハードウェアで持っています。今回はそれを使用するためのライブラリを作ったので紹介します。
自作のRTCCライブラリ
必要なソースファイル
- My_RTCC.h
- My_RTCC.c
- My_button.h
- My_button.c
- main.c
概要
変数
このプログラムでは、時刻情報を持つ変数が3つある。
- PICのRTCCモジュールのレジスタ→カレンダー表記、16進法表記(※厳密には10進だが便宜上16進とする。)
- time_t構造体内のepoch(uint32_t)→2000年1月1日0時00分からの総秒数
- time_t構造体内のYY,MM,DD,EE,hh,mm,ss→それぞれ、年、月、日、曜日、時、分、秒の10進法表記。
以上3つがある。時刻が変わってもRTCC_loop()関数がすべての値を常に一致させているので安心して使用できる。
使い方
- TIOSCのピンに32.768kHzのクリスタルをつなぐ。(12pのコンデンサも)
- CONFIGを設定する。RTCOSC = T1OSCREF
- その次に、RTCC_init();を書く。(初期設定関数)
- mainループ内に、RTCC_loop();を書くこと。(時間の同期関数)
- 任意で時計合わせをする。→時計合わせをしたら、RTCC_from_caltime()かRTCC_from_epoch()を呼んで変更を適用する。
- 時計合わせには、adjust_time_toggle()を呼んでから、adjust_time_cursor()で、好きな項を選択する
- adjust_time_inc()とadjust_time_dec()で調整するとよい。
- 時計合わせが終わったら、adjust_time_toggle()をもう一度呼ぶと時計合わせ終了。
RTCCライブラリ
My_RTCC.h
/*
* File: My_RTCC.h
* Author: Ryotaro Onuki
*
* Created on 2015/03/19, 0:02
*
* PIC18F28J53用リアルタイムクロックプログラム
* ○概要
* このプログラムでは、時刻情報を持つ変数が3つある。
* 1.PICのRTCCモジュールのレジスタ→カレンダー表記、16進法表記(※厳密には10進だが便宜上16進とする。)
* 2.time_t構造体内のepoch(uint32_t)→2000年1月1日0時00分からの総秒数
* 3.time_t構造体内のYY,MM,DD,EE,hh,mm,ss→それぞれ、年、月、日、曜日、時、分、秒の10進法表記。
* 以上3つがある。時刻が変わってもRTCC_loop()関数がすべての値を常に一致させているので安心して使用できる。
* ○使い方
* 1.TIOSCのピンに32.768kHzのクリスタルをつなぐ。(12pのコンデンサも)
* 2.CONFIGを設定する。RTCOSC = T1OSCREF
* 3.その次に、RTCC_init();を書く。(初期設定関数)
* 4.mainループ内に、RTCC_loop();を書くこと。(時間の同期関数)
* 5.任意で時計合わせをする。→時計合わせをしたら、RTCC_from_caltime()かRTCC_from_epoch()を呼んで変更を適用する。
* 6.時計合わせには、adjust_time_toggle()を呼んでから、adjust_time_cursor()で、好きな項を選択する
* 7.adjust_time_inc()とadjust_time_dec()で調整するとよい。
* 8.時計合わせが終わったら、adjust_time_toggle()をもう一度呼ぶと時計合わせ終了。
*/
#ifndef MY_RTCC_H
#define MY_RTCC_H
/** INCLUDES *******************************************************/
#include <xc.h>
#include <stdint.h>
#include "My_button.h"
/** VALUES *********************************************************/
#define MINUTE ((epoch_t)60)
#define HOUR ((epoch_t)60*60)
#define DAY ((epoch_t)60*60*24)
/** STRUCTURE ******************************************************/
// epoch型を定義。2000年1月1日0時00分からの総秒数。
typedef uint32_t epoch_t;
// 時刻合わせ用のフラグの構造体を定義。
typedef struct {
union {
uint8_t flags;
struct {
uint8_t ss : 1;
uint8_t mm : 1;
uint8_t hh : 1;
uint8_t DD : 1;
uint8_t MM : 1;
uint8_t YY : 1;
} flag;
};
} edit_t;
// RTCC関連すべてを詰めた構造体。実際に使用する。
typedef struct {
epoch_t epoch;
uint8_t ss;
uint8_t mm;
uint8_t hh;
uint8_t EE;
uint8_t DD;
uint8_t MM;
uint8_t YY;
uint8_t colon;
uint8_t halfsec;
edit_t edit;
} time_t;
/** VARIABLES ******************************************************/
// 表示用の曜日charをconstで定義。
extern const char weekday_3char[7][4];
// 現在時刻
extern time_t now;
// 時間が変わった時だけフラグが経つ。表示器の時刻の更新はこのフラグの監視をして行えばよい。
extern uint8_t time_change_flag;
// main_init()に書くこと。
void RTCC_init(void);
// Call this in the main loop
void RTCC_task(void);
/** USER FUNCTIONS *************************************************/
/** Transform time User Functions **/
// 時刻をRTCC基準でそろえる
void RTCC_from_RTCC(time_t *tm);
// 時刻をカレンダータイム基準でそろえる
void RTCC_from_caltime(time_t *tm);
// 時刻をエポック基準でそろえる
void RTCC_from_epoch(time_t *tm);
// return month length
uint8_t month_length(uint8_t year, uint8_t month);
/** LCD display **/
// 各項目表示用関数。ユーザーは使わない。
static void display_dec(char *str, uint8_t dec, uint8_t edit);
// 0802サイズ液晶用、文字列作成関数
void display_time_0802(time_t *tm, char *line0, char *line1);
// 1608サイズ液晶用、文字列作成関数
void display_time_1602(time_t *tm, char *line0, char *line1);
/** adjust the time **/
// 時刻編集モードを切り替える
void RTCC_adjust_time_toggle(time_t *tm);
// 編集中の時刻針を切り替える
void RTCC_adjust_time_cursor(time_t *tm);
// 編集中の時刻針を1つ増やす
void RTCC_adjust_time_inc(time_t *tm);
// 編集中の時刻針を1つ減らす
void RTCC_adjust_time_dec(time_t *tm);
// 3つのボタンで時刻合わせ
void RTCC_adjust_time_button(time_t *tm, button_t *mode, button_t *cnt_inc, button_t *cnt_dec);
/** FUNCTIONS ******************************************************/
/** en/decode number **/
// from decimal to hex
static uint8_t d_to_x(uint8_t dec);
// from hex to decimal
static uint8_t x_to_d(uint8_t hex);
// quotをdivで割って、余りを返す。よく使うので関数化した。
static epoch_t get_quot_rem(epoch_t *quot, uint8_t div);
/** Transform time **/
// RTCCをカレンダタイムに変換、上書き。
static void RTCC_to_caltime(time_t *tm);
// カレンダタイムをRTCCに変換、上書き。
static void caltime_to_RTCC(time_t *tm);
// Epochをカレンダタイムに変換、上書き。
static void epoch_to_caltime(time_t *tm);
// get epoch from caltime
static void caltime_to_epoch(time_t *tm);
#endif /* MY_RTCC_H */
My_RTCC.c
#include "My_RTCC.h"
/** INCLUDES *******************************************************/
#include <stdio.h>
#include <string.h>
/** VALUES *********************************************************/
/** VARIABLES ******************************************************/
const char weekday_3char[7][4] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
time_t now;
uint8_t time_change_flag;
/** USER FUNCTIONS *************************************************/
void RTCC_init(void) {
RTCCFGbits.RTCWREN = 1;
if (RTCCFGbits.RTCWREN != 1) {
EECON2 = 0x55;
EECON2 = 0xAA;
RTCCFGbits.RTCWREN = 1;
}
RTCCFGbits.RTCEN = 1;
RTCCFGbits.RTCOE = 0;
PADCFG1bits.RTSECSEL0 = 1;
PADCFG1bits.RTSECSEL1 = 1;
RTCCAL = 0x00;
T1CONbits.T1OSCEN = 1;
RTCC_from_RTCC(&now);
if (now.DD == 0) {
now.epoch = 0;
RTCC_from_epoch(&now);
}
}
void RTCC_task(void) {
static uint8_t prev_halfsec;
if (RTCCFGbits.RTCSYNC)return;
now.halfsec = RTCCFGbits.HALFSEC;
if (prev_halfsec != now.halfsec) {
prev_halfsec = now.halfsec;
now.colon = now.halfsec;
time_change_flag = 1;
RTCC_from_RTCC(&now);
}
}
/** Transform time User Functions **/
void RTCC_from_RTCC(time_t *tm) {
RTCC_to_caltime(tm);
caltime_to_epoch(tm);
}
void RTCC_from_caltime(time_t *tm) {
caltime_to_epoch(tm);
epoch_to_caltime(tm);
caltime_to_RTCC(tm);
}
void RTCC_from_epoch(time_t *tm) {
epoch_to_caltime(tm);
caltime_to_RTCC(tm);
}
uint8_t month_length(uint8_t year, uint8_t month) {
if (month == 2) return 28 + !(year & 3)-!(year % 100)+!(year % 400);
else return 31 - (((-(month & 1)^month)&13) == 4);
// switch (month) {
// case 1:
// case 3:
// case 5:
// case 7:
// case 8:
// case 10:
// case 12:
// return 31;
// case 4:
// case 6:
// case 9:
// case 11:
// return 30;
// case 2:
// if (year % 400 == 0)return 29;
// else if (year % 100 == 0)return 28;
// else if (year % 4 == 0) return 29;
// else return 28;
}
/** LCD display **/
static void display_dec(char *str, uint8_t dec, uint8_t edit) {
char s[4];
sprintf(s, "%02d", dec);
if (edit && now.halfsec)strcat(str, " ");
else strcat(str, s);
}
void display_time_0802(time_t *tm, char *line0, char *line1) {
RTCC_from_RTCC(&now);
strcpy(line0, "");
display_dec(line0, tm->YY, tm->edit.flag.YY);
strcat(line0, "/");
display_dec(line0, tm->MM, tm->edit.flag.MM);
strcat(line0, "/");
display_dec(line0, tm->DD, tm->edit.flag.DD);
strcpy(line1, "");
display_dec(line1, tm->hh, tm->edit.flag.hh);
if (now.colon) strcat(line1, ":");
else strcat(line1, " ");
display_dec(line1, tm->mm, tm->edit.flag.mm);
strcat(line1, "-");
display_dec(line1, tm->ss, tm->edit.flag.ss);
}
void display_time_1602(time_t *tm, char *line0, char *line1) {
RTCC_from_RTCC(&now);
strcpy(line0, "");
display_dec(line0, 20, tm->edit.flag.YY);
display_dec(line0, tm->YY, tm->edit.flag.YY);
strcat(line0, "/");
display_dec(line0, tm->MM, tm->edit.flag.MM);
strcat(line0, "/");
display_dec(line0, tm->DD, tm->edit.flag.DD);
strcat(line0, "(");
strcat(line0, weekday_3char[tm->EE]);
strcat(line0, ")");
strcpy(line1, " ");
display_dec(line1, tm->hh, tm->edit.flag.hh);
if (tm->colon) strcat(line1, ":");
else strcat(line1, " ");
display_dec(line1, tm->mm, tm->edit.flag.mm);
strcat(line1, "-");
display_dec(line1, tm->ss, tm->edit.flag.ss);
}
/** adjust the time **/
void RTCC_adjust_time_toggle(time_t *tm) {
if (tm->edit.flags) {
tm->edit.flags = 0;
} else {
tm->edit.flag.ss = 1;
}
}
void RTCC_adjust_time_cursor(time_t *tm) {
if (tm->edit.flag.ss)tm->edit.flags = 0x02;
else if (tm->edit.flag.mm)tm->edit.flags = 0x04;
else if (tm->edit.flag.hh)tm->edit.flags = 0x08;
else if (tm->edit.flag.DD)tm->edit.flags = 0x10;
else if (tm->edit.flag.MM)tm->edit.flags = 0x20;
else if (tm->edit.flag.YY)tm->edit.flags = 0x01;
else tm->edit.flags = 0x00;
}
void RTCC_adjust_time_inc(time_t *tm) {
RTCC_from_RTCC(tm);
if (tm->edit.flag.ss) tm->epoch += 1;
if (tm->edit.flag.mm) tm->epoch += MINUTE;
if (tm->edit.flag.hh) tm->epoch += HOUR;
if (tm->edit.flag.DD) tm->epoch += DAY;
if (tm->edit.flag.MM) tm->epoch += DAY * month_length(tm->YY, tm->MM);
if (tm->edit.flag.YY) {
for (uint8_t i = tm->MM; i <= 12; i++) {
tm->epoch += DAY * month_length(tm->YY, i);
}
for (uint8_t i = 1; i < tm->MM; i++) {
tm->epoch += DAY * month_length(tm->YY + 1, i);
}
}
if (tm->epoch >= 3155760000)tm->epoch -= 3155760000;
RTCC_from_epoch(&now);
time_change_flag = 1;
}
void RTCC_adjust_time_dec(time_t *tm) {
RTCC_from_RTCC(tm);
if (tm->edit.flag.ss) tm->epoch -= 1;
if (tm->edit.flag.mm) tm->epoch -= MINUTE;
if (tm->edit.flag.hh) tm->epoch -= HOUR;
if (tm->edit.flag.DD) tm->epoch -= DAY;
if (tm->edit.flag.MM) tm->epoch -= DAY * month_length(tm->YY, tm->MM);
if (tm->edit.flag.YY) {
for (uint8_t i = tm->MM; i >= 1; i--) {
tm->epoch -= DAY * month_length(tm->YY, i);
}
for (uint8_t i = 12; i > tm->MM; i--) {
tm->epoch -= DAY * month_length(tm->YY - 1, i);
}
}
if (tm->epoch >= 3155760000)tm->epoch += 3155760000;
RTCC_from_epoch(&now);
time_change_flag = 1;
}
void RTCC_adjust_time_button(time_t *tm, button_t *mode, button_t *cnt_inc, button_t *cnt_dec) {
if (mode->flag.long_holding_3) {
mode->flag.long_holding_3 = 0;
RTCC_adjust_time_toggle(tm);
mode->flags = 0;
cnt_inc->flags = 0;
cnt_dec->flags = 0;
}
if (tm->edit.flags) {
if (mode->flag.press) {
mode->flag.press = 0;
RTCC_adjust_time_cursor(tm);
}
if (cnt_inc->flag.press) {
cnt_inc->flag.press = 0;
RTCC_adjust_time_inc(tm);
}
if (cnt_dec->flag.press) {
cnt_dec->flag.press = 0;
RTCC_adjust_time_dec(tm);
}
}
}
/** FUNCTIONS ******************************************************/
/** en/decode number **/
static uint8_t d_to_x(uint8_t dec) {
// uint8_t quot = dec / 10;
// return quot * 16 + dec - quot * 10;
return dec / 10 * 6 + dec;
}
static uint8_t x_to_d(uint8_t hex) {
return 10 * (0x0F & (hex >> 4)) + (0x0F & hex);
}
static epoch_t get_quot_rem(epoch_t *quot, uint8_t div) {
// num /= div;
// return rem;
epoch_t num = *quot;
return num - (*quot = num / div) * div; // returns rem
}
/** Transform time **/
static void RTCC_to_caltime(time_t *tm) {
while (RTCCFGbits.RTCSYNC);
RTCCFGbits.RTCPTR0 = 1;
RTCCFGbits.RTCPTR1 = 1;
tm->YY = x_to_d(RTCVALL); // YY
uint8_t dumy = RTCVALH; // Reserved
tm->DD = x_to_d(RTCVALL); // DD
tm->MM = x_to_d(RTCVALH); // MM
tm->hh = x_to_d(RTCVALL); // hh
tm->EE = x_to_d(RTCVALH); // EE
tm->ss = x_to_d(RTCVALL); // ss
tm->mm = x_to_d(RTCVALH); // mm
}
static void caltime_to_RTCC(time_t *tm) {
while (RTCCFGbits.RTCSYNC);
RTCCFGbits.RTCPTR0 = 1;
RTCCFGbits.RTCPTR1 = 1;
RTCVALL = d_to_x(tm->YY);
RTCVALH = 0x00;
RTCCFGbits.RTCPTR0 = 0;
RTCCFGbits.RTCPTR1 = 1;
RTCVALL = d_to_x(tm->DD);
RTCVALH = d_to_x(tm->MM);
RTCCFGbits.RTCPTR0 = 1;
RTCCFGbits.RTCPTR1 = 0;
RTCVALL = d_to_x(tm->hh);
RTCVALH = d_to_x(tm->EE);
RTCCFGbits.RTCPTR0 = 0;
RTCCFGbits.RTCPTR1 = 0;
RTCVALL = d_to_x(tm->ss);
RTCVALH = d_to_x(tm->mm);
}
static void epoch_to_caltime(time_t *tm) {
// to get epoch on terminal
// echo $(( (`date -d '2015/03/01' '+%s'` - `date -d '2000/01/01' '+%s'`) / 86400 ))
static uint16_t day_cache = 0; //2015.03.01
static uint8_t month_cache = 1;
static uint8_t year_cache = 0;
uint16_t day_since_epoch;
uint16_t day;
uint8_t year = 0;
uint8_t month = 1; // month is one-based.
epoch_t num;
num = tm->epoch;
tm->ss = get_quot_rem(&num, 60);
tm->mm = get_quot_rem(&num, 60);
tm->hh = get_quot_rem(&num, 24);
day = num;
day_since_epoch = day;
num += 6; // 2000.1.1 is Saturday(6).
tm->EE = get_quot_rem(&num, 7);
// if (day == day_cache) {
// year = year_cache;
// month = month_cache;
// day -= day_cache;
// }
// day is zero - based here.
while (day >= month_length(year, month)) {
LATB2 = 1;
day = day - month_length(year, month);
if (month == 12) {
month = 1; // month is one-based.
year++;
//3155760000 is 2000~2100?100?????
if (year >= 100) {
tm->epoch -= 3155760000;
year = 0;
}
} else {
month++;
}
month_cache = month;
year_cache = year;
}
day_cache = day_since_epoch - day;
day++; // day is one-based, not zero-based.
tm->YY = year;
tm->MM = month;
tm->DD = day;
}
static void caltime_to_epoch(time_t *tm) {
epoch_t epoch = 0;
for (uint8_t year = 0; year < tm->YY; year++) {
for (uint8_t month = 1; month <= 12; month++) {
epoch += DAY * month_length(year, month);
}
}
for (uint8_t month = 1; month < tm->MM; month++) {
epoch += DAY * month_length(tm->YY, month);
}
epoch += DAY * (tm->DD - 1); //day is one-based.
epoch += HOUR * tm->hh;
epoch += MINUTE * tm->mm;
epoch += tm->ss;
tm->epoch = epoch;
}
ボタンライブラリ
My_button.h
/*
* File: My_button.h
* Author: kerikun11
*
* Created on 2015/02/26, 19:19
*/
#ifndef MY_BUTTON_H
#define MY_BUTTON_H
#include <stdint.h>
//*************************** button ***************************//
//タイマー割り込み関数にbutton_timer_interrupt(&button_t,!SW)を書いておくこと。
// 48MHz, 16bit, prescaler=1:4
#define PRESS_LEVEL 2
#define LONG_HOLD_LEVEL1 16
#define LONG_HOLD_LEVEL2 60
#define LONG_HOLD_LEVEL3 150
#define LONG_HOLD_LEVEL4 300
#define LONG_HOLD_LEVEL5 500
#define LONG_HOLD_LEVEL6 700
#define LONG_HOLD_LEVEL7 900
typedef struct button {
uint16_t cnt_sw;
union {
uint16_t flags;
struct {
uint8_t press : 1;
uint8_t long_hold_1 : 1;
uint8_t long_hold_2 : 1;
uint8_t long_hold_3 : 1;
uint8_t long_hold_4 : 1;
uint8_t long_hold_5 : 1;
uint8_t long_hold_6 : 1;
uint8_t long_hold_7 : 1;
uint8_t pressing : 1;
uint8_t long_holding_1 : 1;
uint8_t long_holding_2 : 1;
uint8_t long_holding_3 : 1;
uint8_t long_holding_4 : 1;
uint8_t long_holding_5 : 1;
uint8_t long_holding_6 : 1;
uint8_t long_holding_7 : 1;
} flag;
};
} button_t;
void button_timer_interrupt(button_t *bt, uint8_t sw_value);
#endif /* MY_BUTTON_H */
My_button.h
#include "My_button.h"
void button_timer_interrupt(button_t *bt, uint8_t sw_value) {
if (sw_value) {
if (bt->cnt_sw == LONG_HOLD_LEVEL7)bt->flag.long_holding_7 = 1;
if (bt->cnt_sw == LONG_HOLD_LEVEL6)bt->flag.long_holding_6 = 1;
if (bt->cnt_sw == LONG_HOLD_LEVEL5)bt->flag.long_holding_5 = 1;
if (bt->cnt_sw == LONG_HOLD_LEVEL4)bt->flag.long_holding_4 = 1;
if (bt->cnt_sw == LONG_HOLD_LEVEL3)bt->flag.long_holding_3 = 1;
if (bt->cnt_sw == LONG_HOLD_LEVEL2)bt->flag.long_holding_2 = 1;
if (bt->cnt_sw == LONG_HOLD_LEVEL1)bt->flag.long_holding_1 = 1;
if (bt->cnt_sw == PRESS_LEVEL)bt->flag.pressing = 1;
if (bt->cnt_sw < LONG_HOLD_LEVEL7 + 1) bt->cnt_sw++;
} else {
if (bt->cnt_sw >= LONG_HOLD_LEVEL7)bt->flag.long_hold_7 = 1;
else if (bt->cnt_sw >= LONG_HOLD_LEVEL6)bt->flag.long_hold_6 = 1;
else if (bt->cnt_sw >= LONG_HOLD_LEVEL5)bt->flag.long_hold_5 = 1;
else if (bt->cnt_sw >= LONG_HOLD_LEVEL4)bt->flag.long_hold_4 = 1;
else if (bt->cnt_sw >= LONG_HOLD_LEVEL3)bt->flag.long_hold_3 = 1;
else if (bt->cnt_sw >= LONG_HOLD_LEVEL2)bt->flag.long_hold_2 = 1;
else if (bt->cnt_sw >= LONG_HOLD_LEVEL1)bt->flag.long_hold_1 = 1;
else if (bt->cnt_sw >= PRESS_LEVEL)bt->flag.press = 1;
bt->cnt_sw = 0;
bt->flags &= 0x00FF;
}
}
使用例
UARTで毎秒時刻を送信します。
main.c
/*
* Project: RTCC-Sample.X
* File: main.c
* Author: Ryotaro Onuki
*
* Created on 2015/10/06, 14:23
*/
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
// CONFIG1L
#pragma config WDTEN = OFF, PLLDIV = 2, CFGPLLEN = ON, STVREN = OFF, XINST = OFF
// CONFIG1H
#pragma config CPUDIV = OSC1, CP0 = OFF
// CONFIG2L
#pragma config OSC = INTOSCPLL, SOSCSEL = HIGH, CLKOEC = OFF, FCMEN = OFF, IESO = OFF
// CONFIG2H
#pragma config WDTPS = 1024
// CONFIG3L
#pragma config DSWDTOSC = T1OSCREF, RTCOSC = T1OSCREF, DSBOREN = OFF, DSWDTEN = OFF, DSWDTPS = G2
// CONFIG3H
#pragma config IOL1WAY = OFF, ADCSEL = BIT12, MSSP7B_EN = MSK7
// CONFIG4L
#pragma config WPFP = PAGE_127, WPCFG = OFF
// CONFIG4H
#pragma config WPDIS = OFF, WPEND = PAGE_WPFP, LS48MHZ = SYS48X8
#define _XTAL_FREQ 48000000
#include "My_RTCC.h"
#include "My_button.h"
// I/O Mapping
#define MODE_BUTTON PORTBbits.RB0
#define INC_BUTTON PORTBbits.RB1
#define DEC_BUTTON PORTBbits.RB2
#define LED0 LATAbits.LATA0
button_t mode;
button_t inc;
button_t dec;
void interrupt ISR(void) {
if (PIE1bits.TMR1IE && PIR1bits.TMR1IF) {
PIR1bits.TMR1IF = 0;
}
if (PIE2bits.TMR3IE && PIR2bits.TMR3IF) {
PIR2bits.TMR3IF = 0;
LED0 = !LED0;
button_timer_interrupt(&mode, !MODE_BUTTON);
button_timer_interrupt(&inc, !INC_BUTTON);
button_timer_interrupt(&dec, !DEC_BUTTON);
}
if (PIR1bits.RCIF && PIE1bits.RCIE) {
while (!PIR1bits.TXIF); // 送信完了まで待つ。
TXREG1 = RCREG1; // 受信データをそのまま送信
}
}
void main_init(void) {
OSCCONbits.IRCF = 7;
OSCTUNEbits.PLLEN = 1;
OSCCONbits.SCS = 0;
TRISA = 0b00100000; // IO,IO,Vcap,IO,IO,IO,IO,IO
TRISB = 0b00110111; // IO,IO,SDA,SCL,IO,IO,IO,IO
TRISC = 0b10111010; // RX,TX,D+,D-,Vusb,IO,T1OSI,T1OSO
ANCON0 = 0b11111111; // x,x,x,AN4,AN3,AN2,AN1,AN0
ANCON1 = 0b11111111; // x,x,x,x,AN12,AN11,AN10,AN9,AN8
INTCON2bits.RBPU = 0; // Port:B Pull-up enable
// Timer 1 init
T1CONbits.TMR1CS = 2; // Clock = T1OSC
T1CONbits.T1OSCEN = 1; // Drive Crystal
T1CONbits.T1CKPS = 0; // No devide
T1CONbits.nT1SYNC = 1; // No Sync
T1CONbits.RD16 = 0; // Timer1 = 2 x 8bit timer
T1CONbits.TMR1ON = 1; // module enable
IPR1bits.TMR1IP = 0; // low priority
PIR1bits.TMR1IF = 0;
PIE1bits.TMR1IE = 1;
INTCONbits.PEIE = 1;
// Timer 3 init
T3CONbits.TMR3CS = 0; // Clock = Fosc/4
T3CONbits.T3OSCEN = 0; // Not Drive Crystal
T3CONbits.T3CKPS = 2; // clock/4
T3CONbits.RD163 = 0; // Timer3=16bit timer
T3CONbits.TMR3ON = 1; // module enable
IPR2bits.TMR3IP = 0; // low priority
PIR2bits.TMR3IF = 0;
PIE2bits.TMR3IE = 1; // interrupt enable
INTCONbits.PEIE = 1;
// RTCC init
RTCC_init();
// UART init
TXSTA1bits.TX9 = 0; // 0:8-bit
TXSTA1bits.TXEN = 1; //1:enable
TXSTA1bits.SYNC = 0; // 0:Asynchronous mode
TXSTA1bits.BRGH = 0; // 1:High Speed
RCSTA1bits.SPEN = 1; // 1:Serial Port enable
RCSTA1bits.RX9 = 0; // 0:8-bit
RCSTA1bits.CREN = 1; // 1:continuous receive enable
BAUDCON1bits.BRG16 = 0; // 1:use 16-bit SPBRG
SPBRG1 = _XTAL_FREQ / 64 / 9600 - 1;
SPBRGH1 = 0;
IPR1bits.RC1IP = 0; //0:low priority
PIE1bits.RCIE = 1;
INTCONbits.PEIE = 1;
}
void delay(uint16_t t) {
while (t--)__delay_ms(1);
}
int main(void) {
main_init();
INTCONbits.GIE = 1;
while (1) {
RTCC_task();
RTCC_adjust_time_button(&now, &mode, &inc, &dec);
if (time_change_flag) {
time_change_flag = 0;
char str[30];
sprintf(str, "\t20%02d/%02d/%02d(%s)%02d:%02d-%02d\n",
now.YY,
now.MM,
now.DD,
weekday_3char[now.EE],
now.hh,
now.mm,
now.ss);
for (uint8_t i = 0; str[i]; i++) {
while (!PIR1bits.TXIF); //送信完了まで待つ
TXREG1 = str[i];
}
}
}
return 0;
}