第一:pwm的基本简介
首先来了解一下,pwm的频率是什么?
定义:是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期),也就是说一秒钟PWM有多少个周期。单位:HZ。
pwm的周期:T=1/f 可以认为50Hz=20ms 一个周期。
pwm的占空比:是一个脉冲周期内,高电平的时间与整个周期时间的比例。
单位: % (0%-100%)
表示方式:20%
周期: 一个脉冲信号的时间 1s内测周期次数等于频率
脉宽时间: 高电平时间
上图中 脉宽时间占总周期时间的比例,就是占空比
比方说周期的时间是10ms,脉宽时间是8ms 那么低电平时间就是2ms 总的占空比 8/(8+2)= 80%
这就是占空比为80%的脉冲信号
而我们知道PWM就是脉冲宽度调制 通过调节占空比,就可以调节脉冲宽度(脉宽时间) 而频率 就是单位时间内脉冲信号的次数,频率越大
以20Hz 占空比为80% 举例 就是1秒钟之内输出了20次脉冲信号 每次的高电平时间为40ms
我们换更详细点的图
T1为高电平时间
T2 为低电平时间
假设周期T为 1s 那么频率就是 1Hz 那么高电平时间0.5s ,低电平时间0.5s 总的占空比就是 0.5 /1 =50%
PWM原理
以单片机为例,我们知道,单片机的IO口输出的是数字信号,IO口只能输出高电平和低电平。
假设高电平为5V 低电平则为0V 那么我们要输出不同的模拟电压,就要用到PWM,通过改变IO口输出的方波的占空比从而获得使用数字信号模拟成的模拟电压信号
我们知道,电压是以一种连接1或断开0的重复脉冲序列被夹到模拟负载上去的(例如LED灯,直流电机等),连接即是直流供电输出,断开即是直流供电断开。通过对连接和断开时间的控制,理论上来讲,可以输出任意不大于最大电压值(即0~5V之间任意大小)的模拟电压
比方说 占空比为50% 那就是高电平时间一半,低电平时间一半,在一定的频率下,就可以得到模拟的2.5V输出电压 那么75%的占空比 得到的电压就是3.75V
pwm的调节作用来源于对“占周期”的宽度控制,“占周期”变宽,输出的能量就会提高,通过阻容变换电路所得到的平均电压值也会上升,“占周期”变窄,输出的电压信号的电压平均值就会降低,通过阻容变换电路所得到的平均电压值也会下降
也就是,在一定的频率下,通过不同的占空比 即可得到不同的输出模拟电压。
pwm就是通过这种原理实现D/A转换的。
PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压。
第二:PWM对电机的控制方法
PWM对舵机的控制
舵机的控制就是通过一个固定的频率,给其不同的占空比的,来控制舵机不同的转角
舵机的频率一般为频率为50HZ,也就是一个20ms左右的时基脉冲,而脉冲的高电平部分一般为0.5ms-2.5ms范围。来控制舵机不同的转角
500-2500us的PWM高电平部分对应控制180度舵机的0-180度
以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
第三:鸿蒙中PWM的实现方式
利用板子上的GPIO口模拟输出PWM来控制蜂鸣器发出声音。具体代码实现如下所示。
#include <stdio.h> #include <unistd.h> #include "ohos_init.h" #include "cmsis_os2.h" #include "wifiiot_gpio.h" #include "wifiiot_gpio_ex.h" #include "wifiiot_watchdog.h" #include "wifiiot_pwm.h" #include "hi_pwm.h" static volatile int g_buttonPressed = 0; static const uint16_t g_tuneFreqs[] = { 0, // 40M Hz 对应的分频系数: 38223, // 1046.5 34052, // 1174.7 30338, // 1318.5 28635, // 1396.9 25511, // 1568 22728, // 1760 20249, // 1975.5 51021 // 5_ 783.99 // 第一个八度的 5 }; // 曲谱音符 static const uint8_t g_scoreNotes[] = { // 《两只老虎》简谱:http://www.jianpu.cn/pu/33/33945.htm 1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5, 5, 6, 5, 4, 3, 1, 5, 6, 5, 4, 3, 1, 1, 8, 1, 1, 8, 1, // 最后两个 5 应该是低八度的,链接图片中的曲谱不对,声音到最后听起来不太对劲 }; // 曲谱时值 static const uint8_t g_scoreDurations[] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 8, 3, 1, 3, 1, 4, 4, 3, 1, 3, 1, 4, 4, 4, 4, 8, 4, 4, 8, }; static void *BeeperMusicTask(const char *arg) { (void)arg; printf("BeeperMusicTask start!\r\n"); hi_pwm_set_clock(PWM_CLK_XTAL); // 设置时钟源为晶体时钟(40MHz,默认时钟源160MHz) for (size_t i = 0; i < sizeof(g_scoreNotes)/sizeof(g_scoreNotes[0]); i++) { uint32_t tune = g_scoreNotes[i]; // 音符 uint16_t freqDivisor = g_tuneFreqs[tune]; uint32_t tuneInterval = g_scoreDurations[i] * (125*1000); // 音符时间 printf("%d %d %d %d\r\n", tune, (40*1000*1000) / freqDivisor, freqDivisor, tuneInterval); PwmStart(WIFI_IOT_PWM_PORT_PWM0, freqDivisor/2, freqDivisor); usleep(tuneInterval); PwmStop(WIFI_IOT_PWM_PORT_PWM0); } return NULL; } static void StartBeepMusicTask(void) { osThreadAttr_t attr; GpioInit(); // 蜂鸣器引脚 设置为 PWM功能 IoSetFunc(WIFI_IOT_IO_NAME_GPIO_9, WIFI_IOT_IO_FUNC_GPIO_9_PWM0_OUT); PwmInit(WIFI_IOT_PWM_PORT_PWM0); WatchDogDisable(); attr.name = "BeeperMusicTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 1024; attr.priority = osPriorityNormal; if (osThreadNew((osThreadFunc_t)BeeperMusicTask, NULL, &attr) == NULL) { printf("[LedExample] Falied to create BeeperMusicTask!\n"); } } SYS_RUN(StartBeepMusicTask);
行百里者半九十,接下来的配置和编译过程,如下。
第四:效果实现
总结:鸿蒙系统的使用需要动手实践,在实践的过程中,发现问题并解决问题。