我個人覺得學習力,就是學習某種知識的能力,我們學習的時間越短,效率就越高,能力就越強。不過學習力也是需要培養的,方法和經驗也需要積累的。高手也是從菜鳥開始的,以下是我做上位機的一些感受。
一、我覺得學會搜索很重要。很多東西前人都做過,我們只需站在前人的肩膀上,再加工或修改就會變成自己的,這樣可以縮短時間,提高效率。所以能有效的搜索到最靠近的資料,就越快達到目標。個人覺得www.baigoogledu.com這個集成谷歌、百度的搜索很好用。
二、在什麼都不懂的情況下,我們要先拿來,借鑑別人所作的東西,去完成自己要做的東西。
三、當我們已經會做某一東西時,我們要回過頭來看看。想想爲什麼要這樣做?這樣做的目的是什麼?有沒有其他更好的方法?這種方法有沒有缺點等等。這樣既能鞏固我們學習的知識,又能引發我們的思考,讓我們達到更高的層次。
四、高手們常教導我們,筆記很重要。及時記錄一些內容,並整理有利於以後翻閱,查找,我也是剛剛起步。
以下是我寫上位機的一些重要代碼。一些變量代碼命名有些不規範,希望自己在以後學習和運用中不斷改正。我轉了一篇C++串口調試助手的文章,步驟可以模仿,在這裏就不寫步驟了,就直接貼部分代碼了。
在初始化函數中添加:
// TODO: Add extra initialization here
m_bAutoSend=FALSE; //m_bAutoSend爲全局變量
m_nCycleTime=1000;
m_GPSCOM.SetCommPort(1); //選擇COM1
m_GPSCOM.SetInputMode(1); //輸入方式爲二進制方式
m_GPSCOM.SetInBufferSize(1024); //設置輸入緩衝區大小
m_GPSCOM.SetOutBufferSize(512); //設置輸出緩衝區大小
// m_GPSCOM.SetSettings("9600,n,8,1"); //波特率115200,無校驗,8個數據位,1個停止位
if(m_GPSCOM.GetPortOpen()) //如果串口是打開的
m_GPSCOM.SetPortOpen(FALSE);//則關閉串口
//參數1表示每當串口接收緩衝區中有多於
//或等於1個字符時將引發一個接收數據的OnComm事件
m_GPSCOM.SetRThreshold(1);
m_GPSCOM.SetInputLen(0); //設置當前接收區數據長度爲0
//m_GPSCOM.GetInput(); //先預讀緩衝區以清除殘留數據
顯示接收到的內容
m_RXDATA建立的變量是CEidtl類型,不是CString
static long RXcount=0;
void CGPS_COM1Dlg::OnGPSCOM() //編輯框接收函數——用於顯示串口接收到的數據
{
// TODO: Add your control notification handler code here
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
BYTE rxdata[2048]; //設置BYTE數組 An 8-bit integerthat is not signed.
CString strtemp;
CString strRXData;
strRXData.Empty();
if(m_GPSCOM.GetCommEvent()==2) //事件值爲2表示接收緩衝區內有字符
{
variant_inp=m_GPSCOM.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); //字符型
if(m_hexdisplay.GetCheck())
{
strtemp.Format("%02x ",bt); //將十六進制送入臨時變量strtemp存放
}
else
{
strtemp.Format("%c",bt); //將字符送入臨時變量strtemp存放
}
strRXData=strRXData+strtemp; //加入接收編輯框對應字符串
}
m_RXDATA.ReplaceSel(strRXData);
RXcount=RXcount+len;
CString rxdatacount;
rxdatacount.Format("%ld",RXcount);
// rxdatacount="接收:"+rxdatacount;
m_RXdatacount.SetWindowText(rxdatacount); //顯示接收計數
}
}
//不用UpdateData(),這樣寫的好處就是當一直在接收時,也能自由發送而不受UpdateData()函數影響。
串口打開或關閉
void CGPS_COM1Dlg::OnButton1() //串口打開或關閉
{
// TODO: Add your control notification handler code here
if(m_ctrlAutoSend.GetCheck())
{
AfxMessageBox("請先關閉自動發送,纔可以關閉串口");
}
else
{
if(!m_GPSCOM.GetPortOpen())
{
m_GPSCOM.SetPortOpen(TRUE);//打開串口
SetDlgItemText(IDC_BUTTON1,"關閉串口");
}
else
{
m_GPSCOM.SetPortOpen(FALSE);//關閉串口
SetDlgItemText(IDC_BUTTON1,"打開串口");
}
}
}
m_TXDATA建立的變量是CEidtl類型,不是CString
long TX_count=0;
void CGPS_COM1Dlg::OnButton2Tx() //數據發送函數
{
// TODO: Add your control notification handler code here
if(!m_GPSCOM.GetPortOpen())
{
AfxMessageBox("請先打開串口");
}
else
{
UpdateData(TRUE); //讀取編輯框內容
if(m_strHexSend.GetCheck())
{
CByteArray hexdata;
int len=String2Hex(m_TXDATA,hexdata); //此處返回的len可以用於計算髮送了多少個十六進制數
m_GPSCOM.SetOutput(COleVariant(hexdata)); //發送十六進制數據
TX_count+=(long) ((m_TXDATA.GetLength()+1)/3); //十六進制計數要注意算法
}
else
{
m_GPSCOM.SetOutput(COleVariant(m_TXDATA));//發送ASCII字符數據
TX_count+=m_TXDATA.GetLength();
}
CString strTemp;
strTemp.Format("%d",TX_count);
m_TXcount.SetWindowText(strTemp);
}
}
void CGPS_COM1Dlg::OnButton3Clear() //清除接收編輯框
{
// TODO: Add your control notification handler code here
m_RXDATA.SetWindowText("");//清除接收對話框中的數據
}
void CGPS_COM1Dlg::OnCHECK1hexdisplay()
{
// TODO: Add your control notification handler code here
}
void CGPS_COM1Dlg::OnCOMchose()
{
// TODO: Add your control notification handler code here
char str[10];
int iPos=m_COMChose.GetCurSel();
int iNum=m_COMChose.GetLBText( iPos, (LPTSTR) str) ;
int i=atoi(str+3);
if(m_GPSCOM.GetPortOpen())
{
AfxMessageBox("請先關閉串口,再選擇COM口");
}
if(!m_GPSCOM.GetPortOpen())
{
m_GPSCOM.SetCommPort(i); //選擇COM口
}
}
void CGPS_COM1Dlg::OnHexSend()
{
// TODO: Add your control notification handler code here
}
void CGPS_COM1Dlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case 1: OnButton2Tx();
break;
/* case 2:
m_strCurPath.SetWindowText(m_strCurPath); //重新顯示路徑
KillTimer(2);//關閉定時器
*/
default: ;
break;
}
CDialog::OnTimer(nIDEvent);
}
void CGPS_COM1Dlg::OnCheck2_AutoSend()
{
// TODO: Add your control notification handler code here
m_bAutoSend=!m_bAutoSend; //標誌是否打開自動發送
if(m_bAutoSend)
{
if(!m_GPSCOM.GetPortOpen())
{
m_bAutoSend=!m_bAutoSend;
m_ctrlAutoSend.SetCheck(0);
AfxMessageBox("串口沒有打開,請打開串口");
return;
}
else
SetTimer(1,m_nCycleTime,NULL); //設置定時器1 m_nCycleTime
}
else
{
KillTimer(1); //“殺”掉定時器1
}
}
void CGPS_COM1Dlg::OnChangeEdit_CycleTime()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// TODO: Add your control notification handler code here
CEdit* pEdit=(CEdit*)GetDlgItem(IDC_EDIT1);
CString strText;
pEdit->GetWindowText(strText);
m_nCycleTime=atoi(strText);
}
void CGPS_COM1Dlg::OnClearCount()
{
// TODO: Add your control notification handler code here
RXcount=0;
TX_count=0;
m_RXdatacount.SetWindowText("");//清除接收對話框中的數據
m_TXcount.SetWindowText("");//清除接收對話框中的數據
}
void CGPS_COM1Dlg::OnButtonSavedata()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
CFile m_rFile;
LPCSTR lpszPath="c:\\comdata"; //存盤路徑爲c:\\comdata
SetCurrentDirectory(lpszPath);
CString m_Filename,m_name1;
m_name1=m_strFilename; //填寫的名字
m_Filename=m_name1+".txt"; //以TXT格式存儲
if(0==m_strFilename.GetLength())
{
AfxMessageBox("請先輸入保存的文件名");
}
else
{
if(!m_rFile.Open(m_Filename,CFile::modeCreate | CFile::modeWrite))
{
AfxMessageBox("創建記錄文件失敗!");
return;
}
char TxtTemp[60000]; //字符串的長度
int Maxsize=60000; //
int i=m_RXDATA.GetWindowText(TxtTemp,Maxsize);//將接受編輯框的數據取出放到數組TxtTemp中
//在文件開始處寫上保存日期
CTime t=CTime::GetCurrentTime();
CString str=t.Format("%Y年%m月%d日%H時%M分%S秒\r\n");
m_rFile.Write((LPCTSTR)str,str.GetLength());
//保存數據
m_rFile.Write((LPCTSTR)TxtTemp,m_RXDATA.GetWindowTextLength());
m_rFile.Flush();
m_rFile.Close(); //關閉文件
AfxMessageBox("保存成功");
UpdateData(FALSE);
}
}
在頭文件中要聲明這兩個函數
//由於這個轉換函數的格式限制,在發送框中的十六制字符應該每兩個字符之間插入一個空隔
//如:A1 23 45 0B 00 29
//CByteArray是一個動態字節數組,可參看MSDN幫助
int CGPS_COM1Dlg::String2Hex(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=ConvertHexChar(hstr);
lowhexdata=ConvertHexChar(lstr);
if((hexdata==16)||(lowhexdata==16))
break;
else
hexdata=hexdata*16+lowhexdata;
i++;
senddata[hexdatalen]=(char)hexdata;
hexdatalen++;
}
senddata.SetSize(hexdatalen);
return hexdatalen;
}
//這是一個將字符轉換爲相應的十六進制值的函數
//好多C語言書上都可以找到
//功能:若是在0-F之間的字符,則轉換爲相應的十六進制字符,否則返回-1
char CGPS_COM1Dlg::ConvertHexChar(char ch)
{
if((ch>='0')&&(ch<='9'))
return ch-0x30;
else if((ch>='A')&&(ch<='F'))
return ch-'A'+10;
else if((ch>='a')&&(ch<='f'))
return ch-'a'+10;
else return (-1);
}
我做成時的界面