|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 cjsb37 于 2013-4-29 08:56 编辑
用240做A/D时出现,进入中断子程序后,不能返回主程序
我用240做A/D时出现,不能进入中断子程序。我用的是用定时器2周期中断启动ADC,可我启动定时器计数后却不能不能进入中断子程序。C语言程序如下:
#include <stdio.h>
#include "math.h"
#include "register.h"
ioport unsigned port000c;
#define LED_PORT port000c
void initial(void)
{
asm(" setc SXM "); /* 抑制符号位扩展 */
asm(" clrc OVM "); /* 累加器中结果正常溢出 */
asm(" clrc CNF "); /* B0被配置为数据存储空间 */
*CKCR0=0x0041; /*SYSCLK=CPUCLK/2 */
*CKCR1=0x00BB; /*CLKIN=10 ,CPUCLK=20 */
*CKCR0=0x00C1; /*ENABLE PLL */
*SYSCR=0x40C0; /* CLKOUT=CPUCLK */
*WDCR=0x0EA; /* 不使能看门狗,因为SCSR2中的WDOVERRIDE */
/* 即WD保护位复位后的缺省值为1,故可以用*/
/* 软件禁止看门狗 */
*IMR=0x0004; /* 允许中断3 */
*IFR=0x0FFFF; /*清除全部中断标志,"写1清0" */
*OCRA=0x0400; /*设置OPB端口的功能 */
*OCRB=0x000C; /*设置IOPC端口的功能 */
*PBDATDIR=0x0FF00; /* IOPB端口设置为输出方式 */
*GPTCON=0x003F;
}
void ADINT() /*A/D初始化*/
{
*T2CNT=0x0060; /* 初始化计数寄存器2 */
*T2CON=0x910C; /* 定时器2内部cpu时钟源,周期加载,使用自身使能位 */
*T2PR=0x0060; /*初始化定时器2周期寄存器,周期为 96 */
*EVIFRB=0x00FF; /*清除EVIFRB中断标志*/
*GPTCON=*GPTCON|0x0400; /* 定时器2周期中断启动ADC, */
*ADCTRAL1=0x8906; /*初始化ADC,写"1"清除ADCINTFLAG,选择通道2*/
*ADCTRAL1=*ADCTRAL1|0x0200; /*使能ADC1*/
*ADCTRAL2=0x0005; /*选择预定标系数为16*/
}
void ADSOC()
{
*T2CON=*T2CON|0x40; /*启动定时器2*/
}
void inline disable()
{
asm(" setc INTM "); /* 禁止所有中断 */
}
void inline enable()
{
asm(" clrc INTM "); /* 开中断 */
}
void pwminitial(void)
{
*ACTR=0x0666;
*SACTR=0x0015;
*DBTCON=0x0000; /* 死区定时器周期,并禁止3个全比较单元死区定时器 */
*COMCON=0x4B57;
*COMCON=0xCB57;
*T1PR=0x0800; /*设置PWM的波形周期为 4KHZ */
*T1CMPR=0x0000; /*初始化定时比较器1 */
*T1CNT=0x0000; /* 初始化计数寄存器1 */
}
unsigned int temp,result,j,k;
int u_1=0; /* 定义其它一些临时变量 */
int error=0,error_1=0,error_2=0;
int kp=5,ki=0.1,kd=0;
int LedOnFlag;
void main(void)
{
int i;
disable();
initial(); /* 系统初始化 */
ADINT(); /*a/d初始化*/
pwminitial(); /*pwm初始化*/
j = 1;
LED_PORT = 0x00;
LedOnFlag = 1;
while(1)
{
for(i=1;i<5;i++)
{
enable();
ADSOC(); /*启动定时器2工作,产生A/D转换*/
*PCDATDIR=*PCDATDIR|0x0080;
esult=CALC(temp);
PWM(result);
}
if ( j >= 3000 )
{
if ( LedOnFlag == 1 )
{
LedOnFlag = 0;
LED_PORT = 0x00;
*PCDATDIR=0x0FF00;
j = 0;
}
else
{
LedOnFlag = 1;
LED_PORT = 0x0FF;
*PCDATDIR=0x0FF88;
j = 0;
}
}
else
{
j = j + 1;
}
}
}
/* 直接返回中断服务程序 */
void interrupt c_dummy1( )
{
return;
}
/* AD中断服务子程序 */
void interrupt adint( )
{
asm(" clrc SXM ");
temp=*ADCFIFO1>>6;
*ADCTRAL1=*ADCTRAL1|0x0100; /*写"1"清除ADCINTFLAG*/
enable();
}
int PWM(result)
{
*CMPR1=result;
*CMPR2=1000;
*CMPR3=1500;
*SCMPR3=1000;
*T1CON= 0x900A; /* 连续增计数方式*/
*T1CON= 0x904A; /* 使能比较操作 */
}
int CALC(temp) /*增量式PID控制算法*/
{
int x,yout,y0,u,du,yu; /*定义其它一些临时变量*/
int Perror,Ierror,Derror;
x=temp;
yout=1024-x;
y0 =700.000; /*y0 =734.000;*/
error=y0-yout;
if(error>100)
{
//u=5;
u=2048;
}
else if(error<=-100)
{
u=0;
}
else
{
Perror=error-error_1;
Ierror=error;
Derror=error-2*error_1+error_2;
du=kp*Perror+ki*Ierror+kd*Derror;
u=u_1+du;
if(u>=2048)
{
u=2048;
}
if(u<=0)
{
u=0;
}
u_1=u;
error_2=error_1;
error_1=error;
}
result=u ;
return (result);
}
中断向量程序如下(*.ASM):
.title "vectors.asm"
.ref _c_int0,_c_dummy1,_adint
.sect ".vectors"
reset: b _c_int0
int1: b _c_dummy1
int2: b _c_dummy1
int3: b _adint
int4: b _c_dummy1
int5: b _c_dummy1
int6: b _c_dummy1
计数器正常工作,可就是不能产生中断,我用的是闻亭的实验板,硬件应该没问题,各位大哥,帮帮我吧!现在项目很紧,谢谢!
——————————————————————————————————————
RE:你的主程序里面为什么要循环ad初始化啊,初始化一次就够了把。
你的定时器2是怎么个记数方式呢?
——————————————————————————————————————
问:有道理,我已经改过了,定时器2是连续增计数模式,采用周期中断,*T2PR=0x0060; 我的计数在进行,但产生不了中断。
——————————————————————————————
问:“ *GPTCON=*0x0400; /* 定时器2周期中断启动ADC, */ ”
能启动中断吗?
还是“ int3: b _adint ”有问题?
——————————————————————————————————————
问:应该是我中断没有设置好,“ int3: b _adint ”应该为“ int6: b _adint ”,同时,“*IMR=0x0004; ”改为“*IMR=0x0020; ”,允许中断INT6;为什么这样程序还进不了中断!?????
——————————————————————————————————————
问:我程序现在可以进入中断,但我进入中断以后,不能返回主程序,我把程序改为如下:
#include <stdio.h>
#include "math.h"
#include "register.h"
ioport unsigned port000c;
#define LED_PORT port000c
void initial(void)
{
asm(" setc SXM"); /* 抑制符号位扩展 */
asm(" clrc OVM"); /* 累加器中结果正常溢出 */
asm(" clrc CNF"); /* B0被配置为数据存储空间 */
*CKCR0=0x0041; /*SYSCLK=CPUCLK/2 */
*CKCR1=0x00BB; /*CLKIN=10 ,CPUCLK=20 */
*CKCR0=0x00C1; /*ENABLE PLL */
*SYSCR=0x40C0; /* CLKOUT=CPUCLK */
*WDCR=0x0EA; /* 不使能看门狗,因为SCSR2中的WDOVERRIDE */
/* 即WD保护位复位后的缺省值为1,故可以用*/
/* 软件禁止看门狗 */
*IMR=0x0020; /* 允许中断INT6 */
*IFR=0x0FFFF; /*清除全部中断标志,"写1清0" */
/*OCRA=*OCRA&0x00; /*IOPB端口配置为一般的I/O功能,*/
*OCRA=0x0400; /*设置OPB端口的功能 */
*OCRB=0x000C; /*设置IOPC端口的功能 */
*PBDATDIR=0x0FF00; /* IOPB端口设置为输出方式 */
/*PCDATDIR=0x0FF00;*/
*GPTCON=0x003F;
}
void ADINT() /*启动定时器*/
{
*T2CNT=0x0000; /* 初始化计数寄存器2 */
*T2CON=0x910C; /* 定时器2内部cpu时钟源,周期加载,使用自身使能位 */
*T2PR=0x0060; /*初始化定时器2周期寄存器,周期为 96 */
*EVIFRB=0x0001; /*清除EVIFRB中断标志(T2PINT ENABLE) */
*GPTCON=*GPTCON|0x0400; /* 定时器2周期中断启动ADC, */
*ADCTRAL1=0xCD06; /*初始化ADC,写"1"清除ADCINTFLAG,选择通道2*/
*ADCTRAL1=*ADCTRAL1|0x0200; /*使能ADC1*/
*ADCTRAL2=0x0405; /*选择预定标系数为16*/
}
void pwminitial(void)
{
*ACTR=0x0666;
*SACTR=0x0015;
*DBTCON=0x0000;/* 死区定时器周期,并禁止3个全比较单元死区定时器 */
*COMCON=0x4B57;
*COMCON=0xCB57;
*T1PR=0x0800; /*设置PWM的波形周期为 4KHZ */
*T1CMPR=0x0000; /*初始化定时比较器1 */
*T1CNT=0x0000; /* 初始化计数寄存器1 */
}
unsigned int temp,result,j,k;
int m,u_1,ADRESULT[50]; /* 定义其它一些临时变量 */
int error=0,error_1=0,error_2=0;
int kp=5,ki=0.1,kd=0;
int LedOnFlag;
void main(void)
{
int i;
asm(" setc INTM"); /* 禁止所有中断 */
initial(); /* 系统初始化 */
ADINT(); /*a/d初始化*/
pwminitial(); /*pwm初始化*/
j = 1;
LED_PORT = 0x00;
LedOnFlag = 1;
while(1)
{
for(i=1;i<5;i++)
{
asm(" clrc INTM"); /* 开中断 */
*T2CON=*T2CON|0x40; /*启动定时器2,启动A/D转换*/
while(1)
{
if(m==50) break;
}
*T2CON=*T2CON&0xFFBF;
*PCDATDIR=*PCDATDIR|0x0080;
result=CALC(temp);
PWM(result);
}
if ( j >= 3000 )
{
if ( LedOnFlag == 1 )
{
LedOnFlag = 0;
LED_PORT = 0x00;
*PCDATDIR=0x0FF00;
j = 0;
}
else
{
LedOnFlag = 1;
LED_PORT = 0x0FF;
*PCDATDIR=0x0FF88;
j = 0;
}
}
else
{
j = j + 1;
}
}
}
/* 直接返回中断服务程序 */
void interrupt c_dummy1( )
{
return;
}
/* AD中断服务子程序 */
void interrupt adint( )
{
asm(" clrc SXM");
temp=0;
for(m=0;m<50;m++)
{
ADRESULT[m]=*ADCFIFO1>>6;
temp+=ADRESULT[m];
}
temp=(temp/50);
*ADCTRAL1=*ADCTRAL1|0x0100; /*写"1"清除ADCINTFLAG*/
asm(" clrc INTM"); /* 开中断 */
m=50;
return;
}
int PWM(result)
{
*CMPR1=result;
*CMPR2=1000;
*CMPR3=1500;
*SCMPR3=1000;
*T1CON= 0x900A; /* 连续增计数方式*/
*T1CON= 0x904A; /* 使能比较操作 */
}
int CALC(temp) /*增量式PID控制算法*/
{
int x,yout,y0,u,du,yu; /*定义其它一些临时变量*/
int Perror,Ierror,Derror;
x=temp;
yout=1024-x;
y0 =700.000; /*y0 =734.000;*/
error=y0-yout;
if(error>100)
{
//u=5;
u=2048;
}
else if(error<=-100)
{
u=0;
}
else
{
Perror=error-error_1;
Ierror=error;
Derror=error-2*error_1+error_2;
du=kp*Perror+ki*Ierror+kd*Derror;
u=u_1+du;
if(u>=2048)
{
u=2048;
}
if(u<=0)
{
u=0;
}
u_1=u;
error_2=error_1;
error_1=error;
}
result=u ;
return (result);
}
————————————————————————————————————————
问题找到了:
我的定时器一直在计数,每次到中断结束时,有驱动中断子程序,可我每次中断后都屏蔽中断,?????我现在还找不到合适的定时器周期值(我通过定时器周期中断驱动ADC),我的CUPCLK=20M
程序如下:
#include <stdio.h>
#include "math.h"
#include "register.h"
ioport unsigned port000c;
#define LED_PORT port000c
void initial(void)
{
asm(" setc SXM"); /* 抑制符号位扩展 */
asm(" clrc OVM"); /* 累加器中结果正常溢出 */
asm(" clrc CNF"); /* B0被配置为数据存储空间 */
*CKCR0=0x0041; /*SYSCLK=CPUCLK/2 */
*CKCR1=0x00BB; /*CLKIN=10 ,CPUCLK=20 */
*CKCR0=0x00C1; /*ENABLE PLL */
*SYSCR=0x40C0; /* CLKOUT=CPUCLK */
*WDCR=0x0EA; /* 不使能看门狗,因为SCSR2中的WDOVERRIDE */
/* 即WD保护位复位后的缺省值为1,故可以用*/
/* 软件禁止看门狗 */
*IMR=0x0020; /* 允许中断INT6 */
*IFR=0x0FFFF; /*清除全部中断标志,"写1清0" */
/*OCRA=*OCRA&0x00; // IOPB端口配置为一般的I/O功能,*/
*OCRA=0x0400; /*设置OPB端口的功能 */
*OCRB=0x000C; /*设置IOPC端口的功能 */
*PBDATDIR=0x0FF00; /* IOPB端口设置为输出方式 */
/*PCDATDIR=0x0FF00;*/
*GPTCON=0x003F;
}
void ADINT() /*启动定时器*/
{
*T2CNT=0x0000; /* 初始化计数寄存器2 */
*T2CON=0x910C; /* 定时器2内部cpu时钟源,周期加载,使用自身使能位 */
*T2PR=0x75; /*初始化定时器2周期寄存器,周期为 117 */
*EVIFRB=0x0001; /*清除EVIFRB中断标志(T2PINT ENABLE) */
*GPTCON=*GPTCON|0x0400; /* 定时器2周期中断启动ADC, */
*ADCTRAL1=0xC904; /*初始化ADC,写"1"清除ADCINTFLAG,选择通道2*/
*ADCTRAL1=*ADCTRAL1|0x0200; /*使能ADC1*/
*ADCTRAL2=0x0005; /*选择预定标系数为16*/
}
void pwminitial(void)
{
*ACTR=0x0666;
*SACTR=0x0015;
*DBTCON=0x0000; /* 死区定时器周期,并禁止3个全比较单元死区定时器 */
*COMCON=0x4B57;
*COMCON=0xCB57;
*T1PR=0x0800; /*设置PWM的波形周期为 4KHZ */
*T1CMPR=0x0000; /*初始化定时比较器1 */
*T1CNT=0x0000; /* 初始化计数寄存器1 */
}
unsigned int temp,result,j,k;
int m,n,u_1,ADRESULT[50]; /* 定义其它一些临时变量 */
int error=0,error_1=0,error_2=0;
int kp=5,ki=0.1,kd=0;
int LedOnFlag;
void main(void)
{
int i;
asm(" setc INTM"); /* 禁止所有中断 */
initial(); /* 系统初始化 */
ADINT(); /*a/d初始化*/
pwminitial(); /*pwm初始化*/
j = 1;
LED_PORT = 0x00;
LedOnFlag = 1;
while(1)
{
for(i=1;i<5;i++)
{
for(n=0;n<50;n++) /*ADRESULT[50] 清零;*/
{
ADRESULT[n]=0;
}
temp=0;
for(m=0;m<50;m++)
{
asm(" clrc INTM"); /* 开中断 */
*ADCTRAL2=*ADCTRAL2|0x0400; /*允许事件管理模块启动ADC*/
*T2CON=*T2CON|0x40; /*启动定时器2,启动A/D转换*/
temp+=ADRESULT[m];
}
temp=(temp/50);
/*
while(1)
{
if(m==50) break;
}
*T2CON=*T2CON&0xFFBF;
*/
*PCDATDIR=*PCDATDIR|0x0080;
result=CALC(temp);
PWM(result);
}
if ( j >= 3000 )
{
if ( LedOnFlag == 1 )
{
LedOnFlag = 0;
LED_PORT = 0x00;
*PCDATDIR=0x0FF00;
j = 0;
}
else
{
LedOnFlag = 1;
LED_PORT = 0x0FF;
*PCDATDIR=0x0FF88;
j = 0;
}
}
else
{
j = j + 1;
}
}
}
/* 直接返回中断服务程序 */
void interrupt c_dummy1( )
{
return;
}
/* AD中断服务子程序 */
void interrupt adint( )
{
asm(" setc INTM"); /* 关中断 */
*T2CON=*T2CON&0xFFBF; /*停止定时器2计数*/
asm(" clrc SXM");
*T2CNT=0X0000;
ADRESULT[m]=*ADCFIFO1>>6;
*ADCTRAL1=*ADCTRAL1|0x0100; /*写"1"清除ADCINTFLAG*/
*ADCTRAL2=*ADCTRAL2&0xFBFF; /*禁止事件管理模块启动ADC*/
*EVIFRB=0x0001; /*清除EVIFRB中断标志(T2PINT ENABLE) */
return;
}
int PWM(result)
{
*CMPR1=result;
*CMPR2=1000;
*CMPR3=1500;
*SCMPR3=1000;
*T1CON= 0x900A; /* 连续增计数方式*/
*T1CON= 0x904A; /* 使能比较操作 */
}
int CALC(temp) /*增量式PID控制算法*/
{
int x=0,yout,y0,u,du,yu; /*定义其它一些临时变量*/
int Perror,Ierror,Derror;
x=temp;
yout=1024-x;
y0 =700.000; /*y0 =734.000;*/
error=y0-yout;
if(error>100)
{
//u=5;
u=2048;
}
else if(error<=-100)
{
u=0;
}
else
{
Perror=error-error_1;
Ierror=error;
Derror=error-2*error_1+error_2;
du=kp*Perror+ki*Ierror+kd*Derror;
u=u_1+du;
if(u>=2048)
{
u=2048;
}
if(u<=0)
{
u=0;
}
u_1=u;
error_2=error_1;
error_1=error;
}
result=u ;
return (result);
}
设置断点进行动态调试,数据很好!
为何在运行,会出现几个0值?
现在出现采集后有几个adc值:ADRESULT[m]=0,救救我吧!
dsp中a/d完后,不是自动采集吗?
|
|