在进行S32K312驱动点灯时,选择了WS2812模块,可是商家没有提供对应的C语言驱动,所以修改了豆包的代码完成了驱动的编写。

#include "WS2812.h"
#include "Siul2_Dio_Ip.h"
#include "Siul2_Port_Ip.h"

// LED颜色缓存[R,G,B],二维8位整数数组,更新状态时需要更新发送以更新所有灯的状态
static uint8_t led_colors[LED_NUM][3];

// 1us @120MHz, 用120次循环达到1us延时效果
static void delay_1us(void)
{
    for(volatile uint32_t i=0;i<120;i++);
}

//GCC 编译器的专用编译指令,作用是临时关闭编译器的优化功能,防止后续0/1的延时nop指令被优化
#pragma GCC push_options
#pragma GCC optimize ("O0")


//示波器测量高低电平触发自身约占350ns
//单个nop约增加7ns
//120个nop增加延时至 约1200ns

//发送单个bit 0 or 1 其中T1H≈350ns T1L≈1200ns T0H≈1200ns T0L≈350ns
static void WS2812_SendBit(uint8_t bitVal)
{
    if(bitVal)
    {
    	WS2812_PIN_HIGH();
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        __asm volatile("nop");
        WS2812_PIN_LOW();
    }
    else
    {
    	WS2812_PIN_HIGH();
        WS2812_PIN_LOW();
        __asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");
		__asm volatile("nop");

    }
}

// 发送单个像素 G,R,B,包含 移位(g>>i) 和 与运算&0x01 ,移位是把要检查的二进制数移至最右侧;只看最右边的一位并做与运算,都为1则置1
static void WS2812_SendPixel(uint8_t g, uint8_t r, uint8_t b)
{
    for(int8_t i=7;i>=0;i--) WS2812_SendBit((g>>i)&0x01);
    for(int8_t i=7;i>=0;i--) WS2812_SendBit((r>>i)&0x01);
    for(int8_t i=7;i>=0;i--) WS2812_SendBit((b>>i)&0x01);
}

// 禁用/使能中断,用于临时屏蔽干扰
static inline void disable_irq(void){ __asm volatile("cpsid i"); }
static inline void enable_irq(void){ __asm volatile("cpsie i"); }

// 初始化 WS2812,所有灯RGB值置0
void WS2812_Init(void)
{
    WS2812_PIN_INIT();
    for(uint8_t i=0;i<LED_NUM;i++)
        for(uint8_t j=0;j<3;j++)
            led_colors[i][j]=0;
}

// 刷新 LED,包含:禁用中断,遍历处理数组,使能中断,延时复位进行重置,发送reset锁定颜色配置
void WS2812_Refresh(void)
{
    disable_irq();
    for(uint8_t i=0;i<LED_NUM;i++)
        WS2812_SendPixel(led_colors[i][1], led_colors[i][0], led_colors[i][2]); // [R,G,B]→[G,R,B]
    enable_irq();

    // RESET >280us
    for(uint32_t i=0;i<300;i++) delay_1us();
}

// 全部点亮指定颜色,遍历所有为指定RGB值,在调用Refresh进行更新
void WS2812_AllOn(uint8_t r,uint8_t g,uint8_t b)
{
    for(uint8_t i=0;i<LED_NUM;i++)
    {
        led_colors[i][0]=r;
        led_colors[i][1]=g;
        led_colors[i][2]=b;
    }
    WS2812_Refresh();
}

// 熄灭所有LED,所有RGB为0
void WS2812_AllOff(void)
{
    for(uint8_t i=0;i<LED_NUM;i++)
        for(uint8_t j=0;j<3;j++)
            led_colors[i][j]=0;
    WS2812_Refresh();
}

// 设置单个LED颜色,只更改指定位置的灯
void WS2812_SetLEDColor(uint8_t led_index,uint8_t r,uint8_t g,uint8_t b)
{
    if(led_index>=LED_NUM) return;
    led_colors[led_index][0]=r;
    led_colors[led_index][1]=g;
    led_colors[led_index][2]=b;
}

// LED1控制函数
void LED1_On(uint8_t r, uint8_t g, uint8_t b)
{
    WS2812_SetLEDColor(0, r, g, b);
    WS2812_Refresh();
}

