JH7UBCブログ

アマチュア無線 電子工作 家庭菜園など趣味のブログです

PIC16F1827 MCC RTC(DS1307)時計の試作

2021-08-10 11:26:58 | MPLAB X MCC
 東京オリンピックが終わり、しばらく放っておいたPIC16F1827 RTC 時計のプログラミングを再開しました。

 一応動きましたので、公開します。(まだバグがあるかも知れません)

 まず、回路図です。SETボタンを長押しすると時計セットモードになります。年、月、日、曜、時、分、秒の数値の変更は、UP/DOWNボタンで行います。SETモードでは、SETボタンを押すごとに年から秒まで変更できます。
 以前に試作したArduino Nano RTC(DS1307) 時計と基本的な操作、プログラムのアルゴリズムは同じです。


 MCCの設定です。まず、System moduleです。
 内部クロック、FOSC=16MHzとしました。
 ICSPを利用しますので、RA5は、RESET/MCLR/VPPとします。



 SETボタン=RB2
 UPボタン=RB3
 DOWNボタン=RB5
 として、inputとし、ウィークプルアップします。


 プログラムです。
-----------------------------------------------------------------------------------------------------
/*
* PIC12F1827 MCC RTC TEST
* 2021.08.10
* JH7UBC Keiji Hata
*/

#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"

//LCD関係定義
#define I2C_LCD_addr 0x27
#define LCD_EN 0b00000100//Enable
#define LCD_BL 0b00001000//Back Light
#define LCD_CMD 0x00
#define LCD_CHR 0x01
#define LCD_LINE1 0x80
#define LCD_LINE2 0xC0

//RTC関係定義
#define RTC_addr 0x68

char *week[] = {" ","MON","TUE","WED","THU","FRI","SAT","SUN"};
uint8_t REG[8] = {0x00,0x00,0x00,0x01,0x01,0x01,0x20,0x10};//時刻データ初期値2020/01/01 MON 00:00:00
int OLD_REG[7] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//前の時刻データを保存するレジスタ
int Disp_REG[7];//表示用レジスタ
uint8_t REG_addr = 0x00;

//時計セット関係
#define SET RB2
#define UP RB3
#define DOWN RB5
int Num = 6; //Clock data number 6:year 5:month 4:day 3:week 2:hour 1:mminute 0:second
int count = 0;

//割込み関係
volatile int IntFlag = 0;

//I2C LCDに1byteのdataを書き込む
void I2C_write_data(uint8_t data){
I2C1_Write1ByteRegister(I2C_LCD_addr, (data | LCD_EN | LCD_BL),(data | LCD_BL));
__delay_us(100);
}

//I2C LCDにコマンドまたは文字を送る
void LCD_write(uint8_t data, uint8_t mode){
//上位4bitを送る
I2C_write_data((data & 0xF0) | mode);
//下位4bitを送る
I2C_write_data(((data << 4) & 0xF0) | mode);
}

//I2C LCD 初期化
void LCD_init(){
__delay_ms(40);
LCD_write(0x33,LCD_CMD);//8bit mode set 2回
LCD_write(0x32,LCD_CMD);//8bit mode set 1回,4bit mode set
LCD_write(0x06,LCD_CMD);//Entry mode set
LCD_write(0x0C,LCD_CMD);//display ON,cursol OFF,blink OFF
LCD_write(0x28,LCD_CMD);//Function set 4bit mode,2line
LCD_write(0x01,LCD_CMD);//Clear display
__delay_ms(1);
}

void LCD_home(){
LCD_write(0x02,LCD_CMD);
__delay_ms(1);
}

void LCD_cursor(uint8_t x,uint8_t y){
if(y == 0){
LCD_write(LCD_LINE1 + x,LCD_CMD);
}
if(y == 1){
LCD_write(LCD_LINE2 + x,LCD_CMD);
}
}

//1文字表示
void putch(char ch){
LCD_write(ch,LCD_CHR);
}

//時刻データをRTCに書き込む
void Time_data_write(){
for(uint8_t i=0;i<8;i++){
I2C1_Write1ByteRegister(RTC_addr,i,REG[i]);
}
}

//RTCから時刻データを読みだし、REG[]に格納
void Time_data_read(){
I2C1_WriteNBytes(RTC_addr,&REG_addr,1);
I2C1_ReadNBytes(RTC_addr,&REG,7);
}

//REG[]のデータ(HEX)をDisp_REG[]のデータ(10進)に変換
void HEX2DEC(){
for(uint8_t i=0;i<=7;i++){
Disp_REG[i] = ((REG[i] & 0xF0)>>4)*10 + (REG[i] & 0x0F);
}
}

//Disp_REG[]のデータ(10進)をREG[]のデータ(HEX)に変換
void DEC2HEX(){
for(uint8_t i=0;i<=7;i++){
REG[i] = ((Disp_REG[i] / 10) << 4) | (Disp_REG[i] % 10);
}
}

void LCD_print(uint8_t n){
printf("%02d",Disp_REG[n]);
OLD_REG[n]=Disp_REG[n];
}

