找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1815|回复: 24
打印 上一主题 下一主题
收起左侧

51单片机Uart与RGB兼容性问题

[复制链接]
跳转到指定楼层
楼主
ID:1071654 发表于 2023-9-16 17:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
50黑币
单片机STC89C52RC,晶振采用24MHZ,波特率9600,当前问题是:
1、把RGB()函数放在主函数while(1)里面后,虽然在串口助手看到有收到指令,指令所对应动作无法被执行
2、注释主函数中的RGB()函数后,先发指令1-6能收到且执行,再发送指令9后,RGB灯正常,这时候发送1-6指令,概率性打断RGB执行对应指令
为什么RGB()运行的同时Uart指令无法识别呢?就算去掉RGB()中的Delay()函数,看到的现象跟问题2一致。
感谢各位大神解答,感激不尽!!!

#include <REGX52.H>
#include "UART.H"
#include "MotorDrive.H"
#include "INTRINS.H"    //包含nop指令头文件
#include "Delay.H"
#include "Timer0.H"

#define nop  _nop_();
sbit DIN=P2^6;     //定义信号输出DIN
unsigned char Compare,Compare1,Compare2,Compare3;
unsigned char Counter,Counter1,Counter2,Counter3;
unsigned int IC=2;              //控制TM1804个数
unsigned int LED_PX;            //像素点数
unsigned char PWM=255;          //TM1804灰度数据
unsigned char Rda,Gda,Bda;      //R、G、B灰度数据
unsigned char bdata LED_data;   //可位操作的数据发送暂存变量声明

sbit bit0=LED_data^0;           //被发送的数据各位定义
sbit bit1=LED_data^1;
sbit bit2=LED_data^2;
sbit bit3=LED_data^3;
sbit bit4=LED_data^4;
sbit bit5=LED_data^5;
sbit bit6=LED_data^6;
sbit bit7=LED_data^7;
bit flag=0;

sbit L298N_ENA=P1^4;
sbit L298N_ENB=P1^5;
sbit L298N_ENA1=P1^1;
sbit L298N_ENB1=P0^2;

bit gb_RGB=0;
bit gbRI=0;

unsigned char Data;

void send_data_0()        //发送0码函数,规格书体现低速模式高电平700ns,周期2.5us
{
        //示波器实际测试高1uS,周期4.5uS
                DIN=1;
                _nop_();
                DIN=0;
}


void send_data_1()        //发送1码函数,规格书体现低速模式高电平1800ns,周期2.5us   
{
        //示波器实际测试高1.5uS,周期6uS
                DIN=1;
                _nop_();_nop_();
                DIN=0;
}

void send_data(unsigned char DATA1)        //发送1个字节数据,高位先发               
{
LED_data=DATA1;                          
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();
}

void send_px()        //发送1帧数据
{
unsigned int i;
for(i=0;i<LED_PX;i++)
  {
   send_data(Rda);             //发送R灰度数据
   send_data(Gda);             //发送G灰度数据
   send_data(Bda);             //发送B灰度数据
  }
}


void RGB()        //RGB函数
{
unsigned char i;
LED_PX=IC;                          //像素点数等于TM1804个数
Rda=Gda=Bda=0;                      //R、G、B灰度数据复位清零

   for(i=0;i<PWM;i++)          //红色渐亮  
    {
     Rda=i;              //灰度计算
     send_px();          //发送灰度数据
     Delay(10);          //复位延时
    }
     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);  //复位延时
      }
}

void main()
{
        UART_Init();
        L298N_ENA=1;
        L298N_ENB=1;
        L298N_ENA1=1;
        L298N_ENB1=1;
        while(1)
        {
//                RGB();
                if(Data==0)StopIt();        //停止
                if(Data==1)Forward();        //直行
                if(Data==2)BackOff();        //后退
                if(Data==3)TurnLeft();        //左转
                if(Data==4)TurnRight();        //右转
                if(Data==5)TurnLeftCircle();        //左转弯
                if(Data==6)TurnRightCircle();        //右转弯
                if(Data==9)RGB();                //RGB
                }
        }
void UART_Routine() interrupt 4    //串口中断
{
gbRI=1;       
if(RI==1)   //允许单片机接收数据
{
        Data=SBUF;                   //读取数据
        UART_SendByte(SBUF);  //将接收到的数据发回串口
        RI=0;  //接收标志位清0 软件复位
}
}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1071654 发表于 2023-9-18 13:59 | 只看该作者
自顶下,附件为51控制TM1804_RGB视频

51控制TM1804_RGB.zip

16.9 MB, 下载次数: 4

回复

使用道具 举报

板凳
ID:1071654 发表于 2023-9-18 17:03 | 只看该作者
自顶下,感谢各位大神答疑!
回复

使用道具 举报

地板
ID:1092816 发表于 2023-9-19 11:40 | 只看该作者
串口数据接收部分位于UART_Routine()函数中的串口中断中。这意味着当该中断被触发时,会执行UART_Routine()函数来接收串口数据,并执行相应的动作。

问题1:
将RGB()函数放在主函数while(1)循环内部时,在执行RGB()函数期间,由于没有执行完毕,此时可能无法及时触发串口中断来接收指令。因此,指令所对应的动作无法被执行。你可以尝试在RGB()函数执行完毕后再进行串口指令的接收和执行。

问题2:
这可能是由于程序运行时使用了中断,同时存在几个中断源时,可能导致中断优先级出现问题。为了解决此问题,可以尝试:
1. 在主函数中加入全局变量flag并初始化为0。
2. 将RGB()函数移到主函数的while循环之外。
3. 主函数中加入一个条件语句判断,如果flag等于0,则执行RGB()函数;否则执行串口指令的接收和执行。

在RGB()函数执行期间,flag会被设置为非零值,避免概率性打断RGB灯执行对应指令的问题。当RGB()函数执行完毕后,flag会重新置零,再次执行串口指令的接收和执行。
回复

使用道具 举报

5#
ID:844772 发表于 2023-9-19 14:35 | 只看该作者
好细的电源线啊,是用来两套电源吗?程序没啥问题,就看看电源功率够不够了。
回复

使用道具 举报

6#
ID:404160 发表于 2023-9-19 14:55 | 只看该作者
        Data=SBUF;                   //读取数据
        UART_SendByte(SBUF);  //将接收到的数据发回串口
改成
        Data=SBUF;                   //读取数据
        UART_SendByte(Data);  //将接收到的数据发回串口
试试
回复

使用道具 举报

7#
ID:161164 发表于 2023-9-19 17:47 | 只看该作者
因为用了for循环+阻塞式延时
先办法不用for循环和阻塞式延时来达到同样效果

回复

使用道具 举报

8#
ID:1071654 发表于 2023-9-19 18:30 | 只看该作者
飞云居士 发表于 2023-9-19 14:55
Data=SBUF;                   //读取数据
        UART_SendByte(SBUF);  //将接收到的数据发回 ...

按照您提供的方法验证了,串口助手看到有收到指令,但在执行RGB()函数中,其他指令依然不识别;发指令9执行了RGB(),再发指令9,居然也不识别。
回复

使用道具 举报

9#
ID:1071654 发表于 2023-9-19 18:34 | 只看该作者
glinfei 发表于 2023-9-19 14:35
好细的电源线啊,是用来两套电源吗?程序没啥问题,就看看电源功率够不够了。

电源线由两个18650电池自带的线供电,双电池,给电机升压是SX1308_12V,当单电池供电,L298N使能时候确实有概率会导致供电不足,双电池验证多次均没问题。
我在想单电池时候是不是由于升压IC前端电容容量不够导致电池进入了放电过流保护?
回复

使用道具 举报

10#
ID:844772 发表于 2023-9-20 09:07 | 只看该作者
wen1989jun 发表于 2023-9-19 18:34
电源线由两个18650电池自带的线供电,双电池,给电机升压是SX1308_12V,当单电池供电,L298N使能时候确实 ...

我没看到你的用电功率情况,用了什么高级电机要12V啊,还有能否先不用升压模块试试?这种小车好多问题就不在程序上。
回复

使用道具 举报

11#
ID:1071654 发表于 2023-9-20 09:19 | 只看该作者
glinfei 发表于 2023-9-20 09:07
我没看到你的用电功率情况,用了什么高级电机要12V啊,还有能否先不用升压模块试试?这种小车好多问题就 ...

单电池概率性被拉死情况目前没有去排查,电机用的12V_600转的N20。
回复

使用道具 举报

12#
ID:1071654 发表于 2023-9-20 09:31 | 只看该作者
cjc1029 发表于 2023-9-19 11:40
串口数据接收部分位于UART_Routine()函数中的串口中断中。这意味着当该中断被触发时,会执行UART_Routine() ...

问题1:确认在RGB()执行完成之后能收到其他指令,也能被执行。我只是怀疑难道是因为RGB_DIN这个IO口翻转太快,Uart就收不到指令啦?
问题2:按照您提供的方法验证了,还是不行;RGB()执行期间,Uart收到的指令无法被执行。
另外,您说的同时存在几个中断时候确认会导致RGB()无法正常运行,RGB灯异常闪烁。仅仅加了如下代码并打开了ET0=1;就会导致这个情况发生,也没太搞懂是个啥情况。
void Timer0_Init()        //100微秒@24MHz
{
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0x38;                //设置定时初值
        TH0 = 0xFF;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
        ET0=0;        //1为允许T0中断,0为禁止
        EA=1;        //开启总中断
        PT0=1;        //中断优先级控制
}

void Timer0_Routine() interrupt 1
{
        TL0=0x38;  //设置定时初值
        TH0=0xFF;  //设置定时初值
        Counter++;
        Counter%=100;                //计数值变化范围限制在0~99
        Counter1++;
        Counter1%=100;        //计数值变化范围限制在0~99
        Counter2++;
        Counter2%=100;        //计数值变化范围限制在0~99
        Counter3++;
        Counter3%=100;        //计数值变化范围限制在0~99
        if(Counter<Compare)
        {
                L298N_ENA=1;
        }
        else
        {
                L298N_ENA=0;
        }
        if(Counter1<Compare1)
        {
                L298N_ENB=1;
        }
        else
        {
                L298N_ENB=0;
        }
        if(Counter2<Compare2)
        {
                L298N_ENA1=1;
        }
        else
        {
                L298N_ENA1=0;
        }
        if(Counter3<Compare3)
        {
                L298N_ENB1=1;
        }
        else
        {
                L298N_ENB1=0;
        }
}
回复

使用道具 举报

13#
ID:1071654 发表于 2023-9-20 09:39 | 只看该作者
lkc8210 发表于 2023-9-19 17:47
因为用了for循环+阻塞式延时
先办法不用for循环和阻塞式延时来达到同样效果

谢谢您的指导,我加油!!!
回复

使用道具 举报

14#
ID:844772 发表于 2023-9-20 16:08 | 只看该作者
wen1989jun 发表于 2023-9-20 09:31
问题1:确认在RGB()执行完成之后能收到其他指令,也能被执行。我只是怀疑难道是因为RGB_DIN这个IO口翻转 ...

定时器0设的太短了,对于N20电机的PWM没必要这么快,因为2812的控制对时刻要求特别高,老是中断很影响效果,当然在RGB()运行期间只要中断都会影响效果,2812控制时刻是1微秒级的;
RGB()执行期间当然 ,不能执行指令。这是你程序决定的,但执行完就应该可以啊。
还有我有点拿不准,4个N20启动功率差不多6W,如果加10个2812总功率超过10W了,升压模块应付的了吗?
回复

使用道具 举报

15#
ID:526543 发表于 2023-9-20 17:24 | 只看该作者
可能与串口中断和RGB函数之间的并发执行有关
回复

使用道具 举报

16#
ID:1092816 发表于 2023-9-20 17:50 | 只看该作者
先排除硬件,如果单一模块运行没有问题,对于资源小的单片机,你要优化的是程序的架构,全部放while里不合适。你RGB里面的for也是耗CPU的,降低刷新频率试一下。
回复

使用道具 举报

17#
ID:1071654 发表于 2023-9-21 10:09 | 只看该作者
123456ZXC1 发表于 2023-9-20 17:24
可能与串口中断和RGB函数之间的并发执行有关

兄弟,展开说说看
回复

使用道具 举报

18#
ID:1071654 发表于 2023-9-21 14:35 | 只看该作者
glinfei 发表于 2023-9-20 16:08
定时器0设的太短了,对于N20电机的PWM没必要这么快,因为2812的控制对时刻要求特别高,老是中断很影响效 ...

定时器0当前设置的是100us,这个设置多少合适呢?
RGB控制用的是TM1804哦,用了2Pcs,各控制了7个RGB灯,这两个IC由ETA的DCDC供电
4个N20电机由2个L298N控制,2个L298N由两路SX1308供电,电源来自2个2550mAh的18650电池
回复

