请教一个用串口读取单片机消息在Edit控件中汉字显示不正常的问题

Anjoid 2015-09-19 06:50:16
最近在做一个单片机调试程序,环境是VS2008,用的MSCOMM控件,三个edit,一个发送mEditSend,一个接收只读mEditRcv,另一个显示发送的历史记录只读mEditHsty,现在问题是接收区无法正常显示单片机发回来的中文字符,但发送区和历史记录中可以正常编辑显示汉字



用串口调试助手能正常接收显示单片机发来的中文字符,说明单片机上传的内容是正确的


用16进制查看单片机上传的字符串就是这一段:
6D 6F 74 6F 72 20 74 65 73 74 20 77 69 74 68 20 4C 0A 2F 2F 2F 41 47 43 3A 20 31 37 30 0A 0A CA E4 C8 EB D6 B8 C1 EE 3A 0A

在监视器中跟踪变量,接收到的是正确的,中文都能显示出来,




可最后显示在Edit中就是这么个鸟样了


收发操作的函数代码见下:

void CSatCtrlComDlg::OnBnClickedButton2() //发送数据 并将发送历史在对话框中显示
{

VARIANT str;

UpdateData(true);
str = COleVariant(mEditSend);

cMSCommPort.put_Output(str);
mEditHsty += str;
mEditHsty += "\r\n";

UpdateData(false);

int linecnt = cEditHsty.GetLineCount();
cEditHsty.LineScroll(linecnt-1,0);

}
BEGIN_EVENTSINK_MAP(CSatCtrlComDlg, CDialog)
ON_EVENT(CSatCtrlComDlg, IDC_MSCOMM1, 1, CSatCtrlComDlg::OnCommMscomm1, VTS_NONE)
END_EVENTSINK_MAP()

void CSatCtrlComDlg::OnCommMscomm1() //串口有接收时显示在接收区
{

if(cMSCommPort.get_CommEvent()==2)
{
char str[1024] = {0};
long k;
VARIANT InputData = cMSCommPort.get_Input();
COleSafeArray fs;
fs = InputData;
for(k=0;k<fs.GetOneDimSize();k++)
{
fs.GetElement(&k,str+k);
}
mEditRcv += str;
UpdateData(false);

int linecnt = cEditRcv.GetLineCount();
cEditRcv.LineScroll(linecnt-1,0);
}
}


同编译器设置有关么,因为自动生成的代码老有这么一段



一直做的是单片机开发,VC各种控件特性还不太了解,还请各位高手给分析分析这是什么情况。
谢谢大家了
...全文
232 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
Anjoid 2015-10-17
  • 打赏
  • 举报
回复
上传个效果图
Anjoid 2015-10-17
  • 打赏
  • 举报
回复
问题搞定了 不是汉字编码的问题也不是字节被拆分 两个原因 第一个是串口接受显示部分的代码不太对,在下面加了蓝色的几行就可以正常显示汉字了,抄代码不知怎么漏掉几行 void CSatCtrlComDlg::OnCommMscomm1() //串口有接收时显示在接收区 { CString strTmp; if(cMSCommPort.get_CommEvent()==2) { char str[1024] = {0}; long k; VARIANT InputData = cMSCommPort.get_Input(); COleSafeArray fs; fs = InputData; for(k=0;k<fs.GetOneDimSize();k++) { fs.GetElement(&k,str+k); } for(k=0;k<len;k++) { char bt=*(char*)(str+k); strTmp.Format("%c",bt); mEditRcv += strTmp; } UpdateData(false); int linecnt = cEditRcv.GetLineCount(); cEditRcv.LineScroll(linecnt-1,0); } 第二个原因是单片机输出换行用的是‘\n’,也就是0x0A,而windows下换行符是0x0D 0x0A也就是“\r\n”,另存为txt用记事本打开时好像自动补了0x0D 但位置有时候不对 也不知道为什么 反正现在这样改完就OK了 还是谢谢以上各位了
xiaohuh421 2015-09-22
  • 打赏
  • 举报
