2534|2

1746

帖子

0

TA的资源

五彩晶圆(初级)

楼主
 

中科蓝讯(AB32VG1)开发板(基于RT-Thread系统)--- 音乐播放器--分享 [复制链接]

 
转自CSDN,原创Bruceoxl 原链接https://bruceou.blog.csdn.net/article/details/116097779?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-4.nonecase

开发环境:
RT-Thread版本:4.0.3
操作系统:Windows 10
RT-Thread Studio版本:2.0.1
开发板MCU:AB5301A

 

6.1前言


在前面几章,我们使用AB32VG1做了几个小实验,本章将前面的内容进行组合,做一个音乐播放器,主要功能如下:

1.可存储多首完整音乐;
2.实现歌曲切换;
3.实现音量调节。

当然,以上是最基本的功能,还可以实现歌曲播放模式的选择。本章内容主要实现以上3个基本功能,另外根据音量的大小来改变RGB灯的闪烁频率,非常的炫酷。
好了,接下来就一起来看看如何实现音乐播放器吧。

6.2音乐播放器配置
整个项目配置分三部分:音频部分,存储与文件系统部分,LED、串口等三部分。
关于项目的创建请参看笔者以前的文章:

AB32VG1新建项目

 

6.2.1音频配置


首先看看音频部分。使能硬件是必不可少的。

使能硬件后,我们就可以使用音频设备了,但是音频设备相对其他外设比较复杂,RT-Thread提供了操作音频设备的软件包WavPlay。只需要使能即可。

值得注意的是,WavPlay软件包依赖optparse,因此optparse软件包在 wavplayer 勾选后,自动选择。optparse模块主要用来为脚本传递命令参数,采用预先定义好的选项来解析命令行参数。

 

6.2.2存储文件系统配置


AB32VG1开发板内部存储很小,而音乐文件很大,因此需要使用外部存储设备来存放音乐,这样,这里使用SD卡来存储音乐。首先就需要使能SD卡设备。

使能SD卡设备后,文件系统也就默认勾选了。

当然也可适当修改里面的参数。

 

6.2.3其他配置


前面两部分是这个项目的重要配置,是不可缺少的,接下来就是配置,PWM、UART、KEY设备。
关于PWM和UART的配置参考笔者前面的文章:

PWM LED使用
UART使用

下面再添加一个按键的功能包即可。

MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,非常好用。

好了,关于音乐播放器的配置就到这里了。

6.3音乐播放器实现
本文将通过按键或者通过串口发送指令来播放音乐、切歌、控制音量等操作,另外根据音量的大小来调节PWM的频率,从而改变RGB灯的闪烁频率。

6.3.1 WavPlay播放音频简析
对于音频设备,其操作流程如下:

1.首先查找 Audio 设备获取设备句柄。
2.以只写方式打开 Audio 设备。
3.设置音频参数信息(采样率、通道等)。
4.解码音频文件的数据。
5.写入音频文件数据。
6.播放完成,关闭设备。

如果自己去实现这些操作还是比较复杂的,wavplayer 软件包将音频设备的操作进行了封装。主需要简单调用几个函数接口播放音乐,主要的接口如下:

int wavplayer_play(char *uri);//音乐播放
int wavplayer_stop(void);// 结束播放
int wavplayer_pause(void);//暂停播放
int wavplayer_resume(void):// 继续播放
int wavplayer_volume_set(int volume);//音量设置

当然啦,这里只讲解应用实现,关于音频驱动请参看官方手册。

AUDIO 设备

 

6.3.2 PWM控制RGB灯


