51单片机TM1804控制RGB灯闪烁的问题及例程

今天在调RGB灯带时发现:颜色,数量,都能正常显示

但是就是每隔一会,某颗RGB灯都会闪一下,

正常:

异常:(某个灯闪烁)

最后发现是,是因为中断的影响

因为51单片机没有中断优先级的概念,所以任何意外中断都会打断时序。即使是中断内没有任何代码,进入的过程也会花费几us,导致时序错乱

逻辑分析仪也会抓到了这一点

解决方法:

操作时关闭总中断

c 复制代码
			GIE = 0;				// 关闭总中断
			send_px(10,0,1);		// 操控灯
			GIE = 1;				// 开启总中断

使用方法

TM1804的时序规则(芯片参考手册)

相当于0是短一点的高电平加一段低电平

1是长一点的高电平加一段低电平

发完全部灯后,要间隔200us以上让灯的配置导入

代码

TM1804在8位单片机上的代码(TXD修改成自己的引脚)
当前适配的MCU是16Mhz 2T,单个指令操作是125ns,请修改nop数量来匹配时序

用法示例:

c 复制代码
	#include "RGB_tm1084.h" //导入RGB灯头文件
	void main()
	{
		while(1)
		{
			delay_ms(200);	//间隔200ms切换颜色
			GIE = 0;					//关闭总中断
			send_px_num(3,10,0,1); //点亮3个灯,RGB值10 0 1,满载255
			GIE = 1;					//开启总中断
		}
	}

RGB_tm1084.h

c 复制代码
/*
 * TM1804 RGB灯幻彩变化
*/
#ifndef TM1804_H
#define TM1804_H

#include <sc.h>     // 单片机头文件

// 自定义参数
#define TXD RA0				    //LED控制端口
#define IC  54                  //LED灯总个数


// 操作一个灯
void send_px_one(unsigned char R,unsigned char G,unsigned char B);
// 操作指定个数灯
void send_px_num(unsigned int num,unsigned char R,unsigned char G,unsigned char B);
// 操作所有灯
void send_px_all(unsigned char R,unsigned char G,unsigned char B);

//待加入:
// 呼吸灯
// 彩虹渐变
// 流光效果
// 等等

#endif

RGB_tm1084.c

c 复制代码
/*********************
 * TM1804 RGB灯幻彩变化。
********************/

#include "RGB_tm1084.h"

#define nop  asm("nop")     // 一个nop大概0.125us(16MHz 2T)

unsigned int LED_PX;                        //像素点数
unsigned char PWM;                      //TM1804灰度数据 
unsigned char Rda,Gda,Bda;                  //R、G、B灰度数据

unsigned char LED_data;               //可位操作的数据发送暂存变量声明
#define bit0 ((LED_data) & 0x01)
#define bit1 ((LED_data) & 0x02)
#define bit2 ((LED_data) & 0x04)
#define bit3 ((LED_data) & 0x08)
#define bit4 ((LED_data) & 0x10)
#define bit5 ((LED_data) & 0x20)
#define bit6 ((LED_data) & 0x40)
#define bit7 ((LED_data) & 0x80)

/**********************************延时函数*************************************/
void send_px_reset()                // 总间隔延时 200us以上
{
  unsigned int j;
  
  for(j=550;j>0;j--);
} 

// 注意进入信号操作时,要关闭总中断,不然会打乱时序

/********************发送0码函数,高电平400ns,周期1.25us************************/
inline void send_data_0()   
{
	 TXD=1;  // 高电平 300ns
	 nop;		 // 一个nop大概0.125us(16MHz 2T) 300ns
	 
     TXD=0;  // 低电平 900ns
	 nop;nop;nop;

     //实测:
     //高电平 1个nop   375ns,引脚操作耗费250ns,nop耗费125ns
     //低电平 3个nop   1125ns

     //外面if耗费    625ns
     //切换RGB值耗费 750ns
}

/*******************发送1码函数,高电平800ns,周期1.25us*************************/
inline void send_data_1()    
{
	 TXD=1;   // 高电平 900ns
	 nop;nop;nop;nop;nop;
	 TXD=0;   // 低电平 300ns
	 

    // 实测:
    // 高电平 5个nop   875ns
    // 低电平 0个nop   625ns
}



