#盲盒+码#【FFH】学习设备开发之Hi3861-PWM输出-演奏歌曲 原创 精华
@toc
【本文正在参加「盲盒」+码有奖征文活动】:https://ost.51cto.com/posts/19288
本文代码使用的是传智鸿蒙元气派再封装过的OpenHarmony master版本代码。
一、前言
学习OpenHarmony南向设备开发除了只会普通IO口的输入输出还是远远不够的。普通IO口的输出能控制LED灯的亮灭,PWM输出就可以控制灯亮的程度,深入学习发现舵机的运动也是需要PWM输出控制的。
二、PWM简介
1.什么是PWM
脉冲宽度调制 (PWM) ,英文“Pulse Width Modulation”,简称脉宽调制。它是利用微处理器的数字输出,来对模拟电路进行控制的一种非常有效的技术 。简单一点,就是对脉冲宽度的控制。
这些脉冲将以==方波==的形式出现。在任何给定的时间点,波型要么是高电平或者是低电平。
需要关注两个与之相关的重要参数,一个是PWM占空比,另一个是PWM信号的频率。
2.PWM占空比
由于PWM信号在特定的时间内保持接通状态(高电平),然后在剩余的时间内保持断开状态(低电平),所以引用占空比来表示一个脉冲循环内==接通时间相对于总时间所占的比例==。也就是说在一段连续工作时间内脉冲==高电平时间与总时间的比值==。
举个栗子:如果信号总是处于高电平,它的占空比是100%;如果信号总是处于低电平,那么它的占空比是0%。
通过改变PWM的占空比就可以任意输出0-3.3V/5V的任意电压了。
3.PWM频率
PWM信号的频率决定了PWM完成一个信号周期的速度(==一秒内完成了多少次PWM变换==)。周期是指PWM信号完成一个接通和关闭的时间。计算频率的公式如下所示:
频率 = 1 / 周期
三、demo设计
1.呼吸灯
只需要改变PWM的占空比即可。
首先查看led灯的引脚号。
注意:==不同开发板的led灯对应的引脚号不一样,一定要事先查看原理图!==
::: hljs-center
上主程序代码👇
:::
#include <stdio.h> //标准输入输出头文件
#include <string.h> //字符数组头文件
#include <unistd.h> //操作系统API
#include "ohos_init.h" //鸿蒙操作系统初始化和启动服务和功能的条目
#include "cmsis_os2.h" //微控制器软件接口标准
#include "iot_gpio.h" // GPIO 初始化、输入/输出设置和级别设置
#include "iot_pwm.h" //操作 PWM 设备头文件
#include "iot_io.h" //io口的功能设置
#include "genki_pin.h"//传智鸿蒙元气派再封装过的引脚功能
static void start(void) {
//初始化GPIO口
IoTGpioInit(IOT_IO_NAME_2);
//设置IO口功能为GPIO
IoTIoSetFunc(IOT_IO_NAME_2, IOT_IO_FUNC_2_PWM2_OUT);
//设置IO口输出方向:输出
IoTGpioSetDir(IOT_IO_NAME_2, IOT_GPIO_DIR_OUT);
//初始化PWM功能
IoTPwmInit(IOT_IO_NAME_2);
//不断输出pwm方波
while (1) {
for (int i = 0; i < 20; i++) {//由暗到亮
IoTPwmStart(IOT_IO_NAME_2, i, 10000);
usleep(0.05 * 1000 * 1000);
}
for (int i = 20; i > 0; i--) {//由亮到暗
IoTPwmStart(IOT_IO_NAME_2, i, 10000);
usleep(0.05 * 1000 * 1000);
}
}
}
APP_FEATURE_INIT(start);
2.演奏歌曲
演奏歌曲则需要不断改变PWM的频率了。
2.1材料准备
无源蜂鸣器:无源内部不带震荡源,所以直流信号无法令其鸣叫,必须用方波去驱动它才能鸣叫。
2.2乐理知识准备
每个音符都有对应的震动频率,下面以常见的C大调为例。
歌曲曲谱:
C调,4/4拍(以四分音符为一拍,每小节四拍)
2.3程序编写
#include <stdio.h> //标准输入输出头文件
#include <string.h> //字符数组头文件
#include <unistd.h> //操作系统API
#include "ohos_init.h" //鸿蒙操作系统初始化和启动服务和功能的条目
#include "cmsis_os2.h" //微控制器软件接口标准
#include "iot_gpio.h" // GPIO 初始化、输入/输出设置和级别设置
#include "iot_pwm.h" //操作 PWM 设备头文件
#include "iot_io.h" //io口的功能设置
#include "genki_pin.h" //传智鸿蒙元气派再封装过的引脚功能
#include <math.h> //常用数学运算方法
//C大调各个音符对应的频率数组
static const uint16_t g_tuneFreqs[] = {
0,
1046.5, // 高音1-do
1174.7, // 高音2-re
1318.5, // 高音3-mi
1396.9, // 高音4-fa
1568, // 高音5-so
1760, // 高音6-la
1975.5, // 高音7-si
783.99 // 中音5-so
};
// 曲谱音符
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 music(void *arg)
{
//初始化GPIO口
IoTGpioInit(IOT_IO_NAME_14);
//设置IO口功能为PWM输出,14号引脚支持pwm输出
IoTIoSetFunc(IOT_IO_NAME_14, IOT_IO_FUNC_14_PWM5_OUT);
//设置IO口输出方向:输出
IoTGpioSetDir(IOT_IO_NAME_14, IOT_GPIO_DIR_OUT);
//初始化PWM功能
IoTPwmInit(IOT_PWM_NAME_5);
while (1)
{
for (size_t i = 0; i < sizeof(g_scoreNotes) / sizeof(g_scoreNotes[0]); i++)
{
uint32_t tune = g_scoreNotes[i]; // 曲谱音符、12345678
uint16_t freqDivisor = g_tuneFreqs[tune]; //每个曲谱音符相对应的频率
uint32_t tuneInterval = g_scoreDurations[i] * (125 * 1000); // 音符持续时间
printf("音符:%d 音符对应频率:%d 持续时间:%d\r\n", tune, freqDivisor, tuneInterval);
IoTPwmStart(IOT_PWM_NAME_5, 50, freqDivisor * 4); //占空比50%
usleep(tuneInterval); //每个音符持续时间
IoTPwmStop(IOT_PWM_NAME_5);
}
}
}
static void start(void)
{
osThreadAttr_t attr;
attr.name = "thread_1";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
if (osThreadNew(music, NULL, &attr) == NULL)
{
printf("Falied to create music!\r\n");
}
}
APP_FEATURE_INIT(start);
四、总结
Hi3861的PWM使用流程:
1.初始化io、2. io复用为pwm输出、3. 使能pwm通道4. 开始输出pwm(通道、占空比、频率)5.停止输出pwm
这次学习pwm为下次学习怎么使用舵机打下基础。
标黄的部分用心了
好奇播放效果
音频播放总是对《两只老虎》情有独钟
PWM的用法学习了
可能是节奏比较容易对比吧