📄 m16_rectctrl.c
字号:
i=vol_set-2*MAX_DIF_ERR;
}
else
{
if(vol_set>1023-2*MAX_DIF_ERR)
i=1023;
else
i=vol_set+2*MAX_DIF_ERR;
}
pwm_vol_set=i;
}
}
void calc_cur_lmt_pwm(void) //计算限流输出
{
ulong cur_chg=0;
cur_lmt=(cur_chr<=cur_out)?cur_chr:cur_out; //采用充电限流值或输出限流值
cur_chg=(ulong)51465*cur_lmt; //将命令限流值换算成PWM设置值,cur_chg=(ulong)1725*12*cur_lmt*10/4
cur_chg=(cur_chg/100-1299)/100; //限流值在保证准确的前提下,低一点为宜!
cur_lmt=(uint)cur_chg;
pwm_cur_lmt=cur_lmt; //无修正,按照设定数值输出(原因:限流精度要求不高,正负0.1足矣)
}
void set_pwm_out(void)
{
CLI(); //禁止所有中断
OCR1A=pwm_vol_set; //设置PWM调压值
OCR1B=pwm_cur_lmt; //设置PWM限流值
SEI(); //使能所有中断
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//USART initialisation
// desired baud rate: 19200
// char size: 9 bit
// parity: Disabled
void usart_init(void)
{
UCSRB = 0x00; //disable while setting baud rate
UCSRA = 0x00;
UCSRC|=(1<<UCSZ1)|(1<<UCSZ0); //19200 BPS
UBRRH = 0x00; //set baud rate hi:此两个寄存器初始化的顺序不能颠倒!!
UBRRL = 25; //set baud rate lo
UCSRB|=(1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN)|(1<<UCSZ2);
}
//USART Receive Frame
uchar check_rx_frame(void) //检查接收帧是否完整
{
uchar i=0;
uint sum=0;
for(i=0;i<=3;i++) //检验加法和
sum+=sio_rx_buf[i];
if(sum!=sio_rx_buf[4]*256+sio_rx_buf[5])
return 0;
id_addr=(bittest(PINA,PINA4))?0x41:0x47; //获得模块组地址
return 1;
}
uchar process_rx_frame(void) //接收帧处理
{
rct_addr=sio_rx_buf[0];
if(rct_addr==0b01000000) //若是广播地址(不应答)
{
switch(sio_rx_buf[1])
{
case 0x80: //模块充电限流值
{
cur_chr=sio_rx_buf[2]*256+sio_rx_buf[3];
return 0;
}
case 0x81: //模块全开机
{
rct_pow=0;
return 0;
}
case 0x82: //模块全关机
{
rct_pow=0x3F;
return 0;
}
case 0x83: //模块浮冲命令
{
flag_rct=0;
return 0;
}
case 0x84: //模块均冲命令
{
flag_rct=1;
return 0;
}
case 0x90: //模块浮冲电压值
{
vol_flt=sio_rx_buf[2]*256+sio_rx_buf[3];
return 0;
}
case 0x91: //模块均充电压值
{
vol_ave=sio_rx_buf[2]*256+sio_rx_buf[3];
return 0;
}
case 0x92: //直流输出过压保护值
{
return 0;
}
case 0x93: //直流输出欠压保护值
{
return 0;
}
case 0x94: //交流输入过压保护值
{
return 0;
}
case 0x95: //交流输入欠压保护值
{
return 0;
}
case 0x96: //模块输出限流值
{
cur_out=sio_rx_buf[2]*256+sio_rx_buf[3];
return 0;
}
case 0x97: //模块过温保护值
{
return 0;
}
}
}
else //若不是广播
{
switch(sio_rx_buf[1])
{
case 0x11:
{
sio_tx_buf[1]=0x11;
if((rct_addr-id_addr>=0)&&(rct_addr-id_addr<=5)) //若是本组模块地址
{
sio_tx_buf[2]=rct_cur[rct_addr-id_addr]/256; //模块电流和温度
sio_tx_buf[3]=rct_cur[rct_addr-id_addr]%256;
sio_tx_buf[4]=0;
sio_tx_buf[5]=0;
return 1; //进入应答分支
}
else
return 0;
}
case 0x12:
{
sio_tx_buf[1]=0x12;
if((rct_addr-id_addr>=0)&&(rct_addr-id_addr<=5)) //若是本组模块地址
{
sio_tx_buf[2]=0; //交流输入电压和模块电压
sio_tx_buf[3]=0;
sio_tx_buf[4]=0;
sio_tx_buf[5]=0;
return 1; //进入应答分支
}
else
return 0;
}
case 0x81: //模块开机
{
if((rct_addr-id_addr>=0)&&(rct_addr-id_addr<=5)) //若是本组模块地址
rct_pow&=~(1<<(rct_addr-id_addr)); //则相应位清0
return 0;
}
case 0x82: //模块关机
{
if((rct_addr-id_addr>=0)&&(rct_addr-id_addr<=5)) //若是本组模块地址
rct_pow|=(1<<(rct_addr-id_addr)); //则相应位置1
return 0;
}
}
}
return 0;
}
//USART Tramsmit Frame
void send_tx_frame(void) //发送返回信息帧
{
uchar i=0;
uint sum=0;
//构造发送信息帧
sio_tx_buf[0]=rct_addr;
sio_tx_buf[6]=0;
sio_tx_buf[7]=0;
if((rct_addr-id_addr>=0)&&(rct_addr-id_addr<=5)) //若是本组模块地址
sio_tx_buf[7]|=((bittest(rct_warn,rct_addr-id_addr))<<7);
for(i=0;i<SIO_TX_LEN-2;i++) //校验和
sum+=sio_tx_buf[i];
sio_tx_buf[8]=sum/256;
sio_tx_buf[9]=sum%256;
//构造完毕
YELON; //发送RS485通道开启,接收通道关闭,PB6=0,黄灯亮
sio_tx_num=0;
UCSRB|=(1<<TXB8); //发送第8位————地址为1
UDR=sio_tx_buf[0]; //发送第0个字节,发送完毕中断响应
sio_rx_num=0; //重启接收
}
#pragma interrupt_handler usart_rx_isr:12
void usart_rx_isr(void)
{
//usart has received a character in UDR
uchar sum=0,status,resh,img_RxUDR;
status=UCSRA;
resh=UCSRB;
img_RxUDR=UDR;
if(status&((1<<DOR)|(1<<PE))) //若接收帧有错误
return;
resh=(resh>>1)&0x01; //过滤第8位数据
if(sio_rx_num)
{
sio_rx_buf[sio_rx_num]=img_RxUDR;
sio_rx_num++;
if(sio_rx_num>=SIO_RX_LEN) //若已经接收到尾字节
{
if(check_rx_frame()) //若接收帧正确
{
if(process_rx_frame()) //若帧处理完毕,有应答
send_tx_frame(); //则停止接收,开始发送
else
sio_rx_num=0; //无应答,重新接收
}
else
sio_rx_num=0; //否则重新接收
}
}
else
{
if(resh) //若接收帧是地址
{
if(img_RxUDR&0b01000000) //若符合帧头字节
{
sio_rx_buf[0]=img_RxUDR;
sio_rx_num=1;
}
}
}
}
#pragma interrupt_handler usart_tx_isr:14
void usart_tx_isr(void)
{
//character has been transmitted
sio_tx_num++;
if(sio_tx_num<SIO_TX_LEN) //若未发送完成到尾字节
{
UCSRB&=~(1<<TXB8); //发送第8位————数据为0
UDR=sio_tx_buf[sio_tx_num]; //则继续发送
}
if(sio_tx_num>=SIO_TX_LEN) //若此次发送完成的是尾字节
YELOFF; //则黄灯灭,发送通道关闭,接收通道开启
if(sio_tx_num>SIO_TX_LEN) //若发送计数器超过10
sio_tx_num=SIO_TX_LEN+1; //则发送计数器保持为11,空转
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//call this routine to initialise all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
watchdog_init();
usart_init();
timer1_init();
adc_init();
vol_ave = 5520; //设置均充电压默认值为55.20V
vol_flt = 5360; //设置浮冲电压默认值为53.60V
pwm_vol_set = 5360;
cur_chr = 150; //满载电流值
cur_out = 160; //输出电流最大值
pwm_cur_lmt = 150;
set_pwm_out(); //PWM初值
rct_pow = 0x3F; //模块全开机
delay_us(100); //延时,使控制信号稳定
sio_rx_num = 0;
YELOFF; //使能USART接收
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
PORTB|=(1<<PB7); //继电器闭合(信号稳定,输出)
//all peripherals are now initialised
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main(void)
{
uint register clr;
for(clr=0;clr<1024;clr++) //将内部SRAM清零
DBYTE[clr+0x60]=0;
init_devices();
while(1)
{
rct_measure(); //测量模拟量
pow_process(); //处理关机
get_warn_status(); //测量模块状态
calc_vol_set_pwm(); //计算调压值
calc_cur_lmt_pwm(); //计算限流值
delay_us(1);
set_pwm_out(); //调整PWM输出
WDR();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -