ATK-MB011模块使用说明
这里以正点原子M48Z-M3最小系统板STM32F103版为例,给大家介绍一下模块和板卡的连接方法。其它板卡与模块的硬件连接方法,请大家在“ATK-MB011 RGBLED模块\3,程序源码\相应板卡例程文件夹\readme.txt”路径下查看。
RGBLED模块可通过杜邦线与正点原子M48Z-M3最小系统板STM32F103版进行连接,具体的连接关系,如下表所示:

表1.1 RGBLED模块与M48Z-M3最小系统板STM32F103版连接关系
如果需要连接多个RGBLED模块,RGBLED模块之间的连接关系如下:

表1.2 RGBLED模块之间的连接关系
在本实验中,串口会打印RGBLED模块的实验信息和提示我们根据连接的灯珠数量设置好LED_NUM宏定义。需要查看这部分实验信息的用户,可用杜邦线将最小系统板STM32F103的PA9引脚和GND连接至外部的USB转串口设备,这样就可以通过XCOM上位机查看串口打印的信息了。
本实验支持一个RGB模块或者多个RGB模块的显示,可通过LED_NUM宏定义设置。
共三种显示方式循环:
1、多个灯珠亮相同颜色呼吸灯,共10种颜色
2、多个灯珠亮相同颜色,共10种颜色
3、多个灯珠亮不相同颜色,共10种颜色,颜色会向前传递。
开发板的LED0闪烁,提示程序运行。
打开本实验的工程文件夹,能够在./Drivers/BSP目录下看到ATK_RGBLED文件夹,ATK_RGBLED文件夹中就包含了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灯的亮度,还可以做呼吸灯效果。
实验的测试代码在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模块,也是正常亮的,只是没有流水灯效果而已。
通过串口打印实验提示信息。
将RGBLED模块按照第一节“硬件连接”中介绍的连接方式与开发板连接,并将实验代码编译烧录至开发板中。本实验使用串口输出调试信息,因此需将开发板的 PA9连接至 DAP 虚拟串口(或 USB 转 TTL 模块)的 RX引脚。完成连接后,可通过串口调试助手XCOM查看实验信息输出,如下图所示:

图2.1.3.1 串口调试助手显示内容
注:其它现象请看2.1.1功能说明。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040860/viewspace-3075793/ ,如需转载,请注明出处,否则将追究法律责任。