//Timeデータの表示
void Time_disp(){
if(Disp_REG[6] != OLD_REG[6]){
LCD_cursor(2,0);
LCD_print(6);
}
if(Disp_REG[5] != OLD_REG[5]){
LCD_cursor(5,0);
LCD_print(5);
}
if(Disp_REG[4] != OLD_REG[4]){
LCD_cursor(8,0);
LCD_print(4);
}
if(Disp_REG[3] != OLD_REG[3]){
LCD_cursor(12,0);
printf(week[Disp_REG[3]]);
OLD_REG[3] = Disp_REG[3];
}
if(Disp_REG[2] != OLD_REG[2]){
LCD_cursor(4,1);
LCD_print(2);
}
if(Disp_REG[1] != OLD_REG[1]){
LCD_cursor(7,1);
LCD_print(1);
}
if(Disp_REG[0] != OLD_REG[0]){
LCD_cursor(10,1);
LCD_print(0);
}
}

void Time_UP_DOWN(uint8_t n){
if(UP == 0){
Disp_REG[n]++;
while(UP == 0){
__delay_ms(10);
}
}
if(DOWN == 0){
Disp_REG[n]--;
while(DOWN == 0){
__delay_ms(10);
}
}
}

void Year_set(){
LCD_cursor(0,1);
printf("Y");
while(SET == 1){
Time_UP_DOWN(6);
if(Disp_REG[6]>=100){
Disp_REG[6]=99;
}
if(Disp_REG[6]<0){
Disp_REG[6]=0;
}
Time_disp();
__delay_ms(10);
}
while(SET == 0){
}
OLD_REG[6] = Disp_REG[6];
Num--;
}

void Month_set(){
LCD_cursor(0,1);
printf("M");
while(SET == 1){
Time_UP_DOWN(5);
if(Disp_REG[5]>12){
Disp_REG[5]=1;
}
if(Disp_REG[5]<1){
Disp_REG[5]=12;
}
Time_disp();
__delay_ms(10);
}
while(SET == 0){
}
OLD_REG[5] = Disp_REG[5];
Num--;
}

void Day_set(){
LCD_cursor(0,1);
printf("D");
while(SET == 1){
Time_UP_DOWN(4);
if(Disp_REG[4]>31){
Disp_REG[4]=1;
}
if(Disp_REG[4]<1){
Disp_REG[4]=31;
}
Time_disp();
__delay_ms(10);
}
while(SET == 0){
}
OLD_REG[4] = Disp_REG[4];
Num--;
}

void Week_set(){
LCD_cursor(0,1);
printf("W");
while(SET == 1){
Time_UP_DOWN(3);
if(Disp_REG[3]>7){
Disp_REG[3]=1;
}
if(Disp_REG[3]<1){
Disp_REG[3]=7;
}
Time_disp();
__delay_ms(10);
}
while(SET == 0){
}
OLD_REG[3] = Disp_REG[3];
Num--;
}

void Hour_set(){
LCD_cursor(0,1);
printf("h");
while(SET == 1){
Time_UP_DOWN(2);
if(Disp_REG[2]>23){
Disp_REG[2]=0;
}
if(Disp_REG[2]<0){
Disp_REG[2]=23;
}
Time_disp();
__delay_ms(10);
}
while(SET == 0){
}
OLD_REG[2] = Disp_REG[2];
Num--;
}

void Minute_set(){
LCD_cursor(0,1);
printf("m");
while(SET == 1){
Time_UP_DOWN(1);
if(Disp_REG[1]>59){
Disp_REG[1]=0;
}
if(Disp_REG[1]<0){
Disp_REG[1]=59;
}
Time_disp();
__delay_ms(10);
}
while(SET == 0){
}
OLD_REG[1] = Disp_REG[1];
Num--;
}

void Second_set(){
LCD_cursor(0,1);
printf("s");
while(SET == 1){
Time_UP_DOWN(0);
if(Disp_REG[0]>59){
Disp_REG[0]=0;
}
if(Disp_REG[0]<0){
Disp_REG[0]=59;
}
Time_disp();
__delay_ms(10);
}
while(SET == 0){
}
OLD_REG[0] = Disp_REG[0];
Num--;
}

void Time_set(){
while(Num > -1){
switch(Num){
case 6:
Year_set();
break;
case 5:
Month_set();
break;
case 4:
Day_set();
break;
case 3:
Week_set();
break;
case 2:
Hour_set();
break;
case 1:
Minute_set();
break;
case 0:
Second_set();
break;
}
}
LCD_cursor(0,1);
printf(" ");
DEC2HEX();//Disp_REGデータ(10進)をREGデータ(HEX)に変換する
Time_data_write();//変更されたデータをRTCに書き込む
}

void main(){
// initialize the device
SYSTEM_Initialize();
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();

LCD_init();

Time_data_write();//時刻をセット

//固定文字を表示
LCD_home();
printf("20 / / ( )");
LCD_cursor(6,1);
printf(": :");

//時刻表示
HEX2DEC();
Time_disp();

while (1){
if(IntFlag == 1){ //RB0にIOC割込みがあったら
Time_data_read();//RTCから時刻を読み出し
HEX2DEC(); //HEX→10進変換
Time_disp(); //時刻を表示する
IntFlag = 0; //割込みフラッグを降ろす
}

count = 0;
if(SET == 0){
while(SET == 0){
count++;
__delay_ms(5);
}
}
if(count>100){ //SETボタンが長押しされたら
INTCONbits.IOCIE = 0;//IOC割込み停止
INTCONbits.IOCIF = 0;//IOC割込みフラッグクリア
IntFlag = 0;
Time_set(); //時刻セットルーチンへ
Num = 6;
INTCONbits.IOCIE = 1;//IOC割込み再開
}
__delay_ms(10);
}
}

-----------------------------------------------------------------------------------------------------
ブレッドボードです。