基于低压电力采集平台DW710C的基础开发

实验课题

(1)自己定义通信规约,採用java或C++编写简单的PC端上位机软件,实现採集器与PC机的通信。实验可在DW710C-PCproject下进行。

(2)实现LCD显示字符、数字、汉字和简单的图像,并能依据上位机发送的命令做对应的显示。此实验须要掌握LCD屏幕的显示原理(可參考LCD屏幕指导手冊)。并编敲代码控制LCD显示(可參考projectDW710C-LCD)。知道怎样用字模提取软件提取字模;另外还要改动採集器端接收到的命令的解析程序,实现不同命令显示不同内容。

实验说明

採集器的一个485接口与RS-485与RS-232转换模块的485端相连,RS-485与RS-232转换模块的232端通过串口线与PC的232串口相连,我们通过编写上位机串口通信软件和执行在採集器中的程序实现二者的通信。

并在此基础上实现LCD依据PC传来的不同信息进行对应的图形化动态显示。

实验步骤

(1) 编写PC端上位机串口通信软件。

我们利用MFC进行图形化界面开发。利用windows串口函数实现PC与採集器通信的收发。涉及到的串口编程函数有:


函数名


功能


CreateFile


打开port


SetCommMask


设置事件掩码,当指定事件发生时应用程序会收到通知


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) 相同採集器端也要有串口函数进行收发。我们利用既有的实验project中给出的採集器端用来与PC通信的串口接口进行开发。主要涉及串口接收函数的改动,在当中我们定义自己的通信规则。并返回自己定义信息。

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函数进行发送应答信息。

(3) 至此我们实现了PC与採集器的通信。接下来採集器要依据PC传来的不同信号进行LCD动态显示。为了实现该功能,我们首先将PC与採集器的通信部分与LCD显示部分整合到一起。当中main()变成例如以下:

void main(void)
{
    u8	Year_Mon_Day_tmp[3];
  u8	Hour_Min_Second_tmp[3];

    Str711_Init();	         /*对主芯片STR711进行初始化*/
   Back_Light_On();         /*将液晶屏的背光灯打开*/
    WritMeterParaToFlash();  /*将电表的基本參数写入到外部的Flash中*/
   ReadMeterParaFromFlash();/*将电表的基本參数从外部的Flash中读出来*/
    displayfirst(2);	     /*先让液晶显示屏显示第一屏,这个參数2没有起到作用*/

    /*设置初始的与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();			  /*刷新看门狗的计数器值*/
	   RTC_Read_Date_Time(&Time_Rtc);//读取RTC 当前的日期

        //将表的资产编号、当前电表电量、时间在液晶屏上显示
        Year_Mon_Day_tmp[0] = (ptim.tm_year)%100;
	Year_Mon_Day_tmp[0] =  Dec_2_BCD(Year_Mon_Day_tmp[0]);
	Year_Mon_Day_tmp[1] = Dec_2_BCD(ptim.tm_mon+1);
	Year_Mon_Day_tmp[2] = Dec_2_BCD(ptim.tm_mday);

	Hour_Min_Second_tmp[0]  = Dec_2_BCD(ptim.tm_hour);
	Hour_Min_Second_tmp[1]  = Dec_2_BCD(ptim.tm_min);
	Hour_Min_Second_tmp[2]  = Dec_2_BCD(ptim.tm_sec);

        displaysecond(0x1,Meter_Current_Dl,Year_Mon_Day_tmp,Hour_Min_Second_tmp);

        //**************************/
        if(Global_Task_Flag&TASK_FLAG_RX_PC_BIT_OK)
	{//串口PC的有效数据帧被收到, 运行上位机的相关命令
		Global_Task_Flag &= (~TASK_FLAG_RX_PC_BIT_OK);
		WDG_CntRefresh();
               //刷新看门狗的计数器值
			//Task_1();
                        Send_Ack_Or_Data_To_Host_Uart_PC();

        displaysecond(0x1,Meter_Current_Dl,Year_Mon_Day_tmp,Hour_Min_Second_tmp);

		} 

		if(Global_Task_Flag&TASK_FLAG_25MS_TASK)
		{//25MS运行一次的任务
			Global_Task_Flag &=(~TASK_FLAG_25MS_TASK);
			WDG_CntRefresh();				//刷新看门狗的计数器值
			Task_2();
		}
        WDG_CntRefresh();   //刷新看门狗的计数器值
		Task_3();
	}

