강좌 & 팁
드디어 마지막 시간 입니다.
이번 시간에는 지난 시간에 말씀 드린 바와 같이 UI 동작 구현 시간 입니다.
다이얼 로그 화면을 보면 OPEN 버튼이 있는데 CLOSE 버튼이 없는 것을 볼 수 있습니다.
이건 만든사람 나름인데요 저는 OPEN 되지 않은 포트를 CLOSE 할 필요 없으므로 하나의 버튼을 토글 동작으로 하기 위해 하나만 만들었던 것입니다.
OPEN된 상태에서 버튼에 CLOSE 를 보여주면 되고, CLOSE 된 상태면 OPEN을 버튼에 보여주면 되는 것이지요.
물론 상태에 따라 버튼이 눌려질 때 COM 포트를 열 것인지 닫을 것인지도 달라지게 구현 하면 됩니다.
그래서 현재 포트 상태를 나타내기 위한 변수를 하나 선언 합니다.
선언 위치는 solution view 에서 header File 중 serialDlg.h 의 public: 아래 입니다.
public: BOOL comport_state; CComboBox m_combo_comport_list; CComboBox m_combo_baudrate_list; virtual BOOL PreTranslateMessage(MSG* pMsg); CString m_str_comport; |
1. open/close 버튼 동작 구현 하기
-> 다이얼로그에서 동작을 구현 할 때는 해당 버튼을 더블 클릭 하면 바로 구현 함수가 생성되어 해당 소스 화면으로 이동 됩니다.
위 그림의 붉은 네모처럼 open 버튼을 마우스로 클릭해 소스코드로 이동 하면 아래와 같이 코드를 추가 합니다.
void CserialDlg::OnBnClickedBtConnect() { // TODO: Add your control notification handler code here if(comport_state) { if(m_comm) //컴포트가존재하면 { m_comm->Close(); m_comm = NULL; AfxMessageBox(_T("COM 포트닫힘")); comport_state=false; GetDlgItem(IDC_BT_CONNECT)->SetWindowText(_T("OPEN")); GetDlgItem(IDC_BT_SEND)->EnableWindow(false); } } else { m_comm= new
CMycomm(_T("\\\\.\\")+m_str_comport,m_str_baudrate,_T("None"),_T("8
Bit"),_T("1 Bit")); //
initial Comm port if( m_comm->Create(GetSafeHwnd())
!= 0) //통신포트를열고윈도우의핸들을넘긴다. { AfxMessageBox(_T("COM 포트열림")); comport_state=true; GetDlgItem(IDC_BT_CONNECT)->SetWindowText(_T("CLOSE")); GetDlgItem(IDC_BT_SEND)->EnableWindow(true); } else { AfxMessageBox(_T("ERROR!")); }
} |
-> 코드를 추가 하고 나서 생각해 보니 com_status 초기값도 없고, comport와 baudrate 초기 값도 설정 되지 않았다는 것을
알 수 있습니다. 그래서 다이얼로그 초기화시 이 값들을 초기화 해 주는 코드를 넣어 줍니다.
-> Clsas view 에서 다이얼로그 클래스의 OninitDialog 를 더블클릭 하고, 아래 소스를 추가해 줍니다.
// TODO: Add
extra initialization here m_combo_comport_list.AddString(_T("COM1")); m_combo_comport_list.AddString(_T("COM2")); m_combo_comport_list.AddString(_T("COM3")); m_combo_comport_list.AddString(_T("COM4"));
m_combo_baudrate_list.AddString(_T("9600")); m_combo_baudrate_list.AddString(_T("19200")); m_combo_baudrate_list.AddString(_T("115200"));
comport_state=false; GetDlgItem(IDC_BT_CONNECT)->SetWindowText(_T("OPEN")); m_str_comport
= _T("COM2"); m_str_baudrate
= _T("115200"); UpdateData(FALSE); |
-> 직관적으로 보면 알겠지만 comport_status 는 초기에 false 로 놓고 버튼은 open 으로 보여주며, 초기 설정 포트는 com2
속도는 115200bps 입니다.
여기 까지 하고 나서 컴파일 하고 동작 시켜 보면 포트가 열리고, 닫히고, 수신된 데이터가 중앙의 edit 화면에 보여지는 것 까지 다 됩니다.
그런데 기본설정으로 된 com 포트와 속도가 변경이 되지 않는 것을 알 수 있습니다.
실제 combo box에서 선택된 값이 적용되지 않았기 때문인데요 이부분을 추가 해 주어야 합니다.
2. com 포트 선택 기능 추가 하기
-> combo box 를 마우스로 선택해서 오른쪽 버튼을 눌러 properties 화면을 띄웁니다.
-> 번개 모양 아이콘을 선택 하는데 이건 control event 며, 통칭 통지메시지 라고도 한답니다.
이 CBN_SELCHANGE 는 COMBO BOX 에서 선택된 값이 변경되면 발생하는 이벤트 이고, 이 이벤트가 발생 했을 때 그 값을
적용 하도록 처리 해 주면 되는 것입니다.
-> CBN_SELCHANGE 를 선택 하고 그 옆에 화살표를 누르면 해당 함수가 생성되는데오 거기에 간단히 하래 코드를 추가 합니다.
void CserialDlg::OnCbnSelchangeComboComport() { // TODO: Add
your control notification handler code here UpdateData(); } |
-> UpdateData(); 는 컨트롤 변수에 현재 값을 저장 하는 역할을 합니다.
앞서 combo box의 변수로 m_combo_comport 와 m_combo_buadrate 맴버 변수를 등록해 두었으니, 현재 선택된 값을
이 변수에 저장 하는 기능을 해 주는 것 이지요.
마찬가지로, 보율 선택 콤보박스도 이처럼 통지메시지를 처리하는 루틴을 추가 하고 updatedata(); 코드를 추가해 줍니다.
여기 까지 하면 원하는 통신 포트에 원하는 통신 속도로 포트를 열고 닫기가 가능 하며, 수신된 데이터가 edit box에 나타날 것입니다.
3. 화면 clear 기능 구현 하기
제목은 그럴싸 하지만 너무나 간단히 화면을 클리어 할 수 있습니다.
그냥 clear 버튼을 더블클릭해서 나오는 처리 함수에 아래 코드를 넣으면 됩니다.
void CserialDlg::OnBnClickedBtClear() { // TODO: Add
your control notification handler code here GetDlgItem(IDC_EDIT_RCV_VIEW)->SetWindowText(_T("
")); } |
-> edit box 의 화면을 그냥 " " .. 아무 것도 없는 것으로 출력 하는 것입니다.
4. 송신 구현 하기
이 기능 또한 모든 것은 CMycomm 클래스에 구현돼 있기 때문에 간단히 버튼을 더블 클릭 한 후 처리 함수에 아래 코드만 넣어 주면
됩니다.
void CserialDlg::OnBnClickedBtSend() { // TODO: Add
your control notification handler code here
CString str; GetDlgItem(IDC_EDIT_SEND_DATA)->GetWindowText(str); str+= "\r\n"; m_comm->Send(str,str.GetLength()); } |
-> 그냥 edit에 써진 데이터를 가져와 맨뒤에 \r\n (캐리지리턴,줄바꿈)만 추가해서 보내 주는 것입니다.
드디어 끝났습니다.
컴파일 하고 동작 시켜보면 됩니다.
-> 동작 시켜 보니 ;; 뭔가 좀 어색 하긴 합니다. ㅎ 여튼 동작은 되는군요.
좀더 원활한 사용을 위해 엔터를 누를 경우 send 가 되면 좋겠다는 생각이 들기도 하구요. 나머지는 이강좌를 보신분들의
몫으로 남겨 두겠습니다.
팁 : 혹시 컴파일시 아래와 같은 메시지를 뿌리며 컴파일 되지 않는다면. ..
vs2008 서비스팩 1 을 설치 하면 됩니다.
visual studio 2008 sp1
http://www.microsoft.com/ko-kr/download/details.aspx?id=10986
또는 vs2010 을 열어 open 하면 잘 되는 군요.
총 6차례에 걸친 강좌를 재미있게 잘 들었습니다. 유용한 강좌 감사합니다.^^
다름이 아니고 포트 열고 닫기도 잘됩니다.
하지만 수신 창에 무언가의 데이터를 받기는 하는거 같긴한데 커서가 계속 밑으로 내려가구요
출력이 되지 않네요
그리고 TRACE에서 지정해선 ReadFile in Error 메시지가 계속 뜨고요..
어떻게 해야하죠?
정말 강의 잘봤습니다 ㅠ 동작도 잘되고 정말 뿌듯하네요 한건없지만..ㅋㅋ
저 죄송하지만 질문하나 드려도될까요?
입력받은 신호를 2진수로 받으려면 어디부분을 건드려야 될까요?
그리고 에어콘 신호 같은 경우에는 처음 리더펄스가 있는데 그 부분은 어떻게 처리를 해야 될지 난감하네요 ...ㅠㅠ
6개의 강의 모두 잘들었습니다!!!
여기서 질문 하나 있는데요.....
워낙에 mfc초보인지라..
컴파일하려하면
error C2039: 'ReplaceSel' : 'ATL: CStringT<BaseType, StringTraits>'의 멤버가 아닙니다
error C2039: 'LineScroll' : 'ATL: CStringT<BaseType, StringTraits>'의 멤버가 아닙니다
error C2039: 'GetLineCount' : 'ATL: CStringT<BaseType, StringTraits>'의 멤버가 아닙니다
이렇게 나오는데요... 암만 구글링을 해보고 학교 수업자료를 봐도 어찌해야하는지 모르겠습니다ㅠㅠㅠ
어떤 함수를 추가해야하는것같은데 어찌해야할까요.... 도와주세요!!!
안녕하세요?
강좌 정말 감사히, 재미 있게 잘 봤습니다.
개인적으로 아주 유용한 강좌 였구요.
감사의 말을 드리고 싶어 회원 가입했습니다.
감사합니다. ^^
1부터 4까진 컴파일이 잘 되는데 5부터 에러가 납니다.
프로젝트명까지 똑같이 만들었는데 에러가 13개가 나는군요 원인을 모르겠습니다 .
경고 1 warning C4018: '<' : signed 또는 unsigned가 일치하지 않습니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 34 1 serial
오류 2 error C2614: 'CserialDlg' : 멤버 초기화가 잘못되었습니다. 'CDialogEx'이(가) 기본 또는 멤버가 아닙니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 87 1 serial
오류 3 error C2248: 'CWnd::DoDataExchange' : protected 멤버('CWnd' 클래스에서 선언)에 액세스할 수 없습니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 93 1 serial
오류 4 error C2352: 'CWnd::DoDataExchange' : 비정적 멤버 함수를 잘못 호출했습니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 93 1 serial
오류 5 error C2248: 'CWnd::OnSysCommand' : protected 멤버('CWnd' 클래스에서 선언)에 액세스할 수 없습니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 192 1 serial
오류 6 error C2352: 'CWnd::OnSysCommand' : 비정적 멤버 함수를 잘못 호출했습니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 192 1 serial
오류 7 error C2248: 'CDialog::OnPaint' : protected 멤버('CDialog' 클래스에서 선언)에 액세스할 수 없습니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 221 1 serial
오류 8 error C2352: 'CDialog::OnPaint' : 비정적 멤버 함수를 잘못 호출했습니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 221 1 serial
9 IntelliSense: #error 지시문: Please use the /MD switch for _AFXDLL builds c:\program files\microsoft visual studio 10.0\vc\atlmfc\include\afxver_.h 81 3
10 IntelliSense: "CDialogEx"이(가) 비정적 데이터 멤버 또는 "CserialDlg" 클래스의 기본 클래스가 아닙니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 84 4 serial
11 IntelliSense: ')'가 필요합니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 84 29 serial
12 IntelliSense: 비정적 멤버 참조는 특정 개체에 상대적이어야 합니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 93 2 serial
13 IntelliSense: 비정적 멤버 참조는 특정 개체에 상대적이어야 합니다. c:\documents and settings\mr\my documents\visual studio 2010\projects\serial\serial\serialdlg.cpp 192 3 serial
강의 정말 많은 도움 되었습니다.
제가 edit에 써진 데이터가 아닌 임의의 변수를 송신할려합니다.
이에 앞서 문자열 "123456789c"을 실험삼아 송신해보았습니다.
하지만 열개의 문자를 보내면 5개의 문자만 수신되는데("12345") 원인을 모르겠습니다.
짝수개의 문자면 그 절반만,
홀수개의 문자, 예로 "123456789"를 송신하면 처음에는"1234" 두번째부터는 계속 "51234"가 출력이 됩니다.
많은 분들에게 도움이 되는 페이지라 도움을 요청해 봅니다.
MFC 시리얼 통신 코드는 아래 부분 제외하고 모두 같습니다.
void CCameraDlg::OnBnClickedBtSend()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
//int test = 12345678;
CString str;
str = "123456789c";
//str.Format(_T("\r\n%d\0"), test);
m_comm->Send(str,str.GetLength());
}
참고로 atmega128과 통신합니다.
MFC말고 하이퍼터미널로 통신하는것은 확인했습니다.(아래 코드에서 if(from_pc[ch_cnt] == '\0'(=>'\n'수정하고 통신))
(ETX를 엔터키로만 바꿨습니다. )
수신인터럽트 다음과 같습니다.
ISR(USART0_RX_vect){
from_pc[ch_cnt] = UDR0;
if(from_pc[ch_cnt] == '\0'){
rec_flag = 1;
ch_cnt = 0;
}
else{
++ch_cnt;
}
}
메인 함수에는 다음과 같은 부분을 코딩하였습니다.
if(rec_flag){
tx_data_string(&from_pc[0]);
rec_flag = 0;
ch_cnt = 0;
memset(from_pc,0,sizeof(from_pc)); //배열 초기화
}
문자열 송신 함수인 tx_data_string은 아래와 같습니다.
void tx_data_string(char *string) {
while(*string != '\0') { // null 포인트가 들어올때 까지 전송
tx_char(*string);
string++;
}
}
총 6차례에 걸친 강좌를 재미있게 잘 들었습니다. 유용한 강좌 감사합니다.^^
코드를 보고 따라하던 중에 질문이 있어 이렇게 문의를 드립니다.
PORT를 오픈하고 데이터를 받는 데는 아무런 문제없이 잘 받아집니다.
하지만 CLOSE를 했을때 CMycomm::HandleClose() 함수에서
(정확히는 CloseHandle(m_OLW.hEvent); 이줄 부분)
"First-chance exception at 0x772d706f in serial.exe: 0xC0000008: An invalid handle was specified."
이런 에러가 뜨는데 혹시나 어떤 부분이 문제일지 궁금해서 이렇게 질문을 드립니다.
(Ignore를 하거나 Continue를 두번 하면 COM 포트가 닫히고 종료됩니다.)