目录

LED呼吸灯

直流电机调速

模型结构

波形

定时器初始化函数

中断函数

主程序


上一节讲了电机的工作原理,这一节开始代码演示!

我们上一篇说Ton的时间长Toff时间短电机会快,Ton的时间短Toff时间长电机会慢

并且我们还要保证无论Ton和Toff哪个时间比较长,Ts都得是固定值,因为为了保证周期一定。

下面我们先做一个“呼吸灯”感受一下上一篇博客中提到的PWM的意义:

LED呼吸灯

新创建本节第一个工程:LED呼吸灯

开始代码讲解:

首先根据LED的原理图定义一下引脚,P20(LED)为0时,灯亮。

#include <REGX52.H>

sbit LED=P2^0;//D1号LED的所接的单片机引脚

如果LED亮的时长比LED灭的时长要久,那么灯看上去就比较亮,反之就比较暗。这和前面说的Ton的时间长Toff时间短电机会快,Ton的时间短Toff时间长电机会慢是类似的。并且我们要保证LED亮灭的时间是一定的,即亮灭周期一定。

void Delay(unsigned int t)//传过来一个时间
{
	while(t--);//传过来一个时间,每一次while循环都减1
}

void main()
{
	unsigned char Time,i;
	while(1)
	{
		for(Time=0;Time<100;Time++)		//改变亮灭时间,由暗到亮
		{
			//比如TIME=1时,100-Time=99,然后进去循环20次再出来
			//这时TIME=2,100-Time=98......如此循环
			for(i=0;i<20;i++)			//计次延时
			{
				//TIME+(100-TIME)等于固定值是为了保持周期是一样的
				LED=0;					//LED亮
				Delay(Time);			//延时Time
				LED=1;					//LED灭
				Delay(100-Time);		//延时100-Time
			}
		}
		for(Time=100;Time>0;Time--)		//改变亮灭时间,由亮到暗
		{
			for(i=0;i<20;i++)			//计次延时
			{
				LED=0;					//LED亮
				Delay(Time);			//延时Time
				LED=1;					//LED灭
				Delay(100-Time);		//延时100-Time
			}
		}
	}
}

效果请看视频:

LED呼吸灯

呼吸灯就做成了,但是这种方式的缺点是显而易见的。它需要占用主循环不断地来翻转IO口来延时,在这一段时间内,也就是呼吸灯的整个过程中,主循环是没办法做其他事情的。

我们通常将PWM写到定时器里面,而且现在稍微高级一点的单片机,像STC的12系列或15系列及最新的系列都会有硬件的PWM,或者STM32单片机也会有硬件的PWM。因为不断地翻转IO口是一种比较简单但是比较占用CPU的一种操作,所以通常我们会用硬件来实现。而且硬件实现通常会寄生到定时器里面去,就是定时器既可以定时还可以兼具PWM的任务。但是我们STC89C52是没有这种功能的。所以我们就用定时器中断来实现这个功能。

直流电机调速

接下来我们开始演示第二个代码,并且是用定时器的这种方式来实现PWM。

写这个程序之前,我们先来看看产生PWM的方法。

模型结构

图中的比较值在硬件PWM里面是一个寄存器,我们可以从这个寄存器写一个固定值,那这个比较值就决定了我们的占空比(占空比 = TON / TS)。在我们的程序中可以定义一个变量,把它当做一个比较值,如果占空比不变的话,这个比较值通常也是固定的。

最终我们如何翻转IO口呢?我们就通过一个比较大小(在硬件是硬件比较器,在软件是 if 判断),将计数器的值和比较值进行比较。如果这个计数器的值小于比较值,就会输出0;如果计数器的值大于等于比较值,则输出1。当然,到底是大于输出0还是小于输出0呢,这就涉及到PWM的输出极性,在程序中是可以调节的,在硬件中也有这样相应的配置。

这个模型结构和单片机里面硬件的定时器以及PWM的结构是相似的,如果理解了这个结构,以后再学那些定时器PWM就会比较简单。

我们即将会写程序来模拟这个结构,来看看它是如果产生PWM的。

我们有了这个结构之后,如果知道它怎么工作的呢?主要是看这个波形

波形

