第三节 调试消息队列

# 目录

# 3.0 课程资源

视频课链接 (opens new window) 密码:73enra

源代码链接:文件分享 (opens new window) 密码:vegtf7

消息队列调试-知乎文章 (opens new window)

# 3.1 什么是调试消息队列

单片机对实时性要求很高,也就是说,要求单片机快速反应、快速反馈,千分之一秒也不能等。 大部分调试过程中,要求输出信息都是要等待一段时间,再输出调试信息,无时无刻的输出调试信息是影响到单片机效率的。

消息队列是为了解决这个问题产生的。 我们输出调试信息时,如何保证实时性还尽量少占用单片机资源。最佳方式是消息队列。

它的基本原理是,我们输出简短的信息,甚至仅仅是一个数字、字符。用来展示单片机运行到的关键位置、关键参数。先把这些简短信息保存到一个缓冲区(一般是数组、结构等缓冲区),然后等等1~X秒不等再,把整个数组等缓冲区信息一起发送出来,这样既不影响单片机运行,也能获得我们调试的关键运行流程、关键参数。

# 3.2 目标

  • 学会消息队列方式调试
  • 知道通过消息队列可以节约单片机资源
    • 节省代码空间,
    • 很少占用单片机运行时间片
  • 知道通过消息队列可以指导程序的运行流程
  • 知道通过消息队列可以准确程序问题点

# 3.3 消息队列实现

需要两个文件:

  • message.c
  • message.h

头文件 message.h

#ifndef __MESSAGE_H__
#define __MESSAGE_H__

typedef char message;  

#define  QUEUELEN   64   //消息队列缓冲区大小  

extern void  PutMessage(message m); //送入一个字符到消息队列
extern void  PutMsg(char *strMsg);  //送一个字符串到消息队列
extern void Message_task(void); //将消息发送到串口输出

#endif
1
2
3
4
5
6
7
8
9
10
11
12

源文件 message.c

#include  "message.h"
#include "string.h"
#include "main.h"   //这里注释掉看错误

/*=============消息处理机制定义=================*/

char Messages[QUEUELEN];   //消息队列缓冲区
unsigned char MessageHead = 0;      //消息队头
unsigned char MessageTail = 0;      //消息队尾

void PutMessage(char m);

//消息发布
void PutMessage(char m)
{
    Messages[MessageTail] = m ;
    if(++MessageTail>=(QUEUELEN)) MessageTail=0;
}
//获取消息缓冲区的消息
message GetMessage(void)
{
    message m = Messages[MessageHead];
    if(++MessageHead>=QUEUELEN) MessageHead=0;
    return m ;
}
//判断队列是否空或者错
bit     QueueEmptyOrError(void)
{
    return (MessageHead==MessageTail)?1:0;
}

void Message_task(void)
{
    unsigned char bCount;
    static unsigned int delayRS232;

    if(++delayRS232>200)  //延时输出
    {
        delayRS232=0;
       if(!QueueEmptyOrError())
        {
            for(bCount=0; bCount<QUEUELEN; bCount++) {

                //USART_SendData(UART4,(Messages[bCount]));
                //uartSend(',');
                SendData(Messages[bCount]);
                //rt_kprintf("%c",Messages[bCount]);
            }
                SendData('\r');
                SendData('\n');
        }

    }
}

void PutNumMsg(unsigned char num)
{
    //PutMessage(num/100);
    PutMessage(0x30+(num&0xFF)/10);
    PutMessage(0x30+(num&0xFF)%10);
}

void PutMsg(char *strMsg)
{
    unsigned int i;
    unsigned int length = strlen(strMsg);
        //while(*(strMsg+i)!='\0')
    for(i=0;i<length;i++) 
    {
            PutMessage(strMsg[i]);
            PutMessage(strMsg[i+1]); //双字节存储?? 指针十六位数据?
            i++;
    }
}

/*
void sendstrs(char *str)
{
    static unsigned char i,delay;
    unsigned char length=strlen(str);

    //if(++delay>100)  //如有必要启动延时 此处不用是Message_task调用时已经延时
    {
        delay=0;

        for( i=0; i<length; i++) // sizeof(*str)  如果str是数组 这样得到只是数组首地址尺寸 ...
        {
            //在主函数while(1)中 不延时会陷入死循环
            USART_SendData(UART4,(*(str+i)));

        }

    }

}

uint8 HexToChar(uint8 temp)
{
    uint8 dst;
    if (temp < 10) {
        dst = temp + '0';
    } else {
        dst = temp -10 +'A';
    }
    return dst;
}
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

返回目录

# 3.4 仿真调试

还是使用proteus 仿真测试,具体看视频课程。

# 总结

返回目录

Last Updated: 1/31/2022, 7:37:27 AM