IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> VC++6.0上实现PC机与单片机串口通信的PC端上位机软件 -> 正文阅读

[嵌入式]VC++6.0上实现PC机与单片机串口通信的PC端上位机软件

1.简介

我做这个的主要原因是选了一个PC和单片机的全双工串口通信作为课设题目,单片机端是用汇编语言编程且要预先下载到板子里,关于这个这里我就不多说,主要说说怎么实现PC端的上位机软件。早知道要写软件,鬼才选这个课题。但是自己选的路哭着也要走完。

做的时候我也感觉到,C++真难啊,,,但不可否认它确实是个好东西。

写这样的软件也是有几种方法思路的,因为我怕太难的学不会的话,到时候课设就凉凉了。所以我选择了较为亲民的ActiveX控件的方法。

Microsoft Communications Control(以下简称MSComm)是Microsoft公司提供的简化Windows下串行通信编程的ActiveX控件,它为应用程序提供了通过串行接口收发数据的简便方法。

MSComm 控件通过串行端口传输和接收数据,为应用程序提供串行通讯功能。MSComm控件在串口编程时非常方便,所以我们不必花时间去了解较为复杂的API函数,而且在VC、VB、什么什么等语言中都可以使用。具体来说,它提供了两种处理通信问题的方法:一是事件驱动(Event-driven)方法,另一个是查询法。

1.通讯方式

MSComm控件提供下列两种处理通讯的方式:事件驱动方式查询方式

1.事件驱动方式

事件驱动通讯是处理串行端口交互作用的一种非常有效的方法。在许多情况下,事件发生时需要得到通知,就比如,在串口接收缓冲区中有字符,或者 Carrier Detect (CD) 或 Request To Send (RTS) 线上一个字符到达或一个变化发生时。在这些情况下,可以利用MSComm控件的OnComm事件捕获并处理这些通讯事件。OnComm事件还可以检查和处理通讯错误。所有通讯事件和通讯错误的列表,参阅CommEvent 属性。在编程过程中,就可以在OnComm事件处理函数中加入自己的处理代码。这种方法的优点是程序响应及时,可靠性高。每个MSComm控件对应着一个串行端口。如果应用程序需要访问多个串行端口,必须使用多个 MSComm 控件。

2.查询方式

查询方式本质上还是事件驱动,但在有些情况下,这种方式显得更为便捷。在程序的每个关键功能之后,可以通过检查CommEvent属性的值来查询事件和错误。如果应用程序较小,并且是自保持的,这种方法可能是更可取的。比如,如果写一个简单的电话拨号程序,则没有必要对每接收一个字符都产生事件,因为唯一等待接收的字符是调制解调器的“确定”响应。?

2.MSComm控件常用属性

MSComm 控件有很多重要的属性,但首先必须熟悉几个属性。知道这几个几乎就能横着走了。

CommPort? ? 设置并返回通讯端口号。?

Settings? ? ? ? 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位。?

PortOpen? ? ? 设置并返回通讯端口的状态。也可以打开和关闭端口。?

Input? ? ? ? ? ? ?从接收缓冲区返回和删除字符。?

Output? ? ? ? ? 向传输缓冲区写一个字符串。

1.CommPort属性

设置并返回通讯端口号

语法object.CommPort[value ] (value 一整型值,说明端口号。)?

说明在设计时,value可以设置成从 1 到 16 的任何数(缺省值为 1)。但是如果用PortOpen属性打开一个并不存在的端口时,MSComm 控件会产生错误 68(设备无效)。

注意:必须在打开端口之前设置 CommPort 属性。

2.PortOpen属性

设置并返回通讯端口的状态(开或关)。该属性在设计时无效。

MSComm.PortOpen=true; //打开端口

MSComm.PortOpen=false; //关闭端口并清除接收和传输缓冲区

说明

设置PortOpen属性为True打开端口。设置为False关闭端口并清除接收和传输缓冲区。当应用程序终止时,MSComm 控件自动关闭串行端口。

在打开端口之前,确定 CommPort 属性设置为一个合法的端口号。如果 CommPort 属性设置为一个非法的端口号,则当打开该端口时,MSComm 控件产生错误68(设备无效)。