这部分内容在前面的章节已经讲过了,这里就不讲了,代码如下:

  • #include "led_app.h"
  • #define THREAD_PRIORITY 7
  • #define THREAD_STACK_SIZE 512
  • #define THREAD_TIMESLICE 3
  • uint32_t pulse_pulse = 90000;
  • #define PWM_DEV_NAME_R "t5pwm" /* PWM设备名称 */
  • #define PWM_DEV_CHANNEL_R 1 /* PWM通道 */
  • #define PWM_DEV_NAME_G "lpwm0" /* PWM设备名称 */
  • #define PWM_DEV_CHANNEL_G 1 /* PWM通道 */
  • #define PWM_DEV_NAME_B "lpwm2" /* PWM设备名称 */
  • #define PWM_DEV_CHANNEL_B 3 /* PWM通道 */
  • struct rt_device_pwm *pwm_dev_r; /* PWM设备句柄 */
  • struct rt_device_pwm *pwm_dev_g; /* PWM设备句柄 */
  • struct rt_device_pwm *pwm_dev_b; /* PWM设备句柄 */
  • static rt_thread_t pwm_led_tid = RT_NULL;
  • /* 线程 pwm_led_thread_entry 的入口函数 */
  • /**
  • * @brief pwm_led_thread_entry
  • * @param parameter
  • * @retval None
  • */
  • static void pwm_led_thread_entry(void *parameter)
  • {
  • rt_uint32_t period, pulse_r,pulse_g,pulse_b, dir_r,dir_g,dir_b;
  • period = 655360; /* 周期为0.5ms,单位为纳秒ns */
  • dir_r = 1; /* PWM脉冲宽度值的增减方向 */
  • dir_g = 1;
  • dir_b = 1;
  • pulse_r = 0; /* PWM脉冲宽度值,单位为纳秒ns */
  • pulse_g = 0;
  • pulse_b = 0;
  • rt_uint16_t r,g,b;
  • /* 查找设备 */
  • pwm_dev_r = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME_R);
  • if (pwm_dev_r == RT_NULL)
  • {
  • rt_kprintf("pwm led r run failed! can't find %s device!\n", PWM_DEV_NAME_G);
  • }
  • pwm_dev_g = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME_G);
  • if (pwm_dev_g == RT_NULL)
  • {
  • rt_kprintf("pwm led g run failed! can't find %s device!\n", PWM_DEV_NAME_G);
  • }
  • pwm_dev_b = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME_B);
  • if (pwm_dev_b == RT_NULL)
  • {
  • rt_kprintf("pwm led b run failed! can't find %s device!\n", PWM_DEV_NAME_B);
  • }
  • /* 设置PWM周期和脉冲宽度默认值 */
  • rt_pwm_set(pwm_dev_r, PWM_DEV_CHANNEL_R, period, pulse_r);
  • rt_pwm_set(pwm_dev_g, PWM_DEV_CHANNEL_G, period, pulse_g);
  • rt_pwm_set(pwm_dev_b, PWM_DEV_CHANNEL_B, period, pulse_b);
  • /* 使能设备 */
  • rt_pwm_enable(pwm_dev_r, PWM_DEV_CHANNEL_R);
  • rt_pwm_enable(pwm_dev_g, PWM_DEV_CHANNEL_G);
  • rt_pwm_enable(pwm_dev_b, PWM_DEV_CHANNEL_B);
  • while (1)
  • {
  • for (r =0 ; r < 8; r++)
  • {
  • if (dir_r)
  • {
  • pulse_r += pulse_pulse; /* 从0值开始每次增加5000ns */
  • }
  • else
  • {
  • pulse_r -= pulse_pulse; /* 从最大值开始每次减少5000ns */
  • }
  • if ((pulse_r) >= period)
  • {
  • dir_r = 0;
  • }
  • if (81920 > pulse_r)
  • {
  • dir_r = 1;
  • }
  • /* 设置PWM周期和脉冲宽度 */
  • rt_pwm_set(pwm_dev_r, PWM_DEV_CHANNEL_R, period, pulse_r);
  • for(g = 0; g < 8; g++)
  • {
  • if (dir_g)
  • {
  • pulse_g += pulse_pulse; /* 从0值开始每次增加5000ns */
  • }
  • else
  • {
  • pulse_g -= pulse_pulse; /* 从最大值开始每次减少5000ns */
  • }
  • if ((pulse_g) >= period)
  • {
  • dir_g = 0;
  • }
  • if (81920 > pulse_g)
  • {
  • dir_g = 1;
  • }
  • rt_pwm_set(pwm_dev_g, PWM_DEV_CHANNEL_G, period, pulse_g);
  • for(b = 0; b < 8; b++)
  • {
  • rt_thread_mdelay(10);
  • if (dir_b)
  • {
  • pulse_b += pulse_pulse; /* 从0值开始每次增加5000ns */
  • }
  • else
  • {
  • pulse_b -= pulse_pulse; /* 从最大值开始每次减少5000ns */
  • }
  • if ((pulse_b) >= period)
  • {
  • dir_b = 0;
  • }
  • if (81920 > pulse_b)
  • {
  • dir_b = 1;
  • }
  • rt_pwm_set(pwm_dev_b, PWM_DEV_CHANNEL_B, period, pulse_b);
  • }
  • }
  • }
  • }
  • }
  • /* 线程初始化*/
  • int pwm_led(void)
  • {
  • /* 创建线程,名称是 pwm_led_thread,入口是 pwm_led_thread*/
  • pwm_led_tid = rt_thread_create("pwm_led_thread",
  • pwm_led_thread_entry,
  • RT_NULL,
  • THREAD_STACK_SIZE,
  • THREAD_PRIORITY,
  • THREAD_TIMESLICE);
  • /* 如果获得线程控制块,启动这个线程 */
  • if (pwm_led_tid != RT_NULL)
  • rt_thread_startup(pwm_led_tid);
  • return 0;
  • }
  • /* 导出到 msh 命令列表中 */
  • //MSH_CMD_EXPORT(pwm_led, pwm led);
  • INIT_APP_EXPORT(pwm_led);

 

