OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4371|回复: 14

请教一个问题,在延时的时候进中断再调用延时函数会出现问题吗?

[复制链接]

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
发表于 2015-12-28 13:20:58 | 显示全部楼层 |阅读模式
现在设备上的灯闪,我是在定时器中延时80MS,测试的90个设备中有两个设备跑一段时间后程序运行不正常,现在在在线测试还没有结果,想问下问题会不会出现在这。顺便问一下,板上几个灯间隔闪烁一般用什么方式。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11555
金钱
11555
注册时间
2014-4-1
在线时间
1317 小时
发表于 2015-12-28 13:49:31 | 显示全部楼层
本帖最后由 xuande 于 2015-12-28 13:52 编辑

1、函数重入问题,好像很复杂。    惹不起,最好躲开这种用法。

2、做一个最基础的定时器,溢出时多个变量同时加一,
    每个变量控制一个灯,剩下应当不用多说了。




回复 支持 反对

使用道具 举报

7

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2015-8-18
在线时间
63 小时
发表于 2015-12-28 13:56:06 | 显示全部楼层
两种方法:1.一般用普通延时不停的让CPU跑循环,

                  2.用你的定时器设备,到一段时间中断一次,不过IO口的处理不能在中断处理呀(因为在反汇编中断有异常不好处理),
                  处理办法在中断口设置一个标志位。中断完后在主程序判断和操作IO就可以了。
回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
 楼主| 发表于 2015-12-28 14:53:49 | 显示全部楼层
xuande 发表于 2015-12-28 13:49
1、函数重入问题,好像很复杂。    惹不起,最好躲开这种用法。

2、做一个最基础的定时器,溢出时多个变 ...

现在是用定时器来增加变量,但是他这个灯开机就要亮,有三个双色灯代表不同的东西,并且在开机后要先GPRS连接成功服务器以后才能进入主循环,在进入主循环之前在定时器中断外部都没有可以查询的地方
回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
 楼主| 发表于 2015-12-28 14:54:09 | 显示全部楼层
feisheng168 发表于 2015-12-28 13:56
两种方法:1.一般用普通延时不停的让CPU跑循环,

                  2.用你的定时器设备,到一段时间中 ...

现在是用定时器来增加变量,但是他这个灯开机就要亮,有三个双色灯代表不同的东西,并且在开机后要先GPRS连接成功服务器以后才能进入主循环,在进入主循环之前在定时器中断外部都没有可以查询的地方
回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
 楼主| 发表于 2015-12-28 14:55:43 | 显示全部楼层
xuande 发表于 2015-12-28 13:49
1、函数重入问题,好像很复杂。    惹不起,最好躲开这种用法。

2、做一个最基础的定时器,溢出时多个变 ...

现在是用定时器来增加变量,但是他这个灯开机就要亮,有三个双色灯代表不同的东西,并且在开机后要先GPRS连接成功服务器以后才能进入主循环,在进入主循环之前在定时器中断外部都没有可以查询的地方
回复 支持 反对

使用道具 举报

17

主题

237

帖子

0

精华

高级会员

Rank: 4

积分
925
金钱
925
注册时间
2012-2-27
在线时间
393 小时
发表于 2015-12-28 15:39:59 | 显示全部楼层
不能这么做的,要用不一样的延时函数
回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
 楼主| 发表于 2015-12-28 15:50:31 | 显示全部楼层
k-ad 发表于 2015-12-28 15:39
不能这么做的,要用不一样的延时函数

现在我这90个测试的设备里面只有两个有问题,其他暂时都没有问题,我以前看原子哥说他例成里面的延时函数是可重入的,还有就是如果用另外一个延时的话,中断返回以后原来的延时函数是不是就不准了
回复 支持 反对

使用道具 举报

17

主题

237

帖子

0

精华

高级会员

Rank: 4

积分
925
金钱
925
注册时间
2012-2-27
在线时间
393 小时
发表于 2015-12-28 16:06:28 | 显示全部楼层
我认为这是程序问题,机率!说不定下次再测这90个就有3个有问题了,简单用方式就是用一个定时器去做,count++~~~~~~count%10,count%100,这样去做,如果count要经常清0就volatile这个关键字
回复 支持 反对

使用道具 举报

7

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2015-8-18
在线时间
63 小时
发表于 2015-12-28 16:11:17 | 显示全部楼层
三个双色怎么亮,每个单个亮,还是每个两个都亮,逻辑关系?还有你的灯和GPRS用的是同一个IO端口不,如PB0-15。怎么你的GPRS不能加查询码?
回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
 楼主| 发表于 2015-12-28 16:54:54 | 显示全部楼层
feisheng168 发表于 2015-12-28 16:11
三个双色怎么亮,每个单个亮,还是每个两个都亮,逻辑关系?还有你的灯和GPRS用的是同一个IO端口不,如PB0- ...

一个是网络灯,来显示有没有连接上基站,有没有连接上服务器这些,因为在GPRS初始化以及连接主站的过程中,都是在等待返回命令,这里边要怎么加查询。
回复 支持 反对

使用道具 举报

7

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2015-8-18
在线时间
63 小时
发表于 2015-12-28 22:02:35 | 显示全部楼层
本帖最后由 feisheng168 于 2015-12-28 22:08 编辑

哦,你可以这样呀
其实这些东西可以这样工作的,我个人建议是,初始化等待
所有灯闪烁(颜色和工作颜色一样),以表示正在链接,
工作是一种颜色亮,
故障另一种颜色亮,


第一步初始化定时器让它工作在时基模式
,让LED等闪烁,以200ms灭或亮一次。举例,
定时器50ms中断一次,中断设个计数器,
中断一次计数加1。加到4次后这个标志位赋值1,为200MS。
看程序


int TimeNum=0; 设置为全局变量(extern int TimeNum;)

char InterFlag=0; 设置为全局变量(extern char InterFlag;)


中断程序:
void IT(void)
{

   1,判断中断标志位,
   2,清除中断标志位,
  3,
  if(TimeNum<1000)//为防止计数器溢出加的判断
{
     TimeNum++;

     if((TimeNum>=4)&&(InterFlag!=1))
     {
        InterFlag=1;
     }
   ..........
  }
}


char GPRS_GetStatus(void)
{
  添加GPRS程序访问一次

  判断是否链接完成否反会1,成功返回0;  
}


void GPRS_init(void)
{

  char InterStatus=0;

  int  TimeoutCount=0; //通讯超时计数故障检测

while(TimeoutCount<=10) //数字自己评估添加
{

   if(InterFlag!=0)
  {
      if(InterStatus==0)
     {
        LED=1;亮
        InterStatus=1;
     }
     else
     {
        InterStatus=0;
        LED=0;灭
     }
     TimeNum=0;  //清除计数器
     InterFlag=0;        //请除标志位
     TimeoutCount++;
   }
  if(!GPRS_GetStatus())//获取状态
  {
    break; //退出循环
  }
}

if(TimeoutCount<=10)
{
  LED=1;亮              //表示初始化成功
}
else
{
   另一种颜色亮;表示错误
   while(1)       //等待命令
   {
    }
}
}

void Delay(int n)
{
  short i=72; //72M cpu
  while(n--)
  {
    while(i--);
  }
}

主程序:

int main(void)
{
  Delay(1000);//短暂延时等待系统稳定后
  Delay(1000);//短暂延时等待系统稳定后
  Delay(1000);//短暂延时等待系统稳定后
  Delay(1000);//短暂延时等待系统稳定后
  Delay(1000);//短暂延时等待系统稳定后
  上面一般为5MS以上时间

  初始化时钟;
  初始化各个IO口;
  初始化定时器;
  GPRS_init();
  .. ...
while(1)
{
   自己的循环程序了。
}
}

呵呵  上面程序你可以根据你的想法修改写。上面是我个人意见。


回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
 楼主| 发表于 2015-12-29 10:14:54 | 显示全部楼层
feisheng168 发表于 2015-12-28 22:02
哦,你可以这样呀
其实这些东西可以这样工作的,我个人建议是,初始化等待
所有灯闪烁(颜色和工作颜色一 ...

非常感谢你的耐心解答,现在最不好的地方就是,这个灯亮的方式不是我随便说怎样就怎样,200ms亮,200ms灭不行,他规定必须要闪烁的那样,3S闪烁一次,或者1S闪烁一次这样。大概流程就是,最下边的两个双色灯,第一个一开机就要根据测量数据3S闪一次绿灯或者红灯或者1S闪烁一次红灯,第二个来指示连接状态,连上基站之前,1S闪烁一次红灯,连上服务器后3S闪烁一次绿灯,如果初始化不成功按照没有SIM卡,没有网络信号,没有检测到GPRS模块分别显示三种不同颜色的常亮。
回复 支持 反对

使用道具 举报

7

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
311
金钱
311
注册时间
2015-8-18
在线时间
63 小时
发表于 2015-12-29 13:27:57 | 显示全部楼层
这个简单,不管你3秒,还是1秒。你要稳定性高的话,我建议在中断多设几个计数器和标志位,

就是你有几个灯就设几个标志位,你有几个时间,就设几个计数器,

每个计数器对应不同时间,用到那个计数器就读那个标志位,例子

#define TIME_NUM0   20  //1S
#define TIME_NUM1   60  //3S
#define TIME_NUM2   10 //0.5S


int TimeNum0=0; 设置为全局变量(extern int TimeNum0;)
char InterFlag0=0; 设置为全局变量(extern char InterFlag0;) //闪烁时间

int TimeNum1=0; 设置为全局变量(extern int TimeNum1;)
char InterFlag1=0; 设置为全局变量(extern char InterFlag1;) //1S

int TimeNum2=0; 设置为全局变量(extern int TimeNum2;)
char InterFlag2=0; 设置为全局变量(extern char InterFlag2;) //3S


中断程序:
void IT(void)
{

   1,判断中断标志位,
   2,清除中断标志位,
  3,
if(TimeNum0<1000)//为防止计数器溢出加的判断
{
     TimeNum0++;

     if((TimeNum0>=TIME_NUM0)&&(InterFlag0!=1))  //闪烁时间
     {
        InterFlag0=1;
     }
  }
  if(TimeNum1<1000)//为防止计数器溢出加的判断
{
     TimeNum1++;

     if((TimeNum1>=TIME_NUM1)&&(InterFlag1!=1))  //1秒标志位
     {
        InterFlag1=1;
     }
  }

if(TimeNum2<1000)//为防止计数器溢出加的判断
{
     TimeNum2++;

     if((TimeNum2>=TIME_NUM2)&&(InterFlag2!=1))  //3秒标志位
     {
        InterFlag2=1;
     }
  }
}

这下好了你在主程序想用那个就读那个就好了。1S.3S,0.5S都有了
自己调用就可以实现你的功能了,和上面用法一样了。
回复 支持 反对

使用道具 举报

6

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2014-12-22
在线时间
9 小时
 楼主| 发表于 2015-12-30 19:31:39 | 显示全部楼层
feisheng168 发表于 2015-12-29 13:27
这个简单,不管你3秒,还是1秒。你要稳定性高的话,我建议在中断多设几个计数器和标志位,

就是你有几个 ...

十分谢谢你,我直接改成100MS定时了,看看这轮测试情况怎么样
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-21 19:42

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表