打印
[STM32C0]

基于STM32C031 gpio模拟时序经验分享

[复制链接]
1390|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
elephant00|  楼主 | 2023-4-4 09:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前言
WS2812的驱动方式目前大致为gpio,spi,time+pwm  
gpio会占用cpu,spi或spi+dma需要对spi频率进行配置,time+pwm+dma用起来相对复杂些。
本次用的是gpio通过 ` __NOP() ` 延时来模拟ws2812的时序。
为啥不用spi或pwm是因为spi无法配置为7MHZ或14MHZ stm32c031的时钟48mhz可以/2/4/8/16/32 这几种分频。实际是驱动不了,显示乱的。pwm的话本人实力有限,也不好用丢数据

一、CUBEMX配置









二、WS2812驱动时序
通过示波器将 __NOP();的用时记录然后逐次增加
一个nop大概占用30-40ns
0码为400+850ns
1码为850+400ns

1.WS2812.C
代码如下(示例):
  • #include "ws2812.h"
  • uint8_t ws_data[WS_ARRAY_SIZE]={0};
  • void  WS_0(void)
  • {
  •     LL_GPIO_SetOutputPin(LED1_GPIO_Port, LED1_Pin);
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();
  •     LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();
  • }
  • void WS_1(void)
  • {
  •     LL_GPIO_SetOutputPin(LED1_GPIO_Port, LED1_Pin);
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •                 __NOP();__NOP();__NOP();__NOP();__NOP();
  •     LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();__NOP();__NOP();
  •     __NOP();__NOP();__NOP();
  • }
  • void WS_RST(void)
  • {
  •                 uint16_t i=0;
  •             LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);
  •                         for(i=0;i<860;i++)
  •                         {
  •                                 __NOP();
  •                         }
  • }
  • void ws2812_set_num(uint16_t num ,uint8_t r,uint8_t g,uint8_t b)
  • {
  •         ws_data[(num-1)*3]=g;
  •         ws_data[(num-1)*3+1]=r;
  •         ws_data[(num-1)*3+2]=b;
  • }
  • void ws2812_rgb_all(u8 ws_count,u8 ws_r,u8 ws_g,u8 ws_b)
  • {
  •         static uint8_t rgb_wsi;
  •         for(rgb_wsi=1;rgb_wsi<=ws_count;rgb_wsi++)
  •         {
  •                 ws_data[(rgb_wsi-1)*3]=ws_g;
  •                 ws_data[(rgb_wsi-1)*3+1]=ws_r;
  •                 ws_data[(rgb_wsi-1)*3+2]=ws_b;
  •         }
  •         //ws2812_refresh(ws_count);
  • }
  • void ws2812_refresh(u8 ws_count)
  • {
  •         uint8_t ws_ri=0;
  •         for(;ws_ri<ws_count*3;ws_ri++)
  •         {
  •                 if((ws_data[ws_ri]&0x80)==0)        WS_0();        else WS_1();
  •                 if((ws_data[ws_ri]&0x40)==0)        WS_0();        else WS_1();
  •                 if((ws_data[ws_ri]&0x20)==0)        WS_0();        else WS_1();
  •                 if((ws_data[ws_ri]&0x10)==0)        WS_0();        else WS_1();
  •                 if((ws_data[ws_ri]&0x08)==0)        WS_0();        else WS_1();
  •                 if((ws_data[ws_ri]&0x04)==0)        WS_0();        else WS_1();
  •                 if((ws_data[ws_ri]&0x02)==0)        WS_0();        else WS_1();
  •                 if((ws_data[ws_ri]&0x01)==0)        WS_0();        else WS_1();
  •         }
  •     //延时一段时间
  •         WS_RST();
  • }


复制代码


2.WS2812.H
代码如下(示例):
  • #ifndef _WS2812_H_
  • #define _WS2812_H_
  • #include "gpio.h"
  • typedef unsigned char u8;
  • #define WS_ARRAY_SIZE   64
  • void ws2812_refresh(u8 ws_count);//显示
  • void ws2812_rgb_all(u8 ws_count,u8 ws_r,u8 ws_g,u8 ws_b);//所有LED颜色配置
  • void ws2812_set_num(uint16_t num ,uint8_t r,uint8_t g,uint8_t b);//配置单个显示
  • #endif