PS:蓝色的波形对应的是模型结构图中的计数器那部分,它会定时自增,假设它是从0自增到100再回到0,它的波形就是这样的:

这个比较值是设置值,比如说我们想设置为60(即图中的红线所示),它在时间上就是固定肯定为60的。它会和计数器的值有一个交点。如果我们再把这两个值比较大小的话,那它的输出波形,就会呈现下面这个效果:

比如第一个交点前,计数器的值小于比较值,则输出0,在PWM传输的波形图上就是0。然后第一个交点过后,计数器的值大于比较值,则输出1,在PWM传输的波形图上就是1。

如果将比较值设置为10,则PWM输出的波形也发生相应的变化,占空比会变得高一些。

因此我们通过控制这个比较值就可以控制占空比。 

比较值越大,占空比越小的;比较值越小,占空比越大。我们就利用这一点来控制电机的速度。

下面开始代码讲解:

新创建一个工程:直流电机调速

把这几个程序文件添加进来(下面每一个程序在之前的博客中都讲过了,如果不懂的可以翻之前的博客来看看)

然后新创建主程序main.c

根据原理图定义引脚,如果p10(Motor)=1,则电机旋转

#include <REGX52.H>
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Timer0.h"

sbit Motor=P1^0;

定义四个变量

unsigned char Counter,Compare;	//计数值和比较值,用于输出PWM
unsigned char KeyNum,Speed;//键码和速度

定时器初始化函数

然后初始化定时器,但是我们之前写的定时器初始化函数是1ms中断一次太慢了,我们重新生成一个100微秒中断一次的函数。

将生成的这个重装载值复制下来替换掉我们原先Timer0.c中的重装载值。

void Timer0_Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x9C;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

中断函数

相应的,我们写好的中断函数里的重装载值也要改。(中断函数在之前的博客中也讲过了)

PS:这个PWM驱动电机在一定范围内是越快越好,越快越稳定,但是过快的话也没必要,这会占用资源,并且会增加开关损耗。我们通常设置在10K到20KHz的频率。如果频率比较低的话电机会抖动。如果频率在1K附近的话,电机可能会产生鸣叫。

根据模型结构图中的计数器那部分,设置它会定时自增,假设它是从0自增到100再回到0

所以将Counter设置为Counter%=100;

如果Counter=99,那99对100取余是99,
如果Counter=100,那99对100取余是0,
所以Counter%=100和If(Counter>100)Counter=0是一个效果

然后我们将计数器的值和比较值进行比较。

void Timer0_Routine() interrupt 1 //每100微秒进来一次
{
	TL0 = 0x9C;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	Counter++;
	Counter%=100;	//计数值变化范围限制在0~99
	//如果Counter等于100,Counter自动清零
	
	if(Counter<Compare)	//计数值小于比较值
	{
		Motor=1;		//输出1,电机旋转
	}
	else				//计数值大于比较值
	{
		Motor=0;		//输出0,电机停止
	}
}

注意:我们这里设置的极性和模型结构图上的例子是不一样的,根据原理图Motor(p10)为高电平1时,电机转动,所以我们这里设置成:当计数值小于比较值时输出1,电机旋转,反之则输出0,电机停止。所以如果比较值越大,则输出1的之间就越大,电机速度越快。

主程序

那我们要设置占空比的话只需要设置比较值Compare

void main()
{
	Timer0_Init();//定时器初始化
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)//如果K1按下
		{
			Speed++;
			Speed%=4;//如果speed等于4,speed自动清零
			//设置速度的档次为0,1,2,3
			//比较值compare越大,速度越大
			if(Speed==0){Compare=0;}	//设置比较值,改变PWM占空比
			if(Speed==1){Compare=50;}
			if(Speed==2){Compare=75;}
			if(Speed==3){Compare=100;}
		}
		Nixie(1,Speed);//在第一个数码管上显示速度档次
	}
}

刚上电的时候电机会转一下是因为单片机默认上电时IO口都是高电平。

效果请看视频:

直流电机调速

以上就是本篇的内容,源码会放在评论区,如有问题可评论区留言!

​​​​​​​

相关文章

基于YOLOv8深度学习+Pyqt5的电动车头盔佩戴检测系统

