[STM8] 开启IWDG和AWU后程序进入HALT后通过外部中断唤醒

[复制链接]
6265|15
 楼主| 相耘 发表于 2013-8-23 17:04 | 显示全部楼层 |阅读模式
本帖最后由 相耘 于 2013-8-24 10:48 编辑

开启IWDG和AWU后程序进入HALT后通过外部中断唤醒,但如果刚进HALT大约5秒内由外部唤醒,则正常,即程序会从while(1){}内部开始执行,也就是说在HALT后进AWU喂狗然后再HALT期间,主程序一直在while(){}内部等待外部中断唤醒,但如果进入HALT后大约超过5秒后由外部唤醒 ,则不正常,即程序会从Main(){}开始重新执行,即复位了。且程序在HALT->AWU喂狗->HALT的循环中并不稳定,会自动唤醒。我想可能是AWU中断服务程序有些问题,但尝试了一下,没有解决,看了看技术手册,没找到头绪,有木有了解或遇到过类似情况的朋友?一起讨论一下,:)谢谢!使用的是STM8S103。
  1. #include "STM8S103F.h"

  2. unsigned int num;
  3. unsigned char Display_bat[]={0xff,0xf7,0xf3,0xf1,};
  4. unsigned char Display_cig[]={0x1f,0x9f,0xdf,0xff,};


  5. //                                             STM8S103F
  6. //                 ------------------------
  7. //        SW->PD4-| 1                   20 |-PD3->TIM2_CH2->PWM
  8. //      AIN5->PD5-| 2                   19 |-PD2<-AIN3
  9. //      AIN6->PD6-| 3                   18 |-PD1<->SWIM
  10. //           NRST-| 4                   17 |-PC7->SMALLH
  11. //      BIGH<-PA1-| 5                   16 |-PC6->SMALLM
  12. //      BIGM<-PA2-| 6                   15 |-PC5->SMALLL
  13. //            VSS-| 7                   14 |-PC4->NULL
  14. //           VCAP-| 8                   13 |-PC3->NULL
  15. //            VDD-| 9                   12 |-PB4<-CHARGE
  16. //      BIGL<-PA3-| 10                  11 |-PB5->OPENLOAD
  17. //                 ------------------------


  18. void Init_GPIO(void)        
  19. {
  20.         PC_ODR = 0xff;                //设置PC口输出为高电平,
  21.         PC_DDR = 0xff;                //设置PC口全为输出,置1为输出,置0为输入;
  22.         PC_CR1 = 0xff;                //置1为推挽(输出时)或上拉(输入时)
  23.                                                 //置0为浮空
  24.         PC_CR2 = 0x00;                //设置PC口为推挽输出,置1为中断,置0为非中断
  25.         
  26.         PA_ODR = 0xff;                //设置PC口输出为高电平,
  27.         PA_DDR = 0xff;                //设置PC口全为输出,置1为输出,置0为输入;
  28.         PA_CR1 = 0xff;                //置1为推挽(输出时)或上拉(输入时)
  29.                                                 //置0为浮空
  30.         PA_CR2 = 0x00;                //设置PA口为推挽输出,置1为中断,置0为非中断
  31.         
  32.         PB_ODR = 0x00;                //设置PB输出端口为低电平
  33.         PB_DDR = 0xef;                //设置PB4为输入,其余为输出
  34.         PB_CR1 = 0x00;                //设置PB4为悬浮输入               
  35.         PB_CR2 = 0x00;                //非中断
  36.         
  37.         PD_ODR = 0x00;                 //设置PD输出端口为低电平
  38.         PD_DDR = 0xef;                //设置PD4为输入,其余为输出
  39.         PD_CR1 = 0x10;                //设置PD4为上拉输入        
  40.         PD_CR2 = 0x00;                //非中断
  41.         
  42.         CLK_ICKR |= 0X20;        //进入活跃停机模式关闭 MVR 以省电
  43.         FLASH_CR1 |= 0X04;        //进入活跃停机模式关闭 FLASH 以省电  
  44. }
  45. void IWDG(void)
  46. {
  47.         IWDG_KR=0xcc;                //起动IWDG命令
  48.         IWDG_KR=0x55;                //开起IWDG_PR和IWDG_RLR寄存器写功能
  49.         IWDG_PR|=0x06;                //写入分频值256分频
  50.         IWDG_RLR=0xff;                //128kHz时钟经过256分频再计250个时钟脉冲
  51.         IWDG_KR=0xaa;                //喂狗同时也是封闭IWDG_PR和IWDG_RLR寄存器写功能
  52. }
  53. void IWDG_Refresh(void)
  54. {
  55.         IWDG_KR=0x55;                //开起IWDG_PR和IWDG_RLR寄存器写功能
  56.         IWDG_KR=0xaa;                //喂狗同时也是封闭IWDG_PR和IWDG_RLR寄存器写功能
  57. }
  58. void Open_AWU(void)
  59. {
  60.         AWU_CSR = 0x01;
  61.         AWU_APR = 0x2f;
  62.         AWU_TBR = 0x0a;
  63.         AWU_CSR |= 0x10;
  64. }
  65. void Init_TIM1(void)
  66. {
  67.         TIM1_IER = 0x00;                // interrupt disable
  68.         TIM1_EGR = 0x01;                // enable generator
  69.         TIM1_PSCRH = 0x00;                // 计数器时钟=主时钟/128=2MHZ/128
  70.         TIM1_PSCRL = 0x00;                // 相当于计数器周期为64uS
  71.         TIM1_ARRH = 0xff,                //
  72.         TIM1_ARRL = 0xff;
  73.         TIM1_CNTRH = 0xff;                //
  74.         TIM1_CNTRL = 0xff;
  75.                                                         // 定时周期=(ARR+1)*64=16320uS
  76.         TIM1_CR1 = 0x01;                // b0 = 1,允许计数器工作
  77.                                                         // b1 = 0,允许更新
  78.                                                         // 设置控制器,启动定时器
  79.         TIM1_IER = 0x01;                //interrupt enable
  80. }
  81. void Halt_Perproccess(void)
  82. {
  83.         _asm("sim");
  84.         PA_ODR = 0xff;
  85.         PC_ODR = 0xe0;
  86.         
  87.         PB_ODR = 0x00;                //设置PB输出端口为低电平
  88.         PB_CR2 = 0x10;                //PB4中断
  89.         PD_ODR = 0x00;                 //设置PD输出端口为低电平        
  90.         PD_CR2 = 0x10;                //PD4中断        
  91.         
  92.         EXTI_CR1 = 0x84;        //设置PB口中断为上升沿触发,PD口为下降沿触发
  93.         
  94.         IWDG_Refresh();                //进停机模式前喂狗
  95.        //TIM1_IER = 0x00;        //关闭定时器中断
  96.         _asm("rim");
  97.         _asm("halt");
  98. }
  99. /****************end****************/
  100. void Halt_Mode(void)
  101. {
  102.         if(num==200)        //定时进入停机模式
  103.         {
  104.                 num = 0;
  105.                 Halt_Perproccess();
  106.         }
  107. }
  108. /****************TIM1_INT****************/

  109. @far[url=home.php?mod=space&uid=422518]@interrupt[/url] void TIM1(void)        //定时器1
  110. {
  111.         TIM1_SR1 = 0x00;                        //clean timer status registor
  112.         IWDG_Refresh();
  113.         PC_ODR = Display_cig[1];         
  114. //检测灯
  115.         num++;
  116. }
  117. /****************end****************/
  118. @far@interrupt void AWU(void)
  119. {
  120.         IWDG_Refresh();
  121.         AWU_CSR |= 0x10;
  122.         _asm("halt");
  123. }
  124. /****************EXTI1****************/
  125. [url=home.php?mod=space&uid=1095855]@far[/url] @interrupt void EXTI1(void)        //PB口外部中断
  126. {
  127.         if(PB_IDR&0x10)
  128.         {
  129.                 PB_CR2 = 0x00;
  130.                 PD_CR2 = 0x00;
  131.         }
  132. }
  133. /****************end****************/
  134. /****************EXTI3****************/
  135. @far @interrupt void EXTI3(void)        //PD口外部中断
  136. {
  137.         if(!(PD_IDR&0x10))
  138.         {
  139.                 PB_CR2 = 0x00;
  140.                 PD_CR2 = 0x00;
  141.         }
  142. }
  143. /****************end****************/
  144. /****************MAIN****************/
  145. void main(void)
  146. {
  147.         _asm("sim");
  148.         Init_GPIO();
  149.         Init_TIM1();
  150.         Open_AWU();
  151.         IWDG();
  152.         _asm("rim");
  153.         PC_ODR = Display_cig[0];      //检测灯
  154.         while(1)
  155.         {
  156.                 IWDG_Refresh();
  157.                 PA_ODR = Display_bat[1];      //检测灯
  158.                 Halt_Mode();
  159.         }
  160. }

           
 楼主| 相耘 发表于 2013-8-24 10:01 | 显示全部楼层
定时器中断程序名有乱码,正确应为@far @interrupt void TIM1(void),似乎用插入代码的方式遇到@字符时总会产生些乱码。
 楼主| 相耘 发表于 2013-8-26 11:53 | 显示全部楼层
是太简单还是太复杂了!无人回应
 楼主| 相耘 发表于 2013-8-26 17:56 | 显示全部楼层
看来是没人回应了!
yuanquanquan 发表于 2013-8-26 18:28 | 显示全部楼层
表示没用过看门狗,帮卤煮顶一下。
chuangpu 发表于 2013-8-26 19:34 | 显示全部楼层
帮楼主顶一个   感觉这一块   自己不懂的太多了   还需要好好消化消化   楼主
nil_li 发表于 2013-8-29 15:27 | 显示全部楼层
不知道楼主可知道,看门狗不可关闭!所以,你的程序HALT之后,被看门狗复位了。看门狗最长的复位时间好像是2s,记不清楚了
 楼主| 相耘 发表于 2013-8-31 10:06 | 显示全部楼层
nil_li 发表于 2013-8-29 15:27
不知道楼主可知道,看门狗不可关闭!所以,你的程序HALT之后,被看门狗复位了。看门狗最长的复位时间好像是 ...

看门狗的最长时间是1.02秒,我使用AWU唤醒的目的就是喂狗,
@far@interrupt void AWU(void)
{
        IWDG_Refresh();    //喂狗
        AWU_CSR |= 0x10; //清AWUF
        _asm("halt"); //再睡
}
但就是不按我的思路去运行,进HALT后->AWU唤醒->喂狗->再睡,在以上的过程中,主程序应该一直在while(1)处等待外部中断的唤醒,实际是5秒前由外部中断唤醒是对的,5秒之后再唤醒,程序就复位了,我通过检测灯可以看到,其实我贴的程序只是一个框架,实际产品的程序是含有ADC,PWM,外加一些LED动态显示等,这应该是一个小产品的程序的基本框架。这个程序开WWDG也正常,但开了IWDG后由于要自动喂狗所以加了AWU,结果就有点不对了,我估计还是AWU服务程序可能有点问题,但又说不上来具体在哪里。
 楼主| 相耘 发表于 2013-9-5 11:32 | 显示全部楼层
