微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

实现电脑和单片机通信(单片机如何与电脑相连)

实现电脑和单片机通信(单片机如何与电脑相连)

第2节介绍了如何用单片机控制 LED 小灯闪烁起来,在此基础上,又在上一节讨论了如何制作“呼吸灯”。

缺乏交互的单片机

不过,这两节制作的小灯时,我们把使用 C语言编写的控制程序烧写到单片机后,就无法再控制 LED 小灯了,也就是说,“只能看不能动”,交互性比较差。接下来两节,将介绍一种交互方法,目的是烧写 C语言控制程序到单片机后,仍然能够从外界控制 LED 小灯。

既然想实现交互,单片机就得能捕捉外界的变化,最简单的方法就是通过按键。不过这里不打算使用按键,而是通过“输入命令”的方式控制 LED 小灯。

将单片机内部的信息,printf 传递给电脑

一般的软件开发中,如果想查看某个变量的值,或者想输出一句提示信息,直接使用 printf 将信息输出到屏幕即可。遇到分支流程需要外界选择时,我们也只需按一下键盘就可以。但是对于 51 单片机来说,怎么输入命令给它呢?我的这款 51 单片机可既没有配屏幕,也没有配键盘

其实 printf 只是将信息输出到终端,终端不一定必须是屏幕,也可以是其他字符设备,比如一般单片机都会有的串口外设。所以,没有屏幕的 51 单片机也能够使用 printf 函数,只需要将其输出重定向到串口即可。

重定向的工作 keil4 已经做好了,剩下需要我们做的工作仅仅只是配置一下单片机的串口寄存器而已,这项工作非常简单,C语言代码可以如下写,请看:

void init_uart(unsigned int baud)

{

SCON = 0x5a;

TMOD = 0x20;

Th3 = TL1 = -(FOSC/12/32/baud);

TR1 = 1;

ES = 1;

EA = 1;

}

其中 FOSC 是单片机的晶振频率,我使用的单片机频率是 11.0592MHz。现在包含一下“stdio.h”头文件就可以使用 printf 函数了:

#include "reg51.h"

#include "stdio.h"

void main()

{

init_uart(9600);

printf("hello world,num: %dn",98);

while(1);

}

编译程序并烧写到单片机,打开电脑中的串口调试软件,发现字符串都正确,但是C语言程序明明想传递的是 98,电脑端的串口工具显示的数字却是 25088!

这个问题估计是因为我使用的单片机是 8 位的原因。解决问题的方法,其实 keil 帮助文件里也提了:

使用格式符 “%bd”代替“%d”即可,或者将要输出的数字强转为 int 类型也可以:

...

printf("hello world,num: %bdn",98);

printf("hello world,(int)98);

...

再编译烧写,发现输出正常了。

将信息传递给单片机

以后可以使用 printf 函数将单片机内部的信息传递给电脑了,但是既然是“交互”,就应该还能把电脑端的信息传递给单片机才行。那么,怎样把电脑端的信息传给单片机呢?其实还可以借助串口。请看 init_uart() 函数代码,应该能发现C语言程序已经把串口中断打开了,所以可以如下写中断处理程序,请看:

#define MAX_CMD_LEN 32

static bit is_cmd_ready = 0;

static char cmd[MAX_CMD_LEN] = {0};

static unsigned char cmd_len = 0;

void interrupt_uart() interrupt 4

{

static unsigned char i = 0;

if(RI){

RI = 0;

cmd[i%MAX_CMD_LEN] = SBUF;

if(cmd[i%MAX_CMD_LEN]=='n'){

cmd_len = i;

i = 0;

is_cmd_ready = 1;

}else

i++;

}

}

当电脑通过串口发送数据给单片机时,串口数据会被逐字节放入 SBUF,而 C语言程序则会立刻进入 interrupt_uart() 函数,这时可以将串口数据用全局变量 cmd 接收。我们与电脑端约定,每次发送的命令都以换行符 ‘n’ 结束,所以当接收到 ‘n’ 时,就可以把 is_cmd_ready 标志位置 1 了。

我们常说的“通信协议”其实就是一系列约定,这么看来,这里说的“每次发送的命令都以换行符 ‘n’ 结束”其实也属于一种“通信协议”。

也就是说,电脑端通过串口发送的命令都会被自动放入 cmd 里,因此我们可以如下定义接收命令的 C语言函数

unsigned char get_uart_cmd(char* oCmd)

{

unsigned char i = 0;

while(!is_cmd_ready);

for(i=0;i

;i++)>

这个函数会阻塞等待 is_cmd_ready 标志位,收到电脑端发送来的命令后,将命令通过 oCmd 传出,返回接收到的命令长度。现在可以如下写测试程序了:

void main()

{

char mycmd[32] = {0};

init_uart(9600);

printf("enter a num...n");

get_uart_cmd(mycmd);

printf("cmd: %dn",(int)(mycmd[0]));

printf("enter a string...n");

get_uart_cmd(mycmd);

printf("cmd: %sn",mycmd);

while(1);

}

编译C语言程序并烧写,会在电脑端的串口调试工具中发现如下提示信息:

因为单片机先需要一个数字,且命令需要换行符结尾,所以勾选了下面的选项,点击发送,发现终端输出

104正好等于十六进制的 68,接着再输入一段字符串:

一切与预期一致。

通信模块封装成库

这一步是简单的,只需要删去 my_uart.c 文件里的 main 函数,然后再新建一个文件,如下图:

以后在其他功能开发中,如果需要与电脑端交互,直接把这两个文件加入工程就可以了。接下来,将使用本节介绍的交互模块,目的是能够通过电脑控制单片机,决定单片机的动作。例如:

在电脑端输入 led twinkle 命令,LED 小灯会闪烁。

在电脑端输入 led breath 命令,LED 小灯会变成“呼吸灯”,并且在变暗阶段向电脑端输出“呼气”,在变亮阶段向电脑端输出“吸气”。

限于篇幅,下一节再介绍了。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