[SPI+DMA] 驱动WS2812B显示时钟

实现原理

本人一个大学萌新,偶然间发现RGB时钟这神奇的玩意,就想试试。目前初步实现时钟显示,第一次写博客,只是为了记录自己的学习成果方便以后查看,大家感兴趣的话也可以看看。
欢迎大家批评指正,如果有好的想法也可以告诉我,大家一起交流交流,一起学习,一起进步。
先贴几篇文章
[STM32]PWM+DMA控制WS2812
STM32F407通过SPI+DMA的方式驱动WS2812
我觉得大家通过这两篇文章大概就能明白点亮RGB灯的原理并成功点亮。

使用的硬件

1.一块淘宝上随便搜的rgb灯板

2.一块stm32最小系统板

时钟显示代码实现

显示样式

代码实现

ws2812初始化

void ws281x_init(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef  SPI_InitStructure;DMA_InitTypeDef DMA_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //PORTA时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //SPI1时钟使能     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //使能DMA传输/* PA7  SPI1_MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PA7复用推挽输出 SPIGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOASPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;        //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;       //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;        //串行同步时钟的空闲状态为低电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;  //串行同步时钟的第2个跳变沿(上升或下降)数据被采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;     //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;       //定义波特率预分频的值:波特率预分频值为16SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;  //CRC值计算的多项式SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_Cmd(SPI1, ENABLE); //使能SPI外设SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);DMA_DeInit(DMA1_Channel3);   //将DMA的通道1寄存器重设为缺省值DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(SPI1 -> DR); //cpar;  //DMA外设ADC基地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pixelBuffer; //cmar;  //DMA内存基地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //数据传输方向,从内存读取发送到外设DMA_InitStructure.DMA_BufferSize = PIXEL_NUM * 24; //cndtr;  //DMA通道的DMA缓存的大小DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输DMA_Init(DMA1_Channel3, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器 ws281x_closeAll();  //关闭全部的灯delay_ms(100); //关闭全部的灯需要一定的时间
}

颜色传输及颜色划分

uint32_t ws281x_color(uint8_t red, uint8_t green, uint8_t blue)//颜色传输
{return green << 16 | red << 8 | blue;
}void ws281x_setPixelColor(u8 x,u8 y,uint32_t GRBcolor)//点亮任意单个灯  画点
{int n,i;if(x>8||y>32)return ;n=rgb[x][y];for(i=0; i < 24; ++i){pixelBuffer[n][i] = (((GRBcolor << i) & 0X800000) ? WS_HIGH : WS_LOW);}ws281x_show();delay_ms(42);
}/ Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
//颜色划分
uint32_t ws281x_wheel(uint8_t wheelPos)
{wheelPos = 255 - wheelPos;if(wheelPos < 85) {return ws281x_color(255 - wheelPos * 3, 0, wheelPos * 3);}if(wheelPos < 170) {wheelPos -= 85;return ws281x_color(0, wheelPos * 3, 255 - wheelPos * 3);}wheelPos -= 170;return ws281x_color(wheelPos * 3, 255 - wheelPos * 3, 0);
}

画点及字符显示

