?? m16_rectctrl.c
字號:
// ATmega16_MCtrl_4.0 : 2005-02-24
//ICC-AVR application builder : 2004-12-8 11:04:46
// Target : M16
// Crystal: 8.0000Mhz
#include <iom16v.h>
#include <macros.h>
#include <slavr.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
uchar *DBYTE; //DBYTE指針,指向字節地址
//Signal bit definitions
#define YELON PORTB&=~(1<<PB6) //黃燈亮,USART發送
#define YELOFF PORTB|=(1<<PB6) //黃燈滅,USART接收
#define SIO_RX_LEN 6
#define SIO_TX_LEN 10
#define RCT_CUR_RANG 400 //1023 -- 40A
//聲明變量一定要賦初值!!
//UART Parameters
uchar sio_rx_num=0; //接收字節數
uchar sio_tx_num=0; //發送字節數
uchar sio_rx_buf[SIO_RX_LEN]; //接收幀緩沖區
uchar sio_tx_buf[SIO_TX_LEN]; //應答幀緩沖區
//Other Parameters
uchar rct_cur_channel=0; //AD通道
uint adc_rel=0; //AD轉換結果
uint ibuf[9]; //AD采樣數組
uchar flag_rct=0; //0:浮沖(默認) 1:均充
uint vol_flt=0; //模塊浮沖電壓
uint vol_ave=0; //模塊均充電壓
uint cur_chr=0; //模塊充電限流
uint cur_out=0; //模塊輸出限流
uint ad_vol_set=0; //調壓輸出測量值
uint pwm_vol_set=0; //PWM調壓輸出(0-1023)
uint pwm_cur_lmt=0; //PWM調壓輸出(0-1023)
uint vol_set=0; //調壓輸出設置值(0-1023)
uint cur_lmt=0; //限流輸出設置值(0-1023)
uchar id_addr=0; //模塊組地址
uchar rct_addr=0; //模塊地址
uchar rct_pow=0; //模塊關機————聲明變量時一定要賦初值(編譯器的Bug)!!
uchar rct_warn=0; //模塊告警
uint rct_cur[6]; //模塊電流
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
uchar bittest(uchar var,uchar bitno) //位測試
{
if((var>>bitno)&0x01==1)
return 1;
else
return 0;
}
void port_init(void)
{
PORTA = 0b00000000; //AD不要上拉電阻
DDRA = 0b00000000;
PORTB = 0b11000000; //模塊全開機
DDRB = 0b11111111;
PORTC = 0b11111111;
DDRC = 0b01010000;
PORTD = 0b11111111;
DDRD = 0b00110010;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Watchdog initialize
// prescale: 2048K
void watchdog_init(void)
{
WDR(); //看門狗計數清零 - this prevents a timout on enabling
WDTCR = 0x0F; //使能watchdog,并且,采用2048K分頻,典型溢出時間5V時2.1S - dont forget to issue WDRs
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void get_warn_status(void) //獲得模塊狀態
{
uchar t=0,img_PINC=0,img_PIND=0;
PORTC|=(1<<PC6); //VSET=1,設置模塊狀態比較值3.3V
delay_us(10);
img_PINC=PINC;
img_PIND=PIND;
t=((img_PINC&0x02)>>1)|((img_PINC&0x01)<<1)|((img_PIND&0x80)>>5)|((img_PIND&0x40)>>3)|((img_PIND&0x08)<<1)|((img_PIND&0x04)<<3);
rct_warn=t&0x3F; //獲得模塊告警信號
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void pow_process(void) //關機處理(0為開機,1為關機)
{
if(bittest(rct_pow,0)) //開機0
PORTB&=~(1<<PB0);
else //SHUT0
PORTB|=(1<<PB0);
if(bittest(rct_pow,1)) //開機1
PORTB&=~(1<<PB1);
else //SHUT1
PORTB|=(1<<PB1);
if(bittest(rct_pow,2)) //開機2
PORTB&=~(1<<PB2);
else //SHUT2
PORTB|=(1<<PB2);
if(bittest(rct_pow,3)) //開機3
PORTB&=~(1<<PB3);
else //SHUT3
PORTB|=(1<<PB3);
if(bittest(rct_pow,4)) //開機4
PORTB&=~(1<<PB4);
else //SHUT4
PORTB|=(1<<PB4);
if(bittest(rct_pow,5)) //開機5
PORTB&=~(1<<PB5);
else //SHUT5
PORTB|=(1<<PB5);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ADC initialize
// Conversion time: 208uS
void adc_init(void)
{
ADCSRA= 0x00; //disable adc
ADMUX = 0x1F; //select adc input GND
ACSR = 0x80; //禁用模擬比較器
ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS2)|(1<<ADPS1); //使能ADC,128預分頻
}
void adc_start(uchar adc_chn) //啟動一次指定通道AD轉換,返回轉換結果
{
ADMUX=adc_chn&0x07; //指定通道
delay_us(20); //延時以使通道穩定!!
ADCSRA|=(1<<ADSC); //啟動一次轉換
while(bittest(ADCSRA,ADSC)); //等待轉換完畢
adc_rel=ADC&0x3ff; //轉換完畢,立刻得到結果
}
uint adc_execute(uchar adc_chn) //執行9次AD轉換,對轉換結果進行防脈沖干擾平均濾波
{
uchar i=0;
uint sum=0;
uint ad_max=0,ad_min=0;
for(i=0;i<9;i++) //采樣9次(約20ms)
{
adc_start(adc_chn);
ibuf[i]=adc_rel;
}
ad_max=ad_min=ibuf[0]; //求出9次采樣的最大值和最小值
for(i=1;i<9;i++)
{
if(ibuf[i]<ad_min)
ad_min=ibuf[i];
if(ibuf[i]>ad_max)
ad_max=ibuf[i];
}
for(i=0;i<9;i++) //求排除最大值、最小值之外的7個數的平均值
sum+=ibuf[i];
sum-=ad_max;
sum-=ad_min;
sum/=7;
return sum&0x3ff;
}
void rct_measure(void) //測量每一路電流(電壓)值
{
ulong ad_result=0;
//開始測量一路模塊電流(一次主循環只測一次電流值)
switch(rct_cur_channel)
{
case 0:
{
ad_result=adc_execute(PA7);
break;
}
case 1:
{
ad_result=adc_execute(PA6);
break;
}
case 2:
{
ad_result=adc_execute(PA5);
break;
}
case 3:
{
ad_result=adc_execute(PA3);
break;
}
case 4:
{
ad_result=adc_execute(PA2);
break;
}
case 5:
{
ad_result=adc_execute(PA1);
break;
}
}
ad_result*=RCT_CUR_RANG;
ad_result/=1024;
if(ad_result>RCT_CUR_RANG)
ad_result=0;
rct_cur[rct_cur_channel]=(uint)ad_result;
rct_cur_channel++;
rct_cur_channel%=6;
//結束測量一路模塊電流
ad_result=adc_execute(PA0); //測量電壓控制輸出(反饋)值
ad_vol_set=(uint)ad_result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TIMER1 initialize - prescale:1
// WGM: 3) PWM 10bit phz correct, TOP=0x3FF
// desired value: 3.910KHz
// actual value: 3.910KHz (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
OCR1AH = 0x03;
OCR1AL = 0xFF;
OCR1BH = 0x03;
OCR1BL = 0xFF;
ICR1H = 0x03; //top value
ICR1L = 0xFF;
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11)|(1<<WGM10);
TCCR1B|=(1<<CS10); //start Timer
}
uint uint_abs_sub(uint i,uint j) //無符號整數絕對值減法
{
if(i>j)
return i-j;
else
return j-i;
}
uchar uchar_abs_sub(uchar i,uchar j) //無符號字節絕對值減法
{
if(i>j)
return i-j;
else
return j-i;
}
/**************************************************************
下面函數計算與調整輸出電壓
目的:消除7805供電電壓、ATmega16以及運放等電路產生的輸出誤差
此函數很重要:因為控制電壓信號與模塊輸出電壓有12倍增益關系,
不同模控板之間0.1V的輸出壓差將造成不均流現象。
函數對設定值的設定調整范圍:正負50(實際試驗正負10)
***************************************************************/
#define DIF_ZERO 128
#define MAX_DIF_ERR 25
#define MAX_ITG_ERR 51
void calc_vol_set_pwm(void) //計算與調整輸出電壓
{
static uchar err_itg; //電壓控制信號
uchar t;
uint i;
ulong vol_chg=0;
vol_set=(flag_rct==0)?vol_flt:vol_ave; //采用浮沖電壓或均沖電壓
vol_chg=(ulong)1729*vol_set; //將命令電壓值換算成PWM設置值。考慮到界限母排的電壓降,此PWM值應比命令值略大!!
vol_chg=(vol_chg/100-1299)/100;
vol_set=(uint)vol_chg;
if(uint_abs_sub(vol_set,ad_vol_set)>2*MAX_DIF_ERR) //計算設定于采樣的誤差是否大于50
{
err_itg=DIF_ZERO; //誤差積分清0
if(ad_vol_set<vol_set) //PWM數值步進MAX_DIF_ERR調整
pwm_vol_set=(pwm_vol_set>1023-MAX_DIF_ERR)?1023:pwm_vol_set+MAX_DIF_ERR;
else
pwm_vol_set=(pwm_vol_set<MAX_DIF_ERR)?0:pwm_vol_set-MAX_DIF_ERR;
}
else //計算誤差積分
{
err_itg=(err_itg>DIF_ZERO+2*MAX_DIF_ERR)?DIF_ZERO+2*MAX_DIF_ERR:err_itg;
err_itg=(err_itg<DIF_ZERO-2*MAX_DIF_ERR)?DIF_ZERO-2*MAX_DIF_ERR:err_itg;
if(ad_vol_set<vol_set)
err_itg-=(uchar)(vol_set-ad_vol_set);
else
err_itg+=(uchar)(ad_vol_set-vol_set);
t=uchar_abs_sub(DIF_ZERO,err_itg)/MAX_ITG_ERR; //計算積分誤差調整值,增益1/25(經驗數值,此值過大、過小都引起系統輸出電壓振蕩)
if(t) //根據調正量修正PWM輸出
{
if(err_itg<DIF_ZERO)
pwm_vol_set=(pwm_vol_set>1023-t)?1023:pwm_vol_set+t;
else
pwm_vol_set=(pwm_vol_set<t)?0:pwm_vol_set-t;
}
}
if(uint_abs_sub(vol_set,pwm_vol_set)>2*MAX_DIF_ERR) //修正范圍超出50,按照最大正負50調整
{
if(vol_set>pwm_vol_set)
{
if(vol_set<2*MAX_DIF_ERR)
i=0;
else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -