ITPub博客

首页 > 嵌入式/内核开发 > 嵌入式/内核开发 > 《正点原子BEE BLOCK模块资料》ATK-MB011模块使用说明

《正点原子BEE BLOCK模块资料》ATK-MB011模块使用说明

原创 嵌入式/内核开发 作者:正点原子 时间:2025-03-14 09:28:22 0 删除 编辑

ATK-MB011模块使用说明


        1, 硬件连接

       这里以正点原子M48Z-M3最小系统板STM32F103版为例,给大家介绍一下模块和板卡的连接方法。其它板卡与模块的硬件连接方法,请大家在“ATK-MB011 RGBLED模块\3,程序源码\相应板卡例程文件夹\readme.txt”路径下查看。

       RGBLED模块可通过杜邦线与正点原子M48Z-M3最小系统板STM32F103版进行连接,具体的连接关系,如下表所示:


表1.1 RGBLED模块与M48Z-M3最小系统板STM32F103版连接关系 


       如果需要连接多个RGBLED模块,RGBLED模块之间的连接关系如下:


表1.2 RGBLED模块之间的连接关系


        2,实验功能


       2.1 RGBLED模块测试实验


       2.1.1 功能说明

       在本实验中,串口会打印RGBLED模块的实验信息和提示我们根据连接的灯珠数量设置好LED_NUM宏定义。需要查看这部分实验信息的用户,可用杜邦线将最小系统板STM32F103的PA9引脚和GND连接至外部的USB转串口设备,这样就可以通过XCOM上位机查看串口打印的信息了。

       本实验支持一个RGB模块或者多个RGB模块的显示,可通过LED_NUM宏定义设置。

       共三种显示方式循环:

       1、多个灯珠亮相同颜色呼吸灯,共10种颜色

       2、多个灯珠亮相同颜色,共10种颜色

       3、多个灯珠亮不相同颜色,共10种颜色,颜色会向前传递。

       开发板的LED0闪烁,提示程序运行。


       2.1.2 源码解读

       打开本实验的工程文件夹,能够在./Drivers/BSP目录下看到ATK_RGBLED文件夹,ATK_RGBLED文件夹中就包含了RGBLED模块的驱动文件,如下图所示:


图2.1.2.1 RGBLED模块驱动代码


       2.1.2.1 RGBLED模块驱动

       下面简要介绍atk_rgbled.c中几个重要的API 函数。


       1. 函数atk_rgbled_init ()

       该函数用于初始化RGBLED模块,具体的代码,如下所示:

/**
 * @brief       初始化WS2811F相关IO口,以及配置定时器和DMA功能 并使能时钟
 * @param       无
 * @retval      无
 */
void atk_rgbled_init(void)
{
    TIM_OC_InitTypeDef timx_oc_pwm_chy = {0};  /* 定时器输出句柄 */
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    __HAL_RCC_DMA1_CLK_ENABLE();                /* DMA1时钟使能 */
    GTIM_TIMX_PWM_CHY_GPIO_CLK_ENABLE();      /* 开启通道y的GPIO时钟 */
    GTIM_TIMX_PWM_CHY_CLK_ENABLE();           /* 使能定时器时钟 */
    
    gpio_init_struct.Pin = GTIM_TIMX_PWM_CHY_GPIO_PIN; /* 通道y的GPIO口 */
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;             /* 复用推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;   /* 高速 */
    HAL_GPIO_Init(GTIM_TIMX_PWM_CHY_GPIO_PORT, &gpio_init_struct);
    
    g_timx_pwm_chy_handle.Instance = GTIM_TIMX_PWM;    /* 定时器x */
    g_timx_pwm_chy_handle.Init.Prescaler = (9 - 1);     /* 定时器分频 */
    g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;/* 递增计数 */
    g_timx_pwm_chy_handle.Init.Period = (10 - 1);      /* 自动重装载值 */
    g_timx_pwm_chy_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
g_timx_pwm_chy_handle.Init.AutoReloadPreload = 
TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);     /* 初始化PWM */
        
    timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;           /* 模式选择PWM1 */
    timx_oc_pwm_chy.Pulse = 0;           /* 设置比较值,此值用来确定占空比 */
    timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_HIGH;  /* 输出比较极性为高 */
    timx_oc_pwm_chy.OCFastMode = TIM_OCFAST_DISABLE;
    timx_oc_pwm_chy.OCIdleState = TIM_OCIDLESTATE_RESET;/* 空闲时输出低电平 */
HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, 
GTIM_TIMX_PWM_CHY);     /* 配置TIMx通道y */
/* 很关键,使能CCRX的影子寄存器,当修改CCRX的值时,等产生更新事件在生效 */
    __HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY); 
 
    g_dma_handle.Instance = DMA1_Channel7;               /* 通道 */
    g_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;/* 从内存到外设模式 */
    g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;     /* 外设非增量模式 */
g_dma_handle.Init.MemInc = DMA_MINC_ENABLE;          /* 存储器增量模式 */
/* 外设数据长度:32位 */
g_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; 
/* 存储器数据长度:32位 */
    g_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; 
    g_dma_handle.Init.Mode = DMA_CIRCULAR;                /* 循环模式 */
    g_dma_handle.Init.Priority = DMA_PRIORITY_HIGH;   /* 高优先级 */
    HAL_DMA_Init(&g_dma_handle);
    
/* 将DMA与timer联系起来 */
    __HAL_LINKDMA(&g_timx_pwm_chy_handle, hdma[TIM_DMA_ID_CC4], g_dma_handle); 
    
    HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 1, 1);
    HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}

       本实验,我们使用定时器+DMA的方式来驱动WS2811F,从而点亮RGBLED灯。atk_rgbled_init () 函数负责初始化定时器、DMA、对应的定时器通道IO口和NVIC。


       2. 函数atk_rgbled_dats_send ()

       该函数用于启动DMA和定时器,通过定时器通道输出PWM,发送数据给WS2811F,具体的代码,如下所示:

/**
 * @brief       发送数据给WS2811F
 * @param       无
 * @retval      无
 */
void atk_rgbled_dats_send(void)
{
/* 使用DMA将数据发送到定时器的CCRx */
    HAL_TIM_PWM_Start_DMA(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY,  (uint32_t *)g_pixel_buf, sizeof(g_pixel_buf));
}


       3. 函数atk_rgbled_reset ()

       该函数用于复位WS2811F,具体的代码,如下所示:

/**
 * @brief       复位WS2811F
 * @note        保持低电平280us以上即可
 * @param       无
 * @retval      无
 */
void atk_rgbled_reset(void)
{
/* CCRX设置为0,直接输出低电平 */
    __HAL_TIM_SetCompare(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY, 0);
    delay_ms(1);
}

       复位WS2811F的条件是给WS2811F芯片DIN引脚280us以上低电平即可。


       4. 函数atk_rgbled_display ()

       该函数用于将RGB颜色值转换后发送给WS2811F,从而显示对应的颜色,具体的代码,如下所示:

/**
 * @brief       将GRB888的颜色值转换成逻辑1和逻辑0对应的CCRx值
*               并存放到g_pixel_buf里,并发送给CCRx,生成PWM
 * @note        可指定第几个灯
 * @param       led_num : 需控制灯的数量
 * @param       color   : GRB888颜色值指针
 * @retval      无
 */
void atk_rgbled_display(uint8_t led_num, uint32_t *color_buf)
{
    uint8_t i, j; 
    if(led_num > LED_NUM)return;    /* 防止写入LED数量大于LED总数 */
    
/* 这里是对 g_pixel_buf[i][j]写入一个周期内高电平的持续时间
(是要存放在比较值寄存器CCR的值)*/
    for(i = 0; i < led_num; i++)
    {
        for(j = 0; j < DATA_SIZE; j++)
        {
            g_pixel_buf[i][j] =
 (((color_buf[i] << j) & 0x800000) ? HIGH_LEVEL : LOW_LEVEL);
        }
    }
    
    atk_rgbled_dats_send();/* 将g_pixel_buf发送到定时器的CCRx中,生成相应波形 */
}

       复位WS2811F的条件是给WS2811F芯片DIN引脚280us以上低电平即可。


       5. 中断服务函数和回调函数

       下面是DMA1通道7的中断服务函数和PWM DMA传输完成回调函数,具体的代码,如下所示:

/**
 * @brief       DMA1通道1中断服务函数
 * @param       无
 * @retval      无
 */ 
void DMA1_Channel7_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&g_dma_handle);
}
 
/**
 * @brief   PWM DMA传输完成回调函数
 * @param   htim: 定时器句柄类型指针
 * @retval  无
 */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
    atk_rgbled_reset();
    HAL_TIM_PWM_Stop_DMA(htim, GTIM_TIMX_PWM_CHY);  /* 传输完成后手动停止PWM */
}

       值得注意的点,每次数据传输完成后,要在PWM DMA传输完成回调函数中,调用atk_rgbled_reset()函数,复位WS2811F。


       6. 改变所要显示的RGB颜色亮度函数

       函数源码较长,就不贴出来了,我们看一下函数声明。

/**
 * @brief   改变所要显示的颜色亮度(RGB->HSV->RGB)
 * @param   rgb : GRB888颜色值
 * @param   k   : 亮度值(0.0 ~ 1.0)
 * @retval  改变亮度后的颜色值
 */
uint32_t color_change_brigh(uint32_t rgb, float k);

       该函数有两个形参,分别是rgb和k。rgb是我们要输入的颜色值,k是我们要设置的亮度值(范围是0.0~1.0)。改变亮度后的颜色值作为函数返回值。该函数可用于改变RGB灯的亮度,还可以做呼吸灯效果。


       2.1.2.2 实验测试代码

       实验的测试代码在demo.c文件中,该文件在工程根目录下的 User文件夹。测试代码的入口函数为 demo_run()。此外还实现一个呼吸灯函数,具体的代码,如下所示:

/**
 * @brief   呼吸灯函数
 * @param   led_num : 需控制灯的数量
 * @param   color   : GRB888颜色值指针
 * @retval  无
 */
void dome_breathe(uint8_t led_num, uint32_t *color_buf)
{
    float k = 0;
    uint8_t i, j;
    uint32_t color[led_num];
    
    for(i = 0; i < 100; i++)
    {
        k += 0.01;
 
        for (j = 0; j < led_num; j++)
        {
            color[j] = color_change_brigh(color_buf[j], k);
        }
        
        atk_rgbled_display(led_num, color);
        delay_ms(5);
    }
    
    for(i = 0; i < 100; i++)
    {
        k -= 0.01;
 
        for (j = 0; j < led_num; j++)
        {
            color[j] = color_change_brigh(color_buf[j], k);
        }
        
        atk_rgbled_display(led_num, color);
        delay_ms(5);
    }
}
 
/**
 * @brief       例程演示入口函数
 * @param       无
 * @retval      无
 */
void demo_run(void)
{
    uint8_t k = 0, i = 0, j = 0;
    uint32_t rgb_buf[LED_NUM];   /* 各灯珠RGB颜色缓冲区 */
    
    atk_rgbled_init();            /* 初始化RGBLED模块 */
    
    printf("RGBLED模块实验\r\n");
    printf("请根据您连接的灯珠个数来设置好LED_NUM宏定义\r\n");
    
    while (1)
    {
        /* 多个灯珠亮相同颜色呼吸灯,10种颜色 */
        for(i = 0; i < 10; i++)
        {
            for(j = 0; j < LED_NUM; j++)
            {
                rgb_buf[j] = g_grb888_color[i];
            }
            
            dome_breathe(LED_NUM, rgb_buf);  /* RGBLED灯光显示 */
            delay_ms(100);
        }
        
        /* 多个灯珠亮相同颜色,10种颜色 */
        for(i = 0; i < 10; i++)
        {
            for(j = 0; j < LED_NUM; j++)
            {
                rgb_buf[j] = g_grb888_color[i];
            }
            
            atk_rgbled_display(LED_NUM, rgb_buf);  /* RGBLED灯光显示 */
            delay_ms(1000);
        }
        
        /* 多个灯珠亮不相同颜色,10种颜色向前传递 */
        for(i = 0; i < 10; i++)
        {
            for(j = 0; j < LED_NUM; j++)
            {
                rgb_buf[j] = g_grb888_color[j + k];
            }
            
            k++;
            if (k > 10 - LED_NUM) k = 0;
            atk_rgbled_display(LED_NUM, rgb_buf);  /* RGBLED灯光显示 */
            delay_ms(1000);
        }
    }
}

       注意:我们可以根据自己需要接的RGBLRD模块的个数来修改LED_NUM宏定义,例程中最多支持10个。当然有需要可自行修改代码,以支持更多的RGBLRD模块。

       共三种显示方式循环:

       1、多个灯珠亮相同颜色呼吸灯,共10种颜色

       2、多个灯珠亮相同颜色,共10种颜色

       3、多个灯珠亮不相同颜色,共10种颜色,颜色会向前传递。

       如果只有一个RGBLED模块,也是正常亮的,只是没有流水灯效果而已。

       通过串口打印实验提示信息。


       2.1.3 实验现象

       将RGBLED模块按照第一节“硬件连接”中介绍的连接方式与开发板连接,并将实验代码编译烧录至开发板中。本实验使用串口输出调试信息,因此需将开发板的 PA9连接至 DAP 虚拟串口(或 USB 转 TTL 模块)的 RX引脚。完成连接后,可通过串口调试助手XCOM查看实验信息输出,如下图所示:


图2.1.3.1 串口调试助手显示内容


       注:其它现象请看2.1.1功能说明。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040860/viewspace-3075793/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2024-08-30

  • 博文量
    588
  • 访问量
    764980