上一课:
【小黑嵌入式系统第十二课】μC/OS-III程序设计基础(二)——系统函数使用场合、时间管理、临界区管理、使用规则、互斥信号量
问题的提出:
有一类事件,它们一定会发生,但又无法预测什么时候发生,比如说火灾等故障事件、键盘有按键按下、通信接有数据发来等突发事件。此时可以采取以下两种方式进行处理:
应注意,这个运作流程是由中断系统硬件来实现的,用户程序仅仅是配置中断及编写中断服务程序。中断服务程序并不能由用户调用。中断请求一般允许用户程序发起。
中断包括三个过程:
中断的基本概念:
使用中断的优点:
引起中断的原因,或者能够发出中断申请的来源,称为中断源。
分类:
为了实现各种中断请求,中断系统应具有以下功能:
下降沿动作的异步二进制加法计数器:
三位加法计数器时序图:
定时器、计数器的区别:
定时器的扩展——脉宽调制(PWM)器:
通过在定时器电路中增加比较器等额外电路,容易构成脉宽调制(PWM)器,用于输出一个频率和占空比可调的矩形波。典型地用于电机调速、LED亮度调节、简易数/模转换等等。
定时器/计数器的扩展——捕获(Capture):
通过在定时器/计数器电路中增加锁存器等额外电路,容易实现捕获功能。此时向定时器提供已知频率的时钟,用户通过设置捕获的(硬件)触发条件,可在触发条件发生时刻将当前计数值锁存到捕获寄存器中。
捕获机制典型地用于硬件事件发生时刻的精确定时。可以避免“事件发生时刻→软件获取到计数值”这段时间的计时不准确性。
main
:包含了系统的主要逻辑,根据秒表的状态进行不同的操作,并控制LCD的显示。lcd_printtime
:用于将秒表计时的数值转换为时分秒的格式,并在LCD上进行显示。isr_tmr_Interrupt
:处理定时器中断,并根据按键状态更新全局中断标志 flag_int
。main
函数:主要逻辑控制,不接受参数,不返回数值。调用了 lcd_printtime
函数进行LCD显示,同时根据秒表状态和全局中断标志进行逻辑判断。lcd_printtime
函数:将秒表计时的数值转换为时分秒的格式,并在LCD上进行显示。入口参数为行号、列号和计时数值,不返回数值。isr_tmr_Interrupt
函数:处理定时器中断,更新全局中断标志 flag_int
。不接受参数,不返回数值。
#include <project.h>
#include <stdio.h>
#define COUNTING 0 //正常计时
#define STOP 1 //停止计时
#define LCDSAN 2 //LCD闪烁
#define INT_NONE 0
#define INT_TIMER_MASK 0x01 //计时标记二进制0001
#define INT_SW2ON_MASK 0x02 //SW2开启标记二进制0010
#define INT_SW3ON_MASK 0x04 //SW3开启标记二进制0100
#define INTERVAL_BLINK 10 // LCD闪烁的100微秒的半周期
#define SW_ON 0
#define SW_OFF 1
unsigned char flag_int = INT_NONE;//全局中断
void lcd_printtime(unsigned char row, unsigned char col, unsigned int value);
extern unsigned char flag_int;//输入标记
/* `#END` */
CY_ISR(isr_tmr_Interrupt)
{
#ifdef isr_tmr_INTERRUPT_INTERRUPT_CALLBACK
isr_tmr_Interrupt_InterruptCallback();
#endif /* isr_tmr_INTERRUPT_INTERRUPT_CALLBACK */
/* Place your Interrupt code here. */
/* `#START isr_tmr_Interrupt` */
static unsigned char sw2_status_prev = SW_OFF, sw3_status_prev = SW_OFF;
unsigned char sw2_status_cur, sw3_status_cur;
Timer_1_ReadStatusRegister();
flag_int |= INT_TIMER_MASK;
sw2_status_cur = SW_2_Read();
if((sw2_status_prev == SW_OFF) && (sw2_status_cur == SW_ON))
{
flag_int |= INT_SW2ON_MASK;
}
sw2_status_prev = sw2_status_cur;
sw3_status_cur = SW_3_Read();
if((sw3_status_prev == SW_OFF) && (sw3_status_cur == SW_ON))
{
flag_int |= INT_SW3ON_MASK;
}
sw3_status_prev = sw3_status_cur;
}
int main(void)
{
unsigned int value=0;
unsigned char stopwatch_status;//状态
unsigned char flag_blink;//LCD闪烁标志
unsigned char tmr_blink;//LCD闪烁时长标志
LCD_Start();
Timer_1_Start();
isr_1_Start();
CyGlobalIntEnable;
LCD_Position(0,0);
LCD_PrintString("StopWatch:");
lcd_printtime(1, 3, value);
stopwatch_status = STOP;
flag_blink = 0;
tmr_blink = 0;
value=0;
isr_1_StartEx(isr_tmr_Interrupt);
for(;;)
{
/* Place your application code here. */
switch(stopwatch_status)
{
case COUNTING://计时状态
if((flag_int & INT_SW2ON_MASK) != 0)//进入STOP状态计时停止
{
stopwatch_status=STOP;
LED4_Write(0);
}
else if((flag_int & INT_SW3ON_MASK) != 0)//进入STOP状态计时停止,LCD闪烁标志位开启
{
stopwatch_status=STOP;
flag_blink = 1;
}
else if((flag_int & INT_TIMER_MASK) != 0)//计时的状态的功能
{
value++;
LED4_Write(1);
LCD_DisplayOn();
lcd_printtime(1, 3, value);
}
else//在定时器中断周期退出
{
break;
}
flag_int = INT_NONE;//清除全局中断标志
break;
case STOP://暂停计时
if((flag_int & INT_SW2ON_MASK) != 0)//SW2按下,计时初始化
{
value=0;
stopwatch_status=COUNTING;
LED3_Write(1);
}
else if((flag_int & INT_SW3ON_MASK) != 0)//SW3按下,恢复计时
{
stopwatch_status=COUNTING;
}
else if(((flag_int & INT_TIMER_MASK) != 0))//STOP状态的功能
{
if(flag_blink==1)//若有闪烁标志则进入LCD闪烁状态
stopwatch_status=LCDSAN;
else
stopwatch_status=STOP;
}
else
{
break;
}
flag_int = INT_NONE;
break;
case LCDSAN://LCD闪烁状态
if((flag_int & INT_SW2ON_MASK) != 0)//SW2按下则初始化计时
{
value=0;
flag_blink = 0;
stopwatch_status=COUNTING;
}
else if((flag_int & INT_SW3ON_MASK) != 0)//SW3退出闪烁,并且恢复计时
{
flag_blink = 0;
stopwatch_status=COUNTING;
}
else if((flag_int & INT_TIMER_MASK) != 0)//闪烁程序
{
if(tmr_blink < INTERVAL_BLINK-1)
{
tmr_blink++;
LCD_DisplayOff();
lcd_printtime(1, 3, value);
}
else /* Another blink interval ends. */
{
tmr_blink = 0;
LCD_DisplayOn();
lcd_printtime(1, 3, value);
}
}
else
{
break;
}
flag_int = INT_NONE;
break;
default:
break;
}
}
}
void lcd_printtime(unsigned char row, unsigned char col, unsigned int value)
{
unsigned char hour, min, sec, millisec;
char disp_str[11];
hour = (value/36000)%24;
min = (value%36000)/600;
sec = (value%600)/10;
millisec = value%10;
sprintf(disp_str, "%02u:%02u:%02u.%1u", hour, min, sec, millisec);
LCD_Position(row,col);
LCD_PrintString(disp_str);
}