你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

狂欢三】STM32C031使用TIM定时器DMA方式实现WS2812彩灯输出(三)

[复制链接]
STMWoodData 发布时间:2024-12-23 17:53

前面已经实现了通过DMA方式改变脉冲PWM占空比和个数。本次就利用这个实现WS2812彩灯输出。

首先我们要知道WS2812的驱动方式。WS2812彩灯是通过不同脉冲高电平的占空比来标识0和1的BIT位的。

BIT1:是高低占空比时间为1us-0.25us(800K速率);BIT1:是高低占空比时间为2us-0.5us(400K速率);

BIT0:是高低占空比时间为0.25us-1us(800K速率);BIT0:是高低占空比时间为0.5us-2us(400K速率);

这里要注意,BIT0或者BIT1主要是高电平脉冲要精准,误差要小。而占空比中低电平时间不需要特别精准。意思就是说BIT1的高电平要在1us左右,误差+-0.2us,但是低电平可以0.25us到2us左右都可以识别为BIT1.BIT0也一样。主要是靠高电平时间宽度识别。

WS2812一个RGB彩灯需要3个字节24BIT,RGB3种颜色各1字节8BIT。

这里我初始化了PWM的频率为500K。TIM定时器系统频率48MHz,计数96个为一周期500KHz。

image.png

下面定义WS2812的BIT位占空比数值:

#define WS_BIT1             48          //1us-1.25us
#define WS_BIT0             12          //0.25us-0.5us

#define WS2812_PIXELS       8         // WS2812 LEDs 数量
#define WS_BIT              24u            //一个RGB灯的BIT位数

#define WS_TRANSFER_SIZE   ((WS2812_PIXELS) * (WS_BIT))   // Transfer dataSize

__ALIGNED(4)
volatile uint8_t g_WS2812TxBuf[WS_TRANSFER_SIZE];   // WS2812 Strip transmit data buffer


发送数据:
void WS2812_SendData(void)
{
  HAL_TIM_PWM_Start_DMA(&htim3,TIM_CHANNEL_1,(uint32_t *)g_WS2812TxBuf,WS_TRANSFER_SIZE);
}

发送数据完成中断回调:

void WS2812_SendDataCpl_cb(void)
{
  TIM3->CCR1 = 0;
  if(ws2812_send_lock)   ws2812_send_lock = 0;
}


static void _WS2812_SetPointColor(uint8_t *ptr, uint8_t r, uint8_t g, uint8_t b,uint8_t val)
{
    if(r)
    {
        if( ((r>>7)&0x01))  ptr[0+0] = val;
        if( ((r>>6)&0x01))  ptr[0+1] = val;
        if( ((r>>5)&0x01))  ptr[0+2] = val;
        if( ((r>>4)&0x01))  ptr[0+3] = val;
        if( ((r>>3)&0x01))  ptr[0+4] = val;
        if( ((r>>2)&0x01))  ptr[0+5] = val;
        if( ((r>>1)&0x01))  ptr[0+6] = val;
        if( ((r>>0)&0x01))  ptr[0+7] = val;
    }

    if(g)
    {
        if( ((g>>7)&0x01))  ptr[8+0] = val;
        if( ((g>>6)&0x01))  ptr[8+1] = val;
        if( ((g>>5)&0x01))  ptr[8+2] = val;
        if( ((g>>4)&0x01))  ptr[8+3] = val;
        if( ((g>>3)&0x01))  ptr[8+4] = val;
        if( ((g>>2)&0x01))  ptr[8+5] = val;
        if( ((g>>1)&0x01))  ptr[8+6] = val;
        if( ((g>>0)&0x01))  ptr[8+7] = val;
    }

    if(b)
    {
        if( ((b>>7)&0x01))  ptr[16+0] = val;
        if( ((b>>6)&0x01))  ptr[16+1] = val;
        if( ((b>>5)&0x01))  ptr[16+2] = val;
        if( ((b>>4)&0x01))  ptr[16+3] = val;
        if( ((b>>3)&0x01))  ptr[16+4] = val;
        if( ((b>>2)&0x01))  ptr[16+5] = val;
        if( ((b>>1)&0x01))  ptr[16+6] = val;
        if( ((b>>0)&0x01))  ptr[16+7] = val;
    }
}

void WS2812_PixelSetIndexRGB(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
{  
    if(n < WS2812_PIXELS)
    {
        uint32_t i;
        for(i=0;i<WS_BIT;i++)
        {
            g_WS2812TxBuf[n*WS_BIT + i] = WS_BIT0;
        }
        _WS2812_SetPointColor((uint8_t *)&g_WS2812TxBuf[n*WS_BIT],r,g,b,WS_BIT1);
    }
}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM3)
    {
        if(pwm_lock)   pwm_lock = 0;
        WS2812_SendDataCpl_cb();
    }
}

这样就可以驱动WS2812彩灯了。

在main中调用WS2812驱动接口就可以驱动彩灯了。

image.png

image.png

引脚脉冲:

image.png

image.png

image.png

下面就是驱动8个RGB彩灯效果:

image.png

image.png

收藏 评论0 发布时间:2024-12-23 17:53

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版