6.3.3串口控制音频设备

 

下面先看看UART播放音乐的代码。
 

  • #include "uart_app.h"
  • #include "key_app.h"
  • #include "led_app.h"
  • #define SAMPLE_UART_NAME "uart1"
  • uint8_t ch;
  • uint8_t r_index = 0;
  • uint8_t flag = 0;
  • extern uint32_t cnt_music;
  • extern uint32_t cnt_channels;
  • extern uint32_t cnt_volume;
  • extern uint32_t start_flag;
  • extern char *table[NUM_OF_SONGS];
  • extern uint32_t pulse_pulse;
  • struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置参数 */
  • /* 用于接收消息的信号量 */
  • static struct rt_semaphore rx_sem;
  • static rt_device_t serial;
  • void analyticald_data(void)
  • {
  • uint8_t sum;
  • if(ch == 0x01)
  • {
  • wavplayer_play(table[(cnt_music++) % NUM_OF_SONGS]);
  • }
  • else if(ch == 0x02)
  • {
  • if (cnt_volume < 11 )
  • {
  • if(start_flag)
  • {
  • start_flag = 0;
  • cnt_volume = (int)saia_volume_get()/10;
  • pulse_pulse = 9000;
  • }
  • else
  • {
  • saia_volume_set(cnt_volume * 10);
  • pulse_pulse = cnt_volume*9000;
  • }
  • }
  • else
  • {
  • saia_volume_set(10);
  • cnt_volume = 1;
  • rt_kprintf("The volume has been adjusted to maximum\n");
  • }
  • cnt_volume ++;
  • rt_kprintf("vol=%d\n", saia_volume_get());
  • }
  • else if(ch == 0x03)
  • {
  • if (cnt_channels < 3)
  • {
  • saia_channels_set(cnt_channels);
  • }
  • else
  • {
  • saia_channels_set(cnt_channels);
  • cnt_channels = 1;
  • }
  • cnt_channels++;
  • }
  • }
  • /* 接收数据回调函数 */
  • static rt_err_t uart_rx_ind(rt_device_t dev, rt_size_t size)
  • {
  • /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
  • if (size > 0)
  • {
  • rt_sem_release(&rx_sem);
  • }
  • return RT_EOK;
  • }
  • static char uart_sample_get_char(void)
  • {
  • uint8_t ch;
  • while (rt_device_read(serial, 0, &ch, 1) == 0)
  • {
  • rt_sem_control(&rx_sem, RT_IPC_CMD_RESET, RT_NULL);
  • rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
  • }
  • return ch;
  • }
  • /* 数据解析线程 */
  • static void data_parsing(void)
  • {
  • while (1)
  • {
  • ch = uart_sample_get_char();
  • flag = 1;
  • }
  • }
  • int uart_init(void)
  • {
  • rt_err_t ret = RT_EOK;
  • char uart_name[RT_NAME_MAX];
  • //char str[] = "hello RT-Thread!\r\n";
  • rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
  • /* 查找系统中的串口设备 */
  • serial = rt_device_find(uart_name);
  • if (!serial)
  • {
  • rt_kprintf("find %s failed!\n", uart_name);
  • return RT_ERROR;
  • }
  • /* step2:修改串口配置参数 */
  • config.baud_rate = BAUD_RATE_9600; //修改波特率为9600
  • config.data_bits = DATA_BITS_8; //数据位 8
  • config.stop_bits = STOP_BITS_1; //停止位 1
  • config.bufsz = 128; //修改缓冲区 buff size 为 128
  • config.parity = PARITY_NONE; //无奇偶校验位
  • /* step3:控制串口设备。通过控制接口传入命令控制字,与控制参数 */
  • rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
  • /* 初始化信号量 */
  • rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
  • /* 以中断接收及轮询发送模式打开串口设备 */
  • rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
  • /* 设置接收回调函数 */
  • rt_device_set_rx_indicate(serial, uart_rx_ind);
  • /* 发送字符串 */
  • //rt_device_write(serial, 0, str, (sizeof(str) - 1));
  • /* 创建 serial 线程 */
  • rt_thread_t thread = rt_thread_create("serial", (void (*)(void *parameter))data_parsing, RT_NULL, 2048, 5, 5);
  • /* 创建成功则启动线程 */
  • if (thread != RT_NULL)
  • {
  • rt_thread_startup(thread);
  • }
  • else
  • {
  • ret = RT_ERROR;
  • }
  • return ret;
  • }
  • /* 导出到 msh 命令列表中 */
  • MSH_CMD_EXPORT(uart_init, uart device sample);
  • #define THREAD_PRIORITY 9
  • #define THREAD_TIMESLICE 5
  • #define EVENT_FLAG (1 << 3)
  • /* 事件控制块 */
  • static struct rt_event event;
  • ALIGN(RT_ALIGN_SIZE)
  • /* 线程 1 入口函数 */
  • static void thread1_recv_event(void *param)
  • {
  • rt_uint32_t e;
  • while(1)
  • {
  • /* 第一次接收事件,事件 3 或事件 5 任意一个可以触发线程 1,接收完后清除事件标志 */
  • if (rt_event_recv(&event, (EVENT_FLAG ),
  • RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  • RT_WAITING_FOREVER, &e) == RT_EOK)
  • {
  • rt_kprintf("thread1: recv event 0x%x\n", e);
  • analyticald_data();
  • rt_kprintf("thread1: delay 1s to prepare the second event\n");
  • }
  • rt_thread_mdelay(100);
  • }
  • }
  • ALIGN(RT_ALIGN_SIZE)
  • /* 线程 2 入口 */
  • static void thread2_send_event(void *param)
  • {
  • while(1)
  • {
  • if(flag==1)
  • {
  • flag = 0;
  • rt_kprintf("thread2: send event\n");
  • rt_event_send(&event, EVENT_FLAG);
  • }
  • rt_thread_mdelay(200);
  • }
  • }
  • int event_wavplayer(void)
  • {
  • rt_err_t result;
  • /* 初始化事件对象 */
  • result = rt_event_init(&event, "event", RT_IPC_FLAG_FIFO);
  • if (result != RT_EOK)
  • {
  • rt_kprintf("init event failed.\n");
  • return -1;
  • }
  • rt_thread_t thread1 = rt_thread_create("serial", thread1_recv_event, RT_NULL, 512, 10, 5);
  • rt_thread_startup(thread1);
  • rt_thread_t thread2 = rt_thread_create("serial", thread2_send_event, RT_NULL, 512, 9, 5);
  • rt_thread_startup(thread2);
  • return 0;
  • }
  • /* 导出到 msh 命令列表中 */
  • //MSH_CMD_EXPORT(event_wavplayer, event sample);
  • INIT_APP_EXPORT(event_wavplayer);

