012信号_定时器设定_信号集设定_信号捕捉

AD7766采样率翻倍秘籍:STM32定时器PWM生成1MHz时钟的配置陷阱 本文详细介绍了如何通过STM32定时器PWM生成1MHz时钟信号,实现AD7766 ADC采样率翻倍的技巧。文章深入分析了高频时钟配置中的关键陷阱,包括抖动、占空比稳定性和频率精度,并提供了优化PCB布局和软件校准方法,帮助工程师提升工业级数据采系统的性能。 阅读详情

信号;alarm、setitimer定时器;信号集设定 set、sigprocmask;信号捕捉 signal、sigaction

1.信号

概念:信号是信息的载体。

共性:

  1. 简单
  2. 不能携带大量的信息
  3. 满足某个特定条件才发送

1.1 信号的机制

A给B发送信号,B收到信号之前执行自己的代码,收到信号后,不管执行到程序的什么位置,都要暂停运行,去处理信号,处理完毕再继续执行,与硬件中断类似。但信号是软件层面上实现的中断,早期常被称为“软中断”

信号的特质: 由于信号是通过软件方法实现,其实现手段导致信号有很强的延时性。但对于用户来说,这个延迟时间非常短,不易察觉。

每个进程收到的所有信号,都是由内核负责发送的,内核处理

2. 与信号相关的事件和状态

2.1 信号的产生

  1. 按键产生, 如 ctrl+c ctrl+z ctrl+\
  2. 系统调用产生, 如 kill、raise、abort
  3. 软件条件产生,如 定时器 alarm
  4. 硬件异常产生,如,非法访问内存(段错误)、除0、内存对齐出错(总线错误)
  5. 命令产生,如 kill 命令

2.2 递达 和 未决 的概念:

递达:递送并且到达进程
未决:产生和递达之间的状态。主要由于阻塞(屏蔽)导致该状态

2.3 信号的处理方式:

  1. 执行默认动作(每个信号都有默认的执行动作)
  2. 忽略(丢弃)
  3. 捕捉(调用户处理函数)

2.4 阻塞信号集 和 未决信号集

Linux 内核的进程控制块PCB是一个结构体, task_struct 除了包含进程id,状态,工作目录,用户id,组id、文件描述符表,还包含了信号相关的信息,主要指阻塞信号集和未决信号集。

阻塞信号集(信号屏蔽字): 将某些信号加入集合,对他们设置屏蔽,当屏蔽 x 信号之后,再收到该信号,该信号的处理将推后(解除屏蔽后)

未决信号集:

  1. 信号的产生,未决信号集中描述该信号的位立刻翻转为1.表信号处于未决状态。当信号被处理对应位翻转回为0。这一时刻往往非常的短暂。
  2. 信号产生后由于某些原因(主要是阻塞)不能递达。这类信号的集合称之为未决信号集。再屏蔽解除前,信号一直处于未决状态。

2.5 Linux 常规信号预览

kill -l		// 查看信号列表

1~31 常规信号(每个信号都有对应的默认事件和处理动作)
34~64 实时信号(没有默认事件)

信号四要素(man 7 signal)

  1. 编号
  2. 名称
  3. 事件
  4. 默认处理动作

