📄 pic2448.c
字号:
#include "pic1687x.h" //包含头文件
#include "pic.h"
__IDLOC(15F0);
__CONFIG(HS&WDTDIS&LVPDIS&DUNPROT); //高速晶振,禁止低电压编程,看门狗禁止,禁止代码保护
//__CONFIG(HS&WDTEN&LVPDIS&DUNPROT); 高速晶振,禁止低电压编程,看门狗允许,禁止代码保护
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define bitset(var,bitno) ((var)|=1<<(bitno)) //位置位
#define bitclr(var,bitno) ((var)&=~(1<<(bitno))) //位清零
#define bitchk(var,bitno) (var&(0x01<<(bitno))) //位测试
#define PORTBIT(adr, bit) ((unsigned)(&adr)*8+(bit)) //取得位地址
#define bits_on(var,mask) ((var)|=(mask)) //置位对应位
#define bits_off(var,mask) ((var)&=~0^(mask)) //清零对应位
#define bittst_on(data,bitno) ((data>>bitno)&0x01)
#define hibyte(x) (unsigned char)(x>>8) //取高8位
#define lobyte(x) (unsigned char)(x & 0xFF) //取低8位
#define _NOP_ asm("NOP")
// 以下是口定义
#define ADR_ID RA4 // 地址编码
#define SHUT0 RB0 // 模块关机控制
#define SHUT1 RB1
#define SHUT2 RB2
#define SHUT4 RB4
#define SHUT5 RB5
#define SHUT3 RC0
#define VSET RC3 // 模块状态比较电压控制
#define RLSW RC4 // 输出继电器控制
#define EN485 RC5 // 485 收发转换
#define GIN1 RD6 // 通用输入
#define GIN2 RD7
#define SIO_RX_LEN 6
#define SIO_TX_LEN 10
#define RCT_CUR_RANG 400 /* 1023 -- 40.0 A */
uchar ticks=0,secs=0,norx_secs=0;// 50ms,秒,无通信计时定义
uchar img_RCSTA; // 寄存器影像
uchar img_RCREG;
uchar sio_tx_num; // 发送字节数
uchar sio_rx_num; // 接收字节数
bank1 uchar sio_rx_buf[SIO_RX_LEN]; // 接收缓冲区
bank1 uchar sio_tx_buf[SIO_TX_LEN];
ulong cpu3;
uchar id_addr=0; //模块组地址
uchar rct_addr=0; //模块地址
uint ad_vol_set; // 调压输出测量值
uint pwm_vol_set; // PWM调压输出(0-1023)
uint pwm_cur_lmt; // PWM限流输出(0-1023)
uint vol_set; // 调压输出设置值(0-1023)
uint cur_lmt; // 限流输出设置值(0-1023)
uchar rct_pow; // 整流器关机
uchar rct_warn; // 整流器告警
uchar rct_no=0xff; // 整流器在位
bank1 uint rct_cur[6]; // 整流器电流
bank1 uint ibuf[9]; // AD采样数组
#define CUR_MAX 4000
#define DCV_MAX 6062
uint cur_nc=1023;
uint cur_pc=1023;
uint DC_F=900;
uint DC_J=900;
bit change=0;
#define RCT_CUR_RANG_15B 200 // A/D 1023 -- 20A
#define RCT_CUR_RANG_20D 370 // A/D 1023 -- 37A
#define RCT_CUR_RANG_25D 400 // A/D 1023 -- 40A
#define RCT_CUR_RANG_30D 500 // A/D 1023 -- 50A
#define DCV_MAX_24V 3031 // D/A 24V
#define DCV_MAX_48V 6062 // D/A 48V
#define DCV_MID 3500 // 24V与48V的分界值:35V
#define CUR_MAX_15B 2000 // D/A 15Aor10A
#define CUR_MAX_20D 3700 // D/A 30Aor40A
#define CUR_MAX_25D 4000 // D/A 25A
#define CUR_MAX_30D 5000 // D/A 30Aor40A
uchar cur_type = 0; // 模块电流类型
uchar flag_cfg = 0; // 0:需要配置模块类型 1:模块类型配置完成
void delay(uchar t) // 延时子程序
{
uchar s;
s = 0;
while(t--)
while(--s)
{
_NOP_;
_NOP_;
_NOP_;
_NOP_;
_NOP_;
_NOP_;
_NOP_;
_NOP_;
_NOP_;
CLRWDT();
}
}
uchar bittest(uchar var,uchar bitno) //位测试
{
if((var>>bitno)&0x01==1)
return 1;
else
return 0;
}
uchar bittest0(uchar var,uchar bitno) //位测试
{
if((var>>bitno)&0x01==1)
return 1;
else
return 0;
}
void delay_100us(uchar times) // 延时100us
{
TMR0 = 1;
T0IF = 0;
while(times--)
{
while(!T0IF);
T0IF = 0;
}
}
void wr_eeprom(uchar addr,uchar val) // 内部EEPROM写入(地址,数值)
{
EECON1=0;
while(WR);
EEADRH=0;
EEADR=addr;
EEDATA=val;
EEPGD=0;
WREN=1;
di();
EECON2=0X55;
EECON2=0XAA;
WR=1;
while(WR);
WREN=0;
ei();
}
uchar rd_eeprom(uchar addr) // 内部EEPROM读出(地址),返回数据
{
uchar val;
EECON1=0;
EEADRH=0;
EEADR=addr;
EEPGD=0;
RD=1;
asm("NOP");
val=EEDATA;
return val;
}
uint start_ad(uchar chn) // 启动指定通道的AD转换,换回AD数值
{
uint adres;
ADCON1 = 0x81; /* Result Right_justified, 7 A/D channels, Vref = RA3 - VSS */
chn &= 7;
chn <<= 3;
chn |= 0b10000001; /* set Fosc/32 clock, AD channel,AD operating on */
ADCON0 = chn;
delay_100us(1);
ADGO = 1; /* Start AD */
while(ADGO);
asm("NOP");
asm("NOP");
adres=ADRESH*256+ADRESL;
return adres;
}
uint start_channel(uchar ad_chn) // 对指定通道进行AD转换,换回AD数值(内含数值滤波)
{
uchar t;
uint sum;
uint ad_max,ad_min;
for(t=0;t<9;t++) // 采样9次(大约20ms)
{
ibuf[t] = start_ad(ad_chn);
delay_100us(20);
}
ad_max = ad_min = ibuf[0]; // 求出9次采样最大值,最小值
for(t=1;t<9;t++)
{
if(ibuf[t] < ad_min)
ad_min = ibuf[t];
else if(ibuf[t] > ad_max)
ad_max = ibuf[t];
}
for(t=0,sum=0;t<9;t++) // 求排除最大值,最小值之外的7个数的平均值
sum += ibuf[t];
sum -= ad_max;
sum -= ad_min;
sum /= 7;
return sum;
}
void start_measure()
{
static uchar rct_cur_channel;
ulong ad_result;
rct_cur_channel++; // 开始:测量一路模块电流(一次只测一次)
rct_cur_channel %= 6;
if(rct_cur_channel<3)
ad_result = start_channel(rct_cur_channel);
else
ad_result = start_channel(rct_cur_channel+1);
switch (cur_type)
{
case 15: // 15Bor10D
{
ad_result *= RCT_CUR_RANG_15B;
ad_result>>= 10;
if (ad_result > RCT_CUR_RANG_15B) // 防止超界
ad_result = 0;
break;
}
case 20: // 20D
{
ad_result *= RCT_CUR_RANG_20D;
ad_result>>= 10;
if (ad_result > RCT_CUR_RANG_20D) // 防止超界
ad_result = 0;
break;
}
case 25: // 25D
{
ad_result *= RCT_CUR_RANG_25D;
ad_result>>= 10;
if (ad_result > RCT_CUR_RANG_25D) // 防止超界
ad_result = 0;
break;
}
case 30: // 30Dor40D
{
ad_result *= RCT_CUR_RANG_30D;
ad_result>>= 10;
if (ad_result > RCT_CUR_RANG_30D) // 防止超界
ad_result = 0;
break;
}
default: // 若未配置模块类型
{
ad_result = 0; // 则AD转换结果=0
break;
}
}
//l *= RCT_CUR_RANG;
//l /= 1024;
di();
rct_cur[rct_cur_channel] = (uint)ad_result;
ei(); // 结束:测量一路模块电流
ad_result = start_channel(7); // 测量电压控制输出值
di();
ad_vol_set = (uint)ad_result;
ei();
}
uint uiabs_sub(uint i, uint j) // 无符号整数绝对值减法
{
if(i>j)
return i-j;
else
return j-i;
}
uchar ucabs_sub(uchar i, uchar j)// 无符号字节绝对值减法
{
if(i>j)
return i-j;
else
return j-i;
}
/**************************************************************
重要提示:
下面函数计算与调整输出电压
目的:消除7805供电电压,16F877与运放等电路产生的输出误差
此函数很重要:因为控制电压信号与模块输出电压有12倍增益关系,
不同模控板之间0.1V的输出压差将造成不均流现象。
函数对设定值的设定调整范围:正负50(实际试验正负10)
***************************************************************/
#define DIF_ZERO 128
#define MAX_DIF_ERR 25
#define MAX_ITG_ERR 51
void calcu_vol_set_pwm() // 计算与调整输出电压
{
static uchar err_itg; // 电压控制信号
uchar t;
uint i;
if(uiabs_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 = ucabs_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(uiabs_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
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;
}
di();
pwm_vol_set = i;
ei();
}
}
void calcu_cur_lmt_pwm() // 计算限流输出
{
di();
pwm_cur_lmt = cur_lmt; // 无修正,按照设定数值输出(原因:限流精度要求不高,正负0.1足以)
ei();
}
void set_pwm_out() // 设定PWM输出
{
CCP1X = (pwm_vol_set&0x02)?1:0;
CCP1Y = (pwm_vol_set&0x01)?1:0;
CCPR1L = pwm_vol_set/4;
CCP2X = (pwm_cur_lmt&0x02)?1:0;
CCP2Y = (pwm_cur_lmt&0x01)?1:0;
CCPR2L = pwm_cur_lmt/4;
}
void pow_process() // 关机处理
{
if(rct_pow&0x01) SHUT0 = 1;
else SHUT0 = 0;
if(rct_pow&0x02) SHUT1 = 1;
else SHUT1 = 0;
if(rct_pow&0x04) SHUT2 = 1;
else SHUT2 = 0;
if(rct_pow&0x08) SHUT3 = 1;
else SHUT3 = 0;
if(rct_pow&0x10) SHUT4 = 1;
else SHUT4 = 0;
if(rct_pow&0x20) SHUT5 = 1;
else SHUT5 = 0;
}
void get_warn_status() // 获得模块状态
{
uchar t;
//di();
VSET = 0; // 设模块状态比较值1.67V
TRISD =0b11111111; /* PORT_D as input */
_NOP_;
_NOP_;
_NOP_;
_NOP_;
delay(1);
t = PORTD; // 获模块在位信号
if((t&1)==0)
rct_cur[0] = 0;
if((t&2)==0)
rct_cur[1] = 0;
if((t&4)==0)
rct_cur[2] = 0;
if((t&8)==0)
rct_cur[3] = 0;
if((t&16)==0)
rct_cur[4] = 0;
if((t&32)==0)
rct_cur[5] = 0;
rct_no=t&0x3F; // 获模块在位信号
VSET = 1; // 设模块状态比较值3.3V
TRISD =0b11111111; /* PORT_D as input */
_NOP_;
_NOP_;
_NOP_;
_NOP_;
delay(1);
t = PORTD;
rct_warn = t&0x3F; // 获模块告警信号
_NOP_;
_NOP_;
//ei();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -