好的代码如下:/************* PCA配置函数 **************//*****************************************/
void PCA_config( u8 clk, u8 wide)
{
CR = 0; //停止PCA定时器
CMOD = (CMOD & ~0x0E) | ((clk & 7) << 1); // PCA时钟选择, 0: 12T, 1: 2T, 2: Timer0溢出率, 3: ECI引脚输入, 4: 1T, 5: 4T, 6: 6T, 7: 8T
PCA0_PWM(wide); //PWM宽度 0: 8位PWM, 1: 7位PWM, 2: 6位PWM, 3: 10位PWM
P_SW1 = (P_SW1 & ~0x30) | 0x00; // 将PCA/PWM切换到 P5.5(ECI) P3.1(CCP0) P3.3(CCP1) P5.4(CCP2)
P1n_push_pull(0x02); //头文件的宏, P1.1 设置为推挽输出
CH = 0;
CL = 0;
CR = 1; // 运行PCA定时器
}
void UpdatePwm( u16 pwm_value)
{
PCA_PWM0 = (PCA_PWM0 & ~0x32) | (u8)((pwm_value >> 4) & 0x30);
CCAP0H = (u8)pwm_value;
// PWM0_NORMAL();
}
/*****************************************/
/*****************************************/
/************* PID函数 ******************/
/*****************************************/
typedef struct PID_Value
{
int KP;
int KI;
int KD;
int Inck;
int EkSum;
int Vref;
int Vin;
int Ek;
int Ek_1;
int Ek_2;
int dacOutAmp;
int Acutual_pidout;
}PID_ValueStr;
PID_ValueStr pidStr;
void PID_initial(void)
{
pidStr.KP=10;
pidStr.KI=1;
}
void PID_Caculate()
{
pidStr.Ek=243-VCC ;
pidStr.Inck=pidStr.KP*(pidStr.Ek - pidStr.Ek_1) + pidStr.KI*pidStr.Ek ;
pidStr.Ek_2 = pidStr.Ek_1;
pidStr.Ek_1 = pidStr.Ek;
pidStr.dacOutAmp -= pidStr.Inck;
if(pidStr.dacOutAmp<128)
pidStr.dacOutAmp = 128;
if(pidStr.dacOutAmp>243)
pidStr.dacOutAmp = 243;
pwm_value=pidStr.dacOutAmp;
}
/*****************************************/
/*****************************************/
/************* 中断INT0函数 **********/
/*****************************************/
void INT0_Isr() interrupt 0
{
P37=0;
FLAG=30;
}
/*****************************************/
/*****************************************/
/************* ADC函数 **************/
/*************************************/
uint Get_ADCResult(u8 channel)
{
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = (ADC_CONTR & 0xf0) | 0x40 | channel;
//delay1us(); //对ADC_CONTR操作后等待会儿再访问
while ((ADC_CONTR & 0x20)==0);
ADC_CONTR &=~0x20;
ADC1_DATA=(ADC_RES<<8)|ADC_RESL;
return ADC1_DATA;
}
void ADC_Isr() interrupt 5
{
EADC=0;
ADC_CONTR &= ~0x20; //清中断标志
VCC=(ADC_RES<<8)|ADC_RESL;
PID_Caculate();
UpdatePwm(pwm_value); //更新PWM
}
/*****************************************/
/*****************************************/
/*********************************************
/*函数名称:Timer0_Config(u8 mode, u16 time)
/*函数功能:Timer0配置函数
/*输入参数:mode:速度模式
/* mode=1, 1T模式; mode=2,12T模式
/* time:定时时间
/* 1T模式(max=5.9ms):1ms=1000,2ms=500,5ms=200
/* 12T模式(max=71ms):1ms=1000,10ms=100
/*返回值:无
*********************************************/
void Timer0_Config()
{
AUXR |= 0x80; //定时器0为1T模式
TH0 = 0xFD;
TL0 = 0xE4;
TMOD &= 0xF0; //设置定时器为模式0,16位自动重装载
TR0 = 1; //启动定时器
ET0 = 1; //打开定时器中断
}
void Timer0() interrupt TIMER0_VECTOR
{
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = (ADC_CONTR & 0xf0) | 0x40 | 4;
while ((ADC_CONTR & 0x20)==0);
ADC_CONTR &=~0x20;
EADC=1;
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = (ADC_CONTR & 0xf0) | 0x40 | 4;
}
/*************************************
/*函数名称:LED_Init()
/*函数功能:LED初始化函数
/*输入参数:无
/*返回值:无
*************************************/
void LED_Init(void)
{
//P1M1 &= ~(1<<2); P1M0 |= (1<<2); //设置P1.2为推挽输出
//P1M1 &= ~(1<<3); P1M0 |= (1<<3); //设置P1.3为推挽输出
LED1 = 1; //初始化LED1
LED2 = 1; //初始化LED2
}
/*************************************
/*函数名称:LED_Toggle(unsigned char led_id)
/*函数功能:LED状态取反函数
/*输入参数:LED序号(led_id=1~n)
/*返回值:无
*************************************/
void LED_Toggle(unsigned char led_id)
{
switch(led_id)
{
case 1:
LED1 = ~LED1; //LED1状态取反
break;
case 2:
LED2 = ~LED2; //LED2状态取反
break;
}
}
/******************** 主函数 **************************/
void main(void)
{
P0M1 = 0; P0M0 = 0; //设置为准双向口
P1M1 = 0; P1M0 = 0; //设置为准双向口
P2M1 = 0; P2M0 = 0; //设置为准双向口
P3M1 = 0; P3M0 = 0; //设置为准双向口
P1M0 = (P1M0 & ~0xf8) | 0x04; P1M1 = (P1M1 & ~0x04) | 0xf8; //P1.2推挽输出 P1.3 P1.4 P1.5 P1.6 P1.7 高阻输入
P3M0 |= 0xac; P3M1 &= ~0xac; // P3.2 P3.3 P3.5 P3.7 推挽输出
PID_initial();
PCA_config(4,0);
LED_Init(); //LED初始化函数
Timer0_Config(); //定时器0配置,12T模式,time=10ms
P_SW2 |= 0x80;
ADCTIM = 0x0a;
P_SW2 &= 0x7f; //设置ADC内部时序
ADCCFG = 0x20; //设置ADC时钟为系统时钟/2/16
ADC_CONTR = 0x80; //使能ADC模块
IT0 = 1; //使能INT0下降沿中断
EX0 = 1; //使能INT0中断
IPH=0x03;
IP=0x21;
EA = 1; //允许总中断
while(1)
{ u8 i ;
u16 j ;
for(i=5; i<8; i++)
{
Get_ADCResult(i);
j=Get_ADCResult(i);
if((i==6)&&(j<512))
{
P37=0; //主要是这里,只有一开始上电给低于512的电压他才能给P37置低,如果开始电压比较高,后续再给低电压也不行
}
if((i==7)&&(j<512))
{
P37=0; //这里同上
}
}
}
}
|