Linux 常规信号预览:
1 SIGHUP:当用户退出shell时,由该shell启动的所有进程将收到这个信号,默认动作为终止进程
2 SIGINT:当用户按下<Ctrl+C>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程
3 SIGQUIT:当用户按下<Ctrl+>组合键时产生该信号,用户终端向正在运行中的由终端启动的程序发出信号,默认动作为终止进程
4 SIGILL:CPU检测到某进程执行了非法指令。默认动作为终止进程并产生core文件
5 SIGTRAP:该信号由断点指令或其他trap指令产生。默认动作为终止进程并产生core文件
6 SIGABRT:调用abort函数时产生该信号。默认动作为终止进程并产生core文件
7 SIGBUS:非法访问内存地址,包括内存对齐错误,默认动作为终止进程并产生core文件
8 SIGFPE:在发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。默认动作为终止进程并产生core文件
9 SIGKILL:无条件终止进程。本信号不能被忽略,处理和阻塞。默认动作为终止进程。它向系统管理员提供了可以杀死任何进程的方法
10 SIGUSE1:用户定义 的信号。即程序员可以在程序中定义并使用该信号。默认动作为终止进程
11 SIGSEGV:指示进程进行了无效内存访问。默认动作为终止进程并产生core文件
12 SIGUSE2:用户定义 的信号。即程序员可以在程序中定义并使用该信号。默认动作为终止进程
13 SIGPIPE:Broken pipe向一个没有读端的管道写数据。默认动作为终止进程
14 SIGALRM:定时器超时,超时的时间 由系统调用alarm设置。默认动作为终止进程
15 SIGTERM:程序结束信号,与SIGKILL不同的是,该信号可以被阻塞和终止。通常用来表示程序正常退出。执行shell命令kill时,缺省产生这个信号。默认动作为终止进程
16 SIGSTKFLT:Linux早期版本出现的信号,现仍保留向后兼容。默认动作为终止进程
17 SIGCHLD:子进程状态发生变化时,父进程会受到这个信号。默认动作是忽略这个信号
18 SIGCONT:如果进程已停止,则使其继续运行。默认动作为继续/忽略
19 SIGSTOP:停止进程的执行。信号不能被忽略,处理和阻塞。默认动作为暂停进程
20 SIGSTP:停止终端交互进程的运行。按下<Ctrl+z>组合键时发出这个信号。默认动作为暂停进程
21 SIGTTIN:后台进程读终端控制台。默认动作为暂停进程。
22 SIGTTOU:该信号类似于SIGTTIN,在后台进程要向终端输出数据时发生。默认动作为暂停进程
23 SIGURG:套接字上有紧急数据时,向当前正在运行的进程发出信号,报告有紧急数据到达。如网络带外数据到达,默认动作忽略该信号。
24 SIGXCPU:进程执行时间超过了分配给该进程的CPU时间 ,系统产生该信号并发送给该进程。默认动作为终止进程。
25 SIGXFSZ:超过文件的最大长度设置。默认动作为终止进程
26 SIGVTALRM:虚拟时钟超时时产生该信号。类似于SIGALRM,但是该信号只计算该进程占用CPU的使用时间。默认动作为终止进程
27 SIGPROF:类似于SIGVTALRM,它不仅包括该进程占用CPU时间还包括执行系统调用时间。默认动作为终止进程
28 SIGWINCH:窗口大小发生变化时发出。默认动作为忽略该信号
29 SIGIO:此信号向进程指示发生了一个异步IO事件。默认动作为忽略
30 SIGPWR:关机。默认动作是终止进程
31 SIGSYS:无效的系统调用。默认动作为终止进程并产生core文件
34 SIGRTMIN ~ 64 SIGRTMAX:LINUX的实时信号,它们没有固定的含义(可以由用户自定义)。所有的实时信号的默认动作都为终止进程

默认动作:
1.终止进程
2.忽略信号
3.终止进程,生成core文件
4.停止(暂停)进程
5.继续运行进程

终端按键产生的信号:
<Ctrl+c> 2 SIGINT(终止/中断)
<Ctrl+z> 20 SIGSTP(暂停/停止)
<Ctrl+> 3 SIGQUIT(退出)

硬件异常产生信号:
除0操作 8 SIGFPE(浮点数例外)
非法访问内存 11 SIGSEGV(段错误)
总线错误 7 SIGBUS

2.6 kill 函数/命令产生信号

bash 命令:

kill -信号 pid

kill 函数:

man 2 kill   // send signal to a process
#include<sys/types.h>
#include<signal.h>

int kill(pid_t pid, int sig);

返回值:
成功:0
失败:-1,设置errno

sig 不推荐直接使用数字,应使用宏名(因为不同操作系统信号编号可能不同)!!!

pid>0:发送信号给指定的进程
pid=0:发送信号给与调用kill函数进程属于同一进程组的所有进程
pid<-1:取|pid|发送给对应的进程组(负号代表的是进程组id)
pid=-1:发送给进程有权限发送的系统中所有进程

进程组: 每个进程都属于一个进程组,进程组是一个或多个进程集合,他们相互关联,共同完成一个实体任务,每个进程组都有一个进程组长,默认进程组ID与进程组长ID相同。

权限保护: super用户(root)可以发送信号给任意用户,普通用户是不能向系统用户发送信号的。只能向自己创建的进程发送信号

