【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的系统框图。

软件架构

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

 
					
				
 
			
			
			
						
			 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