使用道具 举报

19#
ID:1094164 发表于 2023-9-21 15:21 | 只看该作者
电源线太细是不是也有点关系啊
回复

使用道具 举报

20#
ID:844772 发表于 2023-9-22 09:13 | 只看该作者
wen1989jun 发表于 2023-9-21 14:35
定时器0当前设置的是100us,这个设置多少合适呢?
RGB控制用的是TM1804哦,用了2Pcs,各控制了7个RGB灯 ...

1,电机有惯性的,几十Hz,也就是10毫秒级就行了;
2. 给机械部分供电一般只降压,没看到电路按你说的理论上确实可以,但实际会出现各种莫名状况;
3.我觉得程序可以达到目的,虽然优化空间较大,但不是主要问题。
4.另外,遥控影响灯效和灯效期间不执行命令这是程序问题,但也不大影响使用。
回复

使用道具 举报

21#
ID:1071654 发表于 2023-9-22 16:13 | 只看该作者
cjc1029 发表于 2023-9-20 17:50
先排除硬件,如果单一模块运行没有问题,对于资源小的单片机,你要优化的是程序的架构,全部放while里不合 ...

单一模块是可以正常工作的,现在就是放在一起没办法同时执行。
降低刷新率是否就是修改RGB()里面的Delay()的值?
回复

使用道具 举报

22#
ID:1071654 发表于 2023-9-23 09:32 | 只看该作者
流利说你好 发表于 2023-9-21 15:21
电源线太细是不是也有点关系啊

这个应该没太大关系了,电源只是影响是否工作,工作是否稳定的吧
回复

使用道具 举报

23#
ID:1071654 发表于 2023-9-25 09:41 | 只看该作者
glinfei 发表于 2023-9-22 09:13
1,电机有惯性的,几十Hz,也就是10毫秒级就行了;
2. 给机械部分供电一般只降压,没看到电路按你说的理 ...

定时器10mS的设置不太行哦,电机会有卡顿。
现在还是卡在没办法同时用,我继续找找问题
回复

使用道具 举报

24#
ID:161164 发表于 2023-9-25 10:38 | 只看该作者
wen1989jun 发表于 2023-9-25 09:41
定时器10mS的设置不太行哦,电机会有卡顿。
现在还是卡在没办法同时用,我继续找找问题

不要用delay
  1. void RGB()        //RGB函数
  2. {
  3.         static unsigned char i=0, j=0;
  4.         static unsigned int DelayCnt = 0;
  5.         LED_PX=IC;                          //像素点数等于TM1804个数
  6.         if(DelayCnt++>=1000)
  7.         {
  8.                 DelayCnt=0;
  9.                 switch(j)
  10.                 {
  11.                 case 0:
  12.                         Rda=Gda=Bda=0;                      //R、G、B灰度数据复位清零
  13.                         j++;
  14.                         break;
  15.                 case 1:
  16.                         Rda=i;              //灰度计算
  17.                         if(++i>=PWM)
  18.                         {
  19.                                 i=0;
  20.                                 j++;
  21.                         }
  22.                         break;
  23.                 case 2:
  24.                         Gda=i;
  25.                         Rda=PWM-i;  //灰度计算
  26.                         if(++i>=PWM)
  27.                         {
  28.                                 i=0;
  29.                                 j++;
  30.                         }
  31.                         break;
  32.                 case 3:
  33.                         Bda=i;
  34.                         Gda=PWM-i;  //灰度计算
  35.                         if(++i>=PWM)
  36.                         {
  37.                                 i=0;
  38.                                 j++;
  39.                         }
  40.                         break;
  41.                 case 4:
  42.                         Rda=i;
  43.                         Bda=PWM-i;  //灰度计算
  44.                         if(++i>=PWM)
  45.                         {
  46.                                 i=0;
  47.                                 j++;
  48.                         }
  49.                         break;
  50.                 }
  51.                 send_px();          //发送灰度数据
  52.         }
  53. }
复制代码
回复

使用道具 举报

25#
ID:1071654 发表于 2023-9-25 11:44 | 只看该作者

使用了您提供的代码,验证RGB()和其他指令不冲突均可运行,但也表现出一个问题:
不管把RGB()函数放进主函数while(1)里面,还是放在主函数if()里面,RGB()函数均执行一次就结束了
不管咋说,真的非常感谢您,我自己再研究学习下,再次感谢您!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表