另外,串行端口设备必须支持Settings 属性当前的设置值。如果 Settings 属性包含硬件不支持的通讯设置值,那么硬件可能不会正常工作。

如果在端口打开之前,DTREnable或RTSEnable属性设置为True,当关闭端口时,该属性设置为False。否则,DTR和RTS线保持其先前的状态。

数据类型:Boolean

3.RThreshold 属性

在MSComm控件设置CommEvent属性为comEvReceive并产生OnComm之前,设置并返回的要接收的字符数

语法object.Rthreshold [ = value ](value 整型表达式,说明在产生OnComm 事件之前要接收的字符数。)

说明当接收字符后,若Rthreshold属性设置为0(缺省值)则不产生 OnComm事件。例如,设置Rthreshold为1,接收缓冲区收到每一个字符都会使MSComm控件产生OnComm事件。

4.CTSHolding 属性

确定是否可通过查询Clear To Send (CTS)线的状态发送数据。Clear To Send 是调制解调器发送到相联计算机的信号,指示传输可以进行。该属性在设计时无效,在运行时为只读。

语法:object.CTSHolding(Boolean)

Mscomm 控件的 CTSHolding 属性设置值:True Clear To Send 线为高电平。?False Clear To Send 线为低电平。?

说明:如果Clear To Send线为低电平 (CTSHolding = False)并且超时时,MSComm控件设置CommEvent?属性为comEventCTSTO (Clear To Send Timeout) 并产生OnComm事件。

Clear To Send 线用于RTS/CTS (Request To Send/Clear To Send) 硬件握手。如果需要确定Clear To Send 线的状态,CTSHolding 属性给出一种手工查询的方法。更详细有关握手协议在?Handshaking 属性。

5.SThreshold 属性

MSComm控件设置CommEvent属性为comEvSend并产生OnComm事件之前,设置并返回传输缓冲区中允许的最小字符数

语法object.SThreshold [ = value ],value整形表达式,代表在OnComm事件产生之前在传输缓冲区中的最小字符数。?

说明:若设置Sthreshold属性为0(缺省值),数据传输事件不会产生OnComm 事件。若设置Sthreshold 属性为 1,当传输缓冲区完全空时,MSComm控件产生OnComm事件。如果在传输缓冲区中的字符数小于value,CommEvent?属性设置为comEvSend,并产生OnComm事件。comEvSend 事件仅当字符数与 Sthreshold 交叉时被激活一次。例如,如果 Sthreshold 等于5,仅当在输出队列中字符数从 5 降到 4 时,comEvSend 才发生。如果在输出队列中从没有比 Sthreshold 多的字符,comEvSend事件将绝不会发生。

6.Handshake 常数

常数值 ??描述?
comNone ??? ?0 ??无握手
comXonXoff? ?1 ??XOn/Xoff 握手
comRTS ?? ? ? 2 ???????Request-to-send/clear-to-send 握手
comRTSXOnXOff? ? 3 ????Request-to-send 和 clear-to-send 握手皆可

? ? ? ? ??? ??

7.OnComm 常数

常数?值?描述?
comEvSend???? ? 1 ????发送事件
comEvReceive?? 2???接收事件
comEvCTS? ? 3 ??clear-to-send线变化
comEvDSR?? 4data-set ready线变化
comEvCD ????5 ??carrier detect 线变化
comEvRing ?? ? ?6 ???????振铃检测
comEvEOF? ? 7 ????文件结束

8.?Error 常数

常数描述
comEventBreak?1001接收到中断信号?
comEventCTSTO1002 ?Clear-to-send 超时?
comEventDSRTO1003 ??Data-set ready 超时
comEventFrame ??1004 ???帧错误?
comEventOverrun1006 ?????端口超速?
comEventCDTO1007??Carrier detect 超时?
comEventRxOver??1008 ??接收缓冲区溢出?
comEventRxParity 1009 ?Parity 错误?
comEventTxFull ??1010 传输缓冲区满
comEventDCB ?1011检索端口设备控制块 (DCB) 时的意外错误?

9.InputMode 常数

常数描述?
????comInputModeText??0 ???(缺省)通过 Input 属性以文本方式取回数据
?comInputModeBinary ??1????通过 Input 属性以二进制方式检取回数据

10.CDHolding属性