void LED1_Off(void)
{
    WS2812_SetLEDColor(0, 0, 0, 0);
    WS2812_Refresh();
}

// LED2 控制函数
void LED2_On(uint8_t r, uint8_t g, uint8_t b)
{
    WS2812_SetLEDColor(1, r, g, b);
    WS2812_Refresh();
}

void LED2_Off(void)
{
    WS2812_SetLEDColor(1, 0, 0, 0);
    WS2812_Refresh();
}

// LED3 控制函数
void LED3_On(uint8_t r, uint8_t g, uint8_t b)
{
    WS2812_SetLEDColor(2, r, g, b);
    WS2812_Refresh();
}

void LED3_Off(void)
{
    WS2812_SetLEDColor(2, 0, 0, 0);
    WS2812_Refresh();
}

// LED4 控制函数
void LED4_On(uint8_t r, uint8_t g, uint8_t b)
{
    WS2812_SetLEDColor(3, r, g, b);
    WS2812_Refresh();
}

void LED4_Off(void)
{
    WS2812_SetLEDColor(3, 0, 0, 0);
    WS2812_Refresh();
}

// LED5 控制函数
void LED5_On(uint8_t r, uint8_t g, uint8_t b)
{
    WS2812_SetLEDColor(4, r, g, b);
    WS2812_Refresh();
}

void LED5_Off(void)
{
    WS2812_SetLEDColor(4, 0, 0, 0);
    WS2812_Refresh();
}

// LED6 控制函数
void LED6_On(uint8_t r, uint8_t g, uint8_t b)
{
    WS2812_SetLEDColor(5, r, g, b);
    WS2812_Refresh();
}

void LED6_Off(void)
{
    WS2812_SetLEDColor(5, 0, 0, 0);
    WS2812_Refresh();
}
#ifndef WS2812_H
#define WS2812_H

#include "S32K312.h"
#include "S32K312_SIUL2.h"
#include "Siul2_Port_Ip.h"
#include "Siul2_Dio_Ip.h"
#include "stdint.h"
#include "stdbool.h"



#define WS2812_PIN_INDEX  1u             			//GPIO 引脚的 “索引编号”,用于硬件驱动函数识别具体是哪个引脚,是操作GPIO的基础参数
#define WS2812_PIN        (1U << WS2812_PIN_INDEX)  //生成该引脚对应的 “位掩码”(bit mask),用于直接操作 GPIO 寄存器的位,后续置高低电平用
#define WS2812_PORT       PTA_L_HALF              	//指定该引脚所属的 GPIO 端口,属于PTA

//WS2812 5050灯珠数量 共6个
#define LED_NUM 6



//初始化WS2812信号口的引脚PTA1,分别进行启用引脚的信号输出能力、设置引脚为输出模式、初始化引脚为低电平
#define WS2812_PIN_INIT()   do { \
    Siul2_Port_Ip_SetOutputBuffer(IP_SIUL2, WS2812_PIN_INDEX, TRUE, PORT_MUX_AS_GPIO); \
    Siul2_Port_Ip_SetPinDirection(IP_SIUL2, WS2812_PIN_INDEX, SIUL2_PORT_OUT); \
    WS2812_PIN_LOW(); \
} while(0)

//寄存器直接控制PTA1引脚的高低电平
#define WS2812_PIN_HIGH()  (PTA_L_HALF->PGPDO |= (1U << 14U))
#define WS2812_PIN_LOW()   (PTA_L_HALF->PGPDO &= ~(1U << 14U))

//WS2812相关函数声明
void WS2812_Init(void);
void WS2812_AllOn(uint8_t r, uint8_t g, uint8_t b);
void WS2812_AllOff(void);
void WS2812_SetLEDColor(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b);
void WS2812_Refresh(void);

void LED1_On(uint8_t r, uint8_t g, uint8_t b);
void LED1_Off(void);
void LED2_On(uint8_t r, uint8_t g, uint8_t b);
void LED2_Off(void);
void LED3_On(uint8_t r, uint8_t g, uint8_t b);
void LED3_Off(void);
void LED4_On(uint8_t r, uint8_t g, uint8_t b);
void LED4_Off(void);
void LED5_On(uint8_t r, uint8_t g, uint8_t b);
void LED5_Off(void);
void LED6_On(uint8_t r, uint8_t g, uint8_t b);
void LED6_Off(void);

#endif

更多推荐