//*************************首先感叹一下C语言的灵活性。
/************************************以下基于STM8单片机**************************/
/****为解决按键时采用死循环,使CPU进入假死机状态,大大浪费单片机资源的情况*******/
/***以下文字为个人理解,大佬建议跳过,当然,也欢迎各位指出偏驳之处***************/
/**单片机在一个时间点只能进行一个动作,并不能做到真正意义上的同时多任务动作,只能在结束一个动作后进行下一个动作,
由于每一个动作所需要耗费的时间特别短,所以在一定情况下可以看作多任务进程。
以下利用中断计时同理,在每一次计时的动作耗费时间特别短,做完这个动作CPU就可以进行其它动作了,相当于摆脱了死循环,
不会让CPU在那无意义地卡住,陷入要等待其它打破标志的死循环**********************/
/***粗略非阻塞(不知道这算不算非阻塞)延时/计时思路:定时器进行规定时间的中断进入,每进一次中断,(符合条件下)次数+1,以此作为粗略的基础时间(1ms/5ms/10ms/100ms……)*****************************/
/*********************以下为代码内容***************************************/
#include <stm8s.h>
#include <stm8s_gpio.h>
#include <stm8s_tim4.h>
#include <stm8s_clk.h>
//按键K1-K2定义,只能读取是否为“0”(按下)/不为“0”(松开),不能读取是否为“1”或者其它的
#define K1 (GPIO_ReadInputData(GPIOC)&GPIO_PIN_1)
#define K2 (GPIO_ReadInputData(GPIOC)&GPIO_PIN_2)
//L1-L2灯亮/灭定义(继电器K1-K2工作/不工作定义)
#define ON 1
#define OFF 0
#define L1(ON_OFF) if(ON_OFF==ON)GPIO_WriteHigh(GPIOB, GPIO_PIN_3);\
else GPIO_WriteLow(GPIOB, GPIO_PIN_3)
#define L2(ON_OFF) if(ON_OFF==ON)GPIO_WriteHigh(GPIOB, GPIO_PIN_2);\
else GPIO_WriteLow(GPIOB, GPIO_PIN_2)
//引脚初始化
void GPIO_Config()
{
//继电器三极管控制引脚 PB2-3 初始化,高电平导通
GPIO_Init(GPIOB, GPIO_PIN_2|GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST);
//按键初始化:无中断无浮点上拉输入
GPIO_Init(GPIOC, GPIO_PIN_1|GPIO_PIN_2, GPIO_MODE_IN_PU_NO_IT);
}
//初始化定时器TIM4
void Init_Timer4(void)
{
TIM4_DeInit();
TIM4_TimeBaseInit(TIM4_PRESCALER_64, 0xFA); /*初始化时基单元。128分频 ,x=16M/128 , 自动重载寄存器值为0xfa=16*15+10=250,
中断溢出=x/0xfa 进中断一次2ms。
64分频下0xFA进中断一次1ms ; 128分频下0x19进中断一次0.2ms***/
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); //使能TIM4更新中断
TIM4_Cmd(ENABLE); //启动定时器
}
//定义全局变量:TIM4每1ms进中断一次 的各按键计次时间sk,各按键对应上一次的计次时间skt
//因为是全局变量,可以在其它地方调用数值后手动进行清零/赋值操作
u16 sk1=0;
u16 sk1t=0;
u16 sk2=0;
u16 sk2t=0;
//TIM4中断服务函数:按键按下开始计时,按键松开停止计时;
//上一次按键按下持续时间数值一直保持,直到下一次按键有效按下后松开(去抖动)。
//各按键独立计时,互不影响
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)
{
//上一次K1按键按下时长:sk1t
if(K1==0) //按键按下
{
sk1++; //TIM4每1ms进中断一次,此时sk1+1
if(sk1==59999) //防止达到计数上限,约59秒
{
sk1=0;
}
}
if(K1!=0) //按键松开
{
if(sk1>=30) //防抖动,也可以避免时间一直刷新
{
sk1t=sk1; //因为是全局变量,可以在调用数值结束后手动进行清零操作
}
sk1=0;
}
//上一次K2按键按下时长:sk2t
if(K2==0) //按键按下
{
sk2++; //TIM4每1ms进中断一次,此时sk2+1
if(sk2==59999) //防止达到计数上限,约59秒
{
sk2=0;
}
}
if(K2!=0) //按键松开
{
if(sk2>=30) //防抖动,也可以避免时间一直刷新
{
sk2t=sk2;
}
sk2=0;
}
TIM4_ClearITPendingBit(TIM4_IT_UPDATE); //清除标志位
}
//控制LED亮灭:上一次按键达到一定时间后亮,否则灭。各按键独立工作,互不影响
void LED12(void)
{
// 按键K1控制灯L1
if(sk1t>=500) //按键K1持续按下约500ms
{
L1(ON);
}
else
{
L1(OFF);
}
// 按键K2控制灯L2
if(sk2t>=5000) //按键K1持续按下约5000ms
{
L2(ON);
}
else
{
L2(OFF);
}
}
//主函数
void main(void)
{
/*下列语句除 while(1){}; 外,其余语句都只执行一次,TIM4的定时器配置是只在函数Init_Timer4()里设置一次*/
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //系统时钟初始化为内部时钟16M
Init_Timer4(); //初始化TIM4定时器配置
GPIO_Config(); //初始化IO口
enableInterrupts(); //使能中断
while(1)
{
LED12();
};
}
//解决报错
#ifdef USE_FULL_ASSERT
void assert_failed(u8* file, u32 line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/***用我理解的方式,有些地方写得不是很好,水平比较低,所以在网上看大佬写的总是感觉云里雾里,复制下来编译一哈发现总是会少些东西,
然后又不知道怎么补,木得办法咯,只能自己慢慢想,啊哈哈。最后祝各位61节日快乐,谁还不是个幼儿园没毕业/刚毕业的孩子呢!***/
|