为了实现LCD动态显示,改动displaysecond()函数。改动后例如以下:

void
displaysecond(u16 Meter_Number,u8 *elec,u8 *date,u8 *time)
{
	memset(lcd_buf,0x00,1024);
         int k=0;

         for(int i=0; i<10; i++)
        {
           find_asc(0x4000F0E0);
           write_lcd_buf_ascii(row, k);
           write_lcd_buf_ascii(row, k+4);
           write_lcd_buf_ascii(row, k+8);
           write_lcd_buf_ascii(row, k+12);
           LCD_Show(lcd_buf);
           k += 16;
           if(k >108)
             k = 0;

         }
}

当中 row是一个u8类型的全局变量,用来接收PC端发来的控制信号,即显示行数,从而实现动态控制。

该变量的接收是在PC与採集器通信的基础上进行改动实现的,改动部分例如以下:

Com_Process_Buf[0]=Com_Recv_Buf[0];
          row = 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;

}

然后在main函数的主循环函数里面,

if(Global_Task_Flag&TASK_FLAG_RX_PC_BIT_OK)

{//串口PC的有效数据帧被收到, 运行上位机的相关命令

Global_Task_Flag &= (~TASK_FLAG_RX_PC_BIT_OK);

WDG_CntRefresh(); //刷新看门狗的计数器值

//Task_1();

Send_Ack_Or_Data_To_Host_Uart_PC();

displaysecond(0x1,Meter_Current_Dl,Year_Mon_Day_tmp,Hour_Min_Second_tmp);

}

该部分在接收到PC端的命令后,即row值发生了改变,再次调用displaysecond函数。LCD在PC端发送的行数显示,至此完毕了PC控制LCD动态显示的功能。

(4)GPRS与採集器通信

首先改动採集器串口波特率38400为9600

BAUD_UART_PC_38400àBAUD_UART_PC_9600

採集器端设置通信规约,仅仅有当手机未向gprs发送信息时。点亮LCD背光灯。

Gprs通过AT指令集进行状态设置,常态串口输出为

****> SEND OK****no msg****

採集器推断接收到的信息是否为以上信息,假设是则不点亮背光灯,当手机向gprs发送信息时。串口输出更改,此时採集器捕捉到信息改动。触发点亮。

体会与感悟

在几周时间里,通过对“基于低压电量採集平台DW710C”的摸索研究,而且自己动手实现了一些功能。比如PC端与採集器通信、PC端控制LCD动态显示。真正地了解了嵌入式开发的基本流程。因为时间较短,我们没有做的非常完美,可是我们解决这个问题的思路和方法是正确的。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-11-08 04:12:35

基于低压电力采集平台DW710C的基础开发的相关文章

基于低压电量采集平台DW710C的基础开发

实验课题 (1)自定义通信规约,采用java或C++编写简单的PC端上位机软件,实现采集器与PC机的通信.实验可在DW710C-PC工程下进行. (2)实现LCD显示字符.数字.汉字和简单的图像,并能根据上位机发送的命令做相应的显示.此实验需要掌握LCD屏幕的显示原理(可参考LCD屏幕指导手册),并编写程序控制LCD显示(可参考工程DW710C-LCD):知道如何用字模提取软件提取字模:另外还要修改采集器端接收到的命令的解析程序,实现不同命令显示不同内容. 实验说明 采集器的一个485接口与RS

基于DM642 RAW采集格式的视频驱动开发及应用

摘 要:为解决C64X系列数字信号处理器(DSP)视频驱动不能应用于原始数据格式(RAW)采集格式的问题,设计了DM642和电耦合元件(CCD)高清传感器的数据传输接口,并分析.修改用于标准格式的视频驱动,使其优化后适用于RAW采集格式,在此基础上开发了基于多级缓存管理机制的应用程序,最终达到采集速率至少每秒15帧的要求.    ?关键词:视频驱动:DM642:CCD高清传感器:RAW采集格式:缓存管理机制  ?中图分类号: TP311.11 文献标志码:A  ?  Abstract: To s

基于微信硬件公众平台的智能控制开发流程