回复
从你那个图, 4个汉字, 占用了12字节, 说明每个汉字是三个字节, 那基本上可以确定你的单片机发过来的汉字编码是utf-8的 VS中能显示, 那是VS自己做判断处理的. 而你的VS环境编辑框默认是unicode编码. 所以要显示正常, 就只需要把你的串由UTF-8 转换成UNICODE即可
笨笨仔 2015-09-21
  • 打赏
  • 举报
回复
我和伙伴开发单片通信时,他都是用ANSI的GB2312,我用Unicode,因为双方编码不同,PC端接收和发送都需要进行编码转换。以下转换函数供参考:

	// ANSI To UNCODE转换
	CString AnsiToUnicode(char * szAnsi, int len=0);
	// Unicod To ANSI转换
	int UnicodToAnsi(CString str,char* buff);

// ANSI To UNCODE转换
CString CStringProc::AnsiToUnicode(char * szAnsi, int len)
{
	CString str;
	// ansi to unicode
	//预转换,得到所需空间的大小
	int wcsLen;
	if(len>0)
		wcsLen=len;
	else
		wcsLen= ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), NULL, 0);
	//分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间
	wchar_t* wszString = new wchar_t[wcsLen + 1];
	//转换
	::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), wszString, wcsLen);
	//最后加上'\0'
	wszString[wcsLen] = '\0';			// UNICODE字串
	str=wszString;
	delete wszString;
	return str;
}

// Unicod To ANSI转换
int CStringProc::UnicodToAnsi(CString str,char* buff)
{
	int len=0;
	// UNICODE编码 转换成 ANSI编码
	len = ::WideCharToMultiByte(CP_ACP, NULL, str, 
		str.GetLength(), NULL, 0, NULL, NULL);		// 取字串长度
	::WideCharToMultiByte(CP_ACP, NULL, str, str.GetLength(), 
		buff, len, NULL, NULL);
	buff[len++]=0x00;				// 写字串尾部结束标志

	return len;					// 转换长度
}
schlafenhamster 2015-09-21
  • 打赏
  • 举报
回复
代码在 “PeekComm.rar” http://download.csdn.net/detail/schlafenhamster/5202391 “本程序 窥视 串口的 活动。主要 hook 了: {"KERNEL32.DLL", "CreateFileA","myCreateFileA",(FARPROC)myCreateFileA}, {"KERNEL32.DLL", "CreateFileW","myCreateFileW",(FARPROC)myCreateFileW}, {"KERNEL32.DLL",”
Anjoid 2015-09-21
  • 打赏
  • 举报
回复
引用 2 楼 schlafenhamster 的回复:
汉字可能被拆分成 2次 接受;