2.6.1 demo 子进程给父进程发送-9信号
  1. fork创建父子进程
  2. 父子进程各自打印pid
  3. 子进程给父进程发送-9信号杀死进程
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<signal.h>


void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

int main(int argc, char * argv [])
{
	pid_t pid;

	pid = fork();
	if (pid >0 )
	{
		printf("parent process, pid = %d\n", getpid());
		while(1);
	}
	else if(pid == 0)
	{
		printf("child pid = %d, ppid = %d\n",getpid(), getppid());
		sleep(2);
		kill(getppid(),SIGKILL);
	}
	return 0;
}

2.6.2 其他几个发信号的函数

#include<signal.h>

int raise(int sig);		// 给自己发信号
#include<stdlib.h>

void abort(void);

3. 软件条件产生信号(alarm 和 setitimer 定时器)

3.1 alarm 函数(使用自然计时法)

  • 设置定时器(闹钟)。在指定 seconds 后,内核会给当前进程发送 14 SIGALRM 信号。进程收到该信号,默认动作终止。
  • 每个进程都有且只有唯一个定时器

函数声明及头文件包含

man alarm
#include<unistd.h>

unsigned int alarm(unsigned int seconds);

返回值:
0或剩余的秒数,无失败

定时
与进程状态无关(自然定时法)!就绪、运行、挂起(阻塞、停止)、终止、僵尸…无论进程处于何种状态,alarm都计时

常用:
alarm(0):取消定时器,返回旧闹钟余下的秒数

3.1.1 demo 测试计算机1秒内能数多少个数
#include<unistd.h>
#include<stdio.h>

int main(void)
{
	int i;
	alarm(1);


	for (i = 0; ; i++)
	{
		printf("%d\n",i);
	}
}

使用 time 命令查看程序执行的时间

time ./alarm.out


实际执行时间 = 系统时间 + 用户时间 + 等待时间(大部分时间在等待设备)

3.2 setitimer 函数

设定定时器(闹钟)。可代替 alarm 函数。精度微妙us,可以实现周期定时

man setitimer

#include<sys/time.h>

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

返回值:
成功: 0
失败:-1,设置errno

参数:

which:指定定时方式
1. 自然定时:ITIMER_REAL14 SIGLARM 计算自然时间
2. 虚拟空间计时(用户空间):ITIMER_VIRTUAL26 SIGVTALRM 只计算进程占用CPU时间
3. 运行时计时(用户 + 内核):ITIMER_PROF27 SIGPROF 计算占用CPU及执行系统调用的时间

new_value:传入参数,设定初始化计时器时间
old_value:传出参数,上次定时剩余时间
new_valueold_value 都是 itimerval 结构体(嵌套结构体)

struct itimerval {
               struct timeval it_interval; /* Interval for periodic timer */
               struct timeval it_value;    /* Time until next expiration */
           };

struct timeval {
               time_t      tv_sec;         /* seconds */
               suseconds_t tv_usec;        /* microseconds */
           };
/* 结构体初始化 */
struct itimerval new_t;
new_t.it_interval.tv_sec = 1;
new_t.it_interval.tv_usec = 0;
new_t.it_value.tv_sec = 0;
new_t.it_value.tv_usec = 0;

it_interval:用来设定两次定时任务之间间隔的时间(用来实现周期定时)
it_value:定时时长(第一次定时的时间)
/* 两个参数都设置为0,即清0操作 */

3.2.1 demo 首次计时2s,周期定时5s,打印 hello world
/* setitimer_cycle.c */
#include<stdio.h>
#include<sys/time.h>
#include<signal.h>

void myfunc(int signo)
{
	printf("hello world\n");
}

int main(void)
{
	struct itimerval newit, oldit;

	signal(SIGALRM, myfunc);  // 捕捉SIGALRM信号的捕捉处理函数

	newit.it_value.tv_sec = 2;		// 第一次定时2s
	newit.it_value.tv_usec = 0;
	newit.it_interval.tv_sec =5;		// 除去第一次定时,周期定时5s
	newit.it_interval.tv_usec = 0;

	if(setitimer(ITIMER_REAL, &newit, &oldit) == -1)
	{
		perror("setimer error\n");
		return -1;
	}
	while(1);

	return 0;
}

