用N32G452CCL7写一个用SPI2+DMA来驱动WS2812的程序
时间: 2023-09-06 16:10:34 浏览: 47
好的,这是一个基于N32G452CCL7单片机使用SPI2和DMA驱动WS2812的示例程序:
```c
#include "N32G452xx.h"
#include "ws2812.h"
#define LED_NUM 60 // WS2812灯珠数量
#define LED_BYTE (LED_NUM * 24) // 一共需要传输的字节数
uint8_t led_data[LED_BYTE]; // 存储RGB数据的数组
void SPI2_Init(void)
{
RCC->AHBCLKCTRL |= RCC_AHBCLKCTRL_DMA1CLKEN_Msk; // 使能DMA时钟
RCC->APBCLKCTRL |= RCC_APBCLKCTRL_SPI2CLKEN_Msk; // 使能SPI2时钟
RCC->APBCLKCTRL |= RCC_APBCLKCTRL_GPIOBCLKEN_Msk; // 使能GPIOB时钟
// 配置SPI2_MISO、SPI2_MOSI和SPI2_CLK引脚为SPI功能
GPIOB->ALTFUNCSET |= GPIO_ALTFUNCSET_PIN5_Msk | GPIO_ALTFUNCSET_PIN6_Msk | GPIO_ALTFUNCSET_PIN7_Msk;
GPIOB->ALTFUNCCLR &= ~(GPIO_ALTFUNCCLR_PIN5_Msk | GPIO_ALTFUNCCLR_PIN6_Msk | GPIO_ALTFUNCCLR_PIN7_Msk);
GPIOB->MODER &= ~(GPIO_MODER_MODE5_Msk | GPIO_MODER_MODE6_Msk | GPIO_MODER_MODE7_Msk);
GPIOB->MODER |= GPIO_MODER_MODE5_1 | GPIO_MODER_MODE6_1 | GPIO_MODER_MODE7_1;
// 配置SPI2为主机模式,16位数据帧,时钟极性为高电平,时钟相位为第一边沿,数据传输高位先传输
SPI2->CTRL0 = SPI_CTRL0_MSTR_Msk | SPI_CTRL0_DFS_Msk | SPI_CTRL0_CPOL_Msk | SPI_CTRL0_CPHA_Msk | SPI_CTRL0_LSB_Msk;
// SPI2时钟分频系数为2(72MHz/2=36MHz)
SPI2->BAUD = SPI_BAUD_DIV2_Msk;
// 配置DMA1通道5为SPI2_TX,8位数据宽度,内存增量模式,循环模式,DMA传输完成中断禁止
DMA1_CH5->CTRL = DMA_CTRL_CHEN_Msk | DMA_CTRL_DIR_Msk | DMA_CTRL_SIZE_Msk | DMA_CTRL_MINC_Msk | DMA_CTRL_CIRC_Msk;
DMA1_CH5->SRCADDR = (uint32_t) led_data;
DMA1_CH5->DSTADDR = (uint32_t) &SPI2->TXDATA;
// 配置NVIC,使能DMA1通道5中断
NVIC_SetPriority(DMA1_IRQn, 0);
NVIC_EnableIRQ(DMA1_IRQn);
}
void DMA1_IRQHandler(void)
{
if (DMA1->INTSTAT & DMA_INTSTAT_INT5_Msk) {
DMA1->INTCLR = DMA_INTCLR_INT5_Msk; // 清除DMA1通道5中断标志位
SPI2->CTRL1 &= ~SPI_CTRL1_SPIEN_Msk; // 禁用SPI2
DMA1_CH5->CTRL |= DMA_CTRL_CHEN_Msk; // 使能DMA1通道5
}
}
void WS2812_SendData(void)
{
uint16_t i, j;
uint8_t bit_val;
for(i = 0; i < LED_NUM; i++) {
for(j = 0; j < 24; j++) {
bit_val = (led_data[i * 24 + j] & 0x80) ? 0x0F : 0x08; // 根据数据的高位或低位选择发送的高电平或低电平
led_data[i * 24 + j] = bit_val; // 更新发送的数据
}
}
DMA1_CH5->CTRL &= ~DMA_CTRL_CHEN_Msk; // 禁用DMA1通道5
SPI2->CTRL1 |= SPI_CTRL1_SPIEN_Msk; // 使能SPI2
}
int main(void)
{
WS2812_Init(LED_NUM); // 初始化WS2812灯珠
SPI2_Init(); // 初始化SPI2
while (1) {
WS2812_SendData(); // 发送数据到WS2812
delay_ms(50); // 延时一段时间
}
}
```
注意:上述代码仅为示例,需要根据具体的硬件连接和WS2812协议进行相应的修改。