该系统利用深度学习技术,通过训练YOLOv8模型来识别电动车骑行者是否佩戴头盔,并在检测到未佩戴头盔的情况下发出警报。因此,开发一种能够实时监测头盔佩戴情况的系统,对于提高骑行者的安全意识和减少交通事故具有重要作用。本文提出的基于YOLOv8的电动车头盔佩戴检测系统,能够有效地提高电动车骑行者的安全意识。YOLOv8是YOLO系列目标检测模型的最新版本,它在前代模型的基础上进行了优化,提高了检测速度和准确性。在不同的场景和光照条件下,模型均能稳定地识别出佩戴和未佩戴头盔的骑行者。wx供重浩:创享日记。

输入捕获模式测频率&amp;PWM输入模式(PWMI)测占空比

设置上升沿触发,分频后的触发信号每来一次,CNT就会向CCR转运一次,又因为CNT是内部的标准时钟驱动的,CNT数值就可以记录两个上升沿之间的时间间隔,也就是周期,取倒数得到频率。异或门其实还是为三相无刷电机服务,三个霍尔传感器检测转子位置,根据转子位置进行换相,在前三个通道接上霍尔传感器,这个定时器就作为无刷电机的接口定时器,去驱动换相电路工作。AS:概念不清,外部中断那是CPU了啊,这里是硬件映射主模式,然后配置从模式。,这样下次上升沿再捕获,取出的CNT 才是两个上升沿的时间间隔。

harmony 鸿蒙系统学习 安装ohpm报错 ohpm install failed

找原因,首先,通过查看文件,先看软件的使用node的配置,发现config用的是 .npmrc文件,去c盘找到对应文件打开看看。确实是,这里的镜像不对。(网上很多攻略要求你卸载以前的node或者卸载这个刚安装的软件,再重装,其实不需要这么麻烦。)

姿态传感器MPU6050模块的姿态解算

对比DMP和自己进行姿态解算:使用DMP我们可以直接得到四元数,但是如果不用DMP的话,就得自己来进行解算,根据得到的各轴角速度以及加速度,再经过滤波,接着计算出四元数或者欧拉角,然后还得进行姿态融合。前者更便捷,但是灵活度差,精度不是特别高;后者麻烦,但是算法处理得当的话,就能有很高的精度。一般应用使用DMP即可。

使用Flash download tool进行ESP32固件烧录

电脑安装完驱动、设置好烧录参数、端口和波特率,随后点击Start或者先Erase再Start,需要手动按住boot按钮,进入烧录模式,下载过程中松手即可。其中bootloader.bin, partitions.bin, firmware.bin是platformio的build文件夹里生成的内容。/.platformio/packages/framework-arduinoespressif32/tools/partitions路径下的。为方便分发固件,可在任意电脑上安装烧录软件,直接将固件烧录进。

C#中的浅度和深度复制(C#如何复制一个对象)

接着,我们修改了复制得到的对象及其引用类型字段的属性值,最后输出原始对象和复制对象的属性值。这意味着如果一个类包含引用类型成员,在执行深度复制时,不仅复制这些引用,还会递归地复制引用所指向的对象,直到所有的引用都指向全新的对象实例。当进行浅复制时,系统会创建一个新的对象实例,但这个新对象的字段将与原始对象中的值类型字段具有相同的值,而对于引用类型字段,则仅仅是复制了。也就是说,如果一个类中有引用类型的成员变量(比如数组、其他自定义类的对象等),那么浅复制后,新对象和原对象的这些引用类型成员仍然指向。

linux docker 部署mysql8以上版本时弹出Access denied for user root @ localhost (using password: YES)的解决方案

mysql8登录第一次遇到MYSQL_ROOT_PASSWORD时会自动把该密码尽兴登录,生成一个秘钥放在mysql的数据文件里面,命令里带的MYSQL_ROOT_PASSWORD密码是个参数,除了第一次运行mysql带上会设置密码生成秘钥,其他次启动而不是设置mysql的密码,而是作为参数去验证这个最初的秘钥是否核对正确,于是我进入挂载的data目录,发现我的猜想是对的。通过docker将服务部署完后,navicat连接报错,密码错误,于是我尝试进入mysql容器登录 发现也报错。

基于单片机的LED显示屏控制电路设计

