这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【EEPW电子鼓DIY活动】成果展示——深受小宝宝喜爱

共6条 1/1 1 跳转至

【EEPW电子鼓DIY活动】成果展示——深受小宝宝喜爱

高工
2023-09-10 23:06:33     打赏

【EEPW电子鼓DIY活动】成果展示——深受小宝宝喜爱

前期准备

在开始电子鼓DIY活动前,想到要给我家这位15个月的小家伙制作第一个玩具,确实有点兴奋。把DIY的焊接工具全部找了出来,又测试了一番,静静地等待审核与快递。当然,等待的时候还是需要学习基础知识的,比如WS2812灯的驱动,DAC外设驱动等。

很快,快递就到了。拿着手中异常整齐的物料,心情甭提多高兴了——反正,我没有这个实力整理得这么好,但我确实希望别人能整理好后给我。嘿嘿!

想看物料整理得有多好!详见《电子鼓DIY开箱帖——收到最用心的材料包》 http://forum.eepw.com.cn/thread/375578/1 

焊接

整齐的物料绝对加速了我的焊接。在焊接前阅读了原理图,0805大电容全部都是104封装。LED灯附近的是1K欧,其余0603封装电阻阻值在PCB丝印上均有标注了。我又全部观看了鹏老师上传到EEPW的教学视频,提前了解到焊接的注意点,易错点,比如WS2812灯珠的对齐方向等。

核对原理图后,我省略了RESET信号的复位按键,如需复位,通过电池的开关完成即可。我还省略了3.5mm音频座,考虑到也不会连接到音箱,或传入音源,所以音频座的意义也就不大了。我还省略了2x5插针座——没有啥可扩展的。

这里有一个小Tips,我先把触摸焊盘用透明胶条覆盖了,免得不小心沾上焊锡无法清理。下面秀一下焊接成果图:

系统框图

根据功能实现,下面是我本次电子鼓DIY的系统框图。

edrum.drawio.png

软件架构

edrum-第 2 页.drawio.png

Blinky闪灯

焊接完成之后,自然是软件的编写。前期准备阶段已经完成系统时钟,LED引脚初始化的代码编写。连接好jlink,直接flash,LED灯闪烁轻松实现。

int main(void)
{
    bsp_init();
    SysTick_Config(72000);
    NVIC_EnableIRQ(SysTick_IRQn);

    while (1)
    {
        if (time_line_ms > 500)
        {
            time_line_ms = 0;
            bsp_led_toggle();
        }
    }
}


电子鼓

程序按照模块化方式编写,软件框图上节已经提供,这里不再重复。直接上代码展示了:

int main(void)
{
    bsp_init();
    SysTick_Config(72000);
    NVIC_EnableIRQ(SysTick_IRQn);

    for (int i = 0; i < 12; i++)
    {
        WS2812_Buff[i][0] = rand();
        WS2812_Buff[i][1] = rand();
        WS2812_Buff[i][2] = rand();

        WS2812_Refresh();
        time_line_ms = 100;
        while (time_line_ms > 0)
        {
            ;
        }
    }

    time_line_ms = 1000;
    while (time_line_ms > 0)
    {
        ;
    }
    for (int i = 0; i < 12; i++)
    {
        WS2812_Buff[i][0] = 0;
        WS2812_Buff[i][1] = 0;
        WS2812_Buff[i][2] = 0;
    }
    WS2812_Refresh();

    while (1)
    {
        if (key_code < 6)
        {
            for (int i = 0; i < 12; i++)
            {
                WS2812_Buff[i][0] = 0;
                WS2812_Buff[i][1] = 0;
                WS2812_Buff[i][2] = 0;
            }
            // WS2812_Refresh();
            WS2812_Buff[ws2812_led_couple[key_code][0]][0] = rand() & 0x0F;
            WS2812_Buff[ws2812_led_couple[key_code][0]][1] = rand() & 0x0F;
            WS2812_Buff[ws2812_led_couple[key_code][0]][2] = rand() & 0x0F;
            WS2812_Buff[ws2812_led_couple[key_code][1]][0] = rand() & 0x0F;
            WS2812_Buff[ws2812_led_couple[key_code][1]][1] = rand() & 0x0F;
            WS2812_Buff[ws2812_led_couple[key_code][1]][2] = rand() & 0x0F;
            WS2812_Refresh();
            time_line_ms = 800;
            key_code = 6;
        }
        else if ((time_line_ms == 0) && (key_code == 6))
        {
            for (int i = 0; i < 12; i++)
            {
                WS2812_Buff[i][0] = 0;
                WS2812_Buff[i][1] = 0;
                WS2812_Buff[i][2] = 0;
            }
            WS2812_Refresh();
            key_code = 7;
        }
    }
}

DIY软件

完全重复鹏老师的作品,那算不上DIY,由于有了以下几个DIY的成果:

1. 击鼓声的声源波形数组。

* 原参考程序的波形数组使用了int16_t格式,在应用程序传入DAC数据寄存器前,又做了线性计算。

reg = wave[i] / 16 + 2048;

其实,浪费了MCU的时间,我们在DIY前将其数值计算出来并更新,再存入wave[]数组,减少MCU的计算时间,提升MCU的效率。

* 波形数组使用了十进制数字书写。在格式上面混乱不堪,本次更新为uint16_t,使用16进制数字,在形式上更整齐,阅读代码时更舒心。

 DAC外设初始化