代码还是比较简单的,有两部分内容,一部分是是串口的操作,另一部分是串口数据的解析事件,当串口收到指令后,event_wavplayer解析串口的指令,根据相应的指令来操作音频设备。串口指令如下:

 

6.3.4按键控制音频设备


这里使用MultiButton软件包,代码如下:

  • #include "key_app.h"
  • #include "led_app.h"
  • extern uint32_t pulse_pulse;
  • #define BUTTON_PIN_0 rt_pin_get("PF.0")
  • #define BUTTON_PIN_1 rt_pin_get("PF.1")
  • static struct button btn_0;
  • static struct button btn_1;
  • uint32_t cnt_channels = 1;
  • uint32_t cnt_volume = 1;
  • uint32_t cnt_music = 0;
  • uint32_t start_flag = 1;
  • char *table[NUM_OF_SONGS] =
  • {
  • "/Try.wav",
  • "/Bad.wav",
  • };
  • static uint8_t button_read_pin_0(void)
  • {
  • return rt_pin_read(BUTTON_PIN_0);
  • }
  • static uint8_t button_read_pin_1(void)
  • {
  • return rt_pin_read(BUTTON_PIN_1);
  • }
  • static void button_0_callback(void *btn)
  • {
  • uint32_t btn_event_val;
  • btn_event_val = get_button_event((struct button *)btn);
  • switch(btn_event_val)
  • {
  • case SINGLE_CLICK:
  • if (cnt_volume < 11 )
  • {
  • if(start_flag)
  • {
  • start_flag = 0;
  • cnt_volume = (int)saia_volume_get()/10;
  • pulse_pulse = 9000;
  • }
  • else
  • {
  • saia_volume_set(cnt_volume * 10);
  • pulse_pulse = cnt_volume*9000;
  • }
  • }
  • else
  • {
  • saia_volume_set(10);
  • cnt_volume = 1;
  • rt_kprintf("The volume has been adjusted to maximum\n");
  • }
  • cnt_volume ++;
  • rt_kprintf("vol=%d\n", saia_volume_get());
  • rt_kprintf("button 0 single click\n");
  • break;
  • case DOUBLE_CLICK:
  • if (cnt_channels < 3)
  • {
  • saia_channels_set(cnt_channels);
  • }
  • else
  • {
  • saia_channels_set(cnt_channels);
  • cnt_channels = 1;
  • }
  • cnt_channels++;
  • rt_kprintf("button 0 double click\n");
  • break;
  • case LONG_PRESS_START:
  • rt_kprintf("button 0 long press start\n");
  • break;
  • case LONG_PRESS_HOLD:
  • rt_kprintf("button 0 long press hold\n");
  • break;
  • }
  • }
  • static void button_1_callback(void *btn)
  • {
  • uint32_t btn_event_val;
  • btn_event_val = get_button_event((struct button *)btn);
  • switch(btn_event_val)
  • {
  • case SINGLE_CLICK:
  • wavplayer_play(table[(cnt_music++) % NUM_OF_SONGS]);
  • rt_kprintf("button 1 single click\n");
  • break;
  • case DOUBLE_CLICK:
  • rt_kprintf("button 1 double click\n");
  • break;
  • case LONG_PRESS_START:
  • rt_kprintf("button 1 long press start\n");
  • break;
  • case LONG_PRESS_HOLD:
  • rt_kprintf("button 1 long press hold\n");
  • break;
  • }
  • }
  • static void btn_thread_entry(void* p)
  • {
  • while(1)
  • {
  • /* 5ms */
  • rt_thread_delay(RT_TICK_PER_SECOND/200);
  • button_ticks();
  • }
  • }
  • static int multi_button_wavplayer(void)
  • {
  • rt_thread_t thread = RT_NULL;
  • /* Create background ticks thread */
  • thread = rt_thread_create("btn", btn_thread_entry, RT_NULL, 512, 10, 10);
  • if(thread == RT_NULL)
  • {
  • return RT_ERROR;
  • }
  • rt_thread_startup(thread);
  • /* low level drive */
  • rt_pin_mode (BUTTON_PIN_0, PIN_MODE_INPUT_PULLUP);
  • button_init (&btn_0, button_read_pin_0, PIN_LOW);
  • button_attach(&btn_0, SINGLE_CLICK, button_0_callback);
  • button_attach(&btn_0, DOUBLE_CLICK, button_0_callback);
  • button_attach(&btn_0, LONG_PRESS_START, button_0_callback);
  • button_attach(&btn_0, LONG_PRESS_HOLD, button_0_callback);
  • button_start (&btn_0);
  • rt_pin_mode (BUTTON_PIN_1, PIN_MODE_INPUT_PULLUP);
  • button_init (&btn_1, button_read_pin_1, PIN_LOW);
  • button_attach(&btn_1, SINGLE_CLICK, button_1_callback);
  • button_attach(&btn_1, DOUBLE_CLICK, button_1_callback);
  • button_attach(&btn_1, LONG_PRESS_START, button_1_callback);
  • button_attach(&btn_1, LONG_PRESS_HOLD, button_1_callback);
  • button_start (&btn_1);
  • return RT_EOK;
  • }
  • MSH_CMD_EXPORT(multi_button_wavplayer, button wavplayer)

