|
楼主 |
发表于 2018-7-9 15:19:03
|
显示全部楼层
真的非常感谢你的解答!谢谢!
现在正常了,问题出在时钟,我使用了内部40MHz,出来的时间有点不准,现在换成外部8MHz时钟,用你的显示程序,完全正常!如下
- /*********************************************************
- * 实验平台:基于STM32F103C8T6
- * 库版本 :ST3.0.0
- *********************************************************/
- #include "stm32f10x.h"
- #include "stm32f10x_spi.h"
- #include "stm32f10x_dma.h"
- #include "led.h"
- #define LEDNUM 40 //显示的灯的数量 , 需要人工指定
- #define PIXNUM LEDNUM*3 //像素数量
- #define SENDLENGTH PIXNUM*12 //发送位数,SPI时钟:10M,每bit0.1us, 用12bit拼接成一个WS2812的数据位
- unsigned char ws2812b_PixBuf[PIXNUM] = {0};//像素缓存区 16个灯*3
- unsigned char spi_SendBuf[SENDLENGTH] = {0,0,0};//SPI的发送缓存区
- void Delay(__IO u32 nCount)
- {
- for(; nCount != 0; nCount--);
- }
- /*
- *****************************************************
- * 功能说明: WS2812b初始化
- * 形 参:
- * 返 回 值:
- * 备 注:
- *****************************************************
- SPI+DMA驱动方式:
- MCU: STM32F103C8T6
- IO配置:PA7(SPI1.MOSI) , 5V上拉电阻(1K)+ 开漏输出
- 外部时钟:8MHz,倍频致40MHz
- SPI时钟:10M,每bit0.1us, 用12bit拼接成一个WS2812的数据位
- */
- void WS2812b_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- SPI_InitTypeDef SPI_InitStructure;
- DMA_InitTypeDef DMA_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_5;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- GPIO_ResetBits(GPIOA,GPIO_Pin_7);//拉低数据线,复位WS2812b
- SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;//一线发送
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主模式
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//时钟空闲时为高
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟的第二个跳变沿采样数据
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件控制片选信号
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//波特率4分频 40M/4 = 10M =0.1us
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
- SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC校验多项式 大于1即可
- SPI_Init(SPI1, &SPI_InitStructure);
-
- DMA_DeInit(DMA1_Channel3);
- DMA_InitStructure.DMA_BufferSize = SENDLENGTH;
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (SPI1->DR);
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)spi_SendBuf;
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
- DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
- DMA_Init(DMA1_Channel3, &DMA_InitStructure); /* DMA1 CH3 = MEM -> DR */
-
- SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
- SPI_Cmd(SPI1, ENABLE);
- DMA_Cmd(DMA1_Channel3, DISABLE);
- }
- /*4位一查表,均衡一下空间和速度
- CPU主频改成40M,SPI时钟4分频是10M,12位是1.2us*/
- const unsigned char LUTbl[16][6] = {
- {0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00},\
- {0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0xF8},\
- {0xE0, 0x0E, 0x00, 0xFF, 0x8E, 0x00},\
- {0xE0, 0x0E, 0x00, 0xFF, 0x8F, 0xF8},\
-
- {0xE0, 0x0F, 0xF8, 0xE0, 0x0E, 0x00},\
- {0xE0, 0x0F, 0xF8, 0xE0, 0x0F, 0xF8},\
- {0xE0, 0x0F, 0xF8, 0xFF, 0x8E, 0x00},\
- {0xE0, 0x0F, 0xF8, 0xFF, 0x8F, 0xF8},\
-
- {0xFF, 0x8E, 0x00, 0xE0, 0x0E, 0x00},\
- {0xFF, 0x8E, 0x00, 0xE0, 0x0F, 0xF8},\
- {0xFF, 0x8E, 0x00, 0xFF, 0x8E, 0x00},\
- {0xFF, 0x8E, 0x00, 0xFF, 0x8F, 0xF8},\
-
- {0xFF, 0x8F, 0xF8, 0xE0, 0x0E, 0x00},\
- {0xFF, 0x8F, 0xF8, 0xE0, 0x0F, 0xF8},\
- {0xFF, 0x8F, 0xF8, 0xFF, 0x8E, 0x00},\
- {0xFF, 0x8F, 0xF8, 0xFF, 0x8F, 0xF8},};
-
- /*当更改完ws2812b_PixBuf后,调用这个函数刷新灯显示*/
- void WS2812b_Display(void)
- {
- unsigned long i;
- unsigned long index = 0;
- unsigned char temp = 0;
- unsigned char const *p;
- for(i = 0;i < PIXNUM;i++)//轮询像素缓存区
- {
- temp = (ws2812b_PixBuf[i] >> 4);
-
- p = LUTbl[temp];
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
-
- temp = (ws2812b_PixBuf[i] & 0x0F);
- p = LUTbl[temp];
-
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
- spi_SendBuf[index++] = *p++;
-
- }
-
- DMA_Cmd(DMA1_Channel3, DISABLE);
- DMA_ClearFlag(DMA1_FLAG_TC3);
- DMA1_Channel3->CNDTR = SENDLENGTH;
- DMA_Cmd(DMA1_Channel3, ENABLE);
-
- }
- void SystemClock_Config(void)
- {
- RCC_DeInit(); //初始化
- RCC_HSEConfig(RCC_HSE_ON); //打开外部时钟HSE 8MHz
-
- if(RCC_WaitForHSEStartUp() == SUCCESS) //等待HSE启动成功
- {
-
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_5); //选择PLL的时钟源并5倍 40Mhz
- RCC_PLLCmd(ENABLE); //使能PLL时钟
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待PLL时钟就绪
- {
- }
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //系统时钟选择PLL作为时钟源
- // * - 0x00: HSI used as system clock
- // * - 0x04: HSE used as system clock
- // * - 0x08: PLL used as system clock
- // * - 0x0C: HSI48 used as system clock, applicable only for STM32F072 devices
- while(RCC_GetSYSCLKSource()!=0x08) //判断返回的时钟源是否为PLL时钟源
- {
- }
- RCC_HCLKConfig(RCC_SYSCLK_Div1); //PLL不分频给系统时钟 40MHz
- }
- }
- int main(void)
- {
- int i;
- SystemClock_Config();
- LED_GPIO_Config(); //LED 端口初始化
- WS2812b_Init();
-
- for(i=0;i<PIXNUM;i+=3)
- {
- ws2812b_PixBuf[i] = 0x00;
- ws2812b_PixBuf[i+1] = 0x00;
- ws2812b_PixBuf[i+2] = 0xff;
- }
- WS2812b_Display();
- while (1)
- {
- LED1( ON ); // 亮
- Delay(0x200000);
- LED1( OFF ); // 灭
- Delay(0x200000);
-
- }
- }
复制代码
再次感谢你热心的解答!!! |
|