/************************************************************** PV用DCDCコンバータ制御プログラム(汎用) テスト版 PWMのUP/DOWNによる遅延時間測定 I2C-LCD利用版 for PIC16F1823/PIC12F1822(32MHz clock) PWM 40kHz *************************************************************** author Toshihiko HORIMA Tools: MPLAB X IDE v2.10 MPLAB XC8 compiler ver. 1.31 --------------------------------------------------------------- Date :Time Version Build Note 20140508:0800 0.01 * --------------------------------------------------------------- PIC16F1823 Pin assignment 1:VDD:P:5V(2.7V TO 5V) 2:RA5:I:AD4 Converter 3:RA4:O:None 4:RA3/MCLR:I:None 5:RC5:O:P PWM pulse out 6:RC4:O: 7:RC3:I:AD7 Converter 14:VSS:Power GND 13:RA0:I:ICSPDAT 12:RA1:I:ICSPCLK 11:RA2:I:AD2 Converter 10:RC0:O:SCL 9:RC1:O:SDA 8:RC2:I:AD6 Converter --------------------------------------------------------------- **************************************************************/ #include #include #include #include "i2clcdhw.h" // コンパイラスイッチ(入力、出力の条件を設定する) // CONFIG1ワードの設定 #pragma config CPD = OFF,\ BOREN = ON,\ IESO = OFF,\ FOSC = INTOSC,\ FCMEN = OFF,\ MCLRE = OFF,\ WDTE = OFF,\ CP = OFF,\ PWRTE = ON,\ CLKOUTEN = OFF // CONFIG2ワードの設定 #pragma config WRT = OFF,\ PLLEN = OFF,\ STVREN = ON,\ LVP = OFF,\ BORV = HI #define MHz 000000 #define _XTAL_FREQ 32MHz #define UCHAR unsigned char #define USINT unsigned short int #define SHINT short int // 電圧・電流制御のための値設定 // 鉛蓄電池への充電のための設定 // 電流測定:ACS712電流センサ(20A)100mV/1A // 入力電圧測定:分圧 64V:4.096V // 出力電圧測定 (20V):分圧 20V:4.096V // (42V):分圧 42V:4.096V /* 入力電圧状態コード ↑ VIN_OVER V2 VINHIGH | VIN_NORMAL V1 VINLOW ↓ VIN_UNDER V0 */ #define VINHIGH 0x3FE // 87.0V(4.089V) 4089 #define VINLOW 0x1F9 // 43.0V(2.021V) 2021 #define VIN_DANGER 2 // 入力電圧限界以上(異常電圧緊急停止) #define VIN_NORMAL 1 // 入力電圧正常範囲 #define VIN_UNDER 0 // 入力電圧下限以下(電圧不足で発電休止) /* 制御電圧状態コード ↑ VCTL_OVER V3 VCTLHIGH | VCTL_NORMAL V2 VCTLLOW | VCTL_UNDER V1 VCTLRESET ↓ VCTL_RESET V0 */ #define VCTLHILMT 0x2C1 // 60.0V(2.820V) 2820(10進数) #define VCTLHIGH 0x28E // 55.7V(2.618V) 2618(10進数) //#define VCTLHIGH 0x2FB // 65.0V(3.065V) 3055(10進数) #define VCTLLOW 0x218 // 45.7V(2.148V) 2148 #define VCTLRESET 0x023 // 3.0V(0.141V) 141 チャージポンプ再開閾値 #define VCTL_DANGER 4 // 電圧異常上昇(緊急停止) #define VCTL_OVER 3 // 制御電圧上限以上 #define VCTL_NORMAL 2 // 制御電圧正常範囲 #define VCTL_UNDER 1 // 制御電圧下限以下 #define VCTL_RESET 0 // 制御電圧チャージポンプ再開可能 /* 出力電圧(ベースロードターゲット電圧50V)状態コード ↑ VOUT_DANGER V4 VOUTHILMT | VOUT_OVER V3 VOUTHIGH | VOUT_NOR_h V2 VOUTMID | VOUT_NOR_l V1 VOUTLOW ↓ VOUT_UNDER V0 */ #define VOUTHILMT 0x2C1 // 60.0V(2.820V) 2820(10進数) //#define VOUTHILMT 0x2FF // 65.35V(3.071V) 3071(10進数) #define VOUTHIGH 0x286 // 55.0V(2.585V) 2585 #define VOUTMID 0x257 // 51.0V(2.397V) 2397 #define VOUTLOW 0x210 // 45.0V(2.115V) 2115 #define VOUT_DANGER 4 // 電圧異常上昇(緊急停止) #define VOUT_OVER 3 // 電圧上限以上(緊急低下措置必要) #define VOUT_NOR_H 2 // 電圧正常(蓄電池休止) #define VOUT_NOR_L 1 // 電圧正常(蓄電池連携) #define VOUT_UNDER 0 // 電圧下限以下 // 状態コード(mode_statusに設定される値) // 正論理(262ms毎に0:off/1:onで表示される)表示はビット列右端から左端へ // LEDの表示パタンビット列 // 正常コード(Green LED) #define STOP 0b0000000011111111 // 00FF:入力電圧不足休止中(duty=0) // エラーコード(Red LED) #define ERR_VIN_DANGER 0b0000011101010101 // 0755:入力電圧上限オーバー(緊急停止) #define ERR_VCTL_DANGER 0b0001110001010101 // 1C55:制御電圧上限オーバー(緊急停止) #define ERR_VOUT_DANGER 0b0111000001010101 // 7055:出力電圧上限オーバー(緊急停止) #define ERR_INVALID_INT 0b0001000100010001 // 1111:割込み異常 // LED消灯 #define ALL_OFF 0b0000000000000000 // 0000:消灯 // ADコンバータチャネル #define V_IN 0 // 出力電圧用 #define V_CTL 1 // 制御電圧用 #define V_OUT 2 // 出力電圧用 #define A_CTL 3 // 出力電流用 #define CH_NUM 4 // ADチャネル数 #define CH_V_IN 2 // 出力電圧用:ADチャネル2(Pin11) #define CH_V_CTL 6 // 制御電圧(ダイオード前)用:ADチャネル6(Pin8) #define CH_V_OUT 7 // 出力電圧用:ADチャネル7(Pin7) #define CH_A_CTL 4 // 出力電流用:ADチャネル4(pin2) // 各種設定値 #define PWM_PERIOD 199 // PWMの周期幅(40kHz) (80kHzの場合は99にセット) #define PWM_MAX 30 // PWMの幅をどこまで増やすか(=PWM_PERIODで100%) //#define DISP_CYCLE 32 // LCD表示サイクル(約253ms周期) #define DISP_CYCLE 20000 // LCD表示サイクル(約500ms(25us*20000)周期) //#define DISP_CYCLE 200 // テスト用 #define DELTA 4 // 電圧にPWM制御が反映されたと判断する変化量閾値 // 87.13/1024=0.085V 87.13/200=0.435V 0.435/0.085=5.12 // 電圧測定値保存配列 0:入電圧,1:制電圧,2:出電圧,3:出電流 SHINT duty=0; // PWMパルス幅(0-199) USINT mode_code, err_code; // 動作モードコード USINT advalue[CH_NUM]; // 測定値 UCHAR ad_ch[]={CH_V_IN,CH_V_CTL,CH_V_OUT,CH_A_CTL}; // ADコンバータチャネル USINT pre_advalue_vctl; // 前測定値 UCHAR m_status = 0; // 変化モード(0:変化前,1:開始,2:終了) USINT mod_start=0,mod_end=0; // 遅延時間 USINT val_start=0,val_end=0; // 測定値 USINT vctl_1st; // VCTL初期値 USINT disp_count=DISP_CYCLE; // LED表示タイミングカウンタ(最初0に初期化) //**************************************** void delay_10ms(USINT temp){ //10ms multiple x times while(temp--){ __delay_ms(10); } } // チェック用(HOMEに「*」表示 void print_check(){ lcd_goto_line_top(1); lcd_romwrite_str("Me"); lcd_hex(mod_end,4); lcd_romwrite_str("Ve"); lcd_hex(val_end,4); delay_10ms(100); } // LCD1行目表示(モード、測定値モード、デューティー比) void print_lcd_line1(){ lcd_goto_line_top(1); lcd_romwrite_str("Er"); lcd_hex(mode_code,4); lcd_write_chr('S'); lcd_hex(mod_start,4); lcd_write_chr('E'); lcd_hex(mod_end,4); } // LCD2行目表示(測定値) void print_lcd_line2(){ lcd_goto_line_top(2); // デューティ // lcd_puts(" D"); lcd_write_chr('D'); lcd_hex(duty,3); // 入力電圧 lcd_write_chr('I'); lcd_hex(advalue[V_IN],3); // 制御電圧 lcd_write_chr('S'); lcd_hex(val_start,3); // 出力電圧 lcd_write_chr('E'); lcd_hex(val_end,3); } // LCDディスプレイ表示 void display(void){ print_lcd_line1(); print_lcd_line2(); } // パラメータクリア void reset_params(void){ disp_count = DISP_CYCLE; // 表示タイミングカウンタ m_status = 0; // 変化状態 mod_start = 0; // 上昇開始 mod_end = 0; // 上昇終了 val_start = 0; // 変化開始時値 val_end = 0; // 変化終了時値 } // ADコンバータ USINT adconv(void){ GO_nDONE = 1; // AD変換開始 while(GO_nDONE); // AD変換完了を待つ(1823のRev8はOK、Rev6はバグで使えず) // __delay_us(10); // AD変換は開始後10.5~11TADの間に終了させる必要がある // GO_nDONE = 0; // AD変換終了 return((ADRESH<<8)+(ADRESL)); // 結果 } //**************************************** /* 割込みハンドラ 割込みが発生するとGIEはリセットされ割込み不許可となってこのルーチンが開始 GIE以外のPEIE、ADIEは変化しないため最初に設定したままでOK0 タイマー1割込みは8.192ms間隔で発生し測定値のチェックをし 電圧測定値に基づきモード診断、duty比調整を実行する 32回(約260ms)に1回LED表示切換えを行う 8192回(約67s)に1回MPPTターゲット電圧を再設定する 電圧値測定はmainループでエンドレスに実施 */ void interrupt handler( void ){ static UCHAR up_down; // DUTYの増減方向(1ビットで判定) //★ TMR2割込み(PWMクロック立上りに同期)(25us周期)の場合 if(TMR2IE&&TMR2IF) { // 表示タイミング(TMR2)だったら // 表示処理 if(!disp_count) { // 500ms周期 // V_IN値計測 ADCON0 = (ad_ch[V_IN]<<2)+1; // ADにマルチプレクサ接続 __delay_us(8); // ADサンプル時間待ち advalue[V_IN] = adconv(); ADCON0 = (ad_ch[V_CTL]<<2)+1; // ADにマルチプレクサ接続 if(!mod_end){ mod_end = DISP_CYCLE; // 変化終了測定未の場合 } display(); // LCD表示 reset_params(); // パラメータ初期化 if(up_down&0b00000001){ // duty減の場合 duty--; if(duty<=0) up_down++; // duty=0で反転 } else{ // duty増の場合 duty++; if(duty>=PWM_MAX) up_down++; // duty=PWM_MAXで反転 } // 前測定値初期化 pre_advalue_vctl = adconv(); vctl_1st = pre_advalue_vctl; // PWM設定 CCPR1L = duty; } disp_count--; RA4=1; // ADコンバータでCTL電圧測定 advalue[V_CTL] = adconv(); ///* // 変化終始の測定 if(m_status==0){ // 変化開始を未検知 if(abs(advalue[V_CTL]-vctl_1st)>DELTA){ // 変化が起き始めた mod_start = DISP_CYCLE-disp_count; val_start = vctl_1st; m_status = 1; } } else if(m_status==1){ // 変化開始を検知し、完了を未検知 if(advalue[V_CTL]==pre_advalue_vctl){ // 変化が完了した mod_end = DISP_CYCLE-disp_count; val_end = advalue[V_CTL]; m_status = 2; //print_check(); } } //*/ pre_advalue_vctl = advalue[V_CTL]; } // 割込みフラグクリア // TMR1IF 0; TMR2IF = 0; // 最初にクリアすると割込み周期より長い処理の場合フラグがラッチされるため RA4=0; } //#################### main ################################# main() { // UCHAR sum_buf_counter=0; // 測定値合計バッファのサイクルカウンタ // Port initalize // TMR0初期化 // TMR0:(32MHz/4)*256*256=8.192ms 約8ms毎にタイマー割込みが発生する ////TMR0:(32MHz/4)*256*32 =1.024ms 約1ms毎にタイマー割込みが発生する // 76543210 OSCCON = 0b11110000; // PLL On(コンフィグワード2はOFF),8MHz,IntOSC OPTION_REG = 0b10001000; // PullUp:無効,clkソース:内部,PreScaler:無効 // Port Initialize PORTA = 0b00000000; // Port Initalize, all ports are Low output PORTC = 0b00000000; // ポート初期化(すべてLo) // Output/Input port setting TRISA = 0b00101111; // RA5:In 4:Out 3:In 2:In 1:In 0:In TRISC = 0b00001111; // RC5:Out 4:Out 3:In 2:In 1:In 0:In // Analog/Digital port setting ANSELA = 0b00100100; // RA5:Ain 4:- 3:- 2:Ain 1:- 0:- ANSELC = 0b00001100; // RC5:- 4:- 3:Ain 2:Ain 1:- 0:- // TMR1初期化 // TMR1:(32MHz/4)*1*65536=8.192ms 毎の割込みでモード設定 // 32回カウントで262.144ms(概ね1/4sec)毎にLCDを表示 // T1CON = 0b00000000; // クロック源Fosc/4,プリスケール1:1,TMR1停止 // T1CON = 0b00000000; // クロック源Fosc,プリスケール1:1,TMR1停止 // T1GCON = 0b00000000; // ゲート機能無効(フリーカウントモード) // PWM初期化 (40.0kHz on RC5 @32MHz) // PWMサイクル:40.0kHz( (PR2+1)*4*Tosc*TMR2プリスケール ) // 分解能:PR2=199 40kHz=(199+1)*4*(1/32MHz)*1) // duty 0~100% CCPR1L,CCP1CON<5:4> 0~800(0x320,0b001100100000) // PWM初期化 (80.0kHz on RC5 @32MHz) // PWMサイクル:80.0kHz( (PR2+1)*4*Tosc*TMR2プリスケール ) // 分解能:PR2=99 80kHz=(99+1)*4*(1/32MHz)*1) // duty 0~100% CCPR1L,CCP1CON<5:4> 0~400(0x190,0b000110010000) // PR2とPWM周期 // 31.25kHz:255/40kHz:199/50kHz:159/60kHz:132/70kHz:113/80kHz:99/90kHz:88/100kHz:79 CCP1CON = 0b00001100; //シングルPWMモード,P1A:active-high //CCP1CON = 0b10001101; //ハーフブリッジ,LSBset,P1A:active-high;P1B:active-low //PWM1CON = 0b00000010; // PWM遅延8MHz2クロック分:0.25us(ハーフ時のHi/Lo遅延) T2CON = 0b00000000; // POSTSCALE 1:1 ,TMR2 OFF , PRESCALE 1:1 PR2 = PWM_PERIOD; // PWMの周期(40kHz:199、80kHz:99) // AD Converter初期化 FVRCON = 0b11000011; // FVR enable, 4.096V for ADC // ADCON0 = 0b00000001; // b6-2:Ch0,b1:Go/Done b0:En/Da:最初はch0に接続 ADCON1 = 0b10100011; // 読取値は右寄せ、A/D変換クロックはFOSC/32(32M-1us)、FVRを内部リファレンス ADCON0 = (ad_ch[V_CTL]<<2)+1; // ADにマルチプレクサ接続 // I2C初期化 i2cInit(); // メインループ前初期値設定 CCPR1L = 0; // PWM停止 CCPR1H = 0; // TMR1IF = 0; // TMR1割込みフラグ初期化 // TMR1 = 0; // LED表示制御用タイマ初期化(TMR1H,TMR1Lでアクセス可能) TMR2 = 0; // PWM用タイマ2を初期化 // LCD初期化 delay_10ms(20); //stabilize time lcd_init(); //lcd initalize lcd_goto(LCD_LineNumber1); lcd_romwrite_str("LCD Test Line 1"); lcd_goto(LCD_LineNumber2); lcd_romwrite_str("LCD Test Line 2"); delay_10ms(100); //1sウェイト // 変数初期設定 duty = 0; // PWM初期値は0 mode_code = ALL_OFF; // 初期モードはクリア // LED表示スタート // TMR1IE = 1; // TMR1割込み有効 // TMR1ON = 1; // 表示サイクル開始 TMR2IE = 1; // TMR2割込み有効 TMR2ON = 1; // PWMパルス開始 PEIE = 1; // 周辺装置割込み有効(TMR1割込みに必要) GIE = 1; // 割込み許可 /******************************** メインループ ********************************/ while(1){ // メインループ(実測約162μs/1サイクル) ///* if(err_code){ mode_code = err_code; // 表示のためにエラーコードをモードコードに duty = 0; // PWM幅最小 CCPR1L = 0; // PWM停止 reset_params(); // パラメータクリア delay_10ms(200); // 2秒停止 // duty = 0; // PWM幅最小 mode_code = ALL_OFF; // モードを初期化 err_code = 0; TMR1IF = 0; // TMR1割込みフラグクリア TMR2IF = 0; // TMR2割込みフラグクリア } //*/ } // メインループエンド } // end of main() //#################### main #################################