goo blog サービス終了のお知らせ 

JH7UBCブログ

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

PIC16F1827 MCC RTC(DS1307)テストその2

2021-07-17 22:15:24 | MPLAB X MCC
 前回のテストで、リアルタイムクロックRTC(DS1307)をPIC16F1827でコントロールすることができました。

 今回は、DS1307から1Hzの方形波を出力して、波形の立ち上がりで、RB0にIOC(状態変化割込み)をかけ、1secごとに時刻を表示するテストをします。

 回路図です。

 MCCのセッティングをします。
 System ModuleとMSSP1の設定は、テストその1と同じです。
 Pin Managerで、RB0を入力に設定します。(RB2,RB3,RB5は、次回のテストでスイッチを付ける予定なので、入力に設定しています。)


IOC割込みをInterrupt Moduleで設定します。(IOCIにチェックを入れます)
 Pin ModuleでRB0のIOCを立ち上がり(positive)に設定します。

プログラムです。
その1のプログラムの次の部分を変更します。

まず、DS1307のSQW出力に1Hzの信号を出力するようにします。
これは、DS1307のレジスタ0x07番地に0x10を書き込めばよいので、レジスタへの書き込みデータ初期値REG[8]の最後のデータにセットします。
REG[8] = {0x00,0x00,0x00,0x01,0x01,0x01,0x20,0x10};

IOC割込みの設定は、pin_manager.cのIOCBF0_ISR(void) に下のように設定します。
RB0の入力がLOWからHIGHに変化した(立ち上がり)時に割込みがかかります。
割込みがあったら、IntFlag=1;として割込みフラッグを立てます。


main.cの中のmain()関数の中身です。
-------------------------------------------------------------------------
void main(){
// initialize the device
SYSTEM_Initialize();
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();


LCD_init();

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

while (1){
if(IntFlag == 1){ //RB0にIOC割込みがあったら
Time_data_read();//RTCから時刻を読み出し
Time_disp(); //時刻を表示する
IntFlag = 0; //割込みフラッグを降ろす
}
__delay_ms(10);
}
}
------------------------------------------------------------------
IntFlagという変数を使うmain.cとpin_manager.cの最初の方で、
volatile int IntFlag = 0;
を書いておきます。

ブレッドボードです。時刻の初期値
2020/01/1 (MON)
00:00:00
から1sec1ごとに時刻が動き始めます。

 次回は、スイッチを付けて、時刻設定ができるようにして、時計に仕上げます。


PIC16F1827 MCC RTC(DS1307)テストその1

2021-07-15 22:14:04 | MPLAB X MCC
 先日、ArduinoでRTC(リアルタイムクロック)DS1307をコントロールするテストを行いました。

 これで、DS1307のコントロールの勘所がつかめましたので、PIC16F1827を使って、テストを行います。

 今回は、表示には前の記事で使ったI2Cインターフェース付きLCD1602を使います。
 DS1307とは、I2Cで通信しますので、MCCの設定は、LCD1602のテストの時と同じですが、PICを回路にセットしたまま、プログラムのテストができるように、ICSPを使います。テスト回路図です。


 従って、MCCのpin managerでRA5は、MCLR/VPPのままにしておきます。