/*************发送1个字节数据,8位颜色*******/
inline void send_data(unsigned char LED_data)		
{                       
	if(bit7)	send_data_1();	else send_data_0();
	if(bit6)	send_data_1();	else send_data_0();
	if(bit5)	send_data_1();	else send_data_0();
	if(bit4)	send_data_1();	else send_data_0();
	if(bit3)	send_data_1();  else send_data_0();
	if(bit2)	send_data_1();  else send_data_0();
	if(bit1)	send_data_1();  else send_data_0();
	if(bit0)	send_data_1();	else send_data_0(); 
}
/*********发送1帧数据************/
// 操作一个灯 原来颜色顺序是GRB
void send_px_one(unsigned char R,unsigned char G,unsigned char B) 
{
    send_data(G);             //发送R灰度数据
    send_data(R);             //发送G灰度数据
    send_data(B);             //发送B灰度数据
}

// 操作指定数量的灯
void send_px_num(unsigned int num,unsigned char R,unsigned char G,unsigned char B) //操作指定个数灯
{
    unsigned int i;
    for(i=0;i<num;i++)
    {
		send_data(G);             //发送R灰度数据
		send_data(R);             //发送G灰度数据
		send_data(B);             //发送B灰度数据
    }
}

// 操作所有灯
void send_px_all(unsigned char R,unsigned char G,unsigned char B) 
{
    unsigned int i;
    for(i=0;i<LED_PX;i++)
    {
		send_data(G);             //发送R灰度数据
		send_data(R);             //发送G灰度数据
		send_data(B);             //发送B灰度数据
    }
}


/*===============================主函数=======================================*/
//void main()
//{
//	unsigned char i;
//	LED_PX=IC;                          //像素点数等于TM1804个数
//	Rda=Gda=Bda=0;                      //R、G、B灰度数据复位清零
//	while(1)
//	{
//		for(i=0;i<PWM;i++)          //红色渐亮  
//		{
//			Rda=i;              //灰度计算
//			send_px();          //发送灰度数据
//			delay(10);          //复位延时
//		}
//		flag=1;                     //标志位置位
//		while(flag)                 //标志位置位后循环函数
//		{
//			for(i=0;i<PWM;i++)  //红色渐灭,绿色渐亮 
//			{
//				Gda=i;
//				Rda=PWM-i;  //灰度计算
//				send_px();  //发送灰度数据
//				delay(10);  //复位延时
//			}
//			for(i=0;i<PWM;i++)  //绿色渐灭,蓝色渐亮 
//			{
//				Bda=i;           
//				Gda=PWM-i;  //灰度计算
//				send_px();  //发送灰度数据
//				delay(10);  //复位延时
//			}
//			for(i=0;i<PWM;i++)  //蓝色渐灭,红色渐亮 
//			{
//				Rda=i;
//				Bda=PWM-i;  //灰度计算
//				send_px();  //发送灰度数据
//				delay(10);  //复位延时
//			}
//		}
//	}
//}
/*================================结束==========================================*/
相关推荐
qq_401700412 小时前
单片机电源怎么选
单片机·嵌入式硬件
boneStudent2 小时前
Day36:DMA 配置与使用
stm32·单片机·嵌入式硬件
xiaobuding_QAQ3 小时前
51汇编仿真proteus8.15学习篇一(附源码)
汇编·单片机·学习·proteus
Coder_Boy_3 小时前
【人工智能应用技术】-基础实战-小程序应用(基于springAI+百度语音技术)智能语音控制-Java部分核心逻辑
java·开发语言·人工智能·单片机
richxu202510013 小时前
嵌入式学习之路-->stm32篇-->(0)学习路线
stm32·嵌入式硬件·学习
xiaobuding_QAQ3 小时前
51汇编仿真proteus8.15学习篇二(附源码)
开发语言·汇编·单片机·学习·proteus
长安第一美人11 小时前
C 语言可变参数(...)实战:从 logger_print 到通用日志函数
c语言·开发语言·嵌入式硬件·日志·工业应用开发
悠闲漫步者14 小时前
第2章 MCS-51单片机的串口和最小系统(学习笔记)
笔记·学习·51单片机
Coding Peasant14 小时前
GD32E230 I2C从机功能深度解析与实现指南
c语言·stm32·单片机·mcu·arm