实验课题

(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动态显示。真正地了解了嵌入式开发的基本流程。因为时间较短,我们没有做的非常完美,可是我们解决这个问题的思路和方法是正确的。

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

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

  1. 低压电力采集平台DW710C与PC沟通

    集电极485接口RS-485与RS-232转换模块485端相连.RS-485与RS-232转换模块232通过串行电缆末端PC的232串口.我们通过书面沟通PC通信软件来实现双方并执行收购方案. 1)上 ...

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

    摘 要:为解决C64X系列数字信号处理器(DSP)视频驱动不能应用于原始数据格式(RAW)采集格式的问题,设计了DM642和电耦合元件(CCD)高清传感器的数据传输接口,并分析.修改用于标准格式的视频 ...

  3. TDengine在数益工联工业物联采集平台建设中的初步实践

    作者:易永耀 夏杭泰 邓炜兴 公司介绍 数益工联致力于打造基于数据流+价值流的离散制造业数字化软件:应用新一代的物联网技术与丰富的现场交互手段,融合工业工程精益思想,为离散制造业客户的数字化升级提供从 ...

  4. GPS部标平台的架构设计(三) 基于struts+spring+hibernate+ibatis+quartz+mina框架开发GPS平台

    注意,此版本是2014年研发的基于Spring2.5和Struts2的版本,此版本的源码仍然销售,但已不再提供源码升级的服务,因为目前我们开发的主流新版本是2015-2016年近一年推出的基于spri ...

  5. 白瑜庆:知乎基于Kubernetes的kafka平台的设计和实现

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文首发在云+社区,未经许可,不得转载. 自我介绍 我是知乎的技术中台工程师,现在是负责知乎的存储相关组件.我的分享主要基于三个,一个是简单 ...

  6. ringojs 基于jvm 的javascript 平台试用

    ringojs 是一个基于jvm 的javascript 平台,支持commonjs 模块模式 安装 下载包配置环境变量,或者使用docker,测试使用docker dockerfile deb 包安 ...

  7. 基于GPU的图像处理平台

    基于GPU的图像处理平台 1.  (309)英伟达推Jetson TX1 GPU模块力推人工智能 1.1 产品概述 Jetson TX1 GPU模块,主要针对近年来蓬勃发展的人工智能市场,包括无人机. ...

  8. 基于token的多平台身份认证架构设计

    基于token的多平台身份认证架构设计 1   概述 在存在账号体系的信息系统中,对身份的鉴定是非常重要的事情. 随着移动互联网时代到来,客户端的类型越来越多, 逐渐出现了 一个服务器,N个客户端的格 ...

  9. 基于ThinkPHP3的微信平台开发_1

    微信公众平台是个好东西,具体的就不说了,我直接说技术>_< 下图为目录结构一览: 微信开发 - 文件目录结构 平台功能: 此次开发的平台是面向多微信公众号.微信多公众号主(下面简称号主)的 ...

随机推荐

  1. 使用NSCondition实现多线程同步

    iOS中实现多线程技术有非常多方法. 这里说说使用NSCondition实现多线程同步的问题,也就是解决生产者消费者问题(如收发同步等等). 问题流程例如以下: 消费者取得锁,取产品,假设没有,则wa ...

  2. iSwifting如何发送照片社区

    登录iSwifting社区 1,首先点击"帖子": 2,点击"照片": 3.点击"选择文件上传" 4,上传后的照片: 5,点击上传的照片: ...

  3. 学习FFmpeg API – 解码视频

    本文转载 视频播放过程 首先简单介绍以下视频文件的相关知识.我们平时看到的视频文件有许多格式,比如 avi, mkv, rmvb, mov, mp4等等,这些被称为容器(Container), 不同的 ...

  4. WPF 3D:简单的Point3D和Vector3D动画创造一个旋转的正方体

    原文:WPF 3D:简单的Point3D和Vector3D动画创造一个旋转的正方体 运行结果: 事实上很简单,定义好一个正方体,处理好纹理.关于MeshGeometry3D的正确定义和纹理这里就不多讲 ...

  5. [C++]四种方式求解最大子序列求和问题

    问题 给定整数: A1,A2,-,An,求∑jk=iAk 的最大值(为方便起见,假设全部的整数均为负数,则最大子序列和为0) 比如 对于输入:-2,11,-4,13,-5,-2,答案为20,即从A2到 ...

  6. 主从集群搭建及容灾部署redis

    redis主从集群搭建及容灾部署(哨兵sentinel) Redis也用了一段时间了,记录一下相关集群搭建及配置详解,方便后续使用查阅. 提纲 l  Redis安装 l  整体架构 l  Redis主 ...

  7. Linux下一个OTL 采用long long类型数据库支持BIGINT

    码如下面: #define OTL_BIGINT long long #define OTL_STR_TO_BIGINT(str,n) \ { \ n=atoll(str); \ } #define ...

  8. [LeetCode82]Remove Duplicates from Sorted List II

    题目: Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct  ...

  9. 开源Math.NET基础数学类库使用(13)C#实现其他随机数生成器

    原文:[原创]开源Math.NET基础数学类库使用(13)C#实现其他随机数生成器                本博客所有文章分类的总目录:http://www.cnblogs.com/asxiny ...

  10. UiAutomator喷射事件的源代码分析

    上一篇文章<UiAutomator源代码分析之UiAutomatorBridge框架>中我们把UiAutomatorBridge以及它相关的类进行的描写叙述,往下我们会尝试依据两个实例将这 ...