void ws281x_setPixelColor(u8 x,u8 y,uint32_t GRBcolor)//点亮任意单个灯  画点
{int n,i;if(x>8||y>32)return ;n=rgb[x][y];for(i=0; i < 24; ++i){pixelBuffer[n][i] = (((GRBcolor << i) & 0X800000) ? WS_HIGH : WS_LOW);}ws281x_show();delay_ms(42);
}//画点
//x:0~127
//y:0~63
//t:1 填充 0,清空
//GRBcolor: 颜色设置
void ws281x_DrawPoint(u8 x,u8 y,u8 t,uint32_t GRBcolor)
{if(t==1)ws281x_setPixelColor(x,y,GRBcolor) ;
elsews281x_ResetPixelColor( x,y, GRBcolor);}//在指定位置显示一个字符,包括部分字符
//x:0~8
//y:0~32
//mode:0,反白显示;1,正常显示
//size:选择字体 8
void ws281x_ShowClock(u8 x,u8 y,u8 chr,u8 t,u8 size,uint32_t GRBcolor)
{   u8 temp,s,t1;u8 x0=x;u8 csize=(size/8+((size%8)?1:0))*(size/2);      //得到字体一个字符对应点阵集所占的字节数for(s=0;s<csize;s++){if(csize==4)temp= asc2_0804[chr][s]; else if(csize==3)temp= asc2_0603[chr][s];else return;for(t1=0;t1<8;t1++){if(temp&0x80){        ws281x_DrawPoint(x,y,t,GRBcolor);}else ws281x_DrawPoint(x,y,!t,GRBcolor);temp<<=1;x++;if((x-x0)==8){x=x0;y++;break;}}}
}

字模及取模方式

uint8_t asc2_0603[95][3]=
{{0x7F,0x41,0x7F},/*"0",0*/
{0x00,0x7F,0x00},/*"1",1*/
{0x4F,0x49,0x79},/*"2",2*/
{0x49,0x49,0x7F},/*"3",3*/
{0x78,0x08,0x7F},/*"4",4*/
{0x79,0x49,0x4F},/*"5",5*/
{0x7F,0x49,0x4F},/*"6",6*/
{0x40,0x40,0x7F},/*"7",7*/
{0x7F,0x49,0x7F},/*"8",8*/
{0x79,0x49,0x7F},/*"9",5*/
};

将每个灯封装进二维数组里

uint8_t rgb[8][32]=
{0,15,16,31,32,47,48,63,64,79,80,95,96, 111,112,127,128,143,144,159,160,175,176,191,192,207,208,223,224,239,240,255,
1,14,17,30,33,46,49,62,65,78,81,94,97, 110,113,126,129,142,145,158,161,174,177,190,193,206,209,222,225,238,241,254,
2,13,18,29,34,45,50,61,66,77,82,93,98, 109,114,125,130,141,146,157,162,173,178,189,194,205,210,221,226,237,242,253,
3,12,19,28,35,44,51,60,67,76,83,92,99, 108,115,124,131,140,147,156,163,172,179,188,195,204,211,220,227,236,243,252,
4,11,20,27,36,43,52,59,68,75,84,91,100,107,116,123,132,139,148,155,164,171,180,187,196,203,212,219,228,235,244,251,
5,10,21,26,37,42,53,58,69,74,85,90,101,106,117,122,133,138,149,154,165,170,181,186,197,202,213,218,229,234,245,250,
6,9, 22,25,38,41,54,57,70,73,86,89,102,105,118,121,134,137,150,153,166,169,182,185,198,201,214,217,230,233,246,249,
7,8, 23,24,39,40,55,56,71,72,87,88,103,104,119,120,135,136,151,152,167,168,183,184,199,200,215,216,231,232,247,248,
};

谢谢大家的观看。
精美壁纸奉上