通过查询Carrier Detect (CD)线的状态确定当前是否有传输。Carrier Detect 是从调制解调器发送到相联计算机的一个信号,指示调制解调器正在联机。该属性在设计时无效,在运行时为只读。

语法object.CDHolding

设置值CDHolding属性的设置值为:?

设置?????描述?
True Carrier Detect ??线为高电平?
False Carrier Detect线为低电平

说明:注意当Carrier Detect线为高电平(CDHolding = True)且超时时,MSComm控件设置CommEvent属性为comEventCDTO(Carrier Detect 超时错误),并产生OnComm事件。

注意在主机应用程序中捕获一个丢失的传输是特别重要的,例如一个公告板,因为呼叫者可以随时挂起(放弃传输)。

Carrier Detect也被称为 Receive Line Signal Detect (RLSD)

数据类型 Boolean

11.DSRHolding 属性

确定Data Set Ready (DSR)线的状态。Data Set Ready 信号由调制解调器发送到相连计算机,指示作好操作准备。该属性在设计时无效,在运行时为只读。

语法:object.DSRHolding

object 所在处表示对象表达式,其值是“应用于”列表中的对象。

DSRHolding属性返回以下值:

值 ?????????描述?
True Data Set Ready??线高?
False Data Set Ready??线低?

说明:当Data Set Ready线为高电平(DSRHolding = True)且超时时,MSComm 控件设置CommEvent属性为comEventDSRTO(数据准备超时)并产生OnComm 事件。

当为Data Terminal Equipment (DTE)机器写Data Set Ready/Data Terminal Ready握手例程时该属性是十分有用的。

数据类型:Boolean

12.Settings 属性

设置并返回波特率、奇偶校验、数据位、停止位参数。

语法object.Settings[ = value]

说明:当端口打开时,如果 value 非法,则 MSComm 控件产生错误 380(非法属性值)。

Value 由四个设置值组成,有如下的格式:"BBBB,P,D,S"。BBBB为波特率,P为奇偶校验,D为数据位数,S为停止位数。value 的缺省值是:"9600,N,8,1"。

(1)下表列出合法的波特率:

设置值:110、300、600、1200、2400、9600(缺省)、14400、19200、28800、38400、56000、128000、256000

(2)下表说明合法的奇偶校验值:

设置值??????描述

E ?????????偶数 (Even)

M??????????标记 (Mark)

N ?????????缺省 (Default) None

O ?????????奇数 (Odd)

S ??????????空格 (Space)

(3)下表列出合法的数据位值。

设置值:4、5、6、7、8 (缺省)

(4)下表列出合法的停止位值。

设置值:1(缺省)、1.5、2

13.InputLen 属性

设置并返回 Input 属性从接收缓冲区读取的字符数。该属性在设计时无效,在运行时为只读。

语法object.InputLen [ = value]

InputLen 属性语法包括下列部分:

value 整型表达式,说明 Input 属性从接收缓冲区中读取的字符数。?

说明:InputLen 属性的缺省值是 0。设置 InputLen 为 0 时,使用 Input 将使 MSComm 控件读取接收缓冲区中全部的内容。

InputLen属性确定被Input属性读取的字符数。设置 InputLen 为 0,则 Input 属性读取缓冲区中全部的内容。

InputMode 属性确定用 Input 属性读取的数据类型。如果设置 InputMode 为comInputModeText,Input属性通过一个Variant返回文本数据。如果设置 InputMode为comInputModeBinary,Input 属性通过一个Variant。返回一二进制数据的数组。

若接收缓冲区中 InputLen字符无效,Input属性返回一个零长度字符串 ("")。在使用 Input 前,用户可以选择检查 InBufferCount 属性来确定缓冲区中是否已有需要数目的字符。该属性在从输出格式为定长数据的机器读取数据时非常有用。

数据类型:Variant

14.Output 属性

往传输缓冲区写数据流。该属性在设计时无效,在运行时为只读。

语法

object.Output [ = value]

Output属性语法包括下列部分:

部分???描述
object??对象表达式,其值是“应用于”列表中的对象
value

要写到传输缓冲区中的一个字符串

???

说明

Output 属性可以传输文本数据或二进制数据。用 Output 属性传输文本数据,必须定义一个包含一个字符串的 Variant。发送二进制数据,必须传递一个包含字节数组的 Variant 到 Output 属性。

