利用stm32f103c8t6实现对WS2812的控制(从硬件出发)
调试所用开发板开源平台链接(含原理图,PCB)PB8 为串行数据线(连WS2812)PB9 为三极管基极(连蜂鸣器)PC13为调试指示灯(低电平有效)GPIO设置(基于开头所述 电路图)时钟树配置(系统时钟72mhz)数据传输时间(TH+TL=1.25μs±600ns)T0H 0码高电平时间 0.35μs ± 150nsT0L 0码低电平时间 0.8μs ± 150nsT1H 1码高电平时间 0.
代码思路(IO翻转模拟时序方法)
目录
所用IO资源 电路图
调试所用开发板开源平台链接(含原理图,PCB)https://oshwhub.com/jhx275816/stm32f103c8t6-zui-xiao-xi-tong-ban
PB8 为串行数据线(连WS2812)
PB9 为三极管基极(连蜂鸣器)
PC13为调试指示灯(低电平有效)
STM32CUBEMX配置
GPIO设置(基于开头所述 电路图)
时钟树配置(系统时钟72mhz)
WS2812数据手册部分
数据传输时间(TH+TL=1.25μs±600ns)
T0H 0码高电平时间 0.35μs ± 150ns
T0L 0码低电平时间 0.8μs ± 150ns
T1H 1码高电平时间 0.7μs ± 150ns
T1L 1码低电平时间 0.6μs ± 150ns
RES帧单位 低电平时间 50μs以上
一定时间的高电平 + 一定时间的低电平 = WS2812承认的一位信号
延时函数思路
在keil的C代码里,可以用__NOP()【两个下划线】产生一个有nop效果的指令
因为系统时钟72mhz,所以一个__nop()=1/72 us。(实测波形中第二个高电平持续时间和理论趋于一致)
接下来仍需要构建一个函数,实测N=1时,延时330-360ns之间(第一个高电平时间为N=2,延时约750ns)
void delay_ns(u32 nus)//n=1 330-360ns
{
for(int i=0;i<nus;i++)
__nop();
}
代码部分
要使用单片机控制一个WS2812b灯珠要给它发送24bit的数据,这24bit的数据就是灯珠的RGB值,不过发送的时候要按照GRB的顺序来发送。
24bit数据格式:
G7 G6 G5 G4 G3 G2 G1 G0 R7 R6 R5 R4 R3 R2 R1 R0 B7 B6 B5 B4 B3 B2 B1 B0
我们把24bit数据分为三次发送 先构建一个发 8bit 函数
void RGB_WriteByte(u8 in_data){
uint8_t n = 0;
uint8_t y = 0,z = 0;
n = in_data;
for(y = 0;y < 8;y++){
z = ((n<<y)&0x80);
if(z){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
delay_ns(2);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
__nop();// 1码
}else{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
__nop(); //
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
delay_ns(2);// 0码
}
}
}
分三次发送(注意是RGB,该函数改变了GRB这个难受的发送方式)
// 设置一个灯的颜色
void RGB_ColorSet(u8 red,u8 green,u8 blue)
{
// 灯的实际写入颜色是GRB
RGB_WriteByte(green); // 写入绿色
RGB_WriteByte(red); // 写入红色
RGB_WriteByte(blue); // 写入蓝色
}
放在while里
RGB_ColorSet(0x00,0x00,0xff);
RGB_ColorSet(0xff,0x00,0xff);
RGB_ColorSet(0x00,0xff,0x00);
RGB_ColorSet(0xff,0xff,0x00);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
delay_ns(500);// 大于280us的低电平过来,然后才会将刚刚发送过来的24bit数据应用到灯上
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);//关闭
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
HAL_Delay(500);//作为送数据结束标志
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
HAL_Delay(500);
IO翻转时序法代码链接https://download.csdn.net/download/qq_44125275/86875749
最后效果图
2022.11.9更新(完善代码架构)
test-stm32-ws2812-IO-2022.11.9.7z
/* USER CODE BEGIN PV */
uint8_t rgb_data[24] = {0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0X00,0XFF,0XFF};
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
//IO模拟时序延时
void delay_ns(u32 nus)//n=1 330ns
{
while(nus--);
}
//RGB解算并发送
void send_code(u8 * sdata){ //
uint8_t n = 0,j=0;
uint8_t x = 0,y = 0,z = 0;
for(j = 0;j < led_number;j++)
{
for(x = 0;x < 3;x++)
{ //
n = sdata[x];
for(y = 0;y < 8;y++)
{
z = ((n<<y)&0x80);
if(z)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
delay_ns(7);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
delay_ns(1); //
}
else
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
delay_ns(1);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
delay_ns(7);
}
}
}
}
}
//自定义颜色
void colorset(u8 i)
{
switch(i)
{
case 0:
send_code(&rgb_data[0]);//所有灯清零
break;
case 1:
send_code(&rgb_data[3]);//所有灯变红灯
break;
case 2:
send_code(&rgb_data[6]);//所有灯变绿灯
break;
case 3:
send_code(&rgb_data[9]);//所有灯变蓝灯
break;
case 4:
send_code(&rgb_data[13]);//所有灯变红灯//所有灯变绿灯
break;
case 5:
send_code(&rgb_data[22]);//所有灯变红灯//所有灯变蓝灯
break;
case 6:
send_code(&rgb_data[19]);//所有灯变红灯//所有灯变绿灯//所有灯变蓝灯
break;
case 7:
send_code(&rgb_data[16]);//所有灯变绿灯//所有灯变蓝灯
break;
}
}
// 循环显示各种彩色
void circular_led_show()
{
u8 i=0,j=0;
for(i=0;i<8;i++)
{
colorset(i);
HAL_Delay(300);
}
}
/* USER CODE END PFP */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
circular_led_show();
//reset信号
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
HAL_Delay(500);
}
Tip:2020 RGB颜色查询大全 #000000 【颜色列表】 (改变灯的颜色需要用到的)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)