4. 信号集设定 set 、sigprocmask

通过 set 函数去设置 PCB 中的阻塞信号集

4.1 set 、sigprocmask 、sigpending 函数

4.1.1 set 函数声明及头文件包含

set 创建相应的位图,并对相应信号位进行操作

man emptyset

#include<signal.h>

sigset_t set;    							//自定义信号集
int sigemptyset(sigset_t *set);				// 清空信号集,成功0,失败-1
int sigfillset(sigset_t *set);				// 全部置1,成功0,失败-1
int sigaddset(sigset_t *set, int signum);		// 将一个 信号添加到集合中,成功0,失败-1
int sigdelset(sigset_t *set, int signum);		// 将一个信号从集合中移除,成功0,失败-1
int sigismember(const sigset_t *set, int signum);	// 判断一个信号是否在集合中 在1 不在0
4.1.2 sigprocmask 函数声明及头文件包含

用来屏蔽信号、解除信号。其本质:读取或修改进程的信号屏蔽字(PCB中)
sigprocmask 函数将设置的 set 位,与进程阻塞信号集进行操作

#include<signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

how 参数
SIG_BLOCK: set表示需要屏蔽的信号,相当于 mask = mask|set
SIG_UNBLOCK: set表示需要解除屏蔽的信号,相当于 mask = mask &~ set
SIG_SETMASK: set表示用于替代原始屏蔽及新屏蔽集。相当于 mask=set
若嗲用 SIG_SETMASK解除了对当前若干个信号的阻塞,则在SIG_SETMASK返回前,至少将其中一个信号送达

4.1.3 sigpending 函数声明及头文件包含

读取当前进程的未决信号集

int sigpending(sigset_t *set);		//set传出参数 ,当前进程的未决信号集

返回值
成功:0
失败:-1,设置errno

4.2 demo 信号屏蔽,查看当前信号未决集

将 SIGINT 信号进行屏蔽,然后 <Ctrl+C>发送中断信号,因为屏蔽,所以信号未决集置1

/* sigsfunc.c */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<signal.h>

void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

void print_set(sigset_t* set)
{
	int i,ret;
	
	for(i=1; i<32; i++)
	{
		ret = sigismember(set, i);
		if(ret == 1)
			putchar('1');
		else if(ret == 0)
			putchar('0');
	}
	printf("\n");
}

int main(int argc, char * argv [ ])
{
	sigset_t set, oldset, pendset;
	int ret;

	sigemptyset(&set);
	sigaddset(&set, SIGINT);

	ret = sigprocmask(SIG_BLOCK, &set, &oldset);
	if (ret == -1)
		sys_error("sigprocmask error\n");

	while(1)
	{
		ret = sigpending(&pendset);
		if (ret == -1)
			sys_error("sigpending error\n");

		print_set(&pendset);
		sleep(1);
	}
	return 0;
	
}

注:9号和19号屏蔽字可以设置为1,但是不管用!!!!

5.信号捕捉 (signal、sigaction)

5.1 signal 函数声明及头文件包含

注册一个信号捕捉函数

man 2 signal

#include<signal.h>