static void dac_init(void)
{
    LL_DAC_InitTypeDef DAC_InitStruct = {0};
    LL_TIM_InitTypeDef TIM_InitStruct = {0};

    /* Peripheral clock enable */
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DAC1);
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);

    NVIC_SetPriority(DMA2_Channel3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
    NVIC_EnableIRQ(DMA2_Channel3_IRQn);

    /* DAC_CH1 Init */
    LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
    LL_DMA_SetChannelPriorityLevel(DMA2, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_LOW);
    LL_DMA_SetMode(DMA2, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);
    LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT);
    LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT);
    LL_DMA_SetPeriphSize(DMA2, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_HALFWORD);
    LL_DMA_SetMemorySize(DMA2, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_HALFWORD);
    LL_DMA_SetPeriphAddress(DMA2, LL_DMA_CHANNEL_3, (uint32_t)&DAC->DHR12R1);

    /** DAC channel OUT1 config
     */
    DAC_InitStruct.TriggerSource = LL_DAC_TRIG_EXT_TIM6_TRGO;
    DAC_InitStruct.WaveAutoGeneration = LL_DAC_WAVE_AUTO_GENERATION_NONE;
    DAC_InitStruct.OutputBuffer = LL_DAC_OUTPUT_BUFFER_ENABLE;
    LL_DAC_Init(DAC, LL_DAC_CHANNEL_1, &DAC_InitStruct);
    LL_DAC_EnableDMAReq(DAC, LL_DAC_CHANNEL_1);
    LL_DAC_EnableTrigger(DAC, LL_DAC_CHANNEL_1);
    LL_DAC_Enable(DAC, LL_DAC_CHANNEL_1);

    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
    TIM_InitStruct.Prescaler = 7;
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Autoreload = 815;
    LL_TIM_Init(TIM6, &TIM_InitStruct);
    LL_TIM_EnableARRPreload(TIM6);
    LL_TIM_SetTriggerOutput(TIM6, LL_TIM_TRGO_UPDATE);
    LL_TIM_DisableMasterSlaveMode(TIM6);

    LL_TIM_EnableCounter(TIM6);
    LL_TIM_GenerateEvent_UPDATE(TIM6);
}

波形文件规整

const uint16_t wave_0[] = {
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800,
};

2. DAC驱动

* 使用Timer6进行采样率的匹配设定,使用prescale=7, period=203;计算可得采样率为44.117KHz,但本次限于Flash的空间大小,将采样率缩小为11.02KHz,因此,period=815。

采用DMA + Timer6 + DAC的组合方式实现击鼓声音。每次有按键按下时,配置DMA,启动DMA,启动Timer6。完成声音波形文件的输出。

* 使用更加轻便的LL驱动库.示例程序是HAL库的输出,多少有些冗余。所以在本次DIY时,我使用了LL库,精简了代码,也让程序运行更加流畅。

详细源代码请详见文末工程版全部源代码

DIY硬件

本来计划DIY一个ADC外设,用于采样锂电池的电压,估算其SOC,并使用语音提示需要充电。但无奈硬件设计未能引出引脚。尝试直接在芯片引脚上加焊飞线,未果,遂放弃。

总结

本次利用DIY电子鼓的活动,不仅增强我的动手能力,而且学习到很多知识。电子鼓主要是利用数字转模拟电路的原理实现声音的播放。我在DIY的活动期间也重点学习了DAC的知识,包括STM32F103的DAC外设,DAC采样原理,Timer6的Event触发方式,DMA功能的原理与实现,还有声音波形文件WAV文件格式等等。

本次DIY活动也是我第一次接触WS2812这个简单又实用的彩色RGB灯带。学习了单总线通讯协议的原理,也动手实现了。看着炫丽的灯带成功点亮成就感拉得满满的。

这次DIY活动也有少量遗憾。由于平时带娃占用的精力较大,投入到DIY活动的时间也就非常有限,又赶上小家伙生病2周,我自己又发烧,唉!最后SPI Flash芯片的读写功能未完成在活动结束前搞定。待我完善,再回帖补充上吧!

DIY活动成果

* 《【了解一下】R2R电阻网络DAC》 http://forum.eepw.com.cn/thread/376070/1

* 《还有谁不了解三角波?赶紧点开看看!》http://forum.eepw.com.cn/thread/376608/1

* 《WAV文件格式并不难?让我带大家一步一步分析》 http://forum.eepw.com.cn/thread/376748/1

致谢

感谢EEPW论坛组织本次活动。

感谢鹏老师提供技术帮助。

感谢各位网友们的帮助与关注!

谢谢各位了。

成果展示

1. 电子鼓源代码分享

* EEPW电子鼓DIY工程全部源代码  http://share.eepw.com.cn/share/download/id/391073

* EEPW电子鼓成品hex文件 http://share.eepw.com.cn/share/download/id/391074

2. 视频链接

* 成果视频:http://v.eepw.com.cn/video/play/id/15801





关键词: 成果展示     活动    

助工
2023-09-10 23:22:53     打赏
2楼

你是最棒得


管理员
2023-09-11 15:22:38     打赏
3楼

到位!感谢支持!


院士
2023-09-27 12:06:54     打赏
4楼

不错不错,时间紧,学习、工作、带娃都不误,不容易啊,点赞。


高工
2023-10-07 08:44:52     打赏
5楼

非常漂亮


菜鸟
2024-02-27 20:27:25     打赏
6楼

非常非常棒,怎么联系老师您呢


共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]