按键控制和串口控制差不多,只是按键有限,控制的内容就相对串口少。

SD设备没啥好讲的,值得注意的是,如果没有自动挂载设备,需要在手动挂载SD卡设备,自动挂载的代码如下:

  • #include <rtthread.h>
  • #ifdef BSP_USING_SDIO
  • #include <dfs_elm.h>
  • #include <dfs_fs.h>
  • #include <dfs_posix.h>
  • #include "drv_gpio.h"
  • // #define DRV_DEBUG
  • #define DBG_TAG "app.card"
  • #include <rtdbg.h>
  • void sd_mount(void *parameter)
  • {
  • while (1)
  • {
  • rt_thread_mdelay(500);
  • if(rt_device_find("sd0") != RT_NULL)
  • {
  • if (dfs_mount("sd0", "/", "elm", 0, 0) == RT_EOK)
  • {
  • LOG_I("sd card mount to '/'");
  • break;
  • }
  • else
  • {
  • LOG_W("sd card mount to '/' failed!");
  • }
  • }
  • }
  • }
  • int ab32_sdcard_mount(void)
  • {
  • rt_thread_t tid;
  • tid = rt_thread_create("sd_mount", sd_mount, RT_NULL,
  • 1024, RT_THREAD_PRIORITY_MAX - 2, 20);
  • if (tid != RT_NULL)
  • {
  • rt_thread_startup(tid);
  • }
  • else
  • {
  • LOG_E("create sd_mount thread err!");
  • }
  • return RT_EOK;
  • }
  • INIT_APP_EXPORT(ab32_sdcard_mount);
  • #endif