[SPI+DMA] 驱动WS2812B显示时钟相关推荐

  1. 小熊派 FreeRTOS+SPI+DMA 驱动 TFT-LCD

    文章目录 小熊派 FreeRTOS+SPI+DMA 驱动 TFT-LCD 一.文章前言 二.SPI+DMA 配置 三.FreeRTOS 配置 四.代码编写 五.实验现象 小熊派 FreeRTOS+SP ...

  2. 【STM32】基于STM32CubeIDE SPI+DMA驱动WS2812

    [STM32]基于STM32CubeIDE SPI+DMA驱动WS2812 ✨申明:本文章仅发表在CSDN网站,任何其他网见此内容均为盗链和爬取,请多多尊重和支持原创!

  3. STM32 SPI+DMA 驱动 SRAM LY68L6400SLIT 应用笔记

    关键词:库函数,STM32F407,SPI+DMA ,SPI-DMA,SRAM , LY68L6400SLIT,STM32CubeMX 编 辑:大黄蜂 说明:本笔记记录 基于 STM32F407 + ...

  4. STM32 HAL库 PWM+DMA 驱动WS2812B彩灯(STM32F030F4P6)

    谁不想拥有炫酷的小彩灯呢?WS2812B可以给你机会...... 博主使用STM32驱动WS2812B主要参考了这位佬的文章,因为需求问题,采用了Cortex-M0的stm32f030f4p6(16k ...

  5. 基于STM32F411使用SPI+DMA驱动LCD

    先看效果 F411CE 硬件SPI+DMA驱动LCD 基于HAL库 其实HAL库我用不太习惯,一直也是用的标准库 但HAL库确实是好上手一些,就迅速创建一个新的template 这次就当尝试一下吧,因 ...

  6. STM32 SPI+DMA驱动WS2812

    [举报再看养成习惯,噢 不对,点赞再看养成习惯.感谢支持] 开头不多叨叨,直接进入主题: WS2812的驱动原理: 首先明白高低电平的表示方法: 低电平(0 code): 0.35us的高电平+0.8 ...

  7. [HAL]STM32 SPI+DMA驱动WS2812

    该程序是纯手敲,非Cube生成!所有代码均注释. 源码在文章后面获取 WS2818 简介 Keyword: 单线通讯.归零码.Reset.RGB顺序 RGB一共有24bit位 ->相当于驱动一个 ...

  8. GD32驱动DS3231显示时钟踩坑记录

    近日调试GD32驱动ds3231的程序,程序从STM 32移植过来的,所以就没想太多.当时STM32有HAL库开发,运行在内部晶振经PLL后的64MHZ频率.具体驱动程序网上一大堆,我这里就不在赘述了 ...

  9. 沁恒CH579M使用PWM+DMA驱动WS2812B程序

    TMR1,TMR2 的强大功能: 首先咱们看看CH579M规格书,只有TMR1和TMR2支持DMA中断 先定义一个数组把数组的初始RAM地址和结束地址放在寄存器里,当前缓冲地址不管 DMA可以循环和不 ...

最新文章

  1. ASP.NET 2.0实现自带TreeView的客户端连带选择
  2. iOS开发之打电话,发短信,发送邮件
  3. CSS Library
  4. paddle模块的详细介绍
  5. apache hive_通过6个简单的步骤在Windows上运行Apache Hive
  6. DVWA设置mysql_dvwa安装、配置、使用教程(Linux)
  7. [9] ADB 查看设备信息
  8. 【BZOJ1058】[ZJOI2007]报表统计 STL
  9. scrapy爬虫框架实例一 某平台信息(两次post请求的发起)
  10. mysql数据库事务实现方式_mysql事务的实现原理
  11. Hexo博客中添加Live 2D模型
  12. ftl 页面使用java代码_在FTL文件中使用自定义的Java方法
  13. 关于atoi和atol转换超过10位数字字符串溢出问题
  14. seo怎么优化:手把手的教你SEO优化代码
  15. 跨境解读:亚马逊封号,避雷专题
  16. html 获取浏览器语言,js之获取浏览器语言
  17. 网站APP游戏被入侵渗透破解该怎么解决
  18. 音响设备常用连接头及音视频线材的制作方法
  19. 【企业级物联网】hj212数据解析模块详解
  20. 计算机视觉基础 图像滤波器

热门文章

  1. python读取中文txt乱码问题
  2. 系统学习机器学习之系统认识
  3. (根据关键词)查找论文的一些途径
  4. [K/3Cloud]关于选单操作
  5. 服务器系统做个备份吗,服务器操作系统能做备份吗
  6. 自动化测试框架RobotFrameWork教程03 RF基础关键字
  7. 陕南柿子红了_陕南赤子_新浪博客
  8. 私域流量运营之社交裂变
  9. AD19解决复制粘贴后Designator出现问号的问题——需要更改设置
  10. 25行代码解决财务数据大写金额转换