📄 module.c
字号:
/* module.c
* main program 新驱动(2路7703加2块继电器) 2003/1/11
*/
#include "absacc.h"
#include "math.h"
#include "sja.h"
#include "jdq.h"
#include "pid.h"
#include <reg52.h>
#include <intrins.h>
#include <string.h>
#include "link.h"
#include "ad7703_2.h"
#include "watchdog.h"
#include "delay.h"
#include "exp.h"
#include "L8279.h"
#include "XData.h"
//#include "PinAlarm.h"
/*==================================================================
Main
==================================================================*/
/*
2003-2-27 王嵩
1加入模块PID控制,并有多种算法选择;
2断开模块PID时,由上位机给出控制量;
3上位机能直接控制继电器;
4若无阀位反馈,可用灵敏度法控制;
5新增定时器0中断;
6上位机可优化模块PID各参数;
7实时采集温度数据;
8可一次1帧或5帧收发数据;
*/
/*数据采集双缓冲
采集数据ad_val和cool_temp,外部读取ad_val_bk和cool_temp_bk*/
/*
* 修改:王占成
* zcwang@mail.ustc.edu.cn
* 2003.4.29
* 加入键盘和显示器部分
*
*/
/***************************************************************/
/**********外部变量***************/
BYTE RXdata[11];
BYTE TXdata[11];
idata BYTE nr_frame;
idata BYTE TempTimes;
idata BYTE PIDTimes;
idata BYTE OnNewData;
idata BYTE NewLEDStatus;
idata BYTE TFlag;
idata BYTE DispTtime;
idata BYTE DispTFlag;
idata UINT cool_temp;
idata UINT cool_temp_bk;
idata UINT ad_val_bk[2];
idata UINT SP_nCount = 0;
BYTE p0val;
void data_sample()/*采集AD7703温度角度数据和室温数据*/
{
ad_val00 = read_ad_1(); ad_val10 = read_ad_2();
ad_val01 = read_ad_1(); ad_val11 = read_ad_2();
ad_val02 = read_ad_1(); ad_val12 = read_ad_2();
ad_val03 = read_ad_1(); ad_val13 = read_ad_2();
cool_temp = read_ds_data();
clear_watchdog();
return;
}
void order(UINT * table,BYTE size)/*排序 put the max into ad_val_0[4]*/
{
BYTE i,j;
UINT tmp;
for(i=size-1;i>=1;i--){/*共比较(size-1)轮*/
clear_watchdog();
for(j=0;j<i;j++){
if(table[i] < table[j]){
tmp = table[j];
table[j] = table[i];
table[i] = tmp;
}
}
}
return;
}
void cp_temp()/*处理7703采集的数据*/
{
EA=0;
order((UINT *)XAD0,4);/*将ad_val[i]去掉1个最大值,1个最小值,剩余2个求平均*/
order((UINT *)XAD1,4);
ad_val_bk[0] = (ad_val01+ad_val02)>>1;
ad_val_bk[1] = (ad_val11+ad_val12)>>1;
cool_temp_bk = cool_temp & 0x7FF;
EA=1;
clear_watchdog();
return;
}
void PinAlarm() /***++=蜂鸣器报警程序++=***/
{ BYTE i;
for(i=0;i<500;i++){ /***产生500Hz方波,持1秒***/
P2=0x28; /***选通Y1***/
delay1ms();
P2=0xF8;
delay1ms();
}
clear_watchdog();
AlarmFlag = 0;
}
void init_system() /*系统初始化*/
{
BYTE baud;
EA = 0; /* 禁止中断 */
/* 设置CPU寄存器 */
IE=0x2F; /*定时器0中断计算温度角度*/
/*定时器1中断设定值曲线*/
/*定时器2中断PID计算*/
/*外部中断0收发数据*/
/*外部中断1响应键盘中断*/
IP=0x01; /*外部中断0优先级最高*/
TCON=0x01; /*外部中断0下降沿触发,外部中断1低电平触发*/
T2CON = 0x00; /*中断程序设置T2CON.7 = 0, T2CON.2 = 0 (stop counter) */
T2MOD = 0x00; /*增计数*/
RCAP2H = 0x9E;
RCAP2L = 0x58;/*定时长度25ms*/
TMOD=0x11; /*定时器0,1工作在模式1,16位定时器*/
TH0 = 0;
TL0 = 0; /*定时器0定时长度65ms*/
TH1 = 0x3c;
TL1 = 0xaf; /*定时器0定时长度50ms*/
/* 读取模块地址 */
P2 = 0x08;
p0val = P0; /*不要使用访问内存的方法读取*/
P2 = 0xF8;
/* 设置外设 */
init_watchdog(); /*初始化看门狗*/
Init_8279();
init_jdq();
init_ad7703(); /* 4k Hz */
switch(p0val&0xc0){
case 0x00: baud=0xc3; break;
case 0x40: baud=0xc9; break;
case 0x80: baud=0xd3; break;
case 0xc0: baud=0xe7; break;
}
clear_watchdog();
init_sja(p0val&0x3f,baud);
if((PIDIni != 0x01)&&(RFlag!=0xc5)) { /***+++++ 上电复位时,初始化各PID参数++++****/
Init_Para();
PIDIni = 0x01;
}
EA = 1;
TR0 = 1;/*定时器0开*/
TR2 = 1;/*定时器2开*/
if(RFlag==0xC5)
TR1 = 1; /*定时器1开*/
return;
}
void main()
{
BYTE i;
OnNewData = TRUE;
NewLEDStatus = TRUE;
ResetFlag=0;
TempFlag=1;
PIDFlag = 0;
TFlag = TRUE;
DispTtime = 0;
DispTFlag = TRUE;
AlarmFlag = 0; /*+++++AlarmFlag = 0 不报警 **/
AlarmTime = 0;
AutoFlag = 1; /***自动控制**/
init_system(); /*系统初始化*/
RFlag=0xC5; /**用于区分复位标志**/
do{
if (ResetFlag == 1){
init_system();
ResetFlag=0;
}
if((TFlag == TRUE) && (DispTFlag == TRUE)){
DispT();
DispTFlag = FALSE;
}
if (TempFlag == 1){ /*采样*/
data_sample(); /* 读取来自7703数据 */
cp_temp(); /*AD7703采样数据处理*/
TempFlag=0;
Yk=CalcTemp(); /*计算当前温度*/
Angle=CalcAngle(); /*有反馈,计算当前阀位角度*/
}
if(OnNewData == TRUE) { /*接受到了新帧*/
Update_PID_Para(); /*更新PID参数,为测试用总更新*/
}
if((PIDFlag == 1)&&(AutoFlag == 1)){/*PID计算 每4秒钟执行一次PID控制*/
if (EnablePID==1) { /*由模块自身进行PID控制*/
PID();
PIDFlag=0;
/*=========================
临时:自加标志
=========================*/
TempPIDUINT++;
}
else if( EnablePID == 0 ){ /*上位机给出控制量*/
U=sPID.CalValue.sValue._UH+sPID.CalValue.sValue._UL/256.0;
CheckU();
if ((U-Angle)>Sens) {
set_jdq_mode(2);
MotorDir =2;
} /*正转*/
else if ((U-Angle)<-Sens) {
set_jdq_mode(1);
MotorDir =1;
} /*反转*/
else {
set_jdq_mode(0);
MotorDir = 0;
} /*停转*/
}
else if (EnablePID==2) { /*由上位机直接控制电机正反转*/
set_jdq_mode(sPID.ReceiveValue.sValue.CMod.MotorDirec);
MotorDir=sPID.ReceiveValue.sValue.CMod.MotorDirec;
}
}
UpdateData(); /*所有参数发送上位机,为测试用总更新*/
/****===============****/
if((AutoFlag==0)&&(Angle>0)){ /***==电机反转至关闭==>手动 ==***/
set_jdq_mode(1);
MotorDir =1;
}
/***===++倒计时差1分钟时开始报警,定时器1修改AlarmFlag ++===***/
if((AlarmFlag==1)&&(AutoFlag == 1)){
PinAlarm();
}
}while(1);
}
/* 定时器0中断服务子程序,控制主程序计算温度和角度*/
void timer0_int() interrupt 1 using 1
{
EA=0;
TR0=0;
TempTimes++;
DispTtime++;
if(TempTimes >= 15) /*1秒钟计算一次温度和角度*/
{
TempTimes = 0;
TempFlag=1;
}
if(DispTtime >= 46){ /*******++++++++++++++++++*******/
DispTtime = 0;
DispTFlag = TRUE;
}
TH0=0;
TL0=0;/*定时周期65ms*/
TR0=1;/*start timer*/
EA=1;
return;
}
/* 定时器1中断服务子程序,控制设定值*/
void Timer1_int() interrupt 3 using 1
{
EA = 0; /*关中断*/
TR1 = 0; /*停止计数*/
if(SP_nCount >= 200){ /*每隔10s计数一次*/
if(abs(SP2-Rk) >= SPOneStepVal){
if(SPOneStepValSign == 1){
SP_temp += SPOneStepVal;
}
else {
SP_temp -= SPOneStepVal;
}
SP_nCount = 0;
Rk = SP_temp;
}
/***+++++++++++++++++++++++***/
AlarmTime++;
if(SP1toSP2Time<=1) /***倒计时差一分钟时报警***/
AlarmFlag = 1;
}
SP_nCount++;
if((AlarmTime>=6)&&(SP1toSP2Time>0)){ /***过了一分钟***/
SP1toSP2Time--; /*设定值1到设定值2之间的时间减一*/
AlarmTime=0;
}
TH1 = 0x3c;
TL1 = 0xaf; /*定时周50ms*/
TR1 = 1;
EA = 1;
return;
}
/* 定时器2中断服务子程序,控制计算PID*/
void timer2_int() interrupt 5 using 1
{
EA = 0;
TR2 = 0; /*定时器2停止计数*/
TF2 = 0; /*清除定时器2中断标志位,防止反复中断请求*/
PIDTimes++;
if(PIDTimes > (Ts*50))
{
PIDFlag = 1; /*每个采样周期计算PID,定时周期为20ms,所以乘以50*/
PIDTimes = 0;
}
TR2 = 1; /*定时器2开始计数*/
EA = 1;
return;
}
/*外部中断0 命令帧中断处理函数*/
void sja_receive_int() interrupt 0 using 0
{
BYTE i;
BYTE reg;
BYTE can_status;
BYTE xdata* psb;
EA = 0;
reg=read_sja(4);
write_sja(4,0x00);
can_status=receive();
read_sja(3);
if(can_status==0x00){/* is command frame */
for(i=0;i<=10;i++){
TXdata[i]=RXdata[i];
}
TXdata[1] += 0x40;
TXdata[2] += QD;
TXdata[3] += 0x40;/*封装返回帧头*/
switch(RXdata[4]) {
case 0x02:/* 获取AD7703数据及室温数据 */
if(RXdata[3] >= 0x02)
break;
TXdata[5] = ad_val_bk[RXdata[3]];
TXdata[6] = _iror_(ad_val_bk[RXdata[3]],8);
TXdata[7] = cool_temp_bk;
TXdata[8] = _iror_(cool_temp_bk,8);
btransmit();
break;
case 0x04: /*上位机向模块写ControlMod*/
sPID.ReceiveValue.sValue.CMod.Tsample = RXdata[10];
sPID.ReceiveValue.sValue.CMod.MotorDirec = RXdata[9]; /*电机正反停转,0停1反2正*/
sPID.ReceiveValue.sValue.CMod.PIDNorP = RXdata[8]; /*PID正作用P,1或负作用N,0*/
sPID.ReceiveValue.sValue.CMod.Feedback = RXdata[7]; /*判断有无阀位反馈*/
sPID.ReceiveValue.sValue.CMod.PIDModel = RXdata[6]; /*不同PID选择*/
sPID.ReceiveValue.sValue.CMod.EnPID = RXdata[5]; /* PID开断 */
TXdata[5]=4;
TXdata[6]=4;
TXdata[7]=4;
TXdata[8]=4;
TXdata[9]=4;
TXdata[10]=4;
DataFrame = 2; /*设置标志,供Update_pid_para用*/
OnNewData = TRUE;
btransmit();
break;
case 0x05: /*上位机从模块读ControlMod*/
TXdata[10] = sPID.ReceiveValue.sValue.CMod.Tsample;
TXdata[9] = sPID.ReceiveValue.sValue.CMod.MotorDirec; /*电机正反停转,0停1反2正*/
TXdata[8] = sPID.ReceiveValue.sValue.CMod.PIDNorP; /*PID正作用P,1或负作用N,0*/
TXdata[7] = sPID.ReceiveValue.sValue.CMod.Feedback; /*判断有无阀位反馈*/
TXdata[6] = sPID.ReceiveValue.sValue.CMod.PIDModel; /*不同PID选择*/
TXdata[5] = sPID.ReceiveValue.sValue.CMod.EnPID; /* PID开断 */
btransmit();
break;
case 0x20:/* 上位机向模块写命令 一帧一帧数据发送*/
i=RXdata[3];
if ((i>=0)&&(i<=1)) {
save_pid(i,RXdata+5);
DataFrame=i;
OnNewData = TRUE;
TXdata[5] = 1; /*发送成功消息给上位机*/
btransmit();
}
else {
TXdata[5] = 0; /*发送出错消息给上位机*/
TXdata[6] = i; /*丢失的帧号*/
btransmit();
}
break;
/*========================================================================
临时:测试用
=======================================================================*/
case 0x08:
TXdata[6] = TempPIDUINT;
TXdata[5] = TempPIDUINT >> 8;
/*测试temp值*/
TXdata[10] = Ek;
TXdata[9] = Ek >> 8;
TXdata[8] = Ek >> 16;
TXdata[7] = Ek >> 24;
btransmit();
delay(4);
break;
case 0x21:/* 上位机向模块读命令 一帧一帧数据接收*/
psb = sPID.SendValue.bValue;
if ((RXdata[3]>=0)&&(RXdata[3]<=2)) {
i=RXdata[3];
TXdata[3] = 0x40 + i;
memcpy((BYTE*)(TXdata+5),psb+6*i,6);
btransmit();
delay(4);
}
break;
case 0x25:
ResetFlag=1; /*init_system(); 软件重新初始化*/
TXdata[5]=0x25;
TXdata[6]=0x25;
TXdata[7]=0x25;
TXdata[8]=0x25;
TXdata[9]=0x25;
TXdata[10]=0x25;
btransmit();
break;
case 0x26: /*利用看门狗硬件复位*/
TXdata[5]=0x26;
TXdata[6]=0x26;
TXdata[7]=0x26;
TXdata[8]=0x26;
TXdata[9]=0x26;
TXdata[10]=0x26;
btransmit();
while(1) {;
} /*看门狗复位*/
break;
default:
break;
}
}
write_sja(4,reg);
EA = 1;
return;
}
void KeyBoard_int() interrupt 2 using 0
{
EA = 0; /*关键盘中断*/
ScanKey(); /*扫描键盘*/
EA = 1; /*开键盘中断*/
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -