RGB彩灯总结:
整个RGB彩灯的调试,应该花了不少于两个星期,中间遇到了很多让我很难受甚至很想放弃的problems,但是自己最终还是弄了下来,不能说是坚持了先来,但是至少能实现RGB彩灯的基本功能了,现在也在完善中。既然花了自己这么长时间,那,一定得好好记录一下。也希望大家通过我的调试过程,能够学到你们需要的东西

RGB的调试主要分了两种方法,一种是通过驱动芯片:SM16703、WS2811、TM1829三种芯片进行调试;另外一种是直接通过三个引脚,利用PWM进行调试。

两种方法其实各有优缺点:

---------------------------------------------------------------------------------

第一种方法的优点是:它只需要通过一个IO(DIN),通过给驱动芯片写入数据,就可以控制RGB彩灯的色变,但是它最大的缺点(我认为)是不管是哪个芯片,它的时序要求都是十分十分严格的,如果时序调不对,一般都是上电之后显示的是白光,当初也是因为在网上copy的代码,也没怎么详细的对代码进行分析,上来就开始调试,但是始终没有成功,又开始疯狂的在网上搜集资料,最后结论基本都是一样:调时序,时序、时序、时序是最重要的。

第二种方法,直接用PWM对R、G、B三个灯进行颜色控制,通过改变三个通道的占空比(0~255),三个灯进行颜色的组合,就可以实现不同的颜色。用这种方法虽然占用了三个IO口,但是在操作上确实是比较简单。

第一种方法,利用驱动芯片进行调试,下面以WS2811芯片为例:


WS2811芯片时序的图片。(我当时用的PE6为数据的输入引脚)
根据图表我们可以看得出:

TX0(发送0码时):
PEout(6)=1;延时为500ns;
pEout(6)=0;延时为2us;

TX1(发送1码时):
PEout(6)=1;延时为2us;
pEout(6)=0;延时为500ns;

RES设置为50us以上,我当时延时为80us;

既然延时那么重要,那我就简单的说一下调延时的思路,虽然我当时到最后也没有准确的调出来吧,但是还是想分享一下这个过程,望读者能有一些收获。

一、调ns延时函数思路:
要了解几个知识点:单片机的晶振单片机系统时钟时钟周期__nop()延时;

单片机的时钟:
单片机的系统时钟有几个来源(具体可以参考原子哥:第19讲 STM32时钟系统精讲),其中包括单片机内部晶振和外部晶振,STM32单片机内部和外部晶振均为8MHz,然后经过倍频、分频等一些操作成为系统时钟72MHz(可能写的不太好,也就是自己的简单了解);

上面说到了单片机的晶振,那晶振对于单片机有什么作用?
简单地说,没有晶振,就没有时钟周期,就无法执行程序代码,单片机就无法工作。STM32单片机有内部晶振和外部晶振,共同点是两个晶振都是8MHz;

不同点是:外部晶振稳定 内部晶振的误差比较大,但如果对频率要求不高的话(比如不涉及串口通信和精确定时等的话),用内部晶振就行 。但是内部时钟,频率受温度等其它影响。

时钟周期:
单片机工作时,是一条一条地从RoM中取指令,然后一步一步地执行。单片机访问一次存储器的时间,称之为一个机器周期,这是一个时间基准。—个机器周期包括12个时钟周期。如果一个单片机选择了12MHz晶振,它的时钟周期是1/12us,它的一个机器周期是12×(1/12)us,也就是1us

以STM32C8T6单片机而言:
外部晶振是8MHz,经过7倍频,为72MHz;所以它的一个时钟周期为1/72M=13.89ns

一个__nop();空语句按理来说应该占用的就是一个时钟周期,(这个可以通过逻辑分析仪进行测试)所以一个__nop();语句就是13.89ns;

这样就好说了,既然知道了一个__nop();语句占用的是13.89ns,那么当延时为500ns的时候,就可以500/13.89=36个,

// An highlighted block
void WS0_delay05us()//500ns延时
{__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}
//而延时2us就可以通过调用4次WS0_delay05us()函数,
void WS0_delay2us(u8 i)//当i=4时,即2us
{
while(i--)
{
WS0_delay05us();
}
}
TX0函数:
void TX0() // 发送0
{GPIO_SetBits(GPIOE, GPIO_Pin_6)WS0_delay05us();//高电平延时500nsGPIO_ResetBits(GPIOE, GPIO_Pin_6)WS0_delay2us();//低电平延时2us
}
//同理TX1也是如此,只不过高低电平的持续时间正好相反。

**注意一点的是:**如何去测试TX0的时序是否正确,方法:

把上面的的TX0放到主函数中,主函数中只执行这一条语句,然后用逻辑分析仪去抓PE6引脚,看看它的高低电平持续为多长时间。

// An highlighted block
var foo = 'bar';
以我个人的调试经验,第一次测试的时候,高低电平持续的时间肯定和标准的有很大
的差距,那么怎么办那?
一步一步地调啊,(改变__nop();的数量,或者自己也可以用系统的delay__us();函数)千万千万不要心急,当你调试不出来的时候就想想我,我当时调这个时序的时
候都快要崩溃了,2个星期,所以,不要心急,耐心。
还有一点是,当一个芯片时序实在调试不出来的时候,自己也可以去尝试其他的芯
片,因为这三种芯片在延时函数的精度要求上还是有所区别的。

给大家推荐一个我当时参考的一个视频,我觉得讲的挺不错的,也希望大家能学到一些东西。

延时函数调试链接: link.

---------------------------------------------------------------------------------

接下来给大家说一下如何用PWM直接对RGB进行调试:
原理其实很简单,改变电平的占空比使RGB分别显示出不同的色值,然后通过组合显示出想要的颜色。目前实现的功能,通过PWM调试RGB彩灯能够实现一些特定的颜色,同时也可以同串口通信、485通信发送十六进制的数据来改变RGB的颜色(其中实现过程都采用的串口调试助手进行数据的发送)。

通过网上查阅资料,我搜集到了RGB彩灯的颜色表

RGB颜色链接: link.

我用的是TIM4的三个通道PB6/PB7/PB8
代码的主要配置如下:

timer.h

// An highlighted block
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"void TIM4_PWM_Init();
#endif

timer.c
(也就是PWM的初始化及配置),设置的重装载值为255(即0~255)正好对应RGB的颜色表。

// An highlighted block
#include "timer.h"
#include "usart.h"
#include "485.h"//TIM4 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM4_PWM_Init()
{  GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);   //使能定时器3时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5//设置该引脚为复用输出功能,输出TIM4 CH2的PWM脉冲波形    GPIOB.5GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8; //TIM_CH2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO//初始化TIM4TIM_TimeBaseStructure.TIM_Period =255; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =719; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位//初始化TIM4 Channel/2/3/4 PWM模式TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高//TIM_OCInitStructure.TIM_Pulse=10;TIM_OC1Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC1TIM_OC2Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC2TIM_OC3Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC3TIM_OC4Init(TIM4, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC4TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR1上的预装载寄存器TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR2上的预装载寄存器TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR3上的预装载寄存器TIM_ARRPreloadConfig(TIM4,ENABLE);TIM_Cmd(TIM4, ENABLE);  //使能TIM3TIM_CtrlPWMOutputs(TIM4,ENABLE);}//void RGB_SetDate(int rgb_data[])
//{
//  TIM4_PWM_Init();
//  TIM_SetCompare1(TIM4,rgb_data[0]);
//  TIM_SetCompare2(TIM4,rgb_data[1]);
//  TIM_SetCompare3(TIM4,rgb_data[2]);
//}
//*******************************************
//下面采用的是485通信进行的测试
//
//******************************************
//void RGB_SetDate()
//{
//  //TIM4_PWM_Init();
//  TIM_SetCompare1(TIM4,RS485_RX_BUF[0]);
//  TIM_SetCompare2(TIM4,RS485_RX_BUF[1]);
//  TIM_SetCompare3(TIM4,RS485_RX_BUF[2]);
//}
//下面的是利用串口通信
void RGB_SetDate()
{//TIM4_PWM_Init();TIM_SetCompare1(TIM4,USART_RX_BUF[0]);TIM_SetCompare2(TIM4,USART_RX_BUF[1]);TIM_SetCompare3(TIM4,USART_RX_BUF[2]);
}

main.c函数

// An highlighted block
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "timer.h"
#include "usart.h"
#include "485.h"
int red[3]={255,0,0};
int yellow[3]={255,255,0};
int green[3]={0,255,0};
int blue[3]={0,0,25500};
int qin[3]={0,255,255};
//int zi[3]={160,32,240};
int ziluolan[3]={138,43,226};
int hei[3]={0,0,0};    int main(void){     u8 key;u16 t;   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   //设置NVIC中断分组2:2位抢占优先级,2位响应优先级uart_init(9600);delay_init();             //延时 函数初始化TIM4_PWM_Init();RS485_Init(9600);  //初始化RS485   初始化串口的两个引脚PA2  PA3和PD7(485使能引脚)while(1)            {    //**********下面采用的是485进行调试
//      RS485_Send_Data(RS485_RX_BUF,5);
//      RS485_Receive_Data(RS485_RX_BUF,&key);
//      if(key)//接收到有数据
//      {
//          if(key>5)key=5;//最大是5个数据.
//      }
//**********采用的是485进行调试
//----------------------------------------------------------
//----------------------------------------------------------
//**********下面采用的是串口进行调试if(USART_RX_STA&0x8000){                               for(t=0;t<3;t++){USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束}USART_RX_STA=0;//清零语句是X必须有的,就像哪个输入捕获实验,如果不清零就不会再执行中断函数//RGB_SetDate(USART_RX_BUF);}
//***************采用的是串口进行调试RGB_SetDate(USART_RX_BUF);//RGB_SetDate(RS485_RX_BUF);
//  delay_ms(500);
//      RGB_SetDate(yellow);
//      delay_ms(500);
//      RGB_SetDate(green);
//      delay_ms(500);
//      RGB_SetDate(blue);
//      delay_ms(500);
//      RGB_SetDate(qin);
//      delay_ms(500);
//      RGB_SetDate(hei);
//      delay_ms(500);
//      RGB_SetDate(ziluolan);
//      delay_ms(500);}    }

嗯,最后放一下两个星期的调试成功吧:

RGB彩灯调试

代码链接:
链接:https://pan.baidu.com/s/1d4H_htjQOsrc5Wan0QwTuw
提取码:4yau

哈哈哈哈,不管怎么样,还是调试出来了,高兴,不过还需要继续完善。
//------------------------------------------------------------------------------------------
目前的问题:RGB电压的供电问题(目前是7.98V)控制1米的灯带,以及利用蓝牙通信(串口通信)时,只能收到一次数据的问题

STM32C8T6+RGB彩灯(驱动芯片WS28811、PWM两种调试方法)相关推荐

  1. android app两种调试方法

    方法一: 1.使用apktool的-d选项反编译apk文件 java  -jar  apktool.jar  d  -d  target.apk  -o  output 2.在AndroidManif ...

  2. 快速排序的两种实现方法(c语言版本)

    经过调研发现,对任意无序整数数组,快速排序有两种实现方法,这里简单阐述下思路: 思路一:随意选择一个基准元,一般选择数组的起始元或末尾元,Weiss这本书上特意搞了个算法来选择基准元,--,总之就是基 ...

  3. R语言生存分析COX回归分析实战:两种治疗方法发生肾功能损害的情况

    R语言生存分析COX回归分析实战:两种治疗方法发生肾功能损害的情况 目录

  4. mysql workbench kernelbase.dll_电脑出现kernelbase.dll错误的两种解决方法

    KernelBase.dll是Windows操作系统的重要文件,它为各种应用程序提供服务.如果电脑提示kernelbase.dll错误,这该怎么处理?大家可以用电脑自带的防火墙或者是第三方软件来进行故 ...

  5. 使用定制的NSDictionary的方法,对NSArray进行排序(附:数组排序两种常见方法)

    NSArray中存放的是NSDictionary,可以使用策略的方法对NSDictionary进行定制,增加比较的方法.然后调用NSArray的sortUsingSelector方法对数组进行排序,这 ...

  6. Ext.Ajax.request和formPanel.getForm().submit()两种提交方法的异同:

    Ext.Ajax.request和formPanel.getForm().submit()两种提交方法的异同: 1. 相同点: a) 都是使用异步提交的方式: b) 默认都是使用POST方式来提交数据 ...

  7. java代码二进制转为十六进制_Java 中二进制转换成十六进制的两种实现方法

    Java 中二进制转换成十六进制的两种实现方法 每个字节转成16进制,方法1 /** * 每个字节转成16进制,方法1 * * @param result */ private static Stri ...

  8. python ioc di_Spring介绍,IOC(控制反转),DI(依赖注入)介绍及两种注入方法

    Spring介绍,IOC(控制反转),DI(依赖注入)介绍及两种注入方法 第一中方法:在xml文件中注入: (1)开源的轻量级的应用开发框架 特点:a.简化开发:b.解耦:c.集成: 原理对象与对象之 ...

  9. Json返回时间中出现乱码问题的两种解决方法

    Json返回时间中出现乱码问题的两种解决方法 参考文章: (1)Json返回时间中出现乱码问题的两种解决方法 (2)https://www.cnblogs.com/hanyinglong/archiv ...

最新文章

  1. ubuntu下安装flex和bison
  2. linux 查看日志信息--less命令
  3. 滴滴高管今年集体不拿年终奖 员工奖励力度缩减一半
  4. 小鱼易连电脑版_电脑?不,它是随时就绪的专业电话会议解决方案
  5. java 树 右键菜单_jQuery实现自定义右键菜单的树状菜单效果
  6. zune自搭虚拟服务器离线升级,Zune 30g 固件更新至 3.3 记录
  7. 视觉中的经典图像特征小结(一): 颜色直方图, HOG, LBP
  8. 【牛客 - 318L】彪神666(水题,半高精度,递推,trick)
  9. cad一键标注闭合区域lisp_CAD快捷键大全,你值得学会!
  10. Linux下实现Raid 5软阵列
  11. python | 实现多行向量(matrix)两两计算余弦距离、欧几里德距离
  12. SAP License:会计->用友->金蝶->SAP,我的工作历程
  13. Gradle_04_解决多项目同级依赖时找不到符号的异常
  14. 别等找工作时才明白:程序员只会敲代码是不行的!不看后悔!
  15. 开张第一天,一年之际在于春
  16. 十五、K8s helm包管理与应用
  17. 大学生计算机应用论文,大学生计算机应用论文(共1178字).doc
  18. ftp客户端flashfxp破解教程
  19. dotnet core在Linux下运行的步骤
  20. 关于FPGA软件quartus仿真出现cannot launch the modelsim software问题的解决

热门文章

  1. oracle 存储过程误删,oracle恢复误删的procedure存储过程
  2. NGUI发布后看不见UI层解决
  3. 计算机毕设 SpringBoot智慧外贸平台系统 外贸商城 代购商城 海外代购平台Java Vue MySQL数据库 远程调试 代码讲解
  4. Python3网络爬虫开发实战,Scrapy 爬取新浪微博
  5. 最快引流的10个引流方法
  6. layer.open使用方法和参数
  7. Linux常用命令及软件更新
  8. 【无人机】基于SDRE对NPS II无人机进行点对点(调节)控制(Matlab代码实现)
  9. .net 导出Excel,设置Excel页眉及单元格换行方法
  10. 2009年5月26日