【教你】编写一个串口程序,作为上位机,和单片机通信
novakon2013/05/28软件综合 IP:广东
我们的生活离不开单片机,单片机要和上位机通信,通信最简单的方式是靠串口。


本文介绍,如何编写一个程序,在电脑上向串口那一头的单片机发送信息,以及接收从串口传回的信息。
这种程序(通常叫做串口调试程序),网络上其实到处都是;但是如果大家学会自己去写,就可以定制属于自己的上位机,和其他代码结合,实现丰富多彩的功能。


比如,我可以写一个3D小游戏,从串口获取单片机上陀螺仪给出的姿态数据,控制游戏中物体的动态。


动手之前,你需要:


一个已经编程,可以通过串口接受和发送数据的单片机;
一台电脑,安装了Visual Studio 2010/2012和 .NET Framework 4;考虑到兼容性(win7/vista用户默认安装3.5),可以换用NET Framework 3.5
电脑上的串口可以是原生串口,也可以是USB转串口。


微软开发工具(包括VS2012)到这里下载:https://www.kechuang.org/t/57141

把我写好的程序发上来做个参考:


QQ截图20130528121527.jpg


我在上面的文本框中输入一串字符,点TX按钮发送给单片机;单片机收到这些字符之后,把它们的ascii代码,用十进制数字表示出来,结合一些说明字符(如"recv"),通过串口发回到电脑。电脑收到字符之后产生一个应用程序事件,在事件处理程序中将收到的内容加到界面下方的文本框中。


在这个例子里,串口一次性发送了4个字符,如果单片机接收一个字符,用printf()函数输出一次(每次十几个字符),显然,printf()函数在完成之前,由电脑发来的下一个字符已经到达,这会导致一些字符的丢失。


例子中使用了STM8单片机的中断功能接管收发,并且软件上实现了FIFO缓存(先入先出缓存),所以单片机可以在正常工作不被打扰的情况下,轻松地处理来自串口的数据。
+25  科创币    krfantasy    2013/05/28
来自:计算机科学 / 软件综合
11
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
bin.c
11年0个月前 IP:未同步
529778
良哥用是C#写的??目前我刚开始玩C#.以前用只用VB写过个串口调试助手,单片机配合上位机可以做很多有趣的东西!
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
novakon作者
11年0个月前 IP:未同步
529780
QQ截图20130528121556.jpg
然而,一个像上面这样的串口工具是复杂的。
主程序在这里下载:
attachment icon MySerial.zip 10.66KB ZIP 147次下载
请记得安装.NET Framework 4.0
-----------------------------------------------------------------
如果只实现其基本功能,代码却很简单。下面就用XXXXXT,给各位奉上实现串口功能所需要的最短代码。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
novakon作者
11年0个月前 IP:未同步
529789
如果你会C#,就把语法换成C#语法,相信这不是什么难事。

我们首先实现串口发送功能。

在VS2012里面,新建一个Windows 窗体应用程序,添加一个按钮:

QQ截图20130528125657.jpg

然后代码如下:

QQ截图20130528130215.jpg

在窗体的load事件中,加入初始化代码;在按钮的click事件中,向单片机发送字符串asdf.

启动前请保证串口的名字是程序中的COMxx(到底是COM多少,请打开设备管理器查看)。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
novakon作者
11年0个月前 IP:未同步
529800
运行,按下按钮,于是就向串口发送了4个字节asdf:

DSC_3278.jpg

蓝色是发送,黄色是收到的来自单片机的反馈,同步进行的。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
novakon作者
11年0个月前 IP:未同步
529806
透露一下STM8代码。使用IAR编译

//main.c

#include "libpin.c"
//everything in libpin.c

fifobuffer txbuf,rxbuf;
void send_out(uchar input);
void check_rx();

//life of printf
int putchar(int c)
{
  send_out(c);
  return (c);
}

pin out;

#define high(whatever) pinhigh(&whatever)
#define low(whatever) pinlow(&whatever)
#define flip(whatever) pinflip(&whatever)