提出应用单片机的LED显示屏控制电路。针对LED显示屏的工作原理进行分析,建立LED显示屏驱动策略。再以单片机为主控单元设计显示屏控制电路,通过改变行、列驱动电路,执行所有控制指令。最后,将PI控制算法应用到控制电路中,对比例系数和积分时间两项主要参数进行合理调整,得到控制参数优化后的LED显示屏控制电路。实验结果显示:所提控制电路的延时响应时间为2s,可以满足LED显示屏控制实时性要求。

二维平面阵列波束赋形原理和Matlab仿真

阵面左下角天线位于坐标原点,将坐标原点阵元设为参考阵元,计算每个阵元相对于该参考阵元的入射波程差,从而来计算每个阵元接收的回波信号。实现波束赋形的最基本的方法是对各个天线阵元的信号进行适当延迟后相加,使目标方向的信号同相叠加得到增强,而其他方向均有不同程度的削弱,该方法通常用于模拟信号.根据上述理论推导可以仿真任意平面阵列的方向图,这里对两种典型的阵列(矩形平面阵列和圆形阵列)进行Matlab仿真,其余类型的阵列在此基础上修改即可。根据上述圆形阵列公式做仿真,得到下述的三维空间方向图。

人工智能与机器学习——开启智能时代的里程碑

人工智能是指使计算机系统表现出类似于人类智能的能力。其目标是实现机器具备感知、理解、学习、推理和决策等智能行为。人工智能的发展可以追溯到上世纪50年代,随着计算机技术和算法的不断进步,人工智能得以实现。机器学习是人工智能的一个重要分支,它通过让计算机从数据中学习和改进性能,而不需要明确的编程指令。机器学习可以分为监督学习、无监督学习和强化学习三种主要类型。

大数据深度学习卷积神经网络CNN:CNN结构、训练与优化一文全解

卷积神经网络是一种前馈神经网络,它的人工神经元可以响应周围单元的局部区域,从而能够识别视觉空间的部分结构特征。卷积层: 通过卷积操作检测图像的局部特征。激活函数: 引入非线性,增加模型的表达能力。池化层: 减少特征维度,增加模型的鲁棒性。全连接层: 在处理空间特征后,全连接层用于进行分类或回归。卷积神经网络的这些组件协同工作,使得CNN能够从原始像素中自动学习有意义的特征层次结构。随着深度增加,这些特征从基本形状和纹理逐渐抽象为复杂的对象和场景表现。

计算机组成原理 CPU的功能和基本结构和指令执行过程

根据指令执行过程中的数据和地址的流动方向安排连接线路,避免使用共享的总线,性能较高,但硬件量大。(PC)-&gt;Bus-&gt;MAR   PCout 和 MARin 有效,现行指令地址-&gt;MAR。(MDR)-&gt;Bus-&gt;IR   MDRout 和 IRin有效,现行指令-&gt;IR。每个指令时间可能不同,但是在单指令周期下,所有指令选用相同的执行时间,指令间串行。MEM(MAR)-&gt;数据线-&gt;MDR   操作数从存储器-&gt;数据线-&gt;MDR。MDR-&gt;Bus-&gt;Y   MDRout 和 Yin 有效,操作数-&gt;Y。

基于单片机设计的智慧农业大棚检测系统

本项目基于单片机设计一个智慧农业大棚检测系统,以提供实时监测和管理大棚环境的关键参数。系统支持环境温度、湿度检测,光照强度检测,并能根据预设的阀值进行报警提示。为了实现数据的显示和管理,该系统还利用Qt开发了一款对应的Android手机APP,通过蓝牙传输模块将单片机采集到的数据传递到手机APP上进行显示和管理。

【树莓派安装Homeassistant及基本配置】

时隔一年,我又重新开始玩Homeassistant,发现其中奥妙无穷,惊喜不断。在我浅薄的认知中要学好嵌入式,必须玩过Homeassistant,并且玩出自己的名堂!因为这是最贴切实际的生活应用没有之一,每月更新使得唯有活水来;拥抱大千使得永葆青春的活力;鬼斧神工的操作精彩纷呈,可以堪称软件与硬件的完美落地!

为什么ChatGPT选择了SSE,而不是WebSocket?