typedef void(*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

5.2 demo 注册 SIGINT 的信号捕捉函数

/* signal.c */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<signal.h>

void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

void sig_catch(int signo)
{
	printf("catch you!! %d\n", signo);
	return;
}

int main(int argc, char * argv [ ])
{
	signal(SIGINT, sig_catch);

	while(1);

	return 0;
}

5.3 sigaction 函数

修改信号处理动作(通常在Linux用来注册一个信号的捕捉函数)

man 2 sigaction

#include<signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

struct sigaction{
	void		(*sa_handler)(int);		// 回调函数
	void 	(*sa_sigaction)(int, siginfo_t*, void *);
	sigset_t	sa_mask;					// sa_mask屏蔽字,只在sig_catch工作时有效
	int		sa_flags;					// 默认处理动作
	void		(*sa_restorer)(void);
};

返回值:
成功0
失败 -1,设置 errno

参数
act:传入参数,新的处理方式
oldact:传出参数,旧的处理方式

结构体参数介绍
sa_handler:指定信号捕捉后的处理函数名(即注册函数)。也可赋值为 SIG_IGN 表忽略,或 SIG_DFL 表执行默认动作
sa_mask:调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意:仅在处理函数被调用期间屏蔽生效,是临时性设置
sa_flag:通常设置为0,表使用默认属性

5.4 demo sigaction 屏蔽捕捉信号 SIGINT 和 SIGQUIT

/* sigaction.c */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<signal.h>

void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

void sig_catch(int signo)
{
	if(signo == SIGINT)
		printf("catch you!! %d\n", signo);
	else if(signo == SIGQUIT)
		printf("------catch you!! %d\n",signo);
	return;
}

int main(int argc, char * argv [ ])
{
	struct sigaction act, oldact;
	act.sa_handler = sig_catch;
	sigemptyset(&(act.sa_mask));
	act.sa_flags = 0;
	
	int ret = sigaction(SIGINT, &act, &oldact);
	if(ret == -1)
		sys_error("sigaction error\n");
	ret = sigaction(SIGQUIT, &act, &oldact);
	if(ret == -1)
		sys_error("sigaction error\n");
	while(1);

	return 0;
}

5.5 信号捕捉特性

  1. 进程正常运行时,默认PCB中有一个信号屏蔽字,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由默认信号屏蔽字来指定,而是用sa_mask来指定。调用完信号处理函数后,在恢复默认信号屏蔽字
  2. XXX信号捕捉函数执行期间,XXX信号自动被屏蔽
  3. 阻塞的常规信号不支持排队,产生多次只记录一次(后32个实时信号支持排队)
5.5.1 demo 在捕捉信号SIG_INT期间屏蔽 SIG_QUIT 信号
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<signal.h>

void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

void sig_catch(int signo)
{
	if(signo == SIGINT)
	{
		printf("catch you!! %d\n", signo);
		sleep(10);
	}
	return;
}

int main(int argc, char * argv [ ])
{
	struct sigaction act, oldact;
	act.sa_handler = sig_catch;
	sigemptyset(&(act.sa_mask));
	sigaddset(&(act.sa_mask), SIGQUIT);
	act.sa_flags = 0;
	
	int ret = sigaction(SIGINT, &act, &oldact);
	if(ret == -1)
		sys_error("sigaction error\n");

	while(1);

	return 0;
}

阻塞的常规信号不支持排队,产生多次只记录一次(后32个实时信号支持排队)!!!

5.6 内核实现信号捕捉的过程

6. SIGCHLD 信号

6.1 SIGCHLD 信号产生的条件

  1. 子进程终止时
  2. 子进程接受到SIGSTOP信号停止时
  3. 子进程处在停止态,接收到SIGCONT后唤醒时

6.2 demo 借助SIGCHLD信号回收子进程

解决execl跳转时,不好对子进程回收问题

error demo:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<signal.h>
#include<sys/wait.h>

void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

void catch_child(int signo)
{
	pid_t wpid;
	wpid = wait(NULL);
	if(wpid == -1)
		sys_error("wait error\n");
	printf("catch child is %d\n", wpid);

	return ;
}

int main(int argc, char * argv [ ])
{
	pid_t pid;

	int i;
	for(i = 0; i < 5; i++)
	{
		if((pid = fork()) == 0)
			break;
	}

	if(i ==5)
	{
		struct sigaction act;
		act.sa_handler = catch_child;
		sigemptyset(&(act.sa_mask));
		sigaddset(&(act.sa_mask), SIGCHLD);
		act.sa_flags = 0;

		sigaction(SIGCHLD,&act, NULL);

		printf("I'm parent, pid is %d\n",getpid());

		while(2); 		// 为了让父进程不提前结束
	}
	else
		printf("I'm child pid is %d\n",getpid());

	return 0;
}


信号不排队!!!!!解决办法1:第一次收到消息时就循环回收

success demo:

/* catch_child.c */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<signal.h>
#include<sys/wait.h>

void sys_error(const char * str)
{
	perror(str);
	exit(1);
}

void catch_child(int signo)     //子进程终止,发送SIG_CHLD信号时,该函数会被内核回调
{
	int status;

	while (waitpid(-1, &status, 0) != -1)
	{
		if(WIFEXITED(status))
			printf("-------------catch child is %d, ret = %d\n",getpid(), WEXITSTATUS(status));
	}

	return ;
}

int main(int argc, char * argv [ ])
{
	pid_t pid;
	/* 阻塞 */
	sigset_t set;
	sigemptyset(&set);
	sigaddset(&set,SIGCHLD);

	sigprocmask(SIG_BLOCK, &set, NULL);
	

	int i;
	for(i = 0; i < 5; i++)
	{
		if((pid = fork()) == 0)
			break;
	}

	if(i ==5)
	{
		struct sigaction act;
		act.sa_handler = catch_child;
		sigemptyset(&(act.sa_mask));
		sigaddset(&(act.sa_mask), SIGCHLD);
		act.sa_flags = 0;

		sigaction(SIGCHLD,&act, NULL);

		sigprocmask(SIG_UNBLOCK, &set, NULL);

		printf("I'm parent, pid is %d\n",getpid());

		while(2); 		// 为了让父进程不提前结束
	}
	else
	{
		printf("I'm child pid is %d\n",getpid());
		return i;
	}

	return 0;
}

7. 中断系统调用

系统调用可分为两类:慢速系统调用和其他系统调用。

  1. 慢速系统调用:可能会使进程永远阻塞的一类。如果在阻塞期间收到一个信号,该系统调用就会被中断,不在继续执行(早期),也可以设定系统调用是否重启。如 read、write、pause、wait…
  2. 其他系统调用: getpid、getppid、fork…

慢速系统调用被中断的相关行为,实际上就是pause的行为,

  1. 想中断pause,信号不能被屏蔽
  2. 信号的处理方式必须是捕捉(默认、忽略都不可以)
  3. 中断后返回-1,设置errno为EINTR(表”被信号中断“)

可修改 sa_flags 参数来设置被信号中断后系统调用是否重启。 SA_INTERRURT 不重启 ;SA_RESTART 重启

注:sa_flags还有很多可选参数,适用于不同情况。如捕捉到信号后,在执行捕捉函数期间,不希望自动阻塞该信号,可将sa_flags设置为 SA_NODEFER,除非 sa_mask 中包含该信号

嵌入式定时器TPM模块详解:从PWM生成到输入捕获的实战指南 在嵌入式系统开发中,定时器是控制时序、实现精确时间管理的核心硬件外设。其工作原理基于可编程计数器,通过配置时钟源、预分频器和比较匹配机制,能够以硬件方式生成精确的时间基准或波形,从而将CPU从繁重的周期性任务中解放出来,提升系统实时性与效率。这项技术的核心价值在于为电机控制、电源管理、信号测量等场景提供了可靠的底层时间驱动引擎。其中,脉宽调制(PWM)和输入捕获是两种关键技术:PWM通过调节输出波形的占空比来控制功率器件,广泛应用于电机调速与LED调光;输入捕获则能精准抓取外部事件的时间戳,用于测量脉冲宽度 阅读详情

相关推荐

MC68HC908QY/QT定时器模块(TIM)配置与实战:输入捕获、输出比较与PWM详解

定时器模块是嵌入式微控制器实现精准时序控制的核心外设,其工作原理基于可编程时钟源驱动计数器进行递增。通过配置预分频器、模值寄存器和比较/捕获寄存器,开发者可以精确控制时间基准,实现从微秒级延时到复杂波形生成的技术需求。这一原理在工程实践中价值显著,它使得**输入捕获**能够精确测量外部脉冲宽度与频率,**输出比较**可生成精准的定时信号或驱动波形,而**PWM(脉宽调制)** 模式则广泛应用于电机调速、LED调光等需要模拟量控制的场景。深入理解并掌握这些基础功能的配置与调试技巧,是进行稳定可靠的嵌入式系统开

diaohong5075的博客 468

asio中的信号定时器

信号(signal)是UNIX系统里一种常用的进程间,成熟的UNIX程序几乎都以某种方式支持它。asio库提供了类signal_set,利用异步I/o 的方式很好地处理了UNIX信号。通过它我们可以快速熟悉 asio的基本使用方法。

qq_62309585的博客 1061

MICROSAR OS:第一个task是如何执行起来的?

MICROSAR OS是Vector公司开发的符合AUTOSAR OS规范的实时操作系统。本文介绍MICROSAR

humu7733的博客 2536

Linux通过系统函数设置系统时间

一、描述 通过settimeofday()函数来设置系统时间,这个函数设置的精度可以精确到微秒。 #include <time.h> int settimeofday(const struct timeval *tv , const struct timezone *tz); struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */

轮子工厂 3729

一文搞懂定时器

使用精确的时基,通过硬件的方式,实现定时功能,其核心是:计数器。

fg247778718的博客 2775

Linux使用SIGALARM信号定时器

基本的alarm()函数使用方式 alarm函数的定义: #include &amp;amp;amp;amp;lt;unistd.h&amp;amp;amp;amp;gt; unsigned int alarm(unsigned int seconds); 该函数精确到秒级别,如果失败返回-1 下面给出一个一秒的定时器,每隔一秒执行一次,自动设置。 #include &amp;amp;amp;amp;lt;signal.h&amp;amp;amp;amp;gt; #incl

Erick Lv的笔记 3674

网络编程教程(八)信号定时器

一、信号 1.信号 API (1)发送信号 #include &lt;sys/types.h&gt; #include &lt;signal.h&gt; int kill(pid_t pid, int sig); 函数功能: 向进程ID为pid的进程发送信号sig 函数参数: pid:进程编号 sig:信号值 返回值: 函数成功时返回0,失败则返回-1,并设...

kang___xi的博客 1148

CW32L012小机器人的脉冲宽度调制怎么说?

脉冲宽度调制(Pulse Width Modulation, PWM)是嵌入式系统中应用最广泛的模拟信号数字化控制技术之一,其核心原理是通过周期性改变方波信号的高电平占空比(高电平持续时间与周期的比值),实现对输出平均电压或功率的精准调控。作为连接数字控制与模拟执行的关键桥梁,PWM 技术凭借结构简单、响应迅速、功耗低、控制精度高的优势,成为 MCU(微控制器)对外设进行柔性控制的核心手段。CW32L012内部成了4个通用定时器(GTIM),3个基本定时器(BTIM),1个高级定时器(ATIM)

2501_94370165的博客 514

从零理解STM32定时器时钟分频:CKD位在数字滤波与死区时间中的关键作用

本文深入解析STM32定时器中CKD位的关键作用,详细讲解其在数字滤波与死区时间控制中的机制与应用。通过时钟分频因子的配置,有效提升系统抗干扰能力和时间精度,并给出实战配置策略与常见问题排查指南,帮助开发者优化定时器性能。

gold的博客 844

深入解析STM32通用定时器CR1的CKD[1:0]:时钟分频因子的抗干扰与死区时间优化

本文深入解析STM32通用定时器CR1寄存器中的CKD[1:0]位,即时钟分频因子。它并非用于计数器主时钟分频,而是定义了t_DTS时钟,该时钟是数字滤波器和死区时间生成的基准。文章通过实战场景,详细阐述了如何通过调整CKD值来权衡抗干扰能力与信号延迟/死区时间分辨率,为电机控制、电源等噪声环境下的精确时序应用提供关键配置指导。

l1k9j8h7g6的博客 190

深入解析S08TPMV3定时器/PWM模块:从输入捕获到中心对齐PWM实战

定时器是嵌入式系统的核心外设,负责精确的时间基准生成与事件调度。其工作原理基于可编程计数器,通过时钟源驱动并与比较寄存器匹配,实现定时、波形生成与信号测量三大核心功能。这项技术为实时控制、电机驱动和电源管理等应用提供了关键的时间控制能力。S08TPMV3模块作为经典代表,成了输入捕获、输出比较及边沿/中心对齐PWM模式。其中,**中心对齐PWM**模式通过对称计数有效降低开关损耗与EMI,特别适用于**H桥电机驱动**等高要求场景。本文将以该模块为例,详解其架构、时钟同步机制及寄存器配置要点,帮助开发者从

weixin_34007020的博客 311

DonkeyCar硬件选型与信号链可信度构建指南

自动驾驶入门常从仿真或高级平台起步,但真正夯实基础需回归物理世界——DonkeyCar正是面向初学者的轻量级自动驾驶机电实验平台。其核心价值不在于算法炫技,而在于构建‘可测量、可重复、可追溯’的端到端控制闭环:从树莓派GPIO输出确定性PWM,经PCA9685驱动,到伺服与ESC的毫秒级响应,每一步都受机械刚性、电气噪声和热稳定性制约。理解反电动势系数(Ke)、PWM脉宽精度(±5μs)、I²C抗干扰设计等底层参数,才能规避‘小车乱转’‘原地画圈’等典型故障。本文聚焦硬件可信度验证,覆盖1/16 RC车体选

weixin_30430169的博客 352

嵌入式定时器TIMB模块实战:PWM生成与输入捕获原理详解

在嵌入式系统开发中,定时器是核心外设之一,负责精准的时序控制与信号测量。其基本原理是通过可编程计数器,对时钟源进行分频计数,实现时间基准。从技术价值看,定时器能硬件级实现高精度时间管理,解放CPU资源,提升系统实时性。在应用场景上,它广泛用于电机调速、舵机控制、脉冲测量和通信协议生成等。本文聚焦于飞思卡尔MC68HC908EY16微控制器的TIMB模块,深入解析其输入捕获和PWM生成两大核心功能。输入捕获功能通过硬件捕捉外部事件发生的精确时刻,常用于测量脉冲宽度与频率;而PWM生成则通过输出比较机制,结合计

weixin_30588675的博客 288

Linux 信号signal处理机制、定时器

信号Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念、Linux信号机制的大致实现方法、如何使用信号,以及有关信号的几个系统调用。  信号机制是进程之间相互传递消息的一种方法,信号全称为软中断信号,也有人称作软中断。从它的命名可以看出,它的实质和使用很象中断。所以,信号可以说是进程控制的一部分。  一、信号的基本概念  本节先介绍信号的一些基本概念,然后给出一

mysee1989的专栏 2189

定时器信号的用法

#include #include #include #include /*信号处理程序*/ void handler_sigtime(int signo) { switch (signo) { case SIGALRM: printf("recv SIGALRM\n"); break; case SIGPROF: printf("recv SIGPROF\n

str999_cn的专栏 566

SIGALRM信号与实时定时

1、alarm()函数单次定时(秒位单位):             extern unsigned int alarm(unsigned int __seconds)         每个进程只能有一个闹钟时钟,如果在调用alarm时,以前已为该进程设置过闹钟时钟,而且它还没有超时,则将该闹钟的余留值作为本次alarm函数调用的返回值。以前登记的闹钟时钟则被新值代替。         如果有以前...

宁静以致远 4817

Linux C系统编程:信号定时器的使用

#include <stdio.h> #include <signal.h> void do_alarm(int num); int main(void) { //注册一个定时器 if(signal(SIGALRM , do_alarm) == SIG_ERR) { ...

weixin_33991727的博客 291

Linux下的定时器:alarm()与setitimer()

  Linux下的定时器有两种,以下分别介绍:1、alarm如果不要求很精确的话,用alarm()和signal()就够了unsigned int alarm(unsigned int seconds)函数说明: alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并

jiangxinyu的专栏 1292

Linux信号通道——定时器信号:alarm()和pause()

1

Lindsey's Blog 566

深度学习、图像分类入门,从VGG16卷积神经网络开始

刚开始接触深度学习、卷积神经网络的时候非常懵逼,不知道从何入手,我觉得应该有一个进阶的过程,也就是说,理应有一些基本概念作为奠基石,让你有底气去完全理解一个庞大的卷积神经网络: 本文思路: 一、我认为学习卷积神经网络必须知道的几个概念: 1、卷积过程:   我们经常说卷积神经网络卷积神经网络,到底什么才是卷积?网络层卷积过程到底怎么实现?我们在这里借鉴了另一位博客大牛的动态图来给大

Errors_In_Life的博客 16万+

理想架构的非对称高回退Doherty功率放大器理论与仿真

使用ADS理想电流源对B类和非对称高回退Doherty架构的回退效率、输出阻抗、电压电流进行仿真。Doherty功放是一种利用负载调制技术提高回退效率的功放,其应用背景是为了解决通信系统中调制信号峰均比越来越大,而传统放大器在功率回退点效率低的问题。参考链接:https://blog.csdn.net/weixin_44584198/article/details/135755997

上一篇: 011mmap进程通信
下一篇: 013会话和守护进程
小峰没有疯
博客等级 码龄4年 5粉丝 · 17原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值