void init()
{
  delay(60000);//stable
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
  pininit(&out,'D',7,'p');
  
  fifobufferinit(&txbuf);
  fifobufferinit(&rxbuf);
  
  UART2_Init(9600,UART2_WORDLENGTH_8D,UART2_STOPBITS_1,UART2_PARITY_NO,
             UART2_SYNCMODE_CLOCK_DISABLE ,UART2_MODE_TXRX_ENABLE);
  
  UART2_ITConfig(UART2_IT_TXE, ENABLE);  
  UART2_ITConfig(UART2_IT_RXNE, ENABLE);
  UART2_Cmd(ENABLE);
}

void main()
{
  init();
  enableInterrupts();
  while(1){
    flip(out);
    check_rx();
  }
}

#pragma vector = 22
__interrupt void txe()
{
  if(fifobufferremain(&txbuf)!=0){
    UART2_SendData8(fifobufferout(&txbuf));
  }else{
    UART2_ITConfig(UART2_IT_TXE, DISABLE);
  }
}

#pragma vector = 23
__interrupt void rxne()
{
  fifobufferin(&rxbuf,UART2_ReceiveData8());
}
void check_rx(){
  if(fifobufferremain(&rxbuf)!=0){
    uchar a=fifobufferout(&rxbuf);
    printf("recv ascii %d\\x0d\\x0a",a);
  }
}
inline void send_out(uchar input)
{
  fifobufferin(&txbuf,input);
  UART2_ITConfig(UART2_IT_TXE, ENABLE);
}
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
novakon作者
11年0个月前 IP:未同步
529812
然后我们要给这个程序添加功能,实现接收串口数据。

首先,创建一个timer(定时器)控件,设置interval属性为1000让它每秒触发一次;

QQ截图20130528140832.jpg
QQ截图20130528140813.jpg

界面中添加一个文本框,叫textbox1:
QQ截图20130528141618.jpg   

然后在这个timer1的触发事件里,添加接收串口数据的代码。代码的意思是,当接收缓冲区的字符数量大于0时,不断地从缓冲区读出字节,并转换为字符,添加到文本框textbox1里面。

QQ截图20130528141210.jpg
重点是在窗体load事件中加入timer1.enabled=true,让定时器开始计时。

运行效果如下:程序每隔一秒,刷新一次,将接收缓冲区中的字符加到文本框textbox1里面。只要按下按钮发送asdf,就能收到单片机回传的数据了。如果希望提高刷新速度,请更改timer1的interval属性。

QQ截图20130528141153.jpg

这里是发送和接受示范的源代码(当然,包含工程文件):
attachment icon serialdemo.zip 73.95KB ZIP 104次下载
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
duanyz
11年0个月前 IP:未同步
529848
来学习下,顶楼主
-1
科创币
20!Dopaminor
2013-05-28
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
laji3865689
11年0个月前 IP:未同步
529875
请教楼主:
如果用单片机自带的UART硬件来串口通讯,也需要串口中断吗?UART应该是有一定的缓存空间吧,只要在溢出前由程序取出就行?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
novakon作者
11年0个月前 IP:未同步
529953
引用第8楼laji3865689于2013-05-28 19:05发表的  :
请教楼主:
如果用单片机自带的UART硬件来串口通讯,也需要串口中断吗?UART应该是有一定的缓存空间吧,只要在溢出前由程序取出就行?




STM8S自带的UART2是没有缓冲区的,比如连续发送多个字节,通常除了第一个之外,其他全部没发送。必须等待上一个发完,才能发出下一个。


读取也是一样的,如果收到数据不及时读出,下一个到达的数据会冲走上一个。


缓存只能是软件实现。目前收发都是64byte FIFO buffer
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn
11年0个月前 IP:未同步
529965
求直接I/O写法
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
novakon
学者 机友 笔友
文章
1256
回复
8385
学术分
16
2008/03/29注册,2年3个月前活动

已走,勿送

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}