好的代碼如下:/************* 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; //這里同上
}
}
}
}
|