プログラムです。
--------------------------------------------------------------
/*
* PIC12F1827 MCC RTC TEST
* 2021.07.15
* 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
#define SECOND 0x00
#define MINUTE 0x01
#define HOUR 0x02
#define DAY 0x03//WEEK
#define DATE 0x04
#define MONTH 0x05
#define YEAR 0x06
#define CTRL 0x07

char *week[] = {" ","MON","TUE","WED","THU","FRI","SAT","SUN"};
//時刻データ初期値
uint8_t REG[8] = {0x50,0x59,0x23,0x03,0x14,0x07,0x21,0x00};
uint8_t REG_addr = 0x00;


//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(){
//I2C1_Write1ByteRegister(RTC_addr,0x00,0x00);//先頭アドレス
I2C1_Write1ByteRegister(RTC_addr,SECOND,REG[0]);
I2C1_Write1ByteRegister(RTC_addr,MINUTE,REG[1]);
I2C1_Write1ByteRegister(RTC_addr,HOUR,REG[2]);
I2C1_Write1ByteRegister(RTC_addr,DAY,REG[3]);
I2C1_Write1ByteRegister(RTC_addr,DATE,REG[4]);
I2C1_Write1ByteRegister(RTC_addr,MONTH,REG[5]);
I2C1_Write1ByteRegister(RTC_addr,YEAR,REG[6]);
I2C1_Write1ByteRegister(RTC_addr,CTRL,REG[7]);
}

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

I2C1_ReadNBytes(RTC_addr,&REG,7);
}

//Timeデータの表示
void Time_disp(){
LCD_home();
printf("20");
printf("%02x/",REG[6]);
printf("%02x/",REG[5]);
printf("%02x (",REG[4]);
printf(week[REG[3]]);
printf(")");
LCD_cursor(4,1);
printf("%02x:",REG[2]);
printf("%02x:",REG[1]);
printf("%02x",REG[0]);
}

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

LCD_init();

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

while (1){
Time_data_read();//RTCから時刻データを読み込む
Time_disp(); //時刻を表示する
__delay_ms(1000);
}
}

-------------------------------------------------------------------------------------
ブレッドボードです。
プログタマは、PICKit3を使い、VDD=5Vは、外部から供給する設定にしています。


 ともかく、動作することができましたので、今後、Arduinoの時と同様に、時計として使えるようにしてしてみたいと思います。

PIC16F1827 MCC I2Cインターフェース付きLCD1602表示テスト

2021-07-10 22:26:20 | MPLAB X MCC
 PIC16F1827を使って、MCCを利用して、I2Cインターフェース付きLCD1602の表示テストをします。

 MPLAB Xでprojectを作成して、MCCを立ち上げます。
 まず、System moduleの設定を行います。クロックは、16MHzにしました。
 Low-voltage programing Enableのチェックは外しておきます。

 I2Cを使うためにMSSP1モジュールを導入し、I2C Masterに設定します。
 I2Cのクロックは標準の100KHzとします。


MCC設定のI2Cは割込みを使いますので、Interrupt moduleで割込み設定をします。


 Pin moduleを見るとRB1がSDA1に、RB4がSCL1に設定されています。
 WPU(ウィーク・プルアップ)に一応チェックを入れておきます。(この時、レジスタのタブを開いて、下の方にあるnWUPENをenableにします)

 MCCの設定が終わったら、Generateして、MCCを終了すると関係するヘッダファイルとソースファイルが自動的に生成されます。

 回路図です。

テストプログラムです。LCD1602を4bitモードで動作させます。
MPLABX のプロジェクトのプロパティを開いて、XC8 Global OptionsのC standardは、C90にしてコンパイルしてください。 
----------------------------------------------------------------
/*
* PIC12F1827 MCC I2C LCD1602 TEST
* 2021.07.10
* JH7UBC Keiji Hata
*/

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

#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

//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_clear(){
LCD_write(0x01,LCD_CMD);
__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);
}
}

//文字列の表示
void LCD_str(char *str){
while(*str)
LCD_write(*str++,LCD_CHR); //pointer increment
}

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

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

LCD_init();

char msg[] = "Hello World!";
LCD_str(msg);

int count = 0;
while (1){
LCD_cursor(2,1);
printf("%3d",count);
count++;
__delay_ms(1000);
}
}
----------------------------------------------------------------
 ブレッドボードです。
 LCD1602の表示ドット不良のため、WorldのWの右側が欠けていますが、プログラムは正常に動きました。



PIC12F1822 MCC DAC テスト

2021-06-01 07:42:36 | MPLAB X MCC
 PIC12F1822を使ってMCCで設定して、DAC(デジタル アナログ コンバータ)のテストをします。

 DACのしくみは私のホームページ(JH7UBC Home Page)のここで説明しています。
 DACモジュールの正電源としては、FVR(Fixed Voltage Reference 固定参照電圧)とVDDとVREF+(外部からの参照電圧)が選べますが、今回は、VDDを選びます。乾電池を電源に使いましたので、VDD=3Vです。
 DACの出力は、DACCON1レジスタのbit0:bit4(DACR)に0~31(0x00~0x1F)をセットすれば、DACOUT = VDD*(DACR/32)に対応した電圧が、RA0に出力されます。回路図です。



 まず、プロジェクト作成して、MCCを開きます。
 最初にSystem Moduleの設定です。
 INTOSC,FOSC,16MHz,Low-Voltage Programingなしとしました。


 次に、DACモジュールを組み込み、設定します。
 Positive Referenceは、VDD,Low-Power Voltage Stateはデフォルトのままneg_refとし、Enable OUTPUT on DACOUTにチェックを入れます。
 更に、上記のPin ManagerのDACOUTのPortA0をクリックします。
 ここで、気になったことがあります。DACOUTのDirection(方向)がinputになっています。これって変ですよね。outputじゃないのかな?
 他のPICでの例を見るとoutputになっています。うーん分からない。
 とりあえず、このままにしておきます。

 Pin Moduleを見てみます。
 RA0 DACだけです。GPIOの設定はしなくとも良いようです。


 これだけの設定で、Generateして、MCCを閉じ、設定どおりにcodeが生成されているか確認してみました。

 pin_manager.cを見ると
 TRISA = 0x3E; //0b001111110 RA0は出力、他は入力でOKです。

 dac.cを見ると
 DACCON0 = 0xA0; //0b10100000 DAC enable,DACOE enableになっています。OKです。
 大丈夫のようです。

 main.cに時間とともに電圧を上げていくプログラムを書いて、テストしました。
 プログラムです。
