在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
芯片精品文章合集(500篇!) 创芯人才网--重磅上线啦!
查看: 6259|回复: 3

[原创] [讨论]用240做A/D时出现,进入中断子程序后,不能返回主程序

[复制链接]
发表于 2004-9-12 10:49:05 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

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完后,不是自动采集吗?






 楼主| 发表于 2004-9-17 16:46:48 | 显示全部楼层

[讨论]用240做A/D时出现,进入中断子程序后,不能返回主程序

大家积极发言阿,有奖励
发表于 2009-5-15 10:32:07 | 显示全部楼层
我是技术小白
发表于 2011-3-19 11:17:52 | 显示全部楼层
我也是技术小白
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条


小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-12-22 13:42 , Processed in 0.020464 second(s), 9 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表