タイマーで1ms毎に定期的に割込みがかかるようにして、そこで入力電圧、
そんなことはあるはずがない。
案の定、出力電圧が下がったときの動作がなんかおかしい。。
もし、お暇な方がおられたら、いっしょにデバッグしてくれるとう
以下に現段階のプログラムをフルでご紹介。いい加減な処理がばれちゃうので、あまり詳しく見ないように。。。。(^^ゞ
/
DC-DCコンバータ制御プログラム(PWM割込み制御方式)
From PV pannel 30V To 13.6V-DC(定電圧直流電源)
for PIC16F1823(32MHz clock) PWM 40kHz
******************************
Tools:
MPLAB X IDE v1.41
MPLAB XC8 compiler ver. 1.01
——————————
Date :Time Version Build Note
——————————
Date :Time Version Build Note
20121124:1234 0.01 — modified the program
* ——————————
Pin assignment
1:VDD:P:5V(2.7V TO 5V)
2:RA5:O:LCD RS
3:RA4:O:LCD RW
4:RA3/MCLR:I:None
5:RC5:O:P PWM pulse out
6:RC4:0:LCD E
7:RC3:O:LCD D7
14:VSS:Power GND
13:RA0:I:AD Converter(Input Voltage)
12:RA1:I:AD Converter(Output Current)
11:RA2:I:AD Converter(Output Voltage)
10:RC0:O:LCD D4
9:RC1:0:LCD D5
8:RC2:O:LCD D6
——————————
******************************
//#include <htc.h>
//#include <pic.h>
#include <xc.h>
#include <stdio.h>
#include “lcdrw.h”
#define MHz 000000
#define _XTAL_FREQ 32MHz
// 電圧・電流制御のための値設定
// 鉛蓄電池への充電のための設定
// 電流測定:ACS712電流センサ(20A)100mV/1A
// 電圧測定:分圧 30V:4.096V
// Sharp PV Source
#define VINHIGH 0x3CD // 31.0V(3.898V) (3898)/4=975
#define VINLOW 0x1D7 // 15.0V(for Test)
//#define VINLOW 0x235 // 18.0V(2.260V) (2260)/4=565
#define VOUTHIGH 0x1D7 // 15.0V(1.883V) (1883)/4=471
#define VOUTTGTUP 0x1B2 // 13.8V(1.735V) (1735)/4=434
#define VOUTTGTDN 0x1A1 // 13.3V(1.670V) (1670)/4=417
#define VOUTLOW 0x172 // 11.8V(1.481V) (1481)/4=370
/*
// DV 電源 Source
#define VINHIGH 0x235 // 18.0V(2.260V) (2260)/4=565
#define VINLOW 0x13A // 10.0V(1.255V) (1255)/4=314
#define VOUTHIGH 0x1D7 // 15.0V(1.883V) (1883)/4=471
#define VOUTTGTUP 0x1B2 // 13.8V(1.735V) (1735)/4=434
#define VOUTTGTDN 0x1A1 // 13.3V(1.670V) (1670)/4=417
#define VOUTLOW 0x172 // 11.8V(1.481V) (1481)/4=370
*/
//#define IOUTLIMIT 0x36B // 10A(ACS712:3.5V) (3500)/4=875
#define IOUTLIMIT 0x320 // 7A(ACS712:3.2V) (3200)/4=800
#define IOUTTARGET 0x307 // 6A(ACS712:3.1V) (3100)/4=775
//#define IOUTTARGET 0x2EE // 5A(ACS712:3.0V) (3000)/4=750
//#define IOUTTARGET 0x2D5 // 4A(ACS712:2.9V) (2900)/4=725
#define V_IN 0 // 出力電圧用:ADチャネル0
#define I_OUT 1 // 出力電流用:ADチャネル1
#define V_OUT 2 // 出力電圧用:ADチャネル2
// 状態コード表(status_codeに設定される値)
#define VOUT_NORMAL 0 // 正常(定電圧)モード
#define ADJUSTING_LOW 1 // 調整中(電圧低)モード
#define ADJUSTING_HIGH 2 // 調整中(電圧高)モード
#define VOUTLOW_UNDER 3 // 出力電圧下限アンダー(電池放電停止)
#define VINLOW_UNDER 4 // 入力電圧下限アンダー(電力低下休止)
#define VIN_NORMAL 5 // 入力電圧正常
#define IOUT_NORMAL 6 // 出力電流正常
#define IOUTTARGET_OVER 7 // ターゲット電流値オーバー
#define VOUTTARGET_HIGH 8 // 出力電圧上限オーバー(評価中)
#define VINHIGH_OVER 10 // 入力電圧上限オーバー(緊急停止) ↓以降異常
#define VOUTHIGH_OVER 11 // 出力電圧上限オーバー(緊急停止)
#define IOUTLIMIT_OVER 12 // 出力電流上限オーバー(緊急停止)
#define INVALID_INT 13 // 想定外の割込み発生(緊急停止)
#define INVALID_AD_CH 14 // ADチャネル異常
//#define INVALID_AD_VALUE 15 // AD値異常
#define ERROR_CODE 10 // エラーコード閾値
#define PWM_PERIOD 199 // PWMの周期幅(40kHz)
// CONFIG1ワードの設定
__CONFIG(
FOSC_INTOSC & WDTE_OFF & PWRTE_ON & MCLRE_OFF
& CP_OFF & CPD_OFF & BOREN_ON & CLKOUTEN_OFF
& IESO_OFF & FCMEN_OFF
);
// CONFIG2ワードの設定
__CONFIG(
WRT_OFF & PLLEN_ON & STVREN_ON & LVP_OFF
//WRT_OFF & PLLEN_OFF & STVREN_ON & LVP_OFF
& BORV_LO //
);
//Global settings
short int duty; // PWMパルス幅(0-199)
unsigned int advalue[3]={0,0,0}; // ADチャネルの測定値保存配列 0:入電圧,1:出電流,2:出電圧
unsigned char status_code; // 動作状態コード
unsigned int io_err=0, vo_err=0; // リミットオーバーカウンタ
void delay_10ms(unsigned int temp){ //10ms multiple x times
while(temp–){
__delay_ms(10);
}
}
//Write one character (correspond printf)
void putch(unsigned char c){
lcd_putch(c);
return;
}
// 割込みハンドラ
//
//
//
//
//
// 頻繁に入るため表示間隔が実質0.4s程度になっている。
void interrupt handler( void ){
unsigned char adch; // ADチャネル(0:出力電圧,1:出力電流,2:入力電圧)
// 割込みの種類を判定
if(TMR0IF) // TMR0割込みだったら
TMR0IF = 0; // 割込みフラグクリア
else{ // 他の割込みだったら
status_code=INVALID_INT; // 想定外の割込み発生
return; } // 異常として割込み処理抜け
// AD変換で入力電圧、出力電流、出力電圧を測定
// adch 0:入力電圧、1:出力電流、2:出力電圧
for(adch=0; adch♥; adch++){
ADCON0 = (adch<<2)+1; // 測定するADチャネルを設定
__delay_us(8); // 測定電圧Sample/Hold回路充電時間待ち(要計算)
GO_nDONE = 1; // AD変換開始
__delay_us(10); // 測定電圧Sample/Hold回路充電時間待ち(要計算)
GO_nDONE = 0; // AD変換開始
// while(GO_nDONE); // AD変換完了を待つ
advalue[adch] = (ADRESH<<8)+(ADRESL); // 変換結果を読込み
}
// AD結果の緊急停止処理コード設定
//
// 処理を入れている
// 入力電圧値の異常チェック
if(advalue[V_IN]>VINHIGH) // 緊急停止:入力電圧上限値オーバー
status_code = VINHIGH_OVER;
else if(advalue[V_IN]<VINLOW) // 太陽光パネル電圧低下(光量不足)
status_code = VINLOW_UNDER;
// 出力電流値の異常チェック
else if(advalue[I_OUT]>IOUTLIMIT){ // 緊急停止:出力電流上限値オーバー
if(io_err>100) status_code = IOUTLIMIT_OVER; // ○○ms以上継続したら
else status_code = IOUTTARGET_OVER; // 出力電流オーバーカウント中
io_err++;}
else{
io_err=0;
// 出力電圧値の異常チェック
if(advalue[V_OUT]>VOUTHIGH){ // 緊急停止:出力電圧上限値オーバー
if(vo_err>0xFFFE) status_code = VOUTHIGH_OVER; // XXXms以上継続したら
else status_code = VOUTTARGET_HIGH; // 出力電圧オーバーカウント中
vo_err++;}
else{
vo_err=0;
if(advalue[V_OUT]>VOUTTGTUP) // 出力電圧ターゲット上限を上回った
status_code = ADJUSTING_HIGH; // 出力電圧高調整モード
else if(advalue[V_OUT]>VOUTTGTDN) // 出力電圧ターゲット範囲内
status_code = VOUT_NORMAL; // 出力電圧正常モード
else if(advalue[V_OUT]>=VOUTLOW) // 出力電圧ターゲット下限を下回った
status_code = ADJUSTING_LOW; // 出力電圧低調整モード
else if(advalue[V_OUT]<VOUTLOW) // 出力電圧更なる下限値を下回った
status_code = VOUTLOW_UNDER; // 出力電圧更なる低調整モード
}
}
//ERR_RTN:
// 緊急停止の場合はPWMクロックを停めてリターン
if(status_code>=ERROR_CODE){
CCPR1L = 0; // TMR2(PWM)緊急停止
return;} // 割込み処理抜け
// 正常範囲の出力電流電圧制御処理
// DC-DCコンバータ出力定電圧制御
// 定電圧範囲(VOUTTGTUP)を超えたらPWMデクリメント
//
// 下限値(VOUTLOW)を下回ったらPWMインクリメント
//
switch(status_code){
case VOUTTARGET_HIGH: // 出力電圧が上限を瞬間的に超えた場合(カウント中)
case VINLOW_UNDER: // 太陽光パネル光量不足モードの場合
duty = 0; // TMR2(PWM)停止
break;
case ADJUSTING_HIGH: // ターゲット電圧範囲を超えた場合
duty–; // TMR2(PWM)幅狭める
break;
case ADJUSTING_LOW: // ターゲット電圧範囲を下回った場合
case VOUTLOW_UNDER: // 出力電圧が最低ライン以下のモード
duty++; // TMR2(PWM)幅拡げる
break;
case IOUTTARGET_OVER: // 出力電流が上限を瞬間的に超えた場合(カウント中)
duty-=2; // TMR2(PWM)幅狭める
} // switch end
if(duty>PR2) duty=PR2; // Duty値がPR2(199)を超えたらPR2に
else if(duty<0) duty=0; // Duty値が負になったら0にする
CCPR1L = duty; // 新しいPWM値を設定 CCPR1L/PR2[%]
GIE = 1; // 割込み許可
}
//——————main
main()
{
// Port initalize
// 76543210
OSCCON = 0b01110000; // PLL On(configuration word2), 8MHz, IntOSC
PORTA = 0x00; // Port Initalize, all ports are Low output
PORTC = 0x00; // Port Initalize, all ports are Low output
TRISA = 0b11001111; // RA5:Out 4:Out 3:In 2:In 1:In 0:In
TRISC = 0b11000000; // RC5-0 All Output
// Analog/Digital port setting
ANSELA = 0b00000111; // RA5:- 4:DigitalIO 3:- 2:Ain 1:Ain 0:Ain
ANSELC = 0x00; // All port are use for digital port
// PWM初期化 (40.0kHz on RC5 @32MHz)
// PWMサイクル:40.0kHz( (PR2+1)*4*Tosc*TMR2プリスケール )
// 10kHz=(199+1)*4*(1/32MHz)*1)
// 分解能:PR2=199
// duty 0~100% CCPR1L,CCP1CON<5:4> 0~800(0x320,0b001100100000)
//CCP1SEL = 0 ; // 1822で必要。1823では設定不要
CCP1CON = 0b00001100; //Single output,LSBset,PWM mode: P1A, P1C active-high; P1B, P1D active-high
//CCP1CON = 0b00001111; //Single output,LSBset,PWM mode: P1A, P1C active-low; P1B, P1D active-low
T2CON = 0b00000000; // POSTSCALE 1:1 ,TMR2 OFF , PRESCALE 1:1
PR2 = PWM_PERIOD; // PWMの周期を設定(40kHzで設定)
CCPR1L = 0; // デューティ値は0で初期化
CCPR1H = 0;
duty = 0; // 最初はデューティー比は0から
TMR2 = 0; // PWM用タイマー2を初期化
TMR2ON = 1; // TMR2(PWM)スタート
// TMR0初期化
//
// TMR0:(32MHz/4)*256*32=1.024ms 約1ms毎にタイマー割込みが発生する
//
OPTION_REG = 0b11000100; //
// 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/
// LCD初期化
delay_10ms(20); //stabilize time
lcd_init(); //lcd initalize
lcd_clear(); //lcd clear
lcd_cursoroff(); // Cursor Off
// LCD初期表示
lcd_goto(LCD_LineNumber1);
printf(“Program Start Initialization”);
// ウェイト
delay_10ms(200); // 2.0s wait
// lcd_clear(); //lcd clear
// メインループ前初期値設定
TMR0 = 0; // 割込用タイマー0を初期化
TMR0IE = 1; // TMR0割込み有効
PEIE = 1; // 周辺装置割込み有効
GIE = 1; // 割込み許可
// 電流電圧値測定は割込みルーチンで実行
//
// メインループ
//
while(1){
// 0.1秒に1回表示をリフレッシュ
delay_10ms(10); // 0.1s wait
// 状態LCD表示
lcd_goto(LCD_LineNumber1);
//
printf(“M:%2d E:%04x D:%2d”,status_code,vo_err,duty
// printf(“M:%2d C:%04x D:%3d “,status_code,cnt01,duty); // モードor異常状態表示
lcd_goto(LCD_LineNumber2); // 測定値やduty値表示
printf(“%4dV>%4dV%4dA”,(advalu
//cnt01 = 0;
if(status_code >= ERROR_CODE) // 異常終了メッセージ表示
while(1); // 異常時はここで終了(無限ループ)
} // end of while(1)
//
// メインループエンド
//
} // end of main()