好了,音乐播放器的实现代码就这些了,完整代码请根据后文提示获取。

 

6.4功能演示


首先,需要将普通的音乐文件转换成wav格式。推荐的软件是GoldWave。转换完成后,将音乐放入SD卡,将SD卡插入板子,接下来演示音乐播放。

 

值得注意的是,需用跳线帽连接 J6、J7、J9、J11,SD卡方可使用。

 

6.5总结


本文的音乐播放器只是抛砖引玉,改进的地方还很多,还需改进的地方如下:

1.播放模式改进,比如顺序播放、随机播放、单曲循环;
2.控制方式改进,可外接无线设备,当然也可使用板载蓝牙来控制音乐的播放;
3.音乐文件获取,如果有网络,还可播放网络上的音乐,这样播放的音乐就能多样多化。

总的来说,音乐播放器的应用还是比较简单的,当时音频驱动、SD卡的驱动以及文件系统的底层逻辑还是比较复杂的,有兴趣的可以深入去研究。

最新回复

hey can you plese help me in setting up the RT thread Studio IDE because when ever i try to set up the default code it self gives me errors of utest why d this happen i dont know please help me friend iam wating for you [attach]896774[/attach]     详情 回复 发表于 2025-3-19 10:32

赞赏

1

查看全部赞赏

点赞(1) 关注
 
 

回复
举报

1930

帖子

3

TA的资源

版主

沙发
 

要是有视频就好了~还能听听音质~

 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

hey can you plese help me in setting up the RT thread Studio IDE because when ever i try to set up the default code it self gives me errors of utest why d this happen i dont know please help me friend
iam wating for you

 

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
有奖直播:当AI遇见仿真,会有什么样的电子行业革新之路?
首场直播:Simcenter AI 赋能电子行业研发创新
直播时间:04月15日14:00-14:50

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 9

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表