wifi之1M传输速率时占空比

当设备在找热点时,工作时最低速率1M,按思科的计算公式,在1M时,如果一个是64个字节的包,约可以发1000个包左右,


如果我们的设备一直在找路由器, 那么发送数据包的间隔时间最短为1ms,或更小上点,后面采用避让算法会加长,


按实际与路由器交换数据来看,1秒约通讯了40-60个数据包, 那换算过来说,也是说,当40个左右的设备在同样的环璄中


找路由器就会导致网络不能用。



我正在完成一个OpenHarmony的嵌入式设计项目,功能要求 1.能够使用交通灯板上的蜂蜜器播放选定的曲谱, PWM原理、音符--频率对应关系、音符频率选择、曲谱电子化(转程序数组)、程序逻辑、BUILD.gn出国文件修改、代码编译、固件烧录、串口调试、运行测试等都能在报告中清晰说明、项目答辩阐述清楚、答辩提问回答基本正确。 2. 能够使用交通灯板上的按键切换播放的曲谱, 至少有两首或以上曲谱可以切换(曲谱越多得分越高)、播放出的曲谱音律基本准确。 3. 能够应用OLED显示屏显示当前播放曲谱的相关信息, 能够显示当前播放曲谱的名气、歌词等相关信息。 要求使用vscode中的海思环境和虚拟机Linux系统,硬件设备润和鸿蒙系统的满天星智能家居开发套件。 现在我已经完成了播放音乐,OLED显示歌名,播放音乐交通板红绿灯闪烁的功能。 实现的代码如下: \applications\sample\wifi-iot\app\pwm_demo\display.c: #include <stdio.h> // 标准输入输出 #include <unistd.h> // POSIX标准接口 #include "ohos_init.h" // 用于初始化服务(services)和功能(features) #include "cmsis_os2.h" // CMSIS-RTOS API V2 #include "iot_gpio.h" // OpenHarmony HAL:IoT硬件设备操作接口-GPIO #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口-IO #include "hi_adc.h" // 海思 Pegasus SDK:IoT硬件设备操作接口-ADC #include "oled_ssd1306.h" // OLED显示屏简化版驱动接口文件 // 定义一个宏,用于标识ADC2通道 #define ANALOG_KEY_CHAN_NAME HI_ADC_CHANNEL_2 // 使用PCtoLCD建立字库 // 字符集:铃铛 // 字符轮廓:16 X 16,新宋体 // 每个字32个字节(16*16/8=32) // 根据取模方式,每个字的前16字节是汉字的上半部分,后16字节是汉字的下半部分 // 使用二维数组 uint8_t fonts1[][32] = { {0x40,0x30,0xEF,0x24,0x24,0x40,0x20,0x10,0x0C,0x23,0xCC,0x10,0x20,0x40,0x40,0x00,0x01,0x01,0x7F,0x21,0x11,0x00,0x01,0x09,0x11,0x21,0xD1,0x0D,0x03,0x00,0x00,0x00},/*"铃",0*/ {0x20,0x10,0x2C,0xE7,0x24,0x24,0x40,0x42,0x5C,0x40,0x7F,0x40,0x50,0xCE,0x00,0x00,0x01,0x01,0x01,0x7F,0x21,0x11,0x40,0x44,0x44,0x44,0x44,0x44,0x44,0xFF,0x00,0x00},/*"铛",1*/ }; /// @brief 显示一个汉字(使用PCtoLCD建立的字库) /// @param x x坐标,1像素为单位 /// @param y y坐标,8像素为单位。即页面起始地址 /// @param idx 汉字在字库中的索引 void OledShowChinese1(uint8_t x, uint8_t y, uint8_t idx) { // 控制循环 uint8_t t; // 显示汉字的上半部分 OledSetPosition(x, y); for (t = 0; t < 16; t++) { WriteData(fonts1[idx][t]); } // 显示汉字的下半部分 OledSetPosition(x, y + 1); for (t = 16; t < 32; t++) { WriteData(fonts1[idx][t]); } } // 主线程函数 static void OledTask(void *arg) { (void)arg; // 初始化SSD1306显示屏驱动芯片 OledInit(); // 全屏填充黑色 OledFillScreen(0x00); // 显示"铃铛" // 起始x坐标 = (屏幕宽度128 - (汉字间距18*(字数-1) + 每个汉字的宽度16 - 第一个汉字的坐标0))/2 = 29 OledShowChinese1(29 + 0, 3, 0); //铃 OledShowChinese1(29 + 18, 3, 1); //铛 // 居中显示"OpenHarmony" // 起始x坐标 = (屏幕宽度128 - 字符间距8 * 字母个数11)/2 = 20 OledShowString(20, 5, "OpenHarmony", FONT8x16); // 左上角显示倒计 char digits[] = "8 7 6 5 4 3 2 1"; for (int i = 0; i < 15; i++) { OledShowChar(0, 0, digits[i], FONT6x8); sleep(1); } // 中英文混杂显示 OledFillScreen(0x00); // 全屏填充黑色 // 工作循环 while (1) { // 要显示的字符串 static char text[128] = {0}; // 用于存放ADC2通道的值 unsigned short data = 0; // 读取ADC2通道的值 hi_adc_read(ANALOG_KEY_CHAN_NAME, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0); OledShowString(36, 0, text, FONT8x16); // 等待30ms usleep(30 * 1000); } } // 入口函数 static void OledDemo(void) { // 定义线程属性 osThreadAttr_t attr; attr.name = "OledTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 4096; attr.priority = osPriorityNormal; // 创建线程 if (osThreadNew(OledTask, NULL, &attr) == NULL) { printf("[OledDemo] Falied to create OledTask!\n"); } } // 运行入口函数 APP_FEATURE_INIT(OledDemo); \applications\sample\wifi-iot\app\pwm_demo\music2.c: #include <stdio.h> // 标准输入输出头文件 #include <string.h> // 字符串处理头文件 #include "ohos_init.h" // 用于初始化服务(service)和功能(feature)的头文件 #include "cmsis_os2.h" // CMSIS-RTOS2头文件 #include "iot_gpio.h" // OpenHarmony API:IoT硬件设备操作接口中的GPIO接口头文件 #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的IO接口头文件 #include "hi_pwm.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的PWM接口头文件 #include "ssd1306.h" // OLED显示屏驱动头文件 // 分频倍数数组 // 40MHz 对应的分频倍数 static const uint16_t g_tuneFreqs[] = { 0, // 不使用 38223, // 1046.5Hz C6(do) 34052, // 1174.7Hz D6(re) 30338, // 1318.5Hz E6(mi) 28635, // 1396.9Hz F6(fa) 25511, // 1568Hz G6(so) 22728, // 1760Hz A6(la) 20249, // 1975.5Hz B6(si) 51020 // 784Hz G5(so)低八度 }; // 曲谱音符数组:《铃儿响叮当》 static const uint8_t g_scoreNotes[] = { // 第一句: 3, 3, 3, 3, 3, 3, 3, 5, 1, 2, 3, // 第二句: 4, 4, 4, 4, 3, 3, 3, 2, 2, 1, 2, 5, // 第三句(重复第一句): 3, 3, 3, 3, 3, 3, 3, 5, 1, 2, 3, // 第四句: 4, 4, 4, 4, 3, 3, 5, 5, 4, 2, 1 }; // 曲谱值数组:(单位:1/4拍,4=1拍,8=2拍) static const uint8_t g_scoreDurations[] = { // 第一句:三连音用短值,结尾音稍长 2, 2, 4, 2, 2, 4, 2, 2, 2, 2, 4, // 第二句: 2, 2, 4, 2, 2, 4, 2, 2, 2, 2, 2, 4, // 第三句: 2, 2, 4, 2, 2, 4, 2, 2, 2, 2, 4, // 第四句: 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4 }; // 主线程函数 static void BeeperMusicTask(void *arg) { (void)arg; printf("BeeperMusicTask start!\r\n"); // 日志输出 // 初始化OLED显示屏 ssd1306_Init(); ssd1306_Fill(Black); // 清屏 ssd1306_SetCursor(20, 2); // 设置光标位置 ssd1306_PrintString("送别", Font_11x18, White); // 显示歌曲名称 ssd1306_UpdateScreen(); // 更新显示 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]; // 获取音符间 // 适当拉长间,四分之一拍用125ms,每小节用2s uint32_t tuneInterval = g_scoreDurations[i] * (125*1000); // 日志输出 printf("%d %d %d %d\r\n", tune, (40*1000*1000) / freqDivisor, freqDivisor, tuneInterval); if (tune != 0) { // 0表示休息 // 开始输出PWM信号,占空比为50% hi_pwm_start(HI_PWM_PORT_PWM0, freqDivisor/2, freqDivisor); } // 等待音符间,参数的单位是微秒(千分之一毫秒) usleep(tuneInterval); // 停止输出PWM信号 hi_pwm_stop(HI_PWM_PORT_PWM0); // 停止一个音符后,等待20ms,让两次发音有个间隔,听起来更自然一些 usleep(20*1000); } // 播放完成后显示结束信息 ssd1306_Fill(Black); // 清屏 ssd1306_SetCursor(10, 2); ssd1306_UpdateScreen(); } // 入口函数 static void StartBeepMusicTask(void) { // 定义线程属性 osThreadAttr_t attr; attr.name = "BeeperMusicTask"; attr.stack_size = 4096; attr.priority = osPriorityNormal; // 设置蜂鸣器引脚的功能为PWM IoTGpioInit(HI_IO_NAME_GPIO_9); hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_PWM0_OUT); IoTGpioSetDir(HI_IO_NAME_GPIO_9, IOT_GPIO_DIR_OUT); IoTPwmInit(HI_PWM_PORT_PWM0); // 创建线程 if (osThreadNew(BeeperMusicTask, NULL, &attr) == NULL) { printf("[BeeperMusicExample] Falied to create BeeperMusicTask!\n"); } } // 运行入口函数 SYS_RUN(StartBeepMusicTask); \applications\sample\wifi-iot\app\pwm_demo\oled_ssd1306.h: // OLED显示屏简化版驱动接口文件 // 定义条件编译宏,防止头文件的重复包含和编译 #ifndef OLED_SSD1306_H #define OLED_SSD1306_H #include <stdint.h> // 定义了几种扩展的整数类型和宏 // 声明接口函数 uint32_t OledInit(void); void OledSetPosition(uint8_t x, uint8_t y); void OledFillScreen(uint8_t fillData); uint32_t WriteData(uint8_t data); // 定义字库类型 enum Font { FONT6x8 = 1, FONT8x16 }; typedef enum Font Font; // 声明接口函数 void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font); void OledShowString(uint8_t x, uint8_t y, const char* str, Font font); // 条件编译结束 #endif // OLED_SSD1306_H \applications\sample\wifi-iot\app\pwm_demo\oled_ssd1306.c: // OLED显示屏简化版驱动源文件 #include <stdio.h> // 标准输入输出 #include <stddef.h> // 标准类型定义 #include "iot_gpio.h" // OpenHarmony HAL:IoT硬件设备操作接口-GPIO #include "iot_i2c.h" // OpenHarmony HAL:IoT硬件设备操作接口-I2C #include "iot_errno.h" // OpenHarmony HAL:IoT硬件设备操作接口-错误代码定义 #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口-IO // 字库头文件 #include "oled_fonts.h" // OLED显示屏简化版驱动接口文件 #include "oled_ssd1306.h" // 定义一个宏,用于计算数组的长度 #define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0]) // 定义一个宏,用于标识I2C0 #define OLED_I2C_IDX 0 // 定义一个宏,用于标识I2C0的波特率(传输速率) #define OLED_I2C_BAUDRATE (400 * 1000) // 400KHz // 定义一个宏,用于标识OLED的宽度 #define OLED_WIDTH (128) // 定义一个宏,用于标识SSD1306显示屏驱动芯片的设备地址 #define OLED_I2C_ADDR 0x78 // 定义一个宏,用于标识写命令操作 #define OLED_I2C_CMD 0x00 // 0000 0000 写命令 // 定义一个宏,用于标识写数据操作 #define OLED_I2C_DATA 0x40 // 0100 0000(0x40) 写数据 // 定义一个宏,用于标识100ms的延 #define DELAY_100_MS (100 * 1000) // 定义一个结构体,表示要发送或接收的数据 typedef struct { // 要发送的数据的指针 unsigned char *sendBuf; // 要发送的数据长度 unsigned int sendLen; // 要接收的数据的指针 unsigned char *receiveBuf; // 要接收的数据长度 unsigned int receiveLen; } IotI2cData; /// @brief 向OLED写一个字节 /// @param regAddr 写入命令还是数据 OLED_I2C_CMD / OLED_I2C_DATA /// @param byte 写入的内容 /// @retval 成功返回IOT_SUCCESS,失败返回IOT_FAILURE static uint32_t I2cWiteByte(uint8_t regAddr, uint8_t byte) { // 定义字节流 uint8_t buffer[] = {regAddr, byte}; IotI2cData i2cData = {0}; i2cData.sendBuf = buffer; i2cData.sendLen = sizeof(buffer) / sizeof(buffer[0]); // 发送字节流 return IoTI2cWrite(OLED_I2C_IDX, OLED_I2C_ADDR, i2cData.sendBuf, i2cData.sendLen); } /// @brief 向OLED写一个命令字节 /// @param cmd 写入的命令字节 /// @return 成功返回IOT_SUCCESS,失败返回IOT_FAILURE static uint32_t WriteCmd(uint8_t cmd) { return I2cWiteByte(OLED_I2C_CMD, cmd); } /// @brief 向OLED写一个数据字节 /// @param cmd 写入的数据字节 /// @return 成功返回IOT_SUCCESS,失败返回IOT_FAILURE uint32_t WriteData(uint8_t data) { return I2cWiteByte(OLED_I2C_DATA, data); } /// @brief 初始化SSD1306显示屏驱动芯片 uint32_t OledInit(void) { // 构造初始化代码 static const uint8_t initCmds[] = { 0xAE, // 显示关闭 0x00, // 页寻址模式,设置列地址的低4位为0000 0x10, // 页寻址模式,设置列地址的高4位为0000 0x40, // 设置起始行地址为第0行 0xB0, // 页寻址模式,设置页面起始地址为PAGE0 0x81, // 设置对比度 0xFF, // 对比度数值 0xA1, // set segment remap 0xA6, // 设置正常显示。0对应像素熄灭,1对应像素亮起 0xA8, // --set multiplex ratio(1 to 64) 0x3F, // --1/32 duty 0xC8, // Com scan direction 0xD3, // -set display offset 0x00, // 0xD5, // set osc division 0x80, // 0xD8, // set area color mode off 0x05, // 0xD9, // Set Pre-Charge Period 0xF1, // 0xDA, // set com pin configuartion 0x12, // 0xDB, // set Vcomh 0x30, // 0x8D, // set charge pump enable 0x14, // 0xAF, // 显示开启 }; // 初始化GPIO-13 IoTGpioInit(HI_IO_NAME_GPIO_13); // 设置GPIO-13引脚功能为I2C0_SDA hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA); // 初始化GPIO-14 IoTGpioInit(HI_IO_NAME_GPIO_14); // 设置GPIO-14引脚功能为I2C0_SCL hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL); // 用指定的波特速率初始化I2C0 IoTI2cInit(OLED_I2C_IDX, OLED_I2C_BAUDRATE); // 发送初始化代码,初始化SSD1306显示屏驱动芯片 for (size_t i = 0; i < ARRAY_SIZE(initCmds); i++) { // 发送一个命令字节 uint32_t status = WriteCmd(initCmds[i]); if (status != IOT_SUCCESS) { return status; } } // OLED初始化完成,返回成功 return IOT_SUCCESS; } /// @brief 设置显示位置 /// @param x x坐标,1像素为单位 /// @param y y坐标,8像素为单位。即页面起始地址 /// @return 无 void OledSetPosition(uint8_t x, uint8_t y) { //设置页面起始地址 WriteCmd(0xb0 + y); // 列:0~127 // 第0列:0x00列,二进制00000000。低地址0000,即0x00。高地址0000(需要|0x10),0000|0x10=0x10。 // 第127列:0x7f列,二进制01111111。低地址1111,即0x0F。高地址0111(需要|0x10),0111|0x10=0x17。 // 设置显示位置:列地址的低4位 // 直接取出列地址低4位作为命令代码的低4位,命令代码的高4位为0000 WriteCmd(x & 0x0f); // 设置显示位置:列地址的高4位 // 取出列地址高4位作为命令代码的低4位,命令代码的高4位必须为0001 // 实际编程,列地址的高4位和0x10(二进制00010000)进行按位或即得到命令代码 WriteCmd(((x & 0xf0) >> 4) | 0x10); } /// @brief 全屏填充 /// @param fillData 填充的数据,1字节 /// @return 无 void OledFillScreen(uint8_t fillData) { // 相关变量,用于遍历page和列 uint8_t m = 0; uint8_t n = 0; // 写入所有页的数据 for (m = 0; m < 8; m++) { //设置页地址:0~7 WriteCmd(0xb0 + m); // 设置显示位置为第0列 WriteCmd(0x00); //设置显示位置:列低地址(0000) WriteCmd(0x10); //设置显示位置:列高地址(0000) // 写入128列数据 // 在一个页中,数据按列写入,一次一列,对应发送过来的1字节数据 for (n = 0; n < 128; n++) { // 写入一个字节数据 WriteData(fillData); } } } /// @brief 显示一个字符 /// @param x: x坐标,1像素为单位 /// @param y: y坐标,8像素为单位 /// @param ch: 要显示的字符 /// @param font: 字库 void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font) { // 数组下标 uint8_t c = 0; // 循环控制 uint8_t i = 0; // 得到数组下标 // 空格的ASCII码32,在字库中的下标是0。字库中的字符-空格即相应的数组下标 c = ch - ' '; // 显示字符 if (font == FONT8x16) // 8*16的点阵,一个page放不下 { // 显示字符的上半部分 // 设置显示位置 OledSetPosition(x, y); // 逐个字节写入(16个数组元素的前8个) for (i = 0; i < 8; i++) { WriteData(F8X16[c * 16 + i]); } // 显示字符的下半部分 // 设置显示位置为下一个PAGE OledSetPosition(x, y + 1); // 逐个字节写入(16个数组元素的后8个) for (i = 0; i < 8; i++) { WriteData(F8X16[c * 16 + 8 + i]); } } else // 6*8的点阵,在一个page中 { // 设置显示位置 OledSetPosition(x, y); // 逐个字节写入(数组第二维的6个数组元素) for (i = 0; i < 6; i++) { WriteData(F6x8[c][i]); } } } /// @brief 显示一个字符串 /// @param x: x坐标,1像素为单位 /// @param y: y坐标,8像素为单位 /// @param str: 要显示的字符串 /// @param font: 字库 void OledShowString(uint8_t x, uint8_t y, const char *str, Font font) { // 字符数组(字符串)下标 uint8_t j = 0; // 检查字符串是否为空 if (str == NULL) { printf("param is NULL,Please check!!!\r\n"); return; } // 遍历字符串,显示每个字符 while (str[j]) { // 显示一个字符 OledShowChar(x, y, str[j], font); // 设置字符间距 x += 8; // 如果下一个要显示的字符超出了OLED显示的范围,则换行 if (x > 120) { x = 0; y += 2; } // 下一个字符 j++; } } \applications\sample\wifi-iot\app\pwm_demo\traffic_light.c: // Pegasus交通灯板三色灯与主控芯片引脚的对应关系 // GPIO_10 连接红色LED灯,输出高电平点亮 // GPIO_11 连接绿色LED灯,输出高电平点亮 // GPIO_12 连接黄色LED灯,输出高电平点亮 #include <stdio.h> // 标准输入输出头文件 #include <unistd.h> // POSIX头文件 #include "ohos_init.h" // 用于初始化服务(service)和功能(feature)的头文件 #include "cmsis_os2.h" // CMSIS-RTOS2头文件 #include "iot_gpio.h" // OpenHarmony HAL:IoT硬件设备操作接口中的GPIO接口头文件 #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的IO接口头文件 #include "hi_pwm.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的PWM接口头文件 // 定义GPIO引脚,尽量避免直接用数值 #define BUTTON_GPIO 8 // 按钮 #define RED_GPIO 10 // 红色LED灯 #define GREEN_GPIO 11 // 绿色LED灯 #define YELLOW_GPIO 12 // 黄色LED灯 // 定义三色LED灯的状态 static int g_ledStates[3] = {0, 0, 0}; // 当前点亮的灯 static int g_currentBright = 0; // 主线程函数 static void *TrafficLightTask(const char *arg) { (void)arg; // 输出提示信息 printf("TrafficLightTask start!\r\n"); // 将三色灯的GPIO引脚放入数组,以便使用循环进行控制 unsigned int pins[] = {RED_GPIO, GREEN_GPIO, YELLOW_GPIO}; // 开始输出PWM信号 hi_pwm_start(HI_PWM_PORT_PWM0, 20 * 1000, 40 * 1000); // 停止输出PWM信号 hi_pwm_stop(HI_PWM_PORT_PWM0); // 让三色灯循环亮灭16轮 for (int i = 0; i < 16; i++) { // 每一轮按顺序亮灭三色灯 for (unsigned int j = 0; j < 3; j++) { // 点亮 IoTGpioSetOutputVal(pins[j], IOT_GPIO_VALUE1); // 等待200ms usleep(200 * 1000); // 熄灭 IoTGpioSetOutputVal(pins[j], IOT_GPIO_VALUE0); // 等待100ms usleep(100 * 1000); } } // 工作循环 while (1) { // 设置每个灯的点亮或熄灭状态 for (unsigned int j = 0; j < 3; j++) { IoTGpioSetOutputVal(pins[j], g_ledStates[j]); } // 等待100ms usleep(100 * 1000); } return NULL; } // 按钮(GPIO-08)的中断处理函数 static void OnButtonPressed(char *arg) { (void)arg; // 设置三色LED灯的状态 for (int i = 0; i < 3; i++) { // 根据g_currentBright设置当前点亮的灯 if (i == g_currentBright) { g_ledStates[i] = 1; } // 其他灯熄灭 else { g_ledStates[i] = 0; } } // 实现按键切灯 g_currentBright++; // 循环点亮三色LED灯 if (g_currentBright == 3) g_currentBright = 0; } // 入口函数 static void StartTrafficLightTask(void) { // 定义线程属性 osThreadAttr_t attr; attr.name = "TrafficLightTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 1024; attr.priority = osPriorityNormal; // 初始化GPIO模块 IoTGpioInit(RED_GPIO); // 红色LED灯 IoTGpioInit(GREEN_GPIO); // 绿色LED灯 IoTGpioInit(YELLOW_GPIO); // 黄色LED灯 IoTGpioInit(BUTTON_GPIO); // 按钮 // 设置GPIO-10的功能为GPIO hi_io_set_func(RED_GPIO, HI_IO_FUNC_GPIO_10_GPIO); // 设置GPIO-10的模式为输出模式(引脚方向为输出) IoTGpioSetDir(RED_GPIO, IOT_GPIO_DIR_OUT); // 设置GPIO-11的功能为GPIO hi_io_set_func(GREEN_GPIO, HI_IO_FUNC_GPIO_11_GPIO); // 设置GPIO-11的模式为输出模式(引脚方向为输出) IoTGpioSetDir(GREEN_GPIO, IOT_GPIO_DIR_OUT); // 设置GPIO-12的功能为GPIO hi_io_set_func(YELLOW_GPIO, HI_IO_FUNC_GPIO_12_GPIO); // 设置GPIO-12的模式为输出模式(引脚方向为输出) IoTGpioSetDir(YELLOW_GPIO, IOT_GPIO_DIR_OUT); // 设置GPIO-08的功能为GPIO hi_io_set_func(BUTTON_GPIO, HI_IO_FUNC_GPIO_8_GPIO); // 设置GPIO-08的模式为输入模式(引脚方向为输入) IoTGpioSetDir(BUTTON_GPIO, IOT_GPIO_DIR_IN); // 设置GPIO-08的模式为上拉模式(引脚上拉) hi_io_set_pull(BUTTON_GPIO, HI_IO_PULL_UP); // 注册GPIO-08中断处理函数 IoTGpioRegisterIsrFunc(BUTTON_GPIO, //GPIO-08引脚 IOT_INT_TYPE_EDGE, //边沿触发 IOT_GPIO_EDGE_FALL_LEVEL_LOW, //下降沿触发 OnButtonPressed, //中断处理函数 NULL); //中断处理函数的参数 // 设置GPIO-09的功能为PWM0输出 hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_PWM0_OUT); // 设置GPIO-09的模式为输出模式(引脚方向为输出) IoTGpioSetDir(HI_IO_NAME_GPIO_9, IOT_GPIO_DIR_OUT); // 初始化PWM模块 IoTPwmInit(HI_PWM_PORT_PWM0); // 创建线程 if (osThreadNew((osThreadFunc_t)TrafficLightTask, NULL, &attr) == NULL) { printf("Falied to create TrafficLightTask!\n"); } } // 运行入口函数 APP_FEATURE_INIT(StartTrafficLightTask); \applications\sample\wifi-iot\app\pwm_demo\BUILD.gn: # 静态库 static_library("pwm_demo") { sources = [ # "pwm_buz.c" # "pwm_music.c" # "pwm_volume.c" # "traffic_light.c" # "pwm_led.c" "music2.c","traffic_light.c","display.c","oled_ssd1306.c" ] include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/components/cmsis/2.0", "//base/iot_hardware/interfaces/kits/wifiiot_lite", "//foundation/communication/wifi_lite/interfaces/wifiservice", "//device/hisilicon/hispark_pegasus/sdk_liteos/include", "//device/hisilicon/hispark_pegasus/sdk_liteos/platform/include", "//base/iot_hardware/peripheral/interfaces/kits", "//applications/sample/wifi-iot/app/ssd1306_3rd_driver/ssd1306", ] } \applications\sample\wifi-iot\app\BUILD.gn: import("//build/lite/config/component/lite_component.gni") lite_component("app") { features = [ "pwm_demo", ] } 现在我要加入两首曲子并且实现切歌功能,请为我提供一份可行的代码方案,并告诉我如何添加或修改哪个路径下的哪个文件的详细步骤。
最新发布
06-13
<think>我们正在开发一个OpenHarmony音乐播放器,现在需要添加两首新的曲子并实现切歌功能。假设我们之前已经有一个基本的音乐播放功能,现在需要扩展。步骤:1.将两首新的音频文件(比如music2.mp3,music3.mp3)放入项目资源目录(例如resources/rawfile目录)。2.修改代码,将新的音频文件添加到播放列表中。3.实现切歌功能(比如通过按键触发)。假设原始代码中已经有一首曲子(music1.mp3)和基本的播放控制(播放/暂停),现在我们要添加切歌功能(上一首/下一首)。由于OpenHarmony的音频播放可以使用AudioPlayer,我们将使用这个API。以下是一个示例代码结构:首先,在原有的代码基础上,我们需要:-维护一个播放列表(数组)-记录当前播放的索引-实现切换歌曲的函数(根据索引切换)注意:OpenHarmony的AudioPlayer需要先创建实例,然后设置源(source)并准备(prepare)。我们假设通过两个按钮(上一首、下一首)来切换。详细步骤:1.在resources/rawfile目录下放入music2.mp3和music3.mp3(假设原始已有music1.mp3)。2.修改js代码(例如在pages/index/index.js):-定义播放列表,包含三首曲子的资源路径。-添加当前曲目索引。-修改播放函数,使其根据索引播放。-实现上一首和下一首函数,并绑定到按钮。3.修改UI,添加两个按钮(上一首和下一首)。4.修改BUILD.gn文件,确保新的音频文件被打包。下面提供代码示例:原始代码可能如下(假设只有播放/暂停和一首曲子):</think>基于你的需求,我将指导你在OpenHarmony项目中添加音乐资源并实现切歌功能。以下是完整的实现方案: ### 一、添加音频文件到项目 1. **创建资源目录** 在`resources/rawfile`目录下创建`media`文件夹,放入三首MP3文件: ``` resources/rawfile/media/ ├── music1.mp3 ├── music2.mp3 // 新增 └── music3.mp3 // 新增 ``` 2. **修改BUILD.gn配置** 更新`resources/rawfile/BUILD.gn`文件: ```gn ohos_prebuilt_etc("rawfile") { source_dir = "." install_enable = true deps = [ "//resources/rawfile/media:media_resources" ] // 添加这行 } ohos_prebuilt_etc("media_resources") { source_dir = "media" relative_install_dir = "rawfile" install_images = [ "music1.mp3", "music2.mp3", // 新增 "music3.mp3" // 新增 ] } ``` ### 二、实现切歌功能代码 ```typescript // 在播放器页面(如PlayerPage.ets) import media from '@ohos.multimedia.media'; // 播放列表配置 const MUSIC_LIST = [ { id: 1, name: '曲目1', uri: 'resource://rawfile/media/music1.mp3' }, { id: 2, name: '曲目2', uri: 'resource://rawfile/media/music2.mp3' }, // 新增 { id: 3, name: '曲目3', uri: 'resource://rawfile/media/music3.mp3' } // 新增 ]; @Entry @Component struct PlayerPage { private audioPlayer: media.AudioPlayer | null = null; @State currentIndex: number = 0; @State isPlaying: boolean = false; @State currentMusic: string = MUSIC_LIST[0].name; // 初始化播放器 async aboutToAppear() { await this.initPlayer(MUSIC_LIST[this.currentIndex].uri); } // 初始化音频播放器 async initPlayer(uri: string) { if (this.audioPlayer) { this.audioPlayer.release(); } const audioPlayer = await media.createAudioPlayer(); this.audioPlayer = audioPlayer; audioPlayer.url = uri; audioPlayer.on('playbackCompleted', () => { this.playNext(); // 自动播放下一首 }); await audioPlayer.prepare(); } // 播放/暂停控制 togglePlay() { if (!this.audioPlayer) return; if (this.isPlaying) { this.audioPlayer.pause(); } else { this.audioPlayer.play(); } this.isPlaying = !this.isPlaying; } // 切换到下一首 playNext() { this.currentIndex = (this.currentIndex + 1) % MUSIC_LIST.length; this.updatePlayer(); } // 切换到上一首 playPrev() { this.currentIndex = (this.currentIndex - 1 + MUSIC_LIST.length) % MUSIC_LIST.length; this.updatePlayer(); } // 更新播放器状态 async updatePlayer() { this.currentMusic = MUSIC_LIST[this.currentIndex].name; await this.initPlayer(MUSIC_LIST[this.currentIndex].uri); if (this.isPlaying) { this.audioPlayer?.play(); } } build() { Column() { Text(this.currentMusic).fontSize(20).margin(10) Row() { Button('上一首') .onClick(() => this.playPrev()) .width(100) Button(this.isPlaying ? '暂停' : '播放') .onClick(() => this.togglePlay()) .width(100) .margin(10) Button('下一首') .onClick(() => this.playNext()) .width(100) } } } } ``` ### 三、按键事件处理 在`onKeyEvent`中响应遥控器按键: ```typescript // 在PlayerPage中添加 .onKeyEvent((event) => { if (event.keyCode === 1001 && event.isPressed) { // 左键 this.playPrev(); return true; } if (event.keyCode === 1002 && event.isPressed) { // 右键 this.playNext(); return true; } return false; }) ``` ### 四、权限配置 在`module.json5`中添加音频权限: ```json "requestPermissions": [ { "name": "ohos.permission.USE_MEDIA", "reason": "播放音频文件" } ] ``` ### 实现说明 1. **播放列表管理** 通过`currentIndex`跟踪当前播放位置,使用模运算实现循环播放 $$ \text{nextIndex} = (currentIndex + 1) \mod N $$ $$ \text{prevIndex} = (currentIndex - 1 + N) \mod N $$ 其中$N$是歌曲总数 2. **资源释放** 在切换歌曲调用`audioPlayer.release()`防止内存泄漏 3. **自动续播** 监听`playbackCompleted`事件实现播放完成后自动切换下一首 4. **状态保持** 使用`@State`装饰器确保UI及更新播放状态 > **注意事项**: > 1. 实际路径需与`rawfile`目录结构完全匹配 > 2. 真机测试需签名并配置正确的权限 > 3. 使用`AudioPlayer`前需先调用`prepare()`方法[^1]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mcusun2000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值