15

单片机很好玩5,实现交互,使用电脑控制单片机的执行动作(2)

 3 years ago
source link: https://blog.popkx.com/%E5%8D%95%E7%89%87%E6%9C%BA%E5%BE%88%E5%A5%BD%E7%8E%A95-%E5%AE%9E%E7%8E%B0%E4%BA%A4%E4%BA%92-%E4%BD%BF%E7%94%A8%E7%94%B5%E8%84%91%E6%8E%A7%E5%88%B6%E5%8D%95%E7%89%87%E6%9C%BA%E7%9A%84/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前面两节讨论了如何利用 C语言编程单片机,控制普通 LED 小灯实现类似手机上面的“呼吸灯”,但是这两节介绍的方法交互性比较差,一旦程序烧写,就无法再从外界控制 LED 小灯的动作了。

f2b387fff01dddb1924a71a0240589a9.png

提升交互性

所以,上一节介绍了单片机和电脑通信的方法,旨在能够通过电脑发送命令给单片机控制 LED 小灯的动作。例如制定以下协议:
* 电脑端输入 led twinkle 命令,单片机立刻控制 LED 小灯闪烁。
* 电脑端输入 led breath 命令,单片机立刻控制 LED 小灯成为“呼吸灯”。
* 电脑端输入 led off 命令,单片机立刻关闭 LED 小灯。

最终实现如下效果:

使用更加轻量级的通信函数

上一节说到,keil 将 printf 的输出重定向到串口后,51 单片机也能很方便的使用 printf 将内部信息传输给电脑端。但是,使用这种方法开销非常大:

5c8df96f5fcad34a386860afbf8e393b.png

可以看出,上面的C语言代码仅比下面代码多了一个 printf("") 函数,最终编译生成的代码 size 却多处近 1 倍!这对于资源匮乏的 51 单片机来说,是不可接受的。因此自己实现一个轻量级的通信函数是非常必要的。

这其实也是嵌入式程序开发的特点,不能浪费甚至一个字节。所以,嵌入式程序员都是勤俭持家的好手。

那么,怎样实现轻量级的 printf 函数呢?嵌入式开发中常见的还有一个词——“裁剪”。顾名思义,就是为了节约资源,嵌入式程序员常常把一个模块中用不到的功能剔除,仅留下核心功能。

现在想想,我们仅需 printf 发送字符串的功能,就可以完成需求。所以单片机往电脑端发送数据的C语言函数可以如下定义:

void prints(char* str)
{
    unsigned char i = 0;
    TI = 0;
    for(;str[i]!='\0'; i++){    
        SBUF = str[i];
        while(!TI);
        TI = 0;
    }
}

代码很简单,prints() 函数将 str 逐字节传递给 SBUF 寄存器,单片机则会自动将 SBUF 中的数据传输到串口,并且传送完毕后,将 TI 寄存器置 1。

制定协议,实现电脑用“命令”控制 LED 小灯

现在通信没问题了,那么怎样实现“命令”控制 LED 小灯呢?可以这么干:单片机随时检测串口数据,一旦接收到我们前面定义的命令,就做出相应的动作。所以,C语言代码可以如下写:

#define        TWINKLE     "led twinkle"
#define        BREATH      "led breath"
#define        LEDOFF      "led off"

if(is_new_cmd_ready()){
            cmd_len = get_uart_cmd(cmd);
            prints("recv cmd:");prints(cmd);prints("\n");
            if(is_cmd_match(cmd, BREATH, cmd_len)){
                prints("    match ");prints(BREATH);prints("\n");
                action = 1;
            }else if(is_cmd_match(cmd, TWINKLE, cmd_len)){
                prints("    match ");prints(TWINKLE);prints("\n");
                action = 2;
            }else if(is_cmd_match(cmd, LEDOFF, cmd_len)){
                prints("    match ");prints(LEDOFF);prints("\n");
                action = 3;
            }else{
                prints("    cmd not match\n");
                action = 0;
            }
        }
f79c9f2b208ef73082e5acac9b9408f5.png

上面的C语言代码中, action 会随着电脑端发送过来的命令做出相应改变。例如,电脑端发送“led twinkle”可以把 action 设置为 1,电脑端发送“led off”,可以让 action 等于 3。

接下来,把相应的 LED 小灯动作写入不同的 action 就可以了:

switch(action){
            case 1:
                // 呼吸灯
                break;
            case 2:
                // 闪烁的小灯
                break;
            case 3:
                // 关闭小灯
                break;
            default: break; 
        }

“呼吸灯”,闪烁小灯,以及关闭小灯的动作前面几节已经介绍过,将其填入即可:

29e06e0b8c2ea823c664729c52da2152.png

现在控制程序也就写好了,编译程序并烧写到单片机。

实验,电脑通过发送命令,控制 LED 小灯变化

初始状态如下图,因为电脑端还没有输入相应的命令,所以 LED 小灯处于熄灭状态。

0edc0bcb561605d6a1cc7d77eafff08b.png

接着,在串口调试工具输入“led twinkle”,发送到单片机:
f7db4fb6525aaf36b278426812c1847a.png

可以看到 LED 小灯开始闪烁了:
[video width="544" height="960" mp4="https://blog.popkx.com/usr/uploads/2019/01/1-2.mp4"][/video]
然后再在电脑端输入“led breath”,发送到单片机:
9f6e1d7d935fe3fc17825aebcf43961b.png

会发现 LED 小灯变成呼吸灯了:
[video width="544" height="960" mp4="https://blog.popkx.com/usr/uploads/2019/01/1-1.mp4"][/video]
最后再输入“led off”,能够发现 LED 小灯被熄灭了。
0edc0bcb561605d6a1cc7d77eafff08b.png

完整的流程,请看文章开头的动图。

至此,我们就实现了从电脑端发送命令,控制 LED 小灯动作。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK