OpenEdv-开源电子网

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

stm8s103 利用中断判断长按短按,长按可以实现进入低功耗 短按1-2s跳出低功耗进入工作,实际情况是短按立马跳出低功耗,请各位大侠帮忙看看。附程序

[复制链接]

4

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2012-12-18
在线时间
3 小时
发表于 2013-4-26 10:17:28 | 显示全部楼层 |阅读模式

声明

#include  "STM8S103F2P.h"


#define uint  unsigned int 
#define uchar unsigned char

#define NGI()          _asm("sim");     /* 禁止全局中断 */
#define EGI()          _asm("rim");     /* 使能全局中断 */

#define BitSet(a,b)    (a |= (1<<b))    /* 置1变量a第 b位 */
#define BitClr(a,b)    (a &= ~(1<<b))   /* 置0变量a第 b位 */
#define BitCpl(a,b)    (a^=1<<b)        /* 取反变量a第b位 */
#define GetBit(a,b)    (((a)>>(b))&0X01)/* 获取变量a第b位 */


stm8_interrupt.c

#include  "lt101.h"
void   Sun_check(void);
//void light_control(void);
typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
unsigned char interrupt_instruction;
interrupt_handler_t interrupt_handler;
};

@far @interrupt void NonHandledInterrupt (void)
{
/* in order to detect unexpected events during development, 
  it is recommended to set a breakpoint on the following instruction
*/
return;
}

@far @interrupt void PORTA_Interrupt_IRQHandler (void)
{
key_bit=1;//标志位

}
@far @interrupt void TIM4_UPD_OVF_IRQHandler (void)
{
minisecond++;  //10ms
TIM4_SR &= 0xFE;
if((key_bit==1)&&(GetBit(PA_IDR,3))==0)//按键按下 并且处于低电平
{
counter++;                                    //counter10ms加一次,由此值判断长按短按
}
return;
}

extern void _stext();     /* startup routine */

struct interrupt_vector const _vectab[] = {
{0x82, (interrupt_handler_t)_stext}, /* reset */
{0x82, NonHandledInterrupt}, /* trap  */
{0x82, NonHandledInterrupt}, /* irq0  */
{0x82, NonHandledInterrupt}, /* irq1  */
{0x82, NonHandledInterrupt}, /* irq2  */
{0x82, PORTA_Interrupt_IRQHandler}, /* irq3  */
{0x82, NonHandledInterrupt}, /* irq4  */
{0x82, NonHandledInterrupt}, /* irq5  */
{0x82, NonHandledInterrupt}, /* irq6  */
{0x82, NonHandledInterrupt}, /* irq7  */
{0x82, NonHandledInterrupt}, /* irq8  */
{0x82, NonHandledInterrupt}, /* irq9  */
{0x82, NonHandledInterrupt}, /* irq10 */
{0x82, NonHandledInterrupt}, /* irq11 */
{0x82, NonHandledInterrupt}, /* irq12 */
{0x82, NonHandledInterrupt}, /* irq13 */
{0x82, NonHandledInterrupt}, /* irq14 */
{0x82, NonHandledInterrupt}, /* irq15 */
{0x82, NonHandledInterrupt}, /* irq16 */
{0x82, NonHandledInterrupt}, /* irq17 */
{0x82, NonHandledInterrupt}, /* irq18 */
{0x82, NonHandledInterrupt}, /* irq19 */
{0x82, NonHandledInterrupt}, /* irq20 */
{0x82, NonHandledInterrupt}, /* irq21 */
{0x82, NonHandledInterrupt}, /* irq22 */
{0x82, TIM4_UPD_OVF_IRQHandler}, /* irq23 */
{0x82, NonHandledInterrupt}, /* irq24 */
{0x82, NonHandledInterrupt}, /* irq25 */
{0x82, NonHandledInterrupt}, /* irq26 */
{0x82, NonHandledInterrupt}, /* irq27 */
{0x82, NonHandledInterrupt}, /* irq28 */
{0x82, NonHandledInterrupt}, /* irq29 */
};