正常情况下,如果发送一个 ANSI 字符串到应用程序,可以以文本数据的形式发送。如果发送包含嵌入控制字符、Null 字符等等的数据,要以二进制形式发送。

数据类型:Variant

15. EOFEnable 属性

确定在输入过程中 MSComm 控件是否寻找文件结尾 (EOF) 字符。如果找到EOF字符,将停止输入并激活OnComm事件,此时 CommEvent 属性设置为 comEvEOF。

语法:object.EOFEnable [= value]

EOFEnable属性语法包括下列部分:

value 布尔表达式,确定当找到 EOF 字符时,OnComm 事件是否被激活,如“设置值”中所描述。?

value 的设置值:

True? ? 当 EOF 字符找到时 OnComm 事件被激活。?

False(缺省)当EOF 字符找到时OnComm 事件不被激活。?

说明:当 EOFEnable 属性设置为 False,OnComm 控件将不在输入流中寻找 EOF 字符。

16. 错误消息(MS Comm 控件)

下表列出 MSComm 控件可以捕获的错误,我们可以通过错误代码知道具体出错点

描述
380??无效属性值 comInvalidPropertyValue
383?属性为只读 comSetNotSupported
394属性为只读 comGetNotSupported?
8000端口打开时操作不合法 comPortOpen
8001超时值必须大于 0?
8002?无效端口号 comPortInvalid
8003属性只在运行时有效?
8004属性在运行时为只读?
8005端口已经打开 comPortAlreadyOpen
8006?设备标识符无效或不支持该标识符?
8007不支持设备的波特率?
8008指定的字节大小无效?
8009缺省参数错误?
8010硬件不可用(被其它设备锁定)?
8011函数不能分配队列?
8012??设备没有打开 comNoOpen?
8013设备已经打开?
8014不能使用 comm 通知?
8015不能设置 comm 状态 comSetCommStateFailed
8016不能设置 comm 事件屏蔽?
8018仅当端口打开时操作才有效 comPortNotOpen?
8019?设备忙?
8020?读 comm 设备错误 comReadError
8021??为该端口检索设备控制块时的内部错误 comDCBError?

2.具体实现(附部分代码)

MSComm控件进行串行通信的一般步骤主要就以下几点

(1)设置通信对象、通信端口号及其它属性;

(2)设定通信协议;

(3)打开通信端口,进行数据的传送;

(4)关闭通信端口。

怎么引入控件的具体步骤在这里我就不详细介绍,自己下Visual C++6.0熟悉以下就知道了。下面是我设计的一个程序界面,包含串口数据发送和接收显示以及前期数码管显示的测试程序。

大家可能对这个控件没有具体的概念,简单就上面开始测试的按键来说,打开它的属性如下

?它有一个ID号,这在代码里表现为一个函数的实现

?我们可以发现代码中含有由choosenum为判断条件的判断语句,到这相信大家可以猜到这个是使数码管显示指定数字的实现代码,这些控件都是包含在CDpjDlg类里的。

?这每个值又对应着相应的控件,就说C++这个语言是一个面向对象的编程,这也是它的一个优越性,也是最值得学习的一点。再看那个小按钮的属性界面就应该明白程序界面是怎么和代码相关联的了。但是使用控件之前要在对象里初始化才能用。

?上面就是是简单介绍了一下基本的操作方式,增进以下了解。接下来是比较重要的几段代码,源码我会在课设答辩完成后再放到平台上。

首先是头文件里类的定义

/
// CDpjDlg dialog

class CDpjDlg : public CDialog
{
// Construction
public:
	int Str2Hex(CString str, CByteArray &senddata);
	char HexChar(char c);
	CDpjDlg(CWnd* pParent = NULL);	// standard constructor

// Dialog Data
	//{{AFX_DATA(CDpjDlg)
	enum { IDD = IDD_DPJ_DIALOG };
	CEdit	m_ctrlsend;
	CMSComm	m_ctrlComm;
	CString	m_send;
	CString	m_receive;
	CString	m_state;
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CDpjDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	//{{AFX_MSG(CDpjDlg)
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	virtual void OnOK();
	afx_msg void OnTest();

