PWM开发SG90
-
简介
PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及赋值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。
- 脉冲宽度调制
- 通过占空比编码模拟信号
- 占空比一个周期内,高电平占据时长的百分比
控制舵机
-
什么是舵机
如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号控制。
用处:垃圾桶项目开盖、只能小车的全比例转向、摄像头云台、机械臂等
常见的有0-90°、0-180°、0-360°
-
怎么控制舵机
向黄色信号线输入PWM信号。
PWM波的频率不能太高,大约59Hz,即周期=1/频率=1/50=0.02s=20ms
数据:
0.5ms-------------0度;2.5% 对应函数中占空比为250
1.0ms------------45度;5.0% 对应函数中占空比为500
1.5ms------------90度;7.5% 对应函数中占空比为750
2.0ms-----------135度;10.0% 对应函数中占空比为1000
2.5ms-----------180度;12.5% 对应函数中占空比为1250
0.5为最大公约数,设置定时器为0.5ms,40个0.5ms为20ms一个周期
-
编程实现
#include "reg52.h" #include <intrins.h> sbit pwm = P1^1; int cnt = 0; int jd = 0; void time0_init()//定时器初始化函数 { //1.选择定时器模式 TMOD &= 0xF0; TMOD |= 0x01; //2.给定定时器初值 0.5ms溢出 TL0 = 0x33; TH0 = 0xFE; //3.开启定时器 TR0 = 1; TF0 = 0; //开启中断 EA = 1; ET0 = 1; } void time0_inter() interrupt 1 { //4.溢出后cnt++,同时还原初值 cnt++; TL0 = 0x33; TH0 = 0xFE; if(cnt < jd){//根据jd(角度)值判断高电平什么时候输出结束,确定旋转的角度 pwm = 1;//输出高电平 }else{ pwm = 0;//输出低电平 } //5.cnt=40后,正好0.5*40=20ms一个周期 if(cnt == 40){ cnt = 0;//一个周期后cnt置0,同时输出高电平 pwm = 1; } } void Delay2000ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); i = 15; j = 2; k = 235; do { do { while (--k); } while (--j); } while (--i); } void main() { Delay2000ms(); jd = 1;//初始位置为0° cnt = 0; pwm = 1; time0_init(); while(1){ jd = 1; cnt = 0;//因为有延时函数,防止cnt不为0,改变角度后置cnt为0 Delay2000ms(); jd = 3; cnt = 0; Delay2000ms(); } }
-
超声波模块
超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度,计算出模块到前方障碍物的距离。
-
超声波模块工作时序图
-
怎么让它发送波
Trig ,给Trig端口至少10us的高电平
-
怎么知道它开始发了
Echo信号,由低电平跳转到高电平,表示开始发送波
-
怎么知道接收了返回波
Echo,由高电平跳转回低电平,表示波回来了
-
怎么算时间
Echo引脚维持高电平的时间!
波发出去的那一下,开始启动定时器 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
-
怎么算距离
距离 = 速度 (340m/s)* 时间/2
#include "reg52.h"
#include <intrins.h>
//现象:大于10cm led1亮led2灭;小于10cm led2亮led1灭
sbit Trig = P1^0;
sbit Echo = P1^1;
sbit led1 = P3^7;
sbit led2 = P3^6;
void time0_init()//定时器初始化函数
{
TMOD &= 0xF0;//选择定时器模式,16位
TMOD |= 0x01;
TL0 = 0;//给定定时器初值为0
TH0 = 0;
}
void Delay50ms() //@11.0592MHz
{
unsigned char i, j;
i = 90;
j = 163;
do
{
while (--j);
} while (--i);
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void start_HC()//给trig 10us高电平
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void main()
{
double time;//单片机的参数定义放在最前面,不能放在函数后面
double dis;
Delay1000ms();//稳定一下
time0_init();
while(1){
start_HC();//给trig一个10us的高电平开启测距
while(Echo == 0);//echo由低到高开始计时
TR0 = 1;
while(Echo == 1);//echo由高到低结束计时
TR0 = 0;
time = (TH0*256 + TL0) * 1.085;//计算时间,单位:us
//将TH0和TL0两个8位合成一个16位,需要把TH0向左移8位,则需要将TH0 乘以 2的8次方
dis = 0.017 * time;//计算距离340m/s=34000cm/s=34cm/ms=0.034cm/us 单位:cm
if(dis > 10){//判断距离
led1 = 0;
led2 = 1;
}else{
led1 = 1;
led2 = 0;
}
TL0 = 0;//定时器归零
TH0 = 0;
Delay50ms();//延时一下,防止程序buzy测不了距离
}
}