香橙派使用外设驱动库wiringOP 配合定时器来驱动舵机
舵机认识和硬件接线
关于舵机也是使用过很多次了,详见:
使用PWM波控制开发SG90-CSDN博客
同时再次回顾香橙派的物理引脚对应:
所以舵机的VCC接 2,GND接 6,PWM接 7(此处写的是物理引脚编号)

Linux定时器
驱动舵机必不可少的就是生成PWM波,上节超声波测距的时间计算学习了Linux自带的时间函数,本节生成PWM就正式学习香橙派的定时器,用定时器来生成PWM波!
由于香橙派跑的系统就是Linux,所以其实就是使用Linux来实现定时器,根据舵机的原理,一般使用50Hz频率(周期为20ms)的PWM波来控制,而角度的大小就取决于高电平的占比,20ms中有0.5ms,1.0ms,1.5ms,2.0ms,2.5ms的高电平就分别对应舵机转0度,45度,90度,135度,180度。所以本质上,只要能实现出一个定时0.5ms(500us)的定时器,并让他定时1次,2次,3次,4次,5次就可以实现所有的角度。
Linux定时器的实现,是通过 itimerval 结构体以及函数 setitimer 产生的信号,系统随之使用signal信号处理函数 来处理产生的定时信号,从而实现定时器。
itimerval结构体
struct itimerval
{
/* Value to put into `it_value' when the timer expires. */struct timeval it_interval;
/* Time to the next timer expiration. */struct timeval it_value;
};struct timeval
{__time_t tv_sec; /* Seconds. */__suseconds_t tv_usec; /* Microseconds. */
};
可见,itimerval结构体中有两个成员,这两个成员都属于timeval结构体,timeval结构体上节课接触过,有两个分别代表秒和微秒的成员。
- it_interval:计时器的初始值,一般基于这个初始值来加或者来减,看控制函数的参数配置
- it_value:程序跑到这之后,多久启动定时器
setitimer函数
setitimer()将value指向的结构体设为计时器的当前值,如果ovalue不是NULL,将返回计时器原有值
#include <sys/time.h>int setitimer (__itimer_which_t __which, const struct itimerval *__restrict __new, struct itimerval *__restrict __old)
- which:控制的方法,有以下三种类型
- ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM
- ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM
- ITIMER_PROF //数值为2,进程和系统执行时都递减计时器的值,发送的信号是SIGPROF
- new:指向 itimerval 结构体的指针
- old: 一般不用,设置为NULL
- 返回值:成功返回0,失败返回-1
signal函数
之前在系统编程部分学过,详见:
信号-CSDN博客
#include <signal.h>typedef void (*sighandler_t)(int); //一个指向“传入参数是int 返回值是void的函数”,名为“sighandler_t”的指针sighandler_t signal(int signum, sighandler_t handler);
- signum:信号编号
- handler:函数指针,指向信号处理函数;也可以使用宏,比如使用“SIG_IGN”,则忽略信号
这种方法需要注意的是,一个进程只能创建一个定时器!
代码验证
timer_test.c:
/*该代码实现的功能是: 1s后开启定时器,然后每隔1s向终端打印hello。*/#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>static int i;void signal_handler(int signum)
{i++;if(i == 2000){ //计时2000*500 = 1000000us = 1sprintf("hello\n");i = 0;}
}int main()
{struct itimerval itv;//设定定时时间为500usitv.it_interval.tv_sec = 0;itv.it_interval.tv_usec = 500;//设定开始生效,启动定时器的时间为1秒后itv.it_value.tv_sec = 1;itv.it_value.tv_usec = 0;//设定定时方式if( -1 == setitimer(ITIMER_REAL, &itv, NULL)){perror("timer");exit(-1);}//信号处理signal(SIGALRM,signal_handler);while(1); //防止程序退出return 0;
}

代码编写
SG90_test.c:
#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
#include <wiringPi.h>#define PWM 2int angle;
static int i;void signal_handler(int signum)
{if(i <= angle){digitalWrite(PWM, HIGH);}else{digitalWrite(PWM, LOW);}if(i == 40){ //40*500 = 20000us = 20msi = 0;}i++;}int main()
{struct itimerval itv;wiringPiSetup () ;pinMode (PWM, OUTPUT);//设定定时时间itv.it_interval.tv_sec = 0;itv.it_interval.tv_usec = 500;//设定开始生效,启动定时器的时间itv.it_value.tv_sec = 1;itv.it_value.tv_usec = 0;//设定定时方式if( -1 == setitimer(ITIMER_REAL, &itv, NULL)){perror("error");exit(-1);}//信号处理signal(SIGALRM,signal_handler);while(1){printf("enter the angle: 1 -> 0; 2 -> 45; 3 -> 90; 4 -> 135; 5 -> 180\n");scanf("%d",&angle);i = 0;}return 0;
实现效果:
在Linux界面输入角度值,舵机就会相应的转动多少度:
(缠黑纱绑带的一段视为方向指示端)

相关文章:
香橙派使用外设驱动库wiringOP 配合定时器来驱动舵机
舵机认识和硬件接线 关于舵机也是使用过很多次了,详见: 使用PWM波控制开发SG90-CSDN博客 同时再次回顾香橙派的物理引脚对应: 所以舵机的VCC接 2,GND接 6,PWM接 7(此处写的是物理引脚编号) Li…...
C++学习笔记--函数重载(2)
文章目录 1.3、Function Templates Handling1.3.1、Template Argument Deduction1.3.2、Template Argument Substitution 1.4、Overload Resolution1.4.1、Candidate functions1.4.2、Viable functions1.4.3、Tiebreakers 1.5、走一遍完整的流程1.6、Name Mangling1.7、总结 1.…...
代码随想录算法训练营Day56 || ● 583. 两个字符串的删除操作 ● 72. 编辑距离
今天接触到了真正的距离,但可以通过增删改操作来逼近。 问题1:583. 两个字符串的删除操作 - 力扣(LeetCode) 给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字…...
chrome_elf.dll丢失怎么办?修复chrome_elf.dll文件的方法
Chrome是目前最受欢迎的网络浏览器之一,然而有时用户可能会遇到Chrome_elf.dll丢失的问题。该DLL文件是Chrome浏览器的一个重要组成部分,负责启动和管理程序的各种功能。当Chrome_elf.dll丢失时,用户可能无法正常启动Chrome或执行某些功能。本…...
代码随想录32|738.单调递增的数字,968.监控二叉树,56. 合并区间
738.单调递增的数字 链接地址 class Solution { public:int monotoneIncreasingDigits(int n) {string str to_string(n);int flag str.size();for (int i str.size() - 1; i > 0; i--) {if (str[i] < str[i - 1]) {str[i - 1] - 1;flag i;}}for (int j flag; j <…...
BIO NIO AIO演变
Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能、高可靠的网络服务器和客户端程序。Netty简化了网络程序的开发,是很多框架和公司都在使用的技术。 Netty并非横空出世,它是在BIO,NIO,AIO演变中的产物…...
JVM GC垃圾回收
一、GC垃圾回收算法 标记-清除算法 算法分为“标记”和“清除”阶段:标记存活的对象, 统一回收所有未被标记的对象(一般选择这种);也可以反过来,标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象 。它…...
【数据结构】队列知识点总结--定义;基本操作;队列的顺序实现;链式存储;双端队列;循环队列
欢迎各位看官^_^ 目录 1.队列的定义 2.队列的基本操作 2.1初始化队列 2.2判断队列是否为空 2.3判断队列是否已满 2.4入队 2.5出队 2.6完整代码 3.队列的顺序实现 4.队列的链式存储 5.双端队列 6.循环队列 1.队列的定义 队列(Queue)是一种先…...
嵌入式学习之链表
对于链表,要重点掌握链表和数组区别和实现,链表静态添加和动态遍历,链表中pointpoint-next,链表节点个数的查找,以及链表从指定节点后方插入新节点的知识。...
静态代理和动态代理笔记
总体分为: 1.静态代理: 代理类和被代理类需要实现同一个接口.在代理类中初始化被代理类对象.在代理类的方法中调 用被代理类的方法.可以选择性的在该方法执行前后增加功能或者控制访问 2.动态代理: 在程序执行过程中,实用JDK的反射机制,创建代理对象,并动态的指定要…...
[SM6225][Android13]user版本默认允许root和remount
开发平台基本信息 芯片: 高通SM6225版本: Android 13kernel: msm-5.15 问题描述 刚刚从Framework踏入性能的小殿堂,User版本默认是不会开启root权限的,而且一般调试需要设置一下CPU GPU DDR performance模式或者修改一些schedule util等调核调频节点去…...
pyinstaller打包exe,使用wexpect的问题
参考github首先打包wexpect 1.进入wexpect目录执行 pyinstaller __main__.py -n wexpect 会生成dist文件夹 2.python代码A.py中使用wexpect,注意wexpect.spawn前后必须按照下面添加代码 import sys,os,wexpect #spawn前 real_executable sys.executable try:if sy…...
OpenCV(三十三):计算轮廓面积与轮廓长度
1.介绍轮廓面积与轮廓长度 轮廓面积(Contour Area)是指轮廓所包围的区域的总面积。通常情况下,轮廓面积的单位是像素的平方。 轮廓长度(Contour Length)又称周长(Perimeter),表示轮廓…...
9.11作业
实现一个对数组求和的函数,数组通过实参传递给函数 sum0 arr(11 22 33 44 55) Sum() {for i in ${arr[*]}do$((sumi))donereturn $sum } Sum ${arr[*]} var$? echo $var写一个函数,输出当前用户的uid和gid,并使用变量接收结果 Sum() {aid -…...
AI伦理与未来社会:探讨人工智能的道德挑战与机会
引言 引出AI伦理和社会影响的主题,强调AI的快速发展和广泛应用。 概述博客的主要内容:探讨AI的伦理挑战以及它对社会的影响。 第一部分:AI的伦理挑战 算法偏见: 解释什么是算法偏见,以及它为何在AI中成为一个重要问题。…...
Android窗口层级(Window Type)分析
前言 Android的窗口Window分为三种类型: 应用Window,比如Activity、Dialog;子Window,比如PopupWindow;系统Window,比如Toast、系统状态栏、导航栏等等。 应用Window的Z-Ordered最低,就是在系…...
微信小程序基础加强总结
本篇文章给大家带来了关于微信小程序的相关问题,其中主要介绍了一些基础内容,包括了自定义组件、样式隔离、数据、方法和属性等等内容,下面一起来看一下,希望对大家有帮助。 1、自定义组件 1.1、创建组件 在项目的根目录中&…...
【JAVA - List】差集removeAll() 四种方法实现与优化
一、场景: 二、结论: 1. 四种方法耗时 三、代码: 一、场景: 求差集 List1 - Lsit2 二、结论: 1. 四种方法耗时 初始条件方法名方法思路耗时 List1.size319418 List2.size284900 List..removeAll(Lsit2)1036987ms…...
sql注入基本概念
死在山野的风里,活在自由的梦里 sql注入基本概念 MYSQL基本语法union合并查询2个特性:order by 排序三个重要的信息 Sql Server MYSQL 基本语法 登录 mysql -h ip -u user -p pass基本操作 show databases; 查看数据库crea…...
AIGC系列:1.chatgpt可以用来做哪些事情?
上图的意思:神器轩辕剑 那么,在现在AI盛行的信息时代, 你是否知道如何获得和利用ChatGPT这一把轩辕剑来提升你的攻击力和生存能力呢? 故事 程序员小张: 刚毕业,参加工作1年左右,日常工作是C…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...


