集电极485接口RS-485与RS-232转换模块485端相连。RS-485与RS-232转换模块232通过串行电缆末端PC的232串口。我们通过书面沟通PC通信软件来实现双方并执行收购方案。
1)上位机软件:
採用MFC,主要利用串口函数SetCommState、WriteFile和ReadFile进行串口设置、发送和接收。详细程序例如以下:
void CComplDlg::OnReseved() { DWORD length=0; unsigned char Com_Recv_Buf[256]; ReadFile(hCom,Com_Recv_Buf,20,&length,NULL); //读取串口内容 m_sReseved = 150; //电量 //电表地址,十六进制 m_sAddr1.Format("0x%02x", Com_Recv_Buf[4]); m_sAddr2.Format("0x%02x", Com_Recv_Buf[5]); m_sAddr3.Format("0x%02x", Com_Recv_Buf[6]); m_sAddr4.Format("0x%02x", Com_Recv_Buf[7]); m_sAddr5.Format("0x%02x", Com_Recv_Buf[8]); m_sAddr6.Format("0x%02x", Com_Recv_Buf[9]); UpdateData(false); SetCommMask(hCom,EV_TXEMPTY); UpdateData(false); } void CComplDlg::OnSend() { UpdateData(true); DWORD length=0; unsigned char Com_Send_Buf[10]; Com_Send_Buf[0]=m_sSend; if(WriteFile(hCom,Com_Send_Buf,1,&length,NULL)) { m_cReseved.EnableWindow(true); } else { MessageBox(TEXT("数据发送失败!请重试!"),TEXT("提示"),MB_OK); } } void CComplDlg::OnSetupcom() { UpdateData(true); SetupComm(hCom,1024,1024); COMMTIMEOUTS Timeouts; //DCB dcb GetCommState(hCom,&dcb); dcb.BaudRate=38400;//m_nSetupbt; dcb.ByteSize=8; dcb.StopBits=ONESTOPBIT; dcb.Parity=NOPARITY; SetCommState(hCom,&dcb); UpdateData(false); m_cSend.EnableWindow(true); m_cSend.SetFocus(); m_cSetupcomm.EnableWindow(false); m_cEditsend.SetFocus(); }
2)採集器端程序:
void main(void) { Str711_Init(); //对主芯片STR711进行初始化 /*设置初始的与PC通信的波特率*/ Base_ParaMeter.Baud_to_Pc = BAUD_UART_PC_ORDER_38400; /*由于更改了初始的与PC通信的波特率所以再将数据又一次写回到SPI_Flash中去*/ SPI_Write_161d(BASE_ADDR_BASE_PARA,(u8*)&Base_ParaMeter,sizeof(Base_ParaMeter)); /*配置与PC通信的UART*/ UART_Config(UART_PC, BAUD_UART_PC_38400, UART_EVEN_PARITY, UART_1_StopBits, UARTM_8D_P); //主循环 while(1) { WDG_CntRefresh(); //刷新看门狗的计数器值 //*****************************************************************************/ /*发送一个数据包过去。请求读电量*/ /* if(Global_Task_Flag &TASK_FLAG_BEGIN_LUNXUN) { Global_Task_Flag &=(~TASK_FLAG_BEGIN_LUNXUN); if((Global_Task_Flag&TASK_FLAG_LUNXUN_ING)==0) { WDG_CntRefresh();//刷新看门狗的计数器值 LunXun_Start(); //開始轮询 } }*/ //*****************************************************************************/ if(Global_Task_Flag&TASK_FLAG_RX_PC_BIT_OK) {//串口PC的有效数据帧被收到, 运行上位机的相关命令 Global_Task_Flag &= (~TASK_FLAG_RX_PC_BIT_OK); WDG_CntRefresh(); //刷新看门狗的计数器值 Send_Ack_Or_Data_To_Host_Uart_PC(); } if(Global_Task_Flag&TASK_FLAG_25MS_TASK) {//25MS运行一次的任务 Global_Task_Flag &=(~TASK_FLAG_25MS_TASK); WDG_CntRefresh(); //刷新看门狗的计数器值 Task_2(); } WDG_CntRefresh(); //刷新看门狗的计数器值 Task_3(); } } /********************************************************************************************* *任务函数: Task2() *功能: 25ms 运行一次的任务 *********************************************************************************************/ void Task_2() { WDG_CntRefresh(); //刷新看门狗的计数器值 Parse_Com_Data(3); //串口PC } /********************************************************************************************* *任务函数: Task3() *功能: 推断串口数据的发送是否完毕。假设完毕将状态转换为接收状态 *********************************************************************************************/ void Task_3() { //推断串口PC的发送是否完毕,假设完毕,则将状态转换为接收状态 if(Com_Task_Flag& TASK_FLAG_COM_PC_SEND_COMPLETE) { Com_Task_Flag &= (~TASK_FLAG_COM_PC_SEND_COMPLETE); Com_PC_Send_Total_Len =0; Com_PC_Send_Pos =0; } } /********************************************************************************************* *函数名称: Send_Ack_Or_Data_To_Host_Uart_PC() *功能描写叙述: 对收到串口PC 的上位机命令进行应答 *********************************************************************************************/ void Send_Ack_Or_Data_To_Host_Uart_PC() { u32 i; u8 ch; /*自己定义返回格式与内容,參照DLT 645-1997多功能电能表通信规约的通信协议*/ for(int index=0; index<10; index++) Com_PC_Send_Buf[index] = index; //向上位机发送应答数据帧 Com_PC_Send_Data_Len = 3; Com_PC_Send_Check_Sum = 0; //对数据域加 0x33 for(i=0;i<Com_PC_Send_Data_Len;i++) { Com_PC_Send_Buf[10+i] +=0X33; } for(i=0;i<10+Com_PC_Send_Data_Len;i++) { Com_PC_Send_Check_Sum += Com_PC_Send_Buf[i]; } Com_PC_Send_Buf[i]= Com_PC_Send_Check_Sum; Com_PC_Send_Buf[i+1] = 0x16; Com_PC_Send_Buf[i+2] = 0x16; Com_PC_Send_Buf[i+3] = 0x16; Com_PC_FE_Number =0; //关闭接收中断。取得发送的总长度 Com_PC_Send_Total_Len = Com_PC_Send_Data_Len +14; //包含校验和以及0X16 Com_PC_Send_Pos =0; ch = 0XFE; PC_TX_ENABLE; //PC发送使能 UART_ByteSend(UART_PC,&ch ); UART_ByteSend(UART_PC,&ch ); UART_ByteSend(UART_PC,&ch ); UART_ByteSend(UART_PC,&ch ); do { if(Com_PC_Send_Pos<Com_PC_Send_Total_Len) { UART_ByteSend(UART_PC,&Com_PC_Send_Buf[Com_PC_Send_Pos]); Com_PC_Send_Pos++; } else { break; } }while (!(UART_FlagStatus(UART_PC) & UART_TxFull)); Com_Task_Flag |= TASK_FLAG_COM_PC_SEND_TIME; UART_ItConfig(UART_PC,UART_TxEmpty|UART_TxHalfEmpty,ENABLE); //发送中断使能 UART_ItConfig(UART_PC,UART_RxHalfFull|UART_TimeOutNotEmpty,DISABLE); //接收中断禁止 } /*************************************************************************************************** * FunctionName : Parse_Com_Data * Description : 解析COM口是否有一个完整的数据帧收到 * Parameter(s) : * Com_Number : 是哪一个COM口 2为下行的485口有;3为上行的PC口 * * Return : void ***************************************************************************************************/ void Parse_Com_Data(u8 Com_Number) { u8* Com_Recv_Buf; /*指向串口接收缓冲区的指针*/ u8 Com_Data_Len; /*记录数据帧的数据域长度*/ u8* Com_Recv_Buf_Ptr_W; /*串口接收缓冲区的写指针*/ u8* Com_Recv_Buf_Ptr_R; /*串口接收缓冲区的读指针*/ u16 COM_RECV_BUF_SIZE; /*接收缓冲区的大小*/ u32 TASK_FLAG_COM_RX_OK; /*接收到一个完整的帧的标志位*/ u8* Com_Process_Buf; /*假设接收的帧完整则将这一帧数据转存到这个处理缓冲区中为后面处理做准备*/ u16 i=0; switch(Com_Number) { case 3: Com_Recv_Buf = Com_PC_Recv_Buf; Com_Recv_Buf_Ptr_W = &Com_PC_Recv_Buf_Ptr_W; Com_Recv_Buf_Ptr_R = &Com_PC_Recv_Buf_Ptr_R; Com_Process_Buf = Com_PC_Process_Buf; COM_RECV_BUF_SIZE = COM_RECV_BUF_SIZE_HW_PC; TASK_FLAG_COM_RX_OK = TASK_FLAG_RX_PC_BIT_OK; break; default: return; } /*若发过来的数据是0x99,则视为能够通信。进行应答*/ if(Com_Recv_Buf[0] == 0x99) { Com_Process_Buf[0]=Com_Recv_Buf[0]; //清除缓冲区中全部的数据. memset(Com_Recv_Buf,0,COM_RECV_BUF_SIZE); //读写指针清零也能够. 临时先不清零吧 *Com_Recv_Buf_Ptr_R = 0; *Com_Recv_Buf_Ptr_W = 0; Global_Task_Flag |= TASK_FLAG_COM_RX_OK; } //设置收到串口1有效数据帧标志 return; }
在採集器端25ms进行一次串口数据读取。通过推断接收到的数据是否为0x99,决定是否进行应答。
通过UART_ByteSend功能发送应答信息。
版权声明:本文博客原创文章,博客,未经同意,不得转载。