S32K312驱动WS2812
·
在进行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
更多推荐
所有评论(0)