-----------------------------------------------------------------------
#include "mcc_generated_files/mcc.h"

void main(void)
{
SYSTEM_Initialize();// initialize the device

uint8_t count=0;
for(count=0; count<=30; count++)
{
DAC_SetOutput(count);
__delay_ms(1);
}
}
------------------------------------------------------------------------
RA0の出力をPico Scopeで見てみました。
1msごとに電圧が上昇し、鋸歯状波になっています。


 良く分からないところもあるのですが、とりあえずDACの設定が簡単にできました。


PIC12F1822 MCC IOC テスト

2021-05-25 19:18:18 | MPLAB X MCC
 PIC12F1822を使って、MCCでIOC(Interrupt on Change 状態変化割込み)の設定とテストをします。

 テストする回路です。RA5をプルアップしておき、SWが押すとピンの入力の状態が1から0に変化します。この時発生するIOC割込みで、RA0に接続したLEDを点滅させます。(SWを押すたびにLEDは点灯と消灯を繰り返します。)


 projectを作成して、MCCを開きます。
 System Moduleの設定です。
 INTOSC,FOSC,Clock 8MHzとしました。Low-voltage Programingのチェックを外します。
 RA0はoutput、RA5はinputとし、WPU(ウィークプルアップ)します。

 Pin Moduleです。


Pin ModuleのRegisterを開きます。IOC割込みのため、IOCAN5をenableにします。これによって、RA5の入力が1から0に変化する(立下り)時に割込みが発生します。



 Interrupt Moduleの設定です。
 Pin ModuleのIOCOをEnableにします。

 設定を終了して、Generateして、MCCを終了し、プログラミングに入ります。
main.cです。
--------------------------------------------------------
/*
* PIC12F1822 MCC IOC test
* 2021.05.25
* JH7UBC Keiji Hata
*/
#include "mcc_generated_files/mcc.h"

void main(void)
{
SYSTEM_Initialize();// initialize the device

INTERRUPT_GlobalInterruptEnable();// Enable the Global Interrupts

INTERRUPT_PeripheralInterruptEnable();// Enable the Peripheral Interrupts

LATA0 = 0;
while (1)
{
}
}
--------------------------------------------------------

普通は、このmain()の中に__interrupt() ISR();という記載をして、割込み時に実行する関数(この場合は、ISR())指定するのですが、ありません。

では、どこにあるのでしょうか。interrupt_manager.cの中にあります。
そして、割込みがあった時に、PIN_MANAGER_IOC();が実行されます。

では、PIN_MANAGER_IOC()は、どこにあるのでしょうか。pin_manager.cの中にあります。
更に、IOCAF5のフラッグが立った時に、IOCAF5_ISR();が実行されます。
従って、IOCAF5_ISR()の中に、割込み時に実行する処理を記入します。
今回は、LEDを点滅させる処理を書きました。(赤い四角の部分
ここで使う変数(この場合は、val)は、pin_manager.cの最初の方で定義します。今回は、volatile unsigned char val = 0;としています。


 これで、build,書き込みをしました。
 ブレッドボードです。

 タクトスイッチを押すたびに点灯と消灯を繰り返します。
 ただ、タクトスイッチのチャタリングのため、押し方によっては誤動作します。
 今回のプログラムでは、チャタリング対策はしていません。

 MPLAB X MCCを使っての感想です。
 設定を画面上でできるので、簡単なのですが、一旦設定してから後で変更しても変更内容が反映されないことがあります。

 それから、前の設定やhファイルの記憶が残っていて、エラーがでたりします。

 これらを回避するには、結局プロジェクトを作り直すしかありません。ですから、迷路に入ってしまった時は、問題のプロジェクトを削除して、作り直した方が良いようです。それから、MCC設定に入る前にしっかりと設計を行うことが肝心だと思いました。