通过ESP8266模块与JQ8900模块与RTT实现手机远程控制音乐播放

本例程是一个简单的串口通信的交互例程,通过了RT-thread系统来实现。

简要叙述程序思路:
  1. 创建两个进程句柄,serial与serial2。
  2. 调用一系列初始化串口设备的函数,分别是rt_device_find(查找设备),rt_device_set_rx_indicate(设置接收回调函数)。
  3. 启动线程,调用函数并检测接受到的信息
  4. 接收到对应信息后调用函数向JQ8900模块发送命令
  5. 同时保留了按钮操控的效果,通过rt_pin_attach_irq设置按钮中断函数

以下给出源码:

/*
基于RTT的手机通过esp8266操作JQ8900功放模块的一种方式
所用开发板 野火指南者
WiFi模块   ESP8266
功放模块   JQ8900
RTT版本    4.0.2(野火BSP)
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#ifndef KEY0_PIN_NUM
    #define KEY0_PIN_NUM      GET_PIN(A, 0) /* PA0 Key1 pin脚*/
#endif
#ifndef KEY1_PIN_NUM
    #define KEY1_PIN_NUM      GET_PIN(C, 13) /* PC13 Key2 pin脚*/
#endif
#ifndef SAMPLE_UART_NAME
#define SAMPLE_UART_NAME       "uart2"        /* JQ8900所接串口 请先事先在env中打开*/
#endif
#ifndef UART_NAME
#define UART_NAME              "uart3"        /* ESP8266所接串口*/
#endif
static rt_device_t serial;   
static rt_device_t serial2;   
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 句柄默认设置 */
static struct rt_semaphore rx_sem;
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(&rx_sem);
    return RT_EOK;
}
static void Re_music(void *args)
{
    static char buffer1[4]={0xAA,0x05,0x00,0xAF};    //JQ8900上一曲命令
    rt_uint32_t tx_length;
    tx_length=4;
    int i = 0;
    while(i < 4){
    rt_device_write(serial,0,&buffer1[i],tx_length);  //循环发送
    i++;}
    rt_kprintf("jun\n");
}
static void next_music(void *args)
{
    static char buffer1[4]={0xAA,0x06,0x00,0xB0};    //JQ8900下一曲命令
    rt_uint32_t tx_length;
    tx_length=4;
    int i = 0;
    while(i < 4){
    rt_device_write(serial,0,&buffer1[i],tx_length);
    i++;}
    rt_kprintf("bian\n");
}

static void nmsl(void *parameter){
  
      char ch;

    while (1)
    {
        while (rt_device_read(serial2, -1, &ch, 1) != 1)
        {
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }
        if(ch == 'a'){         //esp8266检测接受信息,为a则调用函数
          Re_music(0);
        }
        if(ch == 'b'){
          next_music(0);
        }

}
}

static void serial_thread_entry(void *parameter)
{
  //  char ch;
    while (1)
      
    {    
    rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, Re_music, RT_NULL);   //设置按钮中断回调函数
    rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);
    rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, next_music, RT_NULL);
    rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);    
    }
}
static int mdr5(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }
    serial = rt_device_find(uart_name);
    serial2 = rt_device_find(UART_NAME);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }
    if (!serial2)
    {
        rt_kprintf("find %s failed!\n", UART_NAME);
        return RT_ERROR;
    }
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    config.baud_rate = BAUD_RATE_9600;    //串口设置为9600
    config.data_bits = DATA_BITS_8;
    config.stop_bits = STOP_BITS_1;
    config.parity = PARITY_NONE;
    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
    rt_device_set_rx_indicate(serial, uart_input);
    
    rt_device_open(serial2, RT_DEVICE_FLAG_INT_RX);
    rt_device_set_rx_indicate(serial2, uart_input);
    rt_thread_t thread1 = rt_thread_create("serial2", nmsl, RT_NULL, 1024, 25, 10);
        if (thread1 != RT_NULL)
    {
        rt_thread_startup(thread1);
    }
    else
    {
        ret = RT_ERROR;
    }
    
    
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }
    return ret;
}
MSH_CMD_EXPORT(mdr5, uart JUN);

值得注意的是,JQ8900模块的波特率是9600,需要使用rt_device_control函数来设置串口波特率,而esp8266则不用

本程序还设置了一个接受信号量,用来在串口接收到信息之后发送信号量,来表示已经接受到数据。

JQ8900的RTT[RT-thread]简易测试代码

-以下为示例代码

可以通过开发板上的按钮来对JQ8900进行操作,达到切换曲目的效果

并且可以自定义修改代码进行更多操作,优化了串口发送信息的方式。

/*
通过RTT例子修改
用于测试YSV0.7是否可用
*/

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>


#define LED0_PIN    GET_PIN(B, 1)    //定位到野火开发板上两个RGB相关的寄存器上
#define LED0_PINE   GET_PIN(B, 0)
#ifndef KEY0_PIN_NUM
    #define KEY0_PIN_NUM      GET_PIN(A, 0) /* PA0 */
#endif
#ifndef KEY1_PIN_NUM
    #define KEY1_PIN_NUM      GET_PIN(C, 13) /* PC13 */
#endif
#define SAMPLE_UART_NAME       "uart2"

static rt_device_t serial;              /* 串口设备句柄 */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 配置参数 */


/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;




/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

static void Re_music(void *args)
{
    static char buffer1[4]={0xAA,0x05,0x00,0xAF};
    rt_uint32_t tx_length;
    tx_length=4;
    int i = 0;
    while(i < 4){
    rt_device_write(serial,0,&buffer1[i],tx_length);
    i++;}
    rt_kprintf("上一条\n");
}
static void next_music(void *args)
{
    static char buffer1[4]={0xAA,0x06,0x00,0xB0};
    rt_uint32_t tx_length;
    tx_length=4;
    int i = 0;
    while(i < 4){
    rt_device_write(serial,0,&buffer1[i],tx_length);
    i++;}
    rt_kprintf("下一条\n");

}

static void serial_thread_entry(void *parameter)
{

  //  char ch;
    int jun = 1;
    while (1)
      
    {		
             /*发送缓冲区是固定为5个字节长度的*/
        static char uart2_tx_buffer[5]={0xAA,0x02,0x00,0xAC,0x05};
        rt_uint32_t tx_length;
        tx_length=5;
    rt_pin_mode(KEY0_PIN_NUM, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(KEY0_PIN_NUM, PIN_IRQ_MODE_FALLING, Re_music, RT_NULL);
    rt_pin_irq_enable(KEY0_PIN_NUM, PIN_IRQ_ENABLE);


    rt_pin_mode(KEY1_PIN_NUM, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(KEY1_PIN_NUM, PIN_IRQ_MODE_FALLING, next_music, RT_NULL);
    rt_pin_irq_enable(KEY1_PIN_NUM, PIN_IRQ_ENABLE);
        if(jun){
        rt_device_write(serial,0,&uart2_tx_buffer[0],tx_length);
        rt_device_write(serial,0,&uart2_tx_buffer[1],tx_length);
        rt_device_write(serial,0,&uart2_tx_buffer[2],tx_length);
        rt_device_write(serial,0,&uart2_tx_buffer[3],tx_length);
        rt_kprintf("测试成功!");}
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */					
             jun = 0;
    }
}

static int mdr1(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];

    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }

    /* 查找系统中的串口设备 */
    serial = rt_device_find(uart_name);

    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 以中断接收及轮询发送模式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    config.baud_rate = BAUD_RATE_9600;    //配置串口通信为9600
    config.data_bits = DATA_BITS_8;
    config.stop_bits = STOP_BITS_1;
    config.parity = PARITY_NONE;
    /* 打开设备后才可修改串口配置参数 */
    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);
    /* 发送字符串 */
//    rt_device_write(serial, 0, str, (sizeof(str) - 1));

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(mdr1, uart JUN);