MAIN.c

/***************************************************************
**************长按进入停机模式,短按开机*********************
****************************************************************
*******/
 
//过放电路由硬件实现
#include  "lt101.h"
#include  "cpu_init.h"
void Sun_check(void);     //电压采样
void Free_WWDG(void);     //窗口看门狗
void light_control(void); //闪烁控制函数
uint   minisecond;        //light_control 函数用到的light
uint counter=0;
uchar  sun=0;
uchar  work_state=0;      //等于0时工作,1时停止工作
uint   cycle= 100;        //灯亮灭周期时间1s
uchar  lighting_time= 15; //灯亮持续时间150ms
uchar  key_mode=0;        //按键模式
uchar  key_bit=0;         //标志位
main()
{
NGI();        /*禁止中断*/
CLK_Init();   /*时钟初始化*/
GPIO_Init();  /*端口初始化*/
EXTI_Init(); /*外部中断触发方式*/
Tim4_Init(); /*定时器初始化*/
ADC_Init();
WWDG_Init();  /*窗口看门狗初始化*/
EGI();
while (1)
{
Free_WWDG();      /*喂狗*/
   Sun_check();      /*ADC采样*/
 light_control();  /*灯闪烁程序*/
if(counter>300)   /*判断按键按下大于3S*/
{

Free_WWDG();      /*喂狗*/
counter=0;        /*清空计数*/
    key_bit=0;        /*清空标志位*/
BitClr(PC_ODR,6); /*清空按键*/
key_mode=0;       /*清空按键*/
_asm("halt");     /*进入到低功耗模式*/
FLASH_CR1 = 0x080; 
}
if((counter>100)&&(counter<200))/*若按键按下1-2s*/
{
Sun_check();
light_control();
}
}
}



/***************************************************************
************** ADC 采样 用来判断白天黑夜的**********************
***************************************************************/
void Sun_check(void)
{
 unsigned char i;
unsigned int AD_Value;
ADC_CSR  = 0x05;//选择通道AIN5
 ADC_CR1 |= 0x01;         /* First set ADON to power on the ADC module.    */
i = 12;                   /* Wait >7us to ensure the ADC power on finished.*/
    while(i--); 
    ADC_CR1 |= 0x01;         /* Set ADON again to start AD convert.           */
    while(!(ADC_CSR & 0x80));/* Waiting for AD convert finished (EOP=1).      */
    
    AD_Value = ((((unsigned int)ADC_DRH)<<2)+ADC_DRL);
if(AD_Value > 25)
 sun = 1;
if(AD_Value < 20)
 sun = 0;
}

/****************************************************************
*********************灯闪烁控制**********************************
*****************************************************************
****************************************************************/
void light_control(void)
{
if(sun == 0)
{
if(minisecond <= lighting_time)
{
BitSet(PC_ODR,6); //输出高电平,灯亮持续时间lighting_time
}
if(minisecond > lighting_time)
{
BitClr(PC_ODR,6);    //输出低电平,灯灭
}
if(minisecond > cycle)          //周期时间cycle 
{
Sun_check();
minisecond = 0;
}
}
if(sun == 1)                          //检测到白天
{
if(minisecond > 100)             
{
BitClr(PC_ODR,6);   //输出低电平
Sun_check();
minisecond = 0;                 
}
}

}
/****************wwdg**************
*************窗口看门狗——喂狗程序**************
***********************************/
void Free_WWDG(void)
{
if((WWDG_CR&0X7F)<=WWDG_WR)//小于窗口值才能喂狗
WWDG_CR|=0X7F;   //重新喂狗 
}

初始化函数

#include  "cpu_init.h"

void CLK_Init(void)
{
 // CLK_ICKR = 0X08;//enable LSI
CLK_SWCR = CLK_SWCR | 0x02;    // SWEN = 1
CLK_SWR = 0XD2;//chose LSI 128K
while((CLK_SWCR & 0x08) == 0); // 等待切换成功
CLK_SWCR = CLK_SWCR & 0xFD;    // 清除切换
CLK_CKDIVR = 0X00; //Fmaster=128KHZ, Fcpu=128KHZ/128=1k
CLK_PCKENR1 = 0x10;//T4
CLK_PCKENR2 = 0x08;//ADC
}

void GPIO_Init(void)
{
/*PA3:KEY  */
BitClr(PA_DDR,3); //PA3 Input.              
BitSet(PA_CR1,3); //
BitSet(PA_CR2,3); //Enable extern interrupt
/*PC3:KEY   */
BitSet(PC_DDR,3); //PC3 Output.             
BitSet(PC_CR1,3); //pull up
BitClr(PC_CR2,6); //
/*PC6OUT*/
BitSet(PC_DDR,6); //PC6 Output.             
BitSet(PC_CR1,6); //pull up
BitClr(PC_CR2,6); //
/*PD5:ADC  */
BitClr(PD_DDR,5); //PD5 Input. .              
BitClr(PD_CR1,5); //
BitClr(PD_CR2,5); //Output speed up to 2MHz.
}
void Tim4_Init(void)
{   
TIM4_IER = 0x00;
TIM4_EGR = 0x01;
TIM4_PSCR =0x03;//128k/8
TIM4_CNTR =0;  
TIM4_ARR  =160;
TIM4_CR1 = 0x01;     
TIM4_SR &= 0xFE;
TIM4_IER = 0x01;
}
void ADC_Init(void)
{
ADC_CR2  = 0x00;
ADC_CR1  = 0x00;    
ADC_TDRL = 0x20;
}


void WWDG_Init(void)
{
//窗口看门狗在计数值降到0x3f时产生复位,而且不能在大于窗口值时喂狗。
//否则复位
WWDG_WR=0x60;      //看门狗窗口值,窗口值必须在0x3F以上,但必须小于计数值,否则无法喂狗
WWDG_CR=0x7F;       //看门狗计数值
WWDG_CR|=0x80;    //使能窗口看门狗
//  128k主频,计数值0x7F 最大延长时间为 (64 * (12288 / 128000)) = 6.14s
//看门狗
}

void EXTI_Init(void)
{
EXTI_CR1=0X02;//PA口下降沿触发
}


1截图1.JPG
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2012-12-18
在线时间
3 小时
 楼主| 发表于 2013-4-26 10:21:07 | 显示全部楼层
请原子哥与各位大侠帮忙看看, 怎么样才能够实现短按1-2s后再跳出停机模式。共同研究下,望各位牛人指点。
回复 支持 反对

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2013-4-26 10:59:35 | 显示全部楼层
我是这样做的:

在关机的时候 备份域的一个数据寄存器写入0,

在初始化之前,等待时钟稳定后,其他的都不初始化, 先读取备份域数据,
如果<5, 则 +1 存储,然后延时200ms 再判断,如果没按键 清零,然后休眠。
否则启动,再初始化其他部分。

有点麻烦,等其他高人解决
回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2012-12-18
在线时间
3 小时
 楼主| 发表于 2013-4-26 11:38:16 | 显示全部楼层
回复【3楼】aleda303:
---------------------------------
期望能有能人给个方法尝试下,我先尝试下你的这个方法,看看能成功不。
回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2012-12-18
在线时间
3 小时
 楼主| 发表于 2013-5-2 09:52:08 | 显示全部楼层
回复【3楼】aleda303:
---------------------------------
你好, 请问方便把按键的这个例子发上来看看吗? 期望回复 谢谢
回复 支持 反对

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2013-5-17 16:24:14 | 显示全部楼层
主函数 

main()
{
 InitClock();//待机模式唤醒后,系统重新执行 初始化时钟
 InitGPIO_Key();//初始化按键, 其他外设不要初始化

 while(GetKey() ) 
 {
  if(++count >= 3000) break; //按键超过3S ,跳出检测,直接运行程序
 }
if(count<3000) ToStandard(); //如果按键没到3s, 则继续休眠
 DeviceInit();初始化其他部分
......//运行

}
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-7-20 04:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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