// "65 A3A8 CAD5 B2D8 A3"  // problem at A3
// "A9 0D0A 0D0A D2BB A1"  // problem at A9 and A1 !!!!
#define SZ  1
BYTE *CPeekCommDlg::KillHalfHZ(BYTE *pdata,UINT len)
{// 
static BYTE HalfHz=0;

	BYTE firstHalf=0;
	UINT HalfAt=0;
	UINT total=0;
	BYTE *copy=0;
	BYTE *pTmp=0;
// 
//	afxDump << len << "\r\n";
//
	if(HalfHz != 0)
	{// add last half HZ to newline
		copy=new BYTE[len+1+SZ];
		memset(copy,0,len+1+SZ);
		copy[0]=HalfHz;
		HalfHz=0;
		memcpy(©[1],pdata,len);
		total=len+1;
	}
	else
	{// keep original
		copy=new BYTE[len+SZ];
		memset(copy,0,len+SZ);
		memcpy(copy,pdata,len+SZ);
		total=len;
	}
	pTmp=copy;
// check this new line
	for(UINT i=0; i < total; i++)
	{
		if(*pTmp >= 0x80) 
		{
			if(firstHalf==0)
			{// half hz
				firstHalf = *pTmp;
				HalfAt = i+1;
			}
			else
			{// has half hz
				if(i==HalfAt)
				{// 1 hz
					HalfAt=0;
					firstHalf=0;
				}
				else
				{// middle or end ? 0xA8 0x44
					break;
				}
			}
		}//if(*pTmp >= 0x80) 
		pTmp++;
	}
// 
	if(HalfAt==0)
	{// newline no half HZ
		copy[total]=0;
	}
	else if (HalfAt==total)
	{// newline has half HZ at end	
		HalfHz=firstHalf;
		copy[total-1]=0;
	}
// you must delete it later !
	return copy;
}
使用 DWORD CPeekCommDlg::AppendText(BYTE *pdata,UINT len,COLORREF FgColor) { CharNewColor(FgColor); // make a sz BYTE *pnew=KillHalfHZ(pdata,len); // LONG nStartChar; LONG nEndChar; m_RichEdit.GetSel(nStartChar,nEndChar); m_RichEdit.SetSel(nEndChar,nEndChar);// go end m_RichEdit.ReplaceSel((char*)pnew); delete [] pnew; // int all=m_RichEdit.GetLineCount(); if(all > 17 ) m_RichEdit.LineScroll(all-17,0); // return len; }
我研究下怎么合到我那个显示的函数里试试 谢谢
Anjoid 2015-09-21
  • 打赏
  • 举报
回复
引用 3 楼 wxhxj0268 的回复:
VS2008用的是Unicode编码,而单片机一般都用GB编码,因此在接收端需要进行码制转换。
我用的是多字符集 Unicode试了也不对 而且把Edit中的文字存在txt文件中打开时正确的 那请问应该怎么转换呢?
笨笨仔 2015-09-19
  • 打赏
  • 举报
回复
VS2008用的是Unicode编码,而单片机一般都用GB编码,因此在接收端需要进行码制转换。
schlafenhamster 2015-09-19
  • 打赏
  • 举报
回复
汉字可能被拆分成 2次 接受;

// "65 A3A8 CAD5 B2D8 A3"  // problem at A3
// "A9 0D0A 0D0A D2BB A1"  // problem at A9 and A1 !!!!
#define SZ  1
BYTE *CPeekCommDlg::KillHalfHZ(BYTE *pdata,UINT len)
{// 
static BYTE HalfHz=0;

	BYTE firstHalf=0;
	UINT HalfAt=0;
	UINT total=0;
	BYTE *copy=0;
	BYTE *pTmp=0;
// 
//	afxDump << len << "\r\n";
//
	if(HalfHz != 0)
	{// add last half HZ to newline
		copy=new BYTE[len+1+SZ];
		memset(copy,0,len+1+SZ);
		copy[0]=HalfHz;
		HalfHz=0;
		memcpy(©[1],pdata,len);
		total=len+1;
	}
	else
	{// keep original
		copy=new BYTE[len+SZ];
		memset(copy,0,len+SZ);
		memcpy(copy,pdata,len+SZ);
		total=len;
	}
	pTmp=copy;
// check this new line
	for(UINT i=0; i < total; i++)
	{
		if(*pTmp >= 0x80) 
		{
			if(firstHalf==0)
			{// half hz
				firstHalf = *pTmp;
				HalfAt = i+1;
			}
			else
			{// has half hz
				if(i==HalfAt)
				{// 1 hz
					HalfAt=0;
					firstHalf=0;
				}
				else
				{// middle or end ? 0xA8 0x44
					break;
				}
			}
		}//if(*pTmp >= 0x80) 
		pTmp++;
	}
// 
	if(HalfAt==0)
	{// newline no half HZ
		copy[total]=0;
	}
	else if (HalfAt==total)
	{// newline has half HZ at end	
		HalfHz=firstHalf;
		copy[total-1]=0;
	}
// you must delete it later !
	return copy;
}
使用 DWORD CPeekCommDlg::AppendText(BYTE *pdata,UINT len,COLORREF FgColor) { CharNewColor(FgColor); // make a sz BYTE *pnew=KillHalfHZ(pdata,len); // LONG nStartChar; LONG nEndChar; m_RichEdit.GetSel(nStartChar,nEndChar); m_RichEdit.SetSel(nEndChar,nEndChar);// go end m_RichEdit.ReplaceSel((char*)pnew); delete [] pnew; // int all=m_RichEdit.GetLineCount(); if(all > 17 ) m_RichEdit.LineScroll(all-17,0); // return len; }
Anjoid 2015-09-19
  • 打赏
  • 举报
回复
补充一下,mEditRcv的属性设置是这样的


谢谢各位

15,978

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