WebSocket是一种网络通信协议,它最早被提出来是为了解决HTTP连接的一大限制:HTTP协议中,一个客户端发送给服务端的请求必须由服务端返回一个响应,这使得服务端无法主动向客户端推送数据。客户端通过发送一个特殊的HTTP请求向服务器请求建立WebSocket连接。这个请求类似于:GET /chat HTTP/1.1 Upgrade: websocket Connection: Upgrade服务器响应这个请求,确认建立WebSocket连接。

使用LOTR合并检索提高RAG性能

为了解决LIM问题并提高检索性能,对RAG系统进行增强是非常重要的。通过设置不同的VectorStores并将它们与Merge retriver结合,以及使用LongContextReorder重新排列结果,可以减少LIM问题并使检索过程更高效。此外,在合并检索器中合并特定领域的嵌入也有着关键作用。这些步骤对于确保我们不会在检索文件的过程中遗漏重要细节至关重要。Lost in the Middle: How Language Models Use Long Contexts 论文。

如何搭建Tomcat服务并结合内网穿透实现公网访问本地站点

Tomcat作为一个轻量级的服务器,不仅名字很有趣(让人想起童年),也拥有强大功能,由于其可以实现JavaWeb程序的装载,就成为配置JSP和Java系统必备的环境软件,也是开发调试JSP程序的首选。Tomcat运行稳定且开源免费,加上apache和Sun的加持即免费和开源的特性,使其广泛应用在中小型系统及并发访问用户较少的场景中。但想要让Tomcat网页能在公共互联网环境下被访问到,就需要cpolar内网穿透的协助。现在。笔者就为大家介绍,如何使用cpolar内网穿透。

【AI】人工智能复兴的推进器之神经网络

神经网络是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)的结构和功能的数学模型或计算模型,用于对函数进行估计或近似。神经网络由大量节点(或神经元)相互关联构成,每两个节点间的连接都代表一个对于通过该连接信号的加权值,称之为权重,这可以看作人工神经元的记忆。网络的输出则依网络的连接方式,权重值和激励函数的不同而不同。而网络自身通常都是对自然界某种算法或者函数的逼近,也可能是对一种逻辑策略的表达。此外,根据网络的结构和运行方式,神经网络可以分为前馈神经网络和反馈神经网络。

Python将列表中的数据写入csv并正确解析出来

用Python做数据处理常常会将数据写到文件中进行保存,又或将保存在文件中的数据读出来进行使用。通过Python将列表中的数据写入到csv文件中很多人都会,可以通过Python直接写文件或借助pandas很方便的实现将列表中的数据写入到csv文件中,但是写进去以后取出有些字段会有变化有些坑还是要避免。本文通过实例来介绍如何将列表中的数据写入文件如csv并正确解析出来使用。

深度解析 PyTorch Autograd:从原理到实践

本文深入探讨了 PyTorch 中 Autograd 的核心原理和功能。从基本概念、Tensor 与 Autograd 的交互,到计算图的构建和管理,再到反向传播和梯度计算的细节,最后涵盖了 Autograd 的高级特性。

如何公网访问内网的群晖NAS随时随地远程访问本地存储的学习资源

对于热爱学习的在校大学生 研究生来说,从网上找学习资源容易,如何存储下来还能随时随地使用始终是个难题。随着固态硬盘价格下降,研究生小张买了一块2T SSD装到电脑上用来存储学习资源,但是每次要背着笔记本去图书馆学习不方便,小张想用iPad在图书馆使用校园WiFi浏览寝室内/实验室中笔记本上的资源,但是iPad存储空间有限,他在网上查询到安装黑群晖可以用群辉的移动端软件访问本地资源,但是黑群晖没有正版的quickconnect服务,只能在本地访问。现在我来帮小张和他的研究生同学们完美解决这个难题!

RPC简介和grpc的使用

调用客户端句柄,执行传递参数。调用本地系统内核发送网络消息。消息传递到远程主机,就是被调用的服务端。服务端句柄得到消息并解析消息。服务端执行被调用方法,并将执行完毕的结果返回给服务器句柄。服务器句柄返回结果,并调用远程系统内核。消息经过网络传递给客户端。客户端接受数据。
返回
顶部