	afx_msg void OnRadio1();
	afx_msg void OnRadio2();
	afx_msg void OnRadio3();
	afx_msg void OnRadio4();
	afx_msg void OnRadio5();

	afx_msg void OnButton1();
    afx_msg void OnButton2();
	
	afx_msg void OnOnCommMscomm();
	virtual void OnCancel();
	afx_msg void OnSetfocusEdit1();
	afx_msg void OnChangeEdit2();
	DECLARE_EVENTSINK_MAP()
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

实现向串口发送由text控件得到的数据的代码,上面的是从控件得到数据的函数

void CDpjDlg::OnSetfocusEdit1() //Edit1文本框得到焦点
{
	// TODO: Add your control notification handler code here

	m_ctrlsend.SetSel(0,-1);//Edit1文本框中字符全选中
	m_ctrlsend.Clear();     //清除Edit1文本框中的所有字符
}

void CDpjDlg::OnOK() 
{
	// TODO: Add extra validation here
    CByteArray hexdata; 
	UpdateData(TRUE);  //读编辑框内容	
	int len=Str2Hex(m_send,hexdata);
 	UpdateData(FALSE);  //更新编辑框内容
	m_ctrlComm.SetOutput(COleVariant(hexdata));

}

实现接收到的消息的处理程序

/
// 消息处理程序

BOOL CDpjDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_ctrlComm.SetCommPort(1);   //选择的COM口
	m_ctrlComm.SetInputMode(1); //输入方式为二进制方式
	m_ctrlComm.SetInBufferSize(1024); //设置输入缓冲区大小
	m_ctrlComm.SetRThreshold(1); //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
    m_ctrlComm.SetSThreshold(1);//参数1表示当传输缓冲区完全空时将引发一个接收数据的OnComm事件
	m_ctrlComm.SetSettings("9600,n,8,1"); //波特率/数据位/停止位
	m_ctrlComm.SetPortOpen(TRUE);//打开串口
    m_send="00";
	UpdateData(FALSE);  //更新编辑框内容

	return TRUE;  // return TRUE  unless you set the focus to a control
}

?主要实现各种状态判断的函数

void CDpjDlg::OnOnCommMscomm() 
{
	// TODO: Add your control notification handler code here
	VARIANT variant_inp;
	COleSafeArray safearray_inp;
	LONG len,k;
	BYTE rxdata[512]; //设置BYTE数组
	CString strtemp;
  	if(m_ctrlComm.GetCommEvent()==2) //事件值为2表示接收缓冲区内有字符
	{
		variant_inp=m_ctrlComm.GetInput(); //读缓冲区
		safearray_inp=variant_inp;  //VARIANT型变量转换为ColeSafeArray型变量
		len=safearray_inp.GetOneDimSize(); //得到有效数据长度
		for(k=0;k<len;k++)
			safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组
		for(k=0;k<len;k++)             //将数组转换为Cstring型变量
		{
			BYTE bt=*(char*)(rxdata+k);    //字符型
			strtemp.Format("%02X",bt);    //将字符送入临时变量strtemp存放
	        m_receive=strtemp;//加入对应字符串m_receive中
		}
  	}
    else
	   m_receive="数据未收到 "; 
	
   if(strtemp=="00")
    {      
		m_state="开始通信!";
	}
	else if(strtemp==m_send)
    {  
      m_state="通信正常!";
    }
	else
	{  
      m_state="通信不正常!";
    }
    if(strtemp=="FF")
    {      
		m_state="通信结束,输入00重新开始!";
	}
   	UpdateData(FALSE);  //更新编辑框内容
}

一个测试单片机的程序,用数码管