本帖最后由 相耘 于 2013-9-5 11:33 编辑
  1. [url=home.php?mod=space&uid=1095855]@far[/url] [url=home.php?mod=space&uid=422518]@interrupt[/url] void AWU(void)
  2. {
  3.         if(AWU_CSR&0x20)
  4.                 IWDG_Refresh();
  5.         AWU_wakeup = 1;
  6. }
  7. void main(void)
  8. {
  9.         _asm("sim");
  10.         Init_GPIO();
  11.         Init_TIM1();
  12.         CLK_Config();
  13.         Flash_Init();
  14.         Open_AWU();
  15.         IWDG();
  16.         _asm("rim");
  17.         PC_ODR = Display_cig[0];
  18.         while(1)
  19.         {
  20.                 IWDG_Refresh();
  21.                 if(AWU_wakeup)
  22.                 {
  23.                         AWU_wakeup = 0;
  24.                         _asm("halt");
  25.                 }
  26.                 else
  27.                 {
  28.                         主程序放在这里
  29.                         PA_ODR = Display_bat[1];
  30.                         Halt_Mode();
  31.                 }
  32.         }
  33. }
当AWU唤醒后只在AWU服务程序中恢复标志位然后回主程序中进HALT,用这样的方式就正常了,但感觉这样的话程序有点绕,问题是可以解决,但总觉得不舒服,不知哪位仁兄另有高见,请不吝赐教,
nil_li 发表于 2013-9-5 11:59 | 显示全部楼层
几点请注意:
1.看门狗是复位。
2.中断程序中HALT,应该要有问题的。
3.看门狗时间和唤醒时间
所以中断中无执行代码,只做标志是比较合理的做法。

评分

参与人数 1威望 +1 收起 理由
相耘 + 1 很给力!

查看全部评分

 楼主| 相耘 发表于 2013-9-24 18:11 | 显示全部楼层
nil_li 发表于 2013-9-5 11:59
几点请注意:
1.看门狗是复位。
2.中断程序中HALT,应该要有问题的。

不要在AWU中断服务程序中执行HALT是正确的,
hkcj 发表于 2013-9-24 19:04 | 显示全部楼层
不懂这一块   楼主   帮你顶一个   看看高手的见解  
pofu007 发表于 2013-9-26 15:39 | 显示全部楼层
IWDG在HALT时,仍然是工作的吧,HALT前是不是先把IWDG停掉。
 楼主| 相耘 发表于 2013-10-15 14:04 | 显示全部楼层
pofu007 发表于 2013-9-26 15:39
IWDG在HALT时,仍然是工作的吧,HALT前是不是先把IWDG停掉。

STM8只要开启IWDG就不可被关闭,开WWDG可以关闭,
这个问题的解决办法是:不要在AWU服务程序中执行进HALT的指令。
l4157 发表于 2014-1-20 11:13 | 显示全部楼层
在AWU中断中用HALT相当于中断嵌套,AWU多了就溢出了,然后复位...
p422984186 发表于 2016-5-9 14:17 | 显示全部楼层
学习下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

11

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部