聚豐項目 > 基于rtt的智能播放器的設計方法
基于rtt的智能播放器,能夠在sd card播放多個音樂,歌曲與歌曲之間的切換,RGB燈實現的閃爍效果。能夠隨著音樂的播放實現燈光同步。
jf_56333662
分享jf_56333662
團隊成員
吳迪 負責人
RT-Thread版本:4.0.3
通過rtt的sd卡接口,放入無損的wav格式音樂。
通過板載的3.5mm耳機口。插入揚聲器
從而實現音樂的輸出。
開啟音樂播放條件
開啟對WAV格式的支持。
開啟對sd卡的支持。
開啟按鈕控制功能
這樣設置好了以后,能夠播放音樂的基本條件就已經實現了。
1.首先查找 Audio 設備獲取設備句柄。
2.以只寫方式打開 Audio 設備。
3.設置音頻參數信息(采樣率、通道等)。
4.解碼音頻文件的數據。
5.寫入音頻文件數據。
6.播放完成,關閉設備。
int wavplayer_play(char *uri);//音樂播放
int wavplayer_stop(void);// 結束播放
int wavplayer_pause(void);//暫停播放
int wavplayer_resume(void):// 繼續播放
int wavplayer_volume_set(int volume);//音量設置
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);
音頻設備的控制方法。
#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);