📄 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 + -