目录
一、舵机的基本认知和硬件接线
1.1 舵机的基本认知:
1.2 硬件接线:
1.3 怎么控制舵机旋转不同的角度:
二、Linux定时器
2.1 定时器setitimer()函数原型和头文件:
2.2 信号处理函数signal()原型和头文件:
2.3 定时器setitimer()函数应用实例:
2.4 使用wiringOP库配合定时器驱动舵机旋转0-180°:
一、舵机的基本认知和硬件接线
1.1 舵机的基本认知:
如下图所示:是一个SG90舵机,常用三根或者四根接线,红色为电源VCC,棕色为电源GND,黄色为PWM信号。
控制用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等常见的有0-90°、0-180°、0-360°
1.2 硬件接线:
1.3 怎么控制舵机旋转不同的角度:
-
向黄色信号线“灌入”PWM信号。PWM波的频率不能太高,50hz,即周期=1/频率=1/50=0.02s,20ms左右数据:不同的PWM波形对应不同的旋转角度,以20ms为周期,50hz为频率的PWM波
定时器需要定时20ms,关心的单位0.5ms, 20ms = 0.5ms * 40
二、Linux定时器
2.1 定时器setitimer()函数原型和头文件:
/* setitimer 是一个UNIX系统上的系统调用函数,用于设置和管理定时器。它通常用于定期触发信号或执行某些操作 */
#include <sys/time.h>int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);int 函数返回值,成功执行时返回0,失败返回-1int whic 指定要设置的定时器类型,可以是 ITIMER_REAL、ITIMER_VIRTUAL 或 ITIMER_PROF 中的一个
1. ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM。
2. ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM。
3. ITIMER_PROF //数值为2,进程和系统执行时都递减计时器的值,发送的信号是SIGPROF。struct itimerval *new_value 一个struct itimerval结构,用于指定新的定时器值。struct itimerval 结构定义如下:struct itimerval {struct timeval it_interval; // 定时器重复的间隔时间struct timeval it_value; // 定时器的初始值
};it_interval 计时器的初始值,一般基于这个初始值来加或者来减,看控制函数的参数配置
it_value 程序跑到这之后,多久启动定时器struct timeval { __time_t tv_sec; /* 秒 */ __suseconds_t tv_usec; /* 微秒 */
};struct itimerval *old_value 一个struct itimerval 结构,用于存储旧的定时器值(可选参数)/*
函数说明:
实现定时器,通过itimerval结构体以及函数setitimer产生的信号,系统随之使用signal信号处理函数来处理产生的定时信号。从而实现定时器。
*/
2.2 信号处理函数signal()原型和头文件:
/*Linux下 man 2 signal查看手册
*/
#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);sighandler_t 函数返回值,返回信号处理程序的前一个值,或者在错误时SIG ERR。如果发生错误,则设置errno来指示原因。int signum 指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号sighandler_t handler 描述了与信号关联的动作,它可以取以下三种值: 1. 一个无返回值的函数地址
此函数必须在signal()被调用前声明,handler中为这个函数的名字。当接收到一个类型为signum的信号时,就执行handler 所指定的函数。这个函数应有如下形式的定义:
void handler(int signum);2. SIG_IGN
这个符号表示忽略该信号,执行了相应的signal()调用后,进程会忽略类型为sig的信号。3. SIG_DFL
这个符号表示恢复系统对信号的默认处理。
2.3 定时器setitimer()函数应用实例:
实现的功能是:1秒后打开定时器,然后每隔一秒打印一次Hello
#include <stdio.h> // 包含标准输入输出库,用于输入输出操作
#include <sys/time.h> // 包含时间处理库,用于获取系统时间
#include <stdlib.h> // 包含标准库,用于内存分配和程序终止等操作
#include <signal.h> // 包含信号处理库,用于处理系统信号static int i = 0; //全局变量i void signal_handler(int signum) //信号处理函数
{i++;if(i == 2000){ //每2000次触发一次printf("Hello\n");i = 0;}
}int main()
{struct itimerval itv; //定义一个itimerval结构体变量//设定定时时间itv.it_interval.tv_sec = 0;itv.it_interval.tv_usec = 500; //每隔0.5毫秒触发一次 //设定启动定时器时间itv.it_value.tv_sec = 1; //启动定时器1秒后触发 itv.it_value.tv_usec = 0; //设定定时方式//int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);if(setitimer(ITIMER_REAL, &itv, NULL) == -1){ //设置定时器 perror("setitimer");exit(-1);}//信号处理signal( SIGALRM, signal_handler); //设置信号处理函数while(1);return 0;
}
2.4 使用wiringOP库配合定时器驱动舵机旋转0-180°:
#include <stdio.h> // 包含标准输入输出库,用于输入输出操作
#include <sys/time.h> // 包含时间处理库,用于获取系统时间
#include <stdlib.h> // 包含标准库,用于内存分配和程序终止等操作
#include <signal.h> // 包含信号处理库,用于处理系统信号
#include <wiringPi.h> // 包含WiringPi库,用于控制GPIO#define SG90Pin 5 // 定义SG90的引脚号static int i = 0; //全局变量i
int jd; //全局变量jd void signal_handler(int signum) //信号处理函数
{if(i <= jd){digitalWrite(SG90Pin, HIGH); //设置SG90引脚为高电平}else{digitalWrite(SG90Pin, LOW); //设置SG90引脚为低电平}if(i == 40){ //每40次信号处理函数被调用一次,输出一次当前时间i = 0; //i归零}i++;
}int main()
{struct itimerval itv; //定义一个itimerval结构体变量jd = 0; //初始化jd为0 wiringPiSetup(); //初始化WiringPi库pinMode(SG90Pin, OUTPUT); //设置SG90引脚为输出模式//设定定时时间itv.it_interval.tv_sec = 0;itv.it_interval.tv_usec = 500; //每隔0.5毫秒触发一次 //设定启动定时器时间itv.it_value.tv_sec = 1; //启动定时器1秒后触发 itv.it_value.tv_usec = 0; //设定定时方式//int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);if(setitimer(ITIMER_REAL, &itv, NULL) == -1){ //设置定时器 perror("setitimer");exit(-1);}//信号处理signal( SIGALRM, signal_handler); //设置信号处理函数while(1){printf("请输入你想要的角度: 1-0 2-45 3-90 4-135 5-180\n");scanf("%d",&jd); //输入角度 }return 0;
}