STM32+ws2812灯条,点灯升级版
ws2812系列灯条,是一种可寻址的RGB LED彩灯,可以自定义颜色、点灯速度等。只需要一个IO就可以控制多个灯。ws2812系列有三根线,分别为VCC、GND、信号控制线。作为优化升级版的ws2813系列,更是具有断点续传功能,比如说有个灯坏了,但是它与后面的信号线没有断,信号可以正常传到后面去。
作为Arduino爱好者,这里推荐两个好用的库hastLed和Neopixel。
这里想和大家分享一下stm32连接ws2812~ 用的单片机是stm32f103zet6,这部分代码换成stm32f103c8t6照样跑的通。
一、添加ws2812.c和ws2812.h文件
直接使用正点原子模板向HARDWARE文件夹下,新建一个文件夹命名为ws2812,然后新建ws2812.c和ws2812.h。
然后把一下文件分别复制到对应c和h文件
1、ws2812.h
#ifndef __WS2812_H
#define __WS2812_H#include "stm32f10x.h"#define PIXEL_NUM 60//硬件spi模拟ws2811时序(用spi的8位数据模拟ws281x的一位数据)
//要将系统时钟设置为56M,分频数设置为8,则SPI的通信频率为7M,传输一位数据的时间约为143纳秒(ns)
//3*143 = 429ns 5*143 = 715ns 符合WS281X芯片的通信时序。
// _____
// | |___| 11111000 high level
// ___
// | |_____| 11100000 low level#define WS_HIGH 0XF8
#define WS_LOW 0XE0void ws281x_init(void);
void ws281x_closeAll(void);
void ws281x_rainbowCycle(uint8_t wait);
uint32_t ws281x_color(uint8_t red, uint8_t green, uint8_t blue);
void ws281x_setPixelColor(uint16_t n ,uint32_t GRBcolor);
void ws281x_show(void);void ws281x_theaterChase(uint32_t c, uint8_t wait);
void ws281x_colorWipe(uint32_t c, uint8_t wait);
void ws281x_rainbow(uint8_t wait);
void ws281x_theaterChaseRainbow(uint8_t wait);#endif /* __WS2812_H */
2、ws2812.c
#include "ws2812.h"
#include "usart.h"
#include "delay.h"uint8_t pixelBuffer[PIXEL_NUM][24] ;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); //关闭全部的灯需要一定的时间
}void ws281x_closeAll(void)
{uint16_t i;uint8_t j;for(i = 0; i < PIXEL_NUM; ++i){for(j = 0; j < 24; ++j){pixelBuffer[i][j] = WS_LOW;}}ws281x_show();
}uint32_t ws281x_color(uint8_t red, uint8_t green, uint8_t blue)
{return green << 16 | red << 8 | blue;
}void ws281x_setPixelColor(uint16_t n ,uint32_t GRBcolor)
{uint8_t i;if(n < PIXEL_NUM){for(i = 0; i < 24; ++i){pixelBuffer[n][i] = (((GRBcolor << i) & 0X800000) ? WS_HIGH : WS_LOW);}}
}void ws281x_setPixelRGB(uint16_t n ,uint8_t red, uint8_t green, uint8_t blue)
{uint8_t i;if(n < PIXEL_NUM){for(i = 0; i < 24; ++i){pixelBuffer[n][i] = (((ws281x_color(red,green,blue) << i) & 0X800000) ? WS_HIGH : WS_LOW);}}
}void ws281x_show(void)
{DMA_Cmd(DMA1_Channel3, DISABLE ); //关闭USART1 TX DMA1 所指示的通道 DMA_ClearFlag(DMA1_FLAG_TC3); DMA_SetCurrDataCounter(DMA1_Channel3,24 * PIXEL_NUM );//DMA通道的DMA缓存的大小DMA_Cmd(DMA1_Channel3, ENABLE); //使能USART1 TX DMA1 所指示的通道
}// 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);
}// Fill the dots one after the other with a color
void ws281x_colorWipe(uint32_t c, uint8_t wait) {for(uint16_t i=0; i<PIXEL_NUM; i++) {ws281x_setPixelColor(i, c);ws281x_show();delay_ms(wait);}
}void ws281x_rainbow(uint8_t wait) {uint16_t i, j;for(j=0; j<256; j++) {for(i=0; i<PIXEL_NUM; i++) {ws281x_setPixelColor(i, ws281x_wheel((i+j) & 255));}ws281x_show();delay_ms(wait);}
}// Slightly different, this makes the rainbow equally distributed throughout
void ws281x_rainbowCycle(uint8_t wait) {uint16_t i, j;for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheelfor(i=0; i< PIXEL_NUM; i++) {ws281x_setPixelColor(i,ws281x_wheel(((i * 256 / PIXEL_NUM) + j) & 255));}ws281x_show();delay_ms(wait);}
}//Theatre-style crawling lights.
void ws281x_theaterChase(uint32_t c, uint8_t wait) {for (int j=0; j<10; j++) { //do 10 cycles of chasingfor (int q=0; q < 3; q++) {for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {ws281x_setPixelColor(i+q, c); //turn every third pixel on}ws281x_show();delay_ms(wait);for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {ws281x_setPixelColor(i+q, 0); //turn every third pixel off}}}
}//Theatre-style crawling lights with rainbow effect
void ws281x_theaterChaseRainbow(uint8_t wait) {for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheelfor (int q=0; q < 3; q++) {for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {ws281x_setPixelColor(i+q, ws281x_wheel( (i+j) % 255)); //turn every third pixel on}ws281x_show();delay_ms(wait);for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {ws281x_setPixelColor(i+q, 0); //turn every third pixel off}}}
}
这两部简单地复制粘贴大家可以跟上的吧,接下来添加库到keil。
3、keil添加库
4、改mian.c代码
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "ws2812.h"int8_t i;
void Delay(u32 count)
{u32 i = 0;for(; i < count; i++);
}int main(void)
{uart_init(115200);delay_init();ws281x_init();while(1){ws281x_colorWipe(ws281x_color(255, 0, 0), 50); // Redws281x_colorWipe(ws281x_color(0, 255, 0), 50); // Greenws281x_colorWipe(ws281x_color(200, 255, 0), 50); //黄色ws281x_colorWipe(ws281x_color(100, 255, 50), 50); //冰蓝ws281x_colorWipe(ws281x_color(155, 255, 0), 50); //嫩绿色}
}
复制完代码编译一下,这时候你会发现报错了!!!
不要方,这是由于我们没有添加stm32spi和dma文件。
添加进去,完美解决。鼓掌
上传代码到单片机,VCC、GND正常接,信号线接到PA7。
工程代码如下
qq-hh/qq-hh-My_Project_stm32 (github.com)
ws2812+stm32视频
STM32+ws2812灯条,点灯升级版相关推荐
- ESP32使用外设RMT控制WS2812灯条
目录 一.简介 二.所需材料 三.官方例程 四.使用方法 4.1 RMT初始化 4.2 WS2812初始化 4.3 点亮WS2812 五.LED颜色渐变 5.1 第一种实现方法 5.2 第二种实现方法 ...
- 自制小爱音箱控制氛围灯(小爱音箱+Arduino+RGB灯条+点灯科技)
硬件准备 1 .wemos d1 mini (ESP8266) 2.灯条应该是ws2813吧 3.小爱音箱 查看资料 点灯科技接入小爱流程 https://diandeng.tech/doc/xiao ...
- STM32使用PWM+DMA方式驱动WS2812灯珠
一. 关于WS2812 WS2812 内部集成了处理芯片和3颗不同颜色的led灯(红,绿,蓝),通过单总线协议分别控制三个灯的亮度强弱,达到全彩的效果. WS2812B Datasheet 二. WS ...
- ESP32 驱动WS2812B 灯条
//WS2812 灯条 #include <Arduino.h> #include <Adafruit_NeoPixel.h>//关键是这个库 #define WS_PIN ...
- WS2812灯珠(三)-- STM32 PWM+DMA方式驱动
WS2812灯珠(三)-- STM32 PWM+DMA方式驱动 文章目录 WS2812灯珠(三)-- STM32 PWM+DMA方式驱动 一.理论 二.代码实践 一.理论 PWM输出就是对外输出脉宽( ...
- arduinows2812灯条程序_Arduino 控制WS2812 LED灯条
传统的LED限制总是很多,比如需要很多的引脚.所以有一种很好的解决方案是用灯条.理论上这种灯条可以通过通讯,用一根数据总线可以控制达到无上限个数的RGB-LED灯珠,并且在数量在1024以下时,延迟是 ...
- ## STM32——闪烁灯程序
STM32--闪烁灯程序 单片机的闪烁灯是继点灯后的一个简单的程序,这也是每一个初学者的必经路程,也并没有我们想象的那么难,我们要相信自己.人生难得几回搏,此时不搏待何时. --至每一个为自己的理想而 ...
- Arduino控制WS2812灯带(灯环)
设计者:STCode(公众号同名) Arduino控制WS2812灯带(灯环) 1) WS2812灯 WS2812灯带 WS2812灯环 WS2812是一个集控制电路与发光电路于一体的智能外空LED光 ...
- 秒上手!使用Arduino控制基于WS2812B的LED灯条
使用Arduino控制基于WS2812B的LED灯条 一.材料准备 硬件部分 1. Arduino UNO R3 开发板 2. 基于WS2812B的LED灯条 3. 杜邦线若干 软件部分 1. Ard ...
最新文章
- ceph 部署单机集群
- java.utilDate和java.sql.Date
- 某同学正为自己安装不上sqlserver数据库而愁眉苦脸,使用朋友给的方法顿时喜笑颜开,那么朋友到底出了个什么样的方法呢?...
- 多项新政催生本年度购房最佳“窗口期”
- Matlab与OpenCV对应函数
- typecho插件库 TeStore 方便监控插件版本
- 第八届开源操作系统年度技术会议(OS2ATC)在京召开, 百位科技菁英到场共鉴“开源协作”
- rsync 安装 配置 实例
- springBoot 2.2.6 项目中html页面样式效果丢失
- c++整人小程序(附源码)
- VisualStudio2017密钥(key)
- java 全局钩子_[原]在全局鼠标钩子中模拟鼠标右键单击
- iRightMouse 1.2.0 中文版 (超赞的Mac右键菜单扩展)
- 从链家爬取北京各区二手房房价进行分析并实现数据可视化
- 车牌识别、证件识别、汽车VIN识别在汽车服务门店中的实际应用
- 蓝牙GATT和GAP层
- 在英文版的remix部署,拿到部署地址在中文版的remix 中 合约地址中输入地址,再部署可以实现调用 java调用智能合约Unmatched arguments from index 2
- 四种主要网络IO虚拟化模型
- 通过C++类方法地址调用类的虚方法
- Vue项目配置本地访问地址和IP访问地址