目录
一、SG90舵机
SG90舵机的控制信号是PWM信号,利用占空比的变化,改变舵机转动的角度。
1、PWM
脉冲宽度调制 (Pulse Width Modulation)<详细解释见百度>
2、占空比
一个周期内(50HZ = 20ms),高电平占据时长的百分比
🔖以0-180度的舵机为例,已知舵机的pwm周期为20ms,占空比和舵机转动角度关系如下:
占空比 | 转动角度 | 高电平持续时间 |
2.5% | 0° | 0.5 ms |
5.0% | 45° | 1.0 ms |
7.5% | 90° | 1.5 ms |
10.0% | 135° | 2.0 ms |
12.5% | 180° | 2.5 ms |
🔖理解:一个周期(20ms)内出现刚好2ms的高电平,舵机转至135°的位置
(个人觉得这里体现在为代码的时候并不好理解)
3、输出PWM的方式
🔖硬件PWM:通过芯片内部模块输出,一般手册或芯片IO口会标明PWM
🔖软件PWM(模拟PWM):如果没有集成PWM功能,可以通过普通I/O口模拟,相对硬件PWM来说精准度略差。
4、编程实现舵机0-135°转动(demo1.c)
#include "reg52.h"
#include <intrins.h>
sbit servo = P3^1;
char cnt = 0;
char angle = 1;
/**********软件延时2s***********/
void Delay2000ms(){
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do{
do{
while (--k);
} while (--j);
} while (--i);
}
/**********软件延时0.5s***********/
void Delay500ms(){
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do{
do{
while (--k);
} while (--j);
} while (--i);
}
/**********定时器0初始化***********/
void timer0Init(){ //500微秒=0.5ms
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x33; //设置定时初始值
TH0 = 0xFE; //设置定时初始值
TR0 = 1; //定时器0开始计时
TF0 = 0; //清除TF0标志
ET0 = 1; //定时器中断
EA = 1; //总中断
}
/**********定时器中断处理***********/
void interruptHandler() interrupt 1{
TL0 = 0x33; //重新设置定时初始值
TH0 = 0xFE; //重新设置定时初始值
cnt++;
if(cnt < angle){ //若此时angle=4(转至135°),cnt=0时拉高电平到cnt=4时不满足拉低,即获得2ms的高电平
servo = 1; //若此时angle=1(转至0°),cnt=0时拉高到cnt=1时不满足拉低,即获得0.5ms的高电平
}else{
servo = 0;
}
if(cnt == 40){ //PWM的周期20ms
cnt = 0;
servo = 1;
}
}
void main(void){
Delay500ms(); //延时让系统稳定
timer0Init(); //打开定时器
servo = 1; //启动定时后,给一个高电平且让angle=1,此时中断第一次触发cnt=1时,cnt < angle不满足,拉低电平
angle = 1; //即获得0.5ms的高电平,让舵机转至0°
while(1){ //每隔2秒,在0°和135°切换
angle = 4;
cnt = 0;
Delay2000ms();
angle = 1;
cnt = 0;
Delay2000ms();
}
}
二、HC-SR04测距
1、测距原理
🔖原理:向 Trig 引脚发送一个 10us 的脉冲信号,开始发送超声波,并把 Echo置为高电平,发射超声波之后,与接收到传回的超声波之前,Echo这个响应引脚会一直呈现高电平,然后准备接收返回的超声波。等到超声波撞到障碍物弹回来并被模块接收,Echo引脚置为低电平。
(有用的话:Echo持续高电平的时间就是超声波往返路程的花费的时间,通过记录时间,再利用路程=速度X时间 可算出路程(注意是往返路程),已知:超声波速度340m/s)
2、测距实现(demo2.c)
#include "reg52.h"
#include <intrins.h>
sbit Trig = P1^0;
sbit Echo = P1^1;
sbit led1 = P3^6;
void Delay10us(){ //软件延时10us
unsigned char i;
i = 2;
while (--i);
}
//定时器模式的初始化 -- 16位
void time0Init(){
TMOD |= 0x1<<0;
TMOD &= ~(0x1<<1);
TL0 = 0;
TH0 = 0;
}
//向Trig发送一个10us的脉冲信号
void startHC(){
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void main(void){
double distance;
led1 = 1;
time0Init();
while(1){
startHC();
while(Echo != 1); //echo非高电平时,循环等待 -- 等待波开始发送
TCON |= 0x1<<4; //执行到这里说明echo为高电平,波开始发送 -- 开启定时器
while(Echo != 0); //echo非低电平时,循环等待 -- 等待波的返回
TCON &= ~(0x1<<4); //到这里说明波已经返回
distance = (((TH0<<8) + TL0) * 1.085)*0.034; //定时器得到时间,计算得到距离(已知速度340m/s)
if((distance/2) < 10){
led1 = 0;
}else{
led1 = 1;
}
TH0 = 0; //重新从0计数
TL0 = 0;
}
}
说明:由于笔者水平有限,文中不可避免有所错漏,敬请各读者斧正