void CDpjDlg::OnTest() 
{
    m_receive="";
    //05 57 01 00 00 00 04 57  数码管显示00
    //05 57 01 00 00 01 04 56  数码管显示01
    //05 57 01 00 00 02 04 55  数码管显示02
    //05 57 01 00 00 03 04 54  数码管显示03
    //05 57 01 00 00 04 04 53  数码管显示04
    //05 57 01 00 00 05 04 52  数码管显示05
    //05 57 01 00 00 06 04 51  数码管显示06
    //05 57 01 00 00 07 04 50  数码管显示07
    //05 57 01 00 00 08 04 5F  数码管显示08
    //05 57 01 00 00 09 04 5E  数码管显示09
    //05 57 01 00 00 0A 04 5D  数码管显示10

    //使数码管显示从0-4  
	CByteArray hexdata; 
    //05 57 01 00 00 00 04 57  数码管显示00 
    m_send="05 57 01 00 00 00 04 57";
	int len=Str2Hex(m_send,hexdata);
 	m_ctrlComm.SetOutput(COleVariant(hexdata));
    Sleep(100);//等待100毫秒
	//05 57 01 00 00 01 04 56  数码管显示01
	m_send="05 57 01 00 00 01 04 56";
    len=Str2Hex(m_send,hexdata);
	m_ctrlComm.SetOutput(COleVariant(hexdata));//发送数据
	Sleep(100);//等待100毫秒
	//05 57 01 00 00 02 04 55  数码管显示02
	m_send="05 57 01 00 00 02 04 55";
    len=Str2Hex(m_send,hexdata);
	m_ctrlComm.SetOutput(COleVariant(hexdata));//发送数据
	Sleep(100);//等待100毫秒
    //05 57 01 00 00 03 04 54  数码管显示03
    m_send="05 57 01 00 00 03 04 54";
    len=Str2Hex(m_send,hexdata);
	m_ctrlComm.SetOutput(COleVariant(hexdata));//发送数据
	Sleep(100);//等待100毫秒
	//05 57 01 00 00 04 04 53  数码管显示04
	m_send="05 57 01 00 00 04 04 53";
    len=Str2Hex(m_send,hexdata);
	m_ctrlComm.SetOutput(COleVariant(hexdata));//发送数据
    Sleep(100);//等待100毫秒
    //05 52 01 03 00 01 04 50    读取地址03H中的值
	m_send="05 52 01 03 00 01 04 50 ";
    len=Str2Hex(m_send,hexdata);
	m_ctrlComm.SetOutput(COleVariant(hexdata));//发送数据
}

这个程序发的只是数字1,2,3,4,,但要想单片机端汇编编程简单一点,我实际用的是直接发送使数码管显示相应数字的两位16进制数。其中关于串口数据传输协议我觉得有必要提一下,从上面的代码也可以看到传的数据是一组由八个两位16进制数组成的东西。

这个我也不太懂,简单来说就比如

m_send="05 57 01 00 00 C0 04 97";

//05-协议引导字节,可以说是默认的,基本不用改
//57-表示写,若是52的话表示读
//01-也是固定的东西
//00-数据的位置
//00-固定的
//C0-要传输的数据
//04-固定的
//97-进行一个异或校验,57和数据的位置和要传的数据的二进制异或结果

应该大概率会需要一个转16进制的代码,这个改一下对象应该就能拿去用

//将字符转换十六进制
char CDpjDlg::HexChar(char c)
{
    if((c>='0')&&(c<='9'))
		return c-0x30;
	else if((c>='A')&&(c<='F'))
		return c-'A'+10;
	else if((c>='a')&&(c<='f'))
		return c-'a'+10;
	else 
		return -1;
}

//将字符串转换成十六进制
int CDpjDlg::Str2Hex(CString str, CByteArray &senddata)
{
    int hexdata,lowhexdata;
	int hexdatalen=0;
	int len=str.GetLength();
	senddata.SetSize(len/2);
	for(int i=0;i<len;)
	{
		char lstr,hstr=str[i];
		if(hstr==' ')
		{
			i++;
			continue;
		}
		i++;
		if(i>=len)
			break;
		lstr=str[i];
		hexdata=HexChar(hstr);    //高位转换
		lowhexdata=HexChar(lstr); //低位转换
		if((hexdata==16)||(lowhexdata==16))
			break;
		else 
			hexdata=hexdata*16+lowhexdata;
		i++;
		senddata[hexdatalen]=(char)hexdata;
		hexdatalen++;
	}
	return hexdatalen;
}

最后是关闭串口的函数,是“关闭”按钮控件的实现

void CDpjDlg::OnCancel() 
{
	// TODO: Add extra cleanup here
	m_ctrlComm.SetPortOpen(FALSE);//关闭串口
	CDialog::OnCancel();
}

最后,温馨提示,上面的代码只是主要实现框架的代码,实际实现远不止于此。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:27:28  更:2022-04-04 12:27:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:47:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码