- 硬件和软件相关的中断源
- 软件错误相关的硬件中断
- 实时时钟
- 为调试程序而设置的中断源
(3) 中断系统的功能
为了实现各种中断请求,中断系统应具有以下功能:
- 实现中断及返回
- 能够实现优先级排队
- 高级中断源能够中断低级的中断处理
4.2 定时器/计数器
- 所有的嵌入式处理器都集成了定时器/计数器模块。
- 系统中至少有一个定时器,用作系统时钟。
- 定时器和计数器都是由带有保存当前值的寄存器和向当前寄存器值加1(或减1)的一个增量输入的加法器逻辑电路组成。或者说是一种能够累计输入脉冲的个数的数字电路。它由触发器构成,具有记忆功能,除了能够完成计数外,还能够用作分频和定时。
下降沿动作的异步二进制加法计数器:
三位加法计数器时序图:
定时器、计数器的区别:
- 定时器的计数装置是连到已知的周期性时钟信号上的,用来测量时间间隔;
- 计数器的计数装置是连到非周期性信号上的,用来计外部事件的发生次数。
因为同样的逻辑电路可以有这两种使用方式,所以该设备经常被称为“定时器/计数器”。
嵌入式处理器上的定时器/计数器具有的作用: - 嵌入式操作系统的任务调度,特别是具有时间片轮转调度功能的操作系统必须使用定时器产生时间片。
- 嵌入式操作系统的软件时钟需要基于硬件定时器产生定时信号。
- 通信电路的波特率发生器。
- 实时时钟电路。
- 集成的片上A/D转换和D/A转换电路。
……
定时器的扩展——脉宽调制(PWM)器:
通过在定时器电路中增加比较器等额外电路,容易构成脉宽调制(PWM)器,用于输出一个频率和占空比可调的矩形波。典型地用于电机调速、LED亮度调节、简易数/模转换等等。
定时器/计数器的扩展——捕获(Capture):
通过在定时器/计数器电路中增加锁存器等额外电路,容易实现捕获功能。此时向定时器提供已知频率的时钟,用户通过设置捕获的(硬件)触发条件,可在触发条件发生时刻将当前计数值锁存到捕获寄存器中。
捕获机制典型地用于硬件事件发生时刻的精确定时。可以避免“事件发生时刻→软件获取到计数值”这段时间的计时不准确性。
5 硬件设计
整体硬件仿真图:
基本思路:
- 定义一个计数器变量,用于记录秒表当前的计时时间,初始值为0。
- 定义一个标志变量,用于记录秒表的状态,包括“运行中”、“暂停中”和“停止”三种状态。
- 定义一个定时器,设置定时器的周期为0.1秒,用于产生中断。在中断服务程序中,更新计数器变量的值,并将计数器的值转换为时分秒的格式,然后将时间显示在LCD上。注意,在中断服务程序中不要直接调用LCD操作函数,而是将需要更新的数据传递给主程序,由主程序在主循环中更新LCD上的显示内容。
- 定义两个外部中断,分别用于处理按键SW2和SW3的按下事件。在外部中断服务程序中,根据按键的状态进行相应的操作。
- 在系统复位时,将计数器变量的值清零,并将标志变量设置为“停止”状态。然后在主循环中更新LCD上的显示内容,将计数器变量的值转换为时分秒的格式,并将时间显示在LCD上。
- 处理按键SW2的按下事件。如果当前秒表状态为“停止”或者“暂停中”,则将计数器变量的值清零,并将标志变量设置为“运行中”状态。如果当前秒表状态为“运行中”,则将标志变量设置为“暂停中”状态。
- 处理按键SW3的按下事件。如果当前秒表状态为“运行中”,则将标志变量设置为“暂停中”状态,并在主循环中将LCD上的显示内容以1Hz的频率闪烁。如果当前秒表状态为“暂停中”,则将标志变量设置为“运行中”状态,并在主循环中将LCD上的显示内容恢复正常。
8.为了消除按键动作时抖动的影响,可以在外部中断服务程序中使用软件延时或者硬件去抖动电路来处理按键的按下事件。例如,在按键按下时,先进行一个短暂的延时,然后再检测按键的状态,如果按键仍然处于按下状态,则认为按键的按下事件有效。
组件设置:
6 软件设计
6.1 总体设计
- 主程序
main
:包含了系统的主要逻辑,根据秒表的状态进行不同的操作,并控制LCD的显示。 - LCD显示函数
lcd_printtime
:用于将秒表计时的数值转换为时分秒的格式,并在LCD上进行显示。 - 定时器中断服务程序
isr_tmr_Interrupt
:处理定时器中断,并根据按键状态更新全局中断标志flag_int
。
接下来,描述一下程序中各模块(函数)的功能、入口参数、返回值、调用与被调用情况: main
函数:主要逻辑控制,不接受参数,不返回数值。调用了lcd_printtime
函数进行LCD显示,同时根据秒表状态和全局中断标志进行逻辑判断。lcd_printtime
函数:将秒表计时的数值转换为时分秒的格式,并在LCD上进行显示。入口参数为行号、列号和计时数值,不返回数值。isr_tmr_Interrupt
函数:处理定时器中断,更新全局中断标志flag_int
。不接受参数,不返回数值。
6.2 详细设计
#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);
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!
piob7EAO-1715626547594)]
[外链图片转存中…(img-OmMSypc1-1715626547594)]
[外链图片转存中…(img-JHZjT0hx-1715626547595)]
[外链图片转存中…(img-VFPmejPR-1715626547595)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!