可以自行添加到RT-thread的BSP中,并烧录到开发板中。

JQ8900模块与单片机通信,达到功放效果|基于RTT

上一篇我们已经进行了JQ8900模块的串口调试,这次我们来把它接上单片机来进行调试。

实现了RTT的串口传输16进制数据

-将JQ8900模块上的串口相关线接上开发板

注意串口TX与RX的反接,笔者这里接了开发板上的UART2接口,分别是PA2(TX),PA3(RX)。

接下来进行程序的编写,我们根据JQ8900的串口手册,相关定义如下

我们进行最简单的播放测试,即01条

以下是测试代码:

/*
通过RTT例子修改
用于测试JQ8900是否可用
*/

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>


#define SAMPLE_UART_NAME       "uart2"

static rt_device_t serial;              /* 串口设备句柄 */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; /* 配置参数 */


/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}




static void serial_thread_entry(void *parameter)
{
  //  char ch;
    int jun = 1;
    while (1)
      
    {		
             /*发送缓冲区是固定为5个字节长度的*/
        static char uart2_tx_buffer[5]={0xAA,0x02,0x00,0xAC,0x05};//测试字段,作用为播放当前音乐
        rt_uint32_t tx_length;
        tx_length=5;
        if(jun){
        rt_device_write(serial,0,&uart2_tx_buffer[0],tx_length);
        rt_device_write(serial,0,&uart2_tx_buffer[1],tx_length);
        rt_device_write(serial,0,&uart2_tx_buffer[2],tx_length);
        rt_device_write(serial,0,&uart2_tx_buffer[3],tx_length);
        rt_kprintf("device message sent!");}
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */						
             jun = 0;
    }
}

static int mdr1(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];

    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }

    /* 查找系统中的串口设备 */
    serial = rt_device_find(uart_name);

    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 以中断接收及轮询发送模式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    config.baud_rate = BAUD_RATE_9600;    //配置串口通信为9600
    config.data_bits = DATA_BITS_8;
    config.stop_bits = STOP_BITS_1;
    config.parity = PARITY_NONE;
    /* 打开设备后才可修改串口配置参数 */
    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(mdr1, uart JUN);

 

代码简要解析

  1. 打开并配置了串口通信为9600,数据位为8,停止位为1
  2. 设置的回调函数中使用了一个数组用来储存16进制,HEX数据
  3. 使用rt_device_write函数分4次把一个完整的命令传输到JQ8900
  4. 实现了串口通信

将本页代码添加到您的RTT-BSP中,编译后进行烧录,通过msh发送mdr1

 \ | /
- RT -     Thread Operating System
 / | \     4.0.2 build Aug 22 2019
 2006 - 2019 Copyright by rt-thread team
msh />mdr1
msh />device message sent!

 

即可听到JQ8900喇叭的声音,测试成功

 

JQ8900模块的基础调试(直接串口调试)

将JQ8900模块按照以下方式进行连接(Rx,Tx,GND与DC5V暂时悬空)

触发输入口笔者暂时只接了I01于I02,仅做测试用

具体接线方式如下:

一般接线方式

接完线之后,将串口相关的线暂时悬空,并接上micro-USB线,并连接到电脑上。

电脑会立即识别到flash映射的可移动磁盘,打开磁盘,下载测试语音包,并将语音包解压复制到可移动磁盘中。

提取码:csat

最终效果如图所示

将micro-USB线拔下,拿出usb转TTL模块,将刚刚悬空的串口相关线接上ttl模块,注意TX与RX的反接

参考接线方式

讲usb转ttl模块接上电脑,测试悬空的I01与I02两条线,将两条线分别接地,看看是否有声音发出,有声音发出说明模块测试ok

 

接着测试串口能否控制模块,打开sscom,如下设置

输入AA 02 00 AC,并点击发送,可以听到喇叭的声音。

至此测试完成,下一篇将会介绍JQ8900与开发板的通信。