一.微信硬件公众平台整体架构 上一篇<物联网架构场景技术分析>已经探讨和分析了物联网架构的演进,基于微信硬件公众平台的智能控制方案即属于文中的第三种架构--基于统一后台服务的物联架构.其中的架构如下: 各部分的角色和分工如下: 1.微信硬件公众号平台服务器,是物联网的基础和核心部分,其负责外设设备ID的认证,类似公安部给每个公民一个身份证一样,保证每个外设都有一个合法并且唯一的ID.目前微信平台的设备ID由两部分组成,一部分是厂商运维的公众号(即手机微信关注的公众号)的原始ID,称为设备类型,

基于成熟网管平台的网管软件开发模式

随着计算机网络的迅速发展,特别是国际互联网的不断地推广,计算机网络的使用越来越广泛,人们的生产生活学习对计算机网络的依赖也越来越大.同时,随着计算机网络的网络规模的不断扩大和连入网络的设备越来越多样,网络的复杂性也越来越高,网络的异构性也越拉越高.于是,网络管理就成为了一个重要的研究课题. 网络管理是对硬件.软件.人力的综合使用和协调,对网络资源进行监视.测试.配置.分析.评价和控制,从而以合理的价格满足网络的需求,如实时运行性能.服务质量等.从定义中可以看出,网络管理包含了两个重要的任务,一是

【教程分享】基于Greenplum Hadoop分布式平台的大数据解决方案及商业应用案例剖析

基于Greenplum Hadoop分布式平台的大数据解决方案及商业应用案例剖析 课程讲师:迪伦 课程分类:Java 适合人群:高级 课时数量:96课时 用到技术:MapReduce.HDFS.Map-Reduce.Hive.Sqoop 涉及项目:Greenplum Hadoop大数据分析平台 更新程度:完毕 对这个课程有兴趣的朋友可以加我的QQ2059055336和我联系 下载地址:链接:   pan.baidu.com/s/1nthYpKH 密码: niyi 随着云计算.大数据迅速发展,亟需

基于AppCan移动云平台搭建“智慧移动门户”

基于AppCan移动云平台,我们做了很多企业级的移动互联网项目,包括政府层面的双创落地实践,本次将结合实践,分享我们最新的项目经验和技术点.今天要分享的是,我们在智慧城市的项目中很重要的一环,区域智慧移动门户的架构设计和移动前端开发技术. 本次分享共三个重点: 1.AppCan移动云平台架构 2.智慧门户的规划 3.智慧门户的建设策略(技术落地) 智慧门户APP功能框架 智慧门户APP技术框架 1.AppCan移动云平台架构 AppCan在2011年底正式推出,用HTML5+CSS3+JavaS

转:基于ArcGIS10.0和Oracle10g的空间数据管理平台一(C#开发)

很久没有写技术博客了,记得最后一次在CSDN上写技术博客还是2010-08-09 00:31的时候了,那个时候还在学校,虽然大部分时间用于学习编程技术,但是还是有一点的时间和精力来写一些自己学到的东西.学到的编程基础知识在很多书籍和google都能很容易找到,所以自己写技术博客偏向技术实践,就是在特定的需求下完成一些技术性的编程工作.现在自己已经毕业4个月左右了,工作一直比较忙,业余时间也在不断的学习新知识.以后会陆续将自己学到的技术知识在具体实践过程中的心得和体会与大家分享.今天准备开始分享的

大数据灵玖通用采集平台发布

12月20日,公司为了让全体员工熟悉公司新产品-"灵玖通用采集平台"的技术原理.主要特点和性能优势,方便大家在技术调用.用户运维和客户拓展中,对该采集平台有更深刻的理解和把握,特邀请到了采集平台的原始开发人员--高莘,为全体员工做了主题<第二代采集平台--"灵玖通用采集平台"介绍>的培训课程. 高莘表示,数据采集是大数据挖掘的最重要的基础,而"灵玖通用采集平台"是一款既可以对网站深度定制,也可以使用最简单的配置快速采集的系统平台,它采

基于GPU的图像处理平台

基于GPU的图像处理平台 1.  (309)英伟达推Jetson TX1 GPU模块力推人工智能 1.1 产品概述 Jetson TX1 GPU模块,主要针对近年来蓬勃发展的人工智能市场,包括无人机.机器人等设备. 1.2 处理板技术指标 1. Jetson TX1 GPU模块包括一颗浮点运算达到teraflop级的 2.  基于Maxwell架构的256核心GPU,64位ARM A57芯片组 3.  4GB LPDDR4 RAM内存(每秒带宽速度达25.6GB) 4.  5GB本地存储模块.8