复制代码


3.显示
  • while (1)
  •     {
  •         /* USER CODE END WHILE */
  •         /* USER CODE BEGIN 3 */
  •         for(i = 1; i < 29; i++)//显示28个
  •         {
  •             ws2812_set_num(i, 1, 0, 0);//红色
  •         }
  •             ws2812_refresh(28);//显示全部数据
  •             ws2812_rgb_all(28, 0, 0, 0);//清除数据
  •             HAL_Delay(800);
  •         for(i = 1; i < 29; i++)//显示28个
  •         {
  •             ws2812_set_num(i, 0, 1, 0);//绿色
  •         }
  •             ws2812_refresh(28);
  •             ws2812_rgb_all(28, 0, 0, 0);
  •             HAL_Delay(800);
  •         for(i = 1; i < 29; i++)//显示28个
  •         {
  •             ws2812_set_num(i, 0, 0, 1);//蓝色
  •         }
  •             ws2812_refresh(28);
  •             ws2812_rgb_all(28, 0, 0, 0);
  •             HAL_Delay(800);
  •     }


复制代码



实验现象



使用特权

评论回复
沙发
Stahan| | 2023-4-4 23:44 | 只看该作者
c0系列主打什么啊?

使用特权

评论回复
板凳
公羊子丹| | 2024-4-22 07:01 | 只看该作者

主电路那些环路产生的噪声会加到控制信号上

使用特权

评论回复
地板
万图| | 2024-4-22 08:04 | 只看该作者

多次检查也会给单片机带来负荷,对功耗不利

使用特权

评论回复
5
Uriah| | 2024-4-22 09:07 | 只看该作者

在GR-SAKURA中,从IO30引脚到IO35引脚接收来自外部的中断信号

使用特权

评论回复
6
帛灿灿| | 2024-4-22 11:03 | 只看该作者

在掌握对象的变化频度时是有效的

使用特权

评论回复
7
Bblythe| | 2024-4-22 12:06 | 只看该作者

中断信号直接从各外部设备通知中断控制器

使用特权

评论回复
8
周半梅| | 2024-4-22 14:02 | 只看该作者

通过交流电源插头从产品中流走

使用特权

评论回复
9
Pulitzer| | 2024-4-22 15:05 | 只看该作者

来自单 片机内部的定时器和GPIO、串行通信设备UART等外设机器的中断被称为外部设备中断

使用特权

评论回复
10
童雨竹| | 2024-4-22 17:01 | 只看该作者

交流电压在发射EMI

使用特权

评论回复
11
Wordsworth| | 2024-4-22 18:04 | 只看该作者

中断产生于单片机内部和外部的各种设备

使用特权

评论回复
12
Clyde011| | 2024-4-22 19:07 | 只看该作者

这样的设定只需在setup()中定义一次便能在整个程序中有效

使用特权

评论回复
13
xiaoqi000| | 2024-8-31 23:12 | 只看该作者
在驱动WS2812 LED时,不同的方法有各自的优缺点。

使用特权

评论回复
14
xiaoqi000| | 2024-8-31 23:13 | 只看该作者
提到的使用GPIO配合__NOP()延时来模拟WS2812的时序是一种较为简单直接的方法

使用特权

评论回复
15
LOVEEVER| | 2024-9-13 17:51 | 只看该作者
nop的时间是固定的嘛?长时间运行会不会不稳定?

使用特权

评论回复
16
xdvca| | 2024-9-17 14:35 | 只看该作者
一个nop大概占用30-40ns 0码为400+850ns 1码为850+400ns

使用特权

评论回复
17
610u| | 2024-9-17 14:57 | 只看该作者
gpio会占用cpu,spi或spi+dma需要对spi频率进行配置

使用特权

评论回复
18
更多更合适ii| | 2024-10-2 21:46 | 只看该作者
本次用的是gpio通过 ` __NOP() ` 延时来模拟ws2812的时序

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

969

主题

2978

帖子

7

粉丝