DLT645是一种应用在电表上的专用协议,你们平时家里使用的电能表就用的是DLT645协议,该协议分为两个版本,DLT645-1997和DLT645-2007,2007是1997的更新升级版,接收数据帧是一样的,只是发送数据帧格式上DID有点区别
1997的标识符编码是2位

2007的标识符编码是4位

发送时配合各自的控制码进行区别发送,接收是一模一样的!!!
这里我就只讲解DLT645-2007版本了,先看数据帧格式
1。串口数据格式采用11位格式,如下图

2。协议格式


以68H开头作为起始帧
紧接着是6位地址码A0~A5
地址域由 6 个字节构成,每字节 2 位 BCD 码,地址长度可达12位十进制数。每块表具有唯一的通信地址,且与物理层信道无关。当使用的地址码长度不足 6 字节时,高位用“0”补足。通信地址999999999999H为广播地址,只针对特殊命令有效,如广播校时和广播冻结等。广播命令不要求从站应答。地址域支持缩位寻址,即从若干低位起,剩余高位补AAH作为通配符进行读表操作,从站应答帧的地址域返回实际通信地址。
地址域传输时低字节在前,高字节在后。
核心的是控制码C,是用它来区分1997和2007版本的

接着是数据长度L
L 为数据域的字节数。读数据时 L≤200,写数据时 L≤50,L=0 表示无数据域。
接着是数据DATA
数据域包括数据标识、密码、操作者代码、数据、帧序号等,其结构随控制码的功能而改变。传输时发送方按字节进行加 33H 处理,接收方按字节进行减 33H 处理。
接着是校验码CS
从第一个帧起始符开始到校验码之前的所有各字节的模 256 的和,即各字节二进制算术和,不计超过 256 的溢出值。
最后是结束码,固定为16H
标识一帧信息的结束,其值为 16H=00010110B。
注意的是,在主站发送帧信息之前,先发送4个字节FEH,以唤醒接收方。也就是先要接收到4个0XFE后,才能收到0x68H,然后接收后面的数据帧,直到16H完成一帧报文的接收。

通信波特率主要支持下面几个值:

数据标识符

3。主站请求帧,控制码是01

从站正常应答 ,控制码是91

以上就是DLT645-2007的协议格式:下面我们开始进行项目搭建
4。打开RAsmart配置工具,新建工程DLT645_2007

5。选择芯片

6。默认

7。默认

8。默认


9。打开原理图,我用到两个串口

这个是板载的USB串口,用来进行debug调试使用

这个是我自定义的串口,用来和上位机DLT-2007通信
这是上位机软件,通信正确可以读到电能参数。

10。定义串口


注意波特率为9600,因为DLT645-2007不支持115200。需要注意
然后生成代码,打开KEIL

选好芯片

选择JLINK

编译代码

有两处错误,是因为需要实现串口的功能函数和中断
void user_uart9_callback (uart_callback_args_t * p_args)
{
if(p_args->event == UART_EVENT_TX_COMPLETE)
{
uart_send_complete_flag = true;
}
if(p_args->event == UART_EVENT_RX_CHAR)
{
}
}
#if 1
/* 重定向 printf 输出 */
#if defined GNUC && !defined clang
int _write(int fd, char *pBuffer, int size); //防止编译警告
int _write(int fd, char *pBuffer, int size)
{
(void)fd;
R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)pBuffer, (uint32_t)size);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return size;
}
#else
int fputc(int ch, FILE *f)
{
(void)f;
R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return ch;
}
#endif
#endif
void user_uart0_callback (uart_callback_args_t * p_args)
{
if(p_args->event == UART_EVENT_TX_COMPLETE)
{
uart_send_complete_flag = true;
}
if(p_args->event == UART_EVENT_RX_CHAR)
{
}
}
测试一下代码


串口已经调通
10。编写DLT645串口解码程序


void dlt645_service(void)
{
int port;
for (port = 0
{
if (ports[port].rx_frame_pending)
{
dlt645_process_rx_message(port, &ports[port].rx_msg.buf, ports[port].rx_msg.len)
ports[port].rx_frame_pending = false
}
}
}
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "communication.h"
#include "dlt645.h"
#include "dlt645-decs.h"
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE (!FALSE)
#endif
#if !defined(NULL)
#define NULL (void *) 0
#endif
static uint8_t comms_status;
enum
{
DLT645_STATUS_PASSWORD_OK = 0x01
};
static const uint8_t address[6] =
{
0x99, 0x99, 0x99, 0x99, 0x99, 0x99
};
static void xtoa ( unsigned long val, char *buf, unsigned radix, int is_neg)
{
char p; / pointer to traverse string */
char firstdig; / pointer to first digit /
char temp; / temp char /
unsigned digval; / value of digit */
p = buf;
if (is_neg) {
*p++ = '-';
val = (unsigned long)(-(long)val);
}
firstdig = p;
do {
digval = (unsigned) (val % radix);
val /= radix; /* get next digit */
if (digval > 9)
*p++ = (char) (digval - 10 + 'a');
else
*p++ = (char) (digval + '0');
} while (val > 0);
*p-- = '\0';
do {
temp = *p;
*p = *firstdig;
*firstdig = temp;
--p;
++firstdig;
} while (firstdig < p);
}
char * ultoa (unsigned long val, char *buf, int radix)
{
xtoa(val, buf, radix, 0);
return buf;
}
void num16_to_array2(uint16_t num,uint8_t *arr)
{
uint8_t i=0;
uint8_t num_h,num_l;
if(num>9999)i=3;
else if(num>99)i=2;
else i=1;
if(i==1)
{
arr[0]=0x00;
arr[1]=((num/10)<<4|(num%10));
}
else if(i==2)
{
num_h=num/100;
num_l=num%100;
arr[0]=((num_h/10)<<4|(num_h%10));
arr[1]=((num_l/10)<<4|(num_l%10));
}
else if(i==3)
{
printf("error!\r\n");
}
}
void num24_to_array3(uint32_t num,uint8_t *arr)
{
uint8_t i=0;
uint32_t num_h,num_l,num_1,num_2;
if(num>999999)i=4;
else if(num>9999)i=3;
else if(num>99)i=2;
else i=1;
if(i==1)
{
arr[0]=0x00;
arr[1]=((num/10)<<4|(num%10));
}
else if(i==2)
{
num_h=num/100;
num_l=num%100;
arr[0]=((num_h/10)<<4|(num_h%10));
arr[1]=((num_l/10)<<4|(num_l%10));
}
else if(i==3)
{
num_2=num/10000;//printf("num_2:%d\r\n",num_2);
num_1=num%10000;//printf("num_1:%d\r\n",num_1);
num_h=num_1/100;//printf("num_h:%d\r\n",num_h);
num_l=num_1%100;//printf("num_l:%d\r\n",num_l);
arr[0]=((num_2/10)<<4|(num_2%10));
arr[1]=((num_h/10)<<4|(num_h%10));
arr[2]=((num_l/10)<<4|(num_l%10));
}
else if(i==4)
{
printf("error!\r\n");
}
}
void num32_to_array4(uint32_t num,uint8_t *arr)
{
uint8_t i=0;
uint32_t num_h,num_l,num_2,num_3,num_4,num_5;
if(num>99999999) i=5;
else if(num>999999) i=4;
else if(num>9999) i=3;
else if(num>99) i=2;
else i=1;
if(i==1)
{
arr[0]=0x00;
arr[1]=0x00;
arr[2]=0x00;
arr[3]=((num/10)<<4|(num%10));
}
else if(i==2)
{
num_h=num/100;//printf("num_h:%d\r\n",num_h);
num_l=num%100;//printf("num_l:%d\r\n",num_l);
arr[0]=0x00;
arr[1]=0x00;
arr[2]=((num_h/10)<<4|(num_h%10));
arr[3]=((num_l/10)<<4|(num_l%10));
}
else if(i==3)
{
num_3=num/10000;//printf("num_3:%d\r\n",num_3);
num_2=num%10000;//printf("num_2:%d\r\n",num_2);
num_h=num_2/100;//printf("num_h:%d\r\n",num_h);
num_l=num_2%100;//printf("num_l:%d\r\n",num_l);
arr[0]=0x00;
arr[1]=((num_3/10)<<4|(num_3%10));
arr[2]=((num_h/10)<<4|(num_h%10));
arr[3]=((num_l/10)<<4|(num_l%10));
}
else if(i==4)
{
num_5=num/1000000;//printf("num_5:%d\r\n",num_5);
num_4=num%1000000;//printf("num_4:%d\r\n",num_4);
num_3=num_4/10000;//printf("num_3:%d\r\n",num_3);
num_2=num_4%10000;//printf("num_2:%d\r\n",num_2);
num_l=num_2/100;//printf("num_l:%d\r\n",num_l);
num_h=num_2%100;//printf("num_h:%d\r\n",num_h);
arr[0]=((num_5/10)<<4|(num_5%10));
arr[1]=((num_3/10)<<4|(num_3%10));
arr[2]=((num_l/10)<<4|(num_l%10));
arr[3]=((num_h/10)<<4|(num_h%10));
}
else if(i==5)
{
printf("error!\r\n");
}
}
static inline void dlt645_insert_address(uint8_t msg[], const uint8_t address[6])
{
int i;
for (i = 0; i < 6; i++)
msg[i] = address[i];
}
static inline void dlt645_insert_di(uint8_t msg[], const uint8_t di[4])
{
int i;
for (i = 0; i < 4; i++)
msg[i] = di[i];
}
static inline void dlt645_insert_date(uint8_t msg[], const rtc_t *date, int n)
{
int i;
i = 0;
if (n == 6)
msg[i++] = date->second;
msg[i++] = date->minute;
msg[i++] = date->hour;
msg[i++] = date->day;
msg[i++] = date->month;
if (n > 4)
msg[i++] = date->year;
}
int dlt645_finalise_tx_message(int port, uint8_t msg[], int len, const uint8_t address[6])
{
int i;
uint8_t *s;
if (len > MAX_DLT645_MSG_BODY)
return FALSE;
for (i = 0; i < 4; i++)
msg[i] = 0xFE;
msg[4] = 0x68;
dlt645_insert_address(&msg[5], address);
msg[11] = 0x68;
msg[13] = len;
msg[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len] = 0;
msg[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len + 1] = 0x16;
for (i = DLT645_PREAMBLE_BYTES; i < DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len; i++)
msg[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len] += msg[i];
len = DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len + DLT645_MESSAGE_TRAILER_BYTES;
if (len > DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + MAX_DLT645_MSG_BODY + DLT645_MESSAGE_TRAILER_BYTES)
return false;
serial_write(port, msg, len);
return TRUE;
}
int prepare_tx_message(int port, int len)
{
int i;
uint8_t *s;
s = ports[port].tx_msg.buf.uint8;
s[0] = 0xFE;
s[1] = 0xFE;
s[2] = 0xFE;
s[3] = 0xFE;
s[4] = 0x68;
s[5] = address[0];
s[6] = address[1];
s[7] = address[2];
s[8] = address[3];
s[9] = address[4];
s[10] = address[5];
s[11] = 0x68;
s[12] = 0x23;
s[13] = len;
s[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len] = 0;
s[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len + 1] = 0x16;
for (i = DLT645_PREAMBLE_BYTES; i < DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len; i++)
s[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len] += s[i];
len = DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + len + DLT645_MESSAGE_TRAILER_BYTES;
if (len > DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES + MAX_DLT645_MSG_BODY + DLT645_MESSAGE_TRAILER_BYTES)
return false;
serial_write(port, s, len);
return true;
}
char displayStr[20];
void ClearStr(void)
{
uint8_t i;
for (i = 0; i < sizeof(displayStr); i++)
{
displayStr[i] = '\0';
}
}
/**
-
@brief
-
@note
-
@param num:转换为字符串的数字
decNums:N位小数
-
@retval 字符串长度
-
@author PWH
-
@date 2023/10
*/
uint8_t Number2String(uint32_t num, uint8_t decNums)
{
int8_t i, j;
char *displayStr_p = displayStr;
char char_;
char FirstZero = TRUE;
uint32_t data_temp;
ClearStr();
for (i = 9; i >= 0; i--) //32位无符号,十进制10位长度
{
data_temp = 1;
for (j = 0; j < i; j++)
{
data_temp *= 10;
}
char_ = num / data_temp % 10 + '0';
if (FirstZero == FALSE || i == 0 || (FirstZero == TRUE && char_ != '0'))
{
*displayStr_p++ = char_;
if (FirstZero == TRUE)
FirstZero = FALSE; //标记出现第一个非0字符,作用是去除非0字符前的0(除了个位的0)
}
if (decNums && decNums == i) //有小数
{
if (FirstZero == TRUE) //如果未出现过非0字符
{
*displayStr_p++ = '0'; //整数部分是0
FirstZero = FALSE;
}
*displayStr_p++ = '.'; //
}
}
return (displayStr_p - displayStr);
}
static void reverseArray(uint8_t *arr, uint16_t length)
{
uint16_t left = 0;
uint16_t right = length - 1;
while (left < right)
{
// 交换元素
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
// 移动指针
left++;
right
}
}
static void dlt645_process_rx_message(int port, serial_msg_t *rx_msg, int rx_len)
{
int32_t z;
int32_t z1;
#if NUM_PHASES == 1
#define phase_no 0
#else
int phase_no;
#endif
uint16_t *last_flash_loc;
serial_msg_buf_t *tx;
uint8_t *tx8;
uint16_t *tx16;
int i;
int msg_len;
int type;
const uint8_t *msg;
tx = &ports[port].tx_msg;
tx8 = &tx->buf.uint8[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES];
tx16 = (uint16_t *) &tx->buf.uint8[DLT645_PREAMBLE_BYTES + DLT645_MESSAGE_HEADER_BYTES];
type = rx_msg->uint8[8];
msg_len = rx_len - 10 - 2;
msg = &rx_msg->uint8[DLT645_MESSAGE_HEADER_BYTES];
uint8_t address[6] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
uint8_t nx[4] = {0x33, 0x35, 0x44, 0x44};
uint8_t nXX[3] = {0};
uint8_t nV[2] = {0};
/*
ClearStr();
uint8_t LEN;
LEN += Number2String(11010200, 2);
printf("len %d %s\r\n",LEN,displayStr);
for (i = 0; i < rx_len; i++)
printf(" %02X", rx_msg->uint8[i]);
printf("\r\n");
printf("msg_len :%d\r\n",msg_len);
*/
//////////////////////////////////////////
num32_to_array4(12345678,nx);
for(i=0;i<4;i++)
{
nx[i] += 0x33;
printf("nx[%d] = 0x%02x\r\n",i,nx[i]);
}
reverseArray(nx,4);
for(i=0;i<4;i++)
{
printf("== nx[%d] = 0x%02x\r\n",i,nx[i]);
}
///////////////////////////////////////////////
num16_to_array2(4300,nV);
for(i=0;i<2;i++)
{
nV[i] += 0x33;
printf("nV[%d] = 0x%02x\r\n",i,nV[i]);
}
reverseArray(nV,2);
////////////////////////////////////////////////
num24_to_array3(123456,nXX);
for(i=0;i<3;i++)
{
nXX[i] += 0x33;
printf("nV[%d] = 0x%02x\r\n",i,nXX[i]);
}
reverseArray(nXX,3);
switch (type)//type control
{
case 0x11:
switch (msg_len)
{
case 4:
printf("Type 0x%02X - len %d\n", type, msg_len);
dlt645_log_di(msg);
printf("\n");
dlt645_send_msg_91(port, tx, address, msg, nx, 4);
//dlt645_send_msg_91(port, tx, address, msg, nV, 2);
//dlt645_send_msg_91(port, tx, address, msg, nXX, 3);
break;
case 5:
printf("Type 0x%02X - len %d\n", type, msg_len);
dlt645_log_di(msg);
printf(", N = 0x%02X\n");
break;
case 10:
printf("Type 0x%02X - len %d\n", type, msg_len);
dlt645_log_di(msg);
printf(", N = 0x%02X, ", msg[4]);
dlt645_log_date(&msg[5], 5);
printf("\n");
break;
}
break;
case 0x91:
printf("Type 0x%02X\n", type);
dlt645_log_di(msg);
printf(" ");
dlt645_log_n(&msg[4], msg_len - 4);
printf("\n");
break;
case 0xB1:
printf("Type 0x%02X\n", type);
dlt645_log_di(msg);
printf(" ");
dlt645_log_n(&msg[4], msg_len - 4);
printf("\n");
break;
case 0xD1:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x12:
printf("Type 0x%02X\n", type);
//dlt645_log_di(&msg[0]);
printf("Seq %d\n", msg[4]);
break;
case 0x92:
printf("Type 0x%02X\n", type);
dlt645_log_di(&msg[0]);
printf(" ");
dlt645_log_n(&msg[4], msg_len - 4);
printf("\n");
break;
case 0xB2:
printf("Type 0x%02X\n", type);
dlt645_log_di(&msg[0]);
printf(" ");
dlt645_log_n(&msg[4], msg_len - 4);
printf("\n");
break;
case 0xD2:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x14:
printf("Type 0x%02X\n", type);
dlt645_log_di(&msg[0]);
printf(" ");
dlt645_log_p(&msg[4]);
printf(" ");
dlt645_log_c(&msg[8]);
printf(" ");
dlt645_log_n(&msg[12], msg_len - 12);
printf("\n");
break;
case 0x94:
printf("Type 0x%02X\n", type);
/* No message body */
break;
case 0xD4:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x13:
printf("Type 0x%02X\n", type);
/* No message body */
break;
case 0x93:
printf("Type 0x%02X\n", type);
dlt645_log_address(&msg[0]);
printf("\n");
break;
case 0x15:
printf("Type 0x%02X\n", type);
dlt645_log_address(&msg[0]);
printf("\n");
break;
case 0x95:
printf("Type 0x%02X\n", type);
/* No message body */
break;
case 0x08:
printf("Type 0x%02X\n", type);
dlt645_log_date(&msg[0], 4);
printf("\n");
break;
case 0x16:
for (i = 0; i < 6; i++)
{
if (address[i] != 0x99)
break;
}
if (i < 6)
printf("Type 0x%02X\n", type);
else
printf("Type 0x%02X - address 99 99 99 99 99 99\n", type);
dlt645_log_date(&msg[0], 4);
printf("\n");
break;
case 0x96:
printf("Type 0x%02X\n", type);
/* No message body */
break;
case 0xD6:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x17:
printf("Type 0x%02X\n", type);
printf("Z %d\n", msg[0]);
break;
case 0x97:
printf("Type 0x%02X\n", type);
printf("Z %d\n", msg[0]);
break;
case 0xD7:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x18:
printf("Type 0x%02X\n", type);
dlt645_log_di(&msg[0]);
printf(" ");
dlt645_log_p(&msg[4]);
printf(" ");
dlt645_log_p(&msg[8]);
printf("\n");
break;
case 0x98:
printf("Type 0x%02X\n", type);
dlt645_log_p(&msg[0]);
printf("\n");
break;
case 0xD8:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x19:
printf("Type 0x%02X\n", type);
dlt645_log_p(&msg[0]);
printf(" ");
dlt645_log_c(&msg[4]);
printf("\n");
break;
case 0x99:
printf("Type 0x%02X\n", type);
/* No message body */
break;
case 0xD9:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x1A:
printf("Type 0x%02X\n", type);
dlt645_log_p(&msg[0]);
printf(" ");
dlt645_log_c(&msg[4]);
printf("\n");
break;
case 0x9A:
printf("Type 0x%02X\n", type);
/* No message body */
break;
case 0xDA:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
case 0x1B:
printf("Type 0x%02X\n", type);
dlt645_log_p(&msg[0]);
printf(" ");
dlt645_log_c(&msg[4]);
printf(" ");
dlt645_log_di(&msg[8]);
printf("\n");
break;
case 0x9B:
printf("Type 0x%02X\n", type);
/* No message body */
break;
case 0xDB:
printf("Type 0x%02X\n", type);
printf("Err %d\n", msg[0]);
break;
}
ports[port].rx_msg.ptr = 0;
ports[port].rx_msg.len = 0;
for (i = 0; i < MAX_SERIAL_MESSAGE_LEN; i++)
{
ports[port].rx_msg.buf.uint8[i] = 0;
}
}
/* This routine is called regularly from the main polling loop, to check for completed incoming
DLT-645 messages, and to service them. */
void dlt645_service(void)
{
int port;
for (port = 0
{
if (ports[port].rx_frame_pending)
{
dlt645_process_rx_message(port, &ports[port].rx_msg.buf, ports[port].rx_msg.len)
ports[port].rx_frame_pending = false
}
}
}
/* This routine is called from within UART port interrupts, so it must be kept lean and mean. */
void dlt645_rx_byte(int port, uint8_t c)
{
int i;
int sum;
if (ports[port].rx_frame_pending)
return;
ports[port].rx_msg.inter_char_timeout = SAMPLES_PER_10_SECONDS/200;
if (ports[port].rx_msg.ptr == 0)
{
if (c == 0x68)
{
ports[port].rx_msg.buf.uint8[ports[port].rx_msg.ptr++] = c;
ports[port].rx_msg.len = 12 + MAX_DLT645_MSG_BODY;
}
}
else
{
if (ports[port].rx_msg.ptr == 9)
{
if (c <= MAX_DLT645_MSG_BODY)
ports[port].rx_msg.len = 12 + c;
else
ports[port].rx_msg.ptr = 0;
}
ports[port].rx_msg.buf.uint8[ports[port].rx_msg.ptr++] = c;
if (ports[port].rx_msg.ptr == ports[port].rx_msg.len)
{
if (ports[port].rx_msg.buf.uint8[ports[port].rx_msg.len - 1] == 0x16)
{
sum = ports[port].rx_msg.buf.uint8[0];
for (i = 1; i < ports[port].rx_msg.len - 2; i++)
sum += ports[port].rx_msg.buf.uint8[i];
if (ports[port].rx_msg.buf.uint8[ports[port].rx_msg.len - 2] == (sum & 0xFF))
{
ports[port].rx_frame_pending = true;
}
}
ports[port].rx_msg.ptr = 0;
}
}
}
void dlt645_send_msg_11(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4])
{
/* 68 A0 ... A5 68 11 04 DI0 ... DI3 CS 16 */
msg[DLT645_TX_TYPE] = 0x11;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
dlt645_finalise_tx_message(port, msg, 4, address);
}
void dlt645_send_msg_11a(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], int n)
{
/* 68 A0 ... A5 68 11 05 DI0 ... DI3 N CS 16 */
msg[DLT645_TX_TYPE] = 0x11;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
msg[DLT645_TX_START_BODY + 4] = n;
dlt645_finalise_tx_message(port, msg, 5, address);
}
void dlt645_send_msg_11b(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], int n, rtc_t date)
{
/ 68 A0 ... A5 68 11 0A DI0 ... DI3 N mm hh DD MM YY CS 16 */
msg[DLT645_TX_TYPE] = 0x11;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
msg[DLT645_TX_START_BODY + 4] = n;
dlt645_insert_date(&msg[DLT645_TX_START_BODY + 5], date, 5);
dlt645_finalise_tx_message(port, msg, 10, address);
}
void dlt645_send_msg_91(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], const uint8_t n[], int m)
{
/* 68 A0 ... A5 68 91 L DI0 ... DI3 N1 ... NM CS 16 */
msg[DLT645_TX_TYPE] = 0x91;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
memcpy(&msg[DLT645_TX_START_BODY + 4], n, m);
dlt645_finalise_tx_message(port, msg, 4 + m, address);
}
void dlt645_send_msg_b1(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], const uint8_t n[], int m)
{
/* 68 A0 ... A5 68 B1 L DI0 ... DI3 N1 ... NM CS 16 */
msg[DLT645_TX_TYPE] = 0xB1;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
memcpy(&msg[DLT645_TX_START_BODY + 4], n, m);
dlt645_finalise_tx_message(port, msg, 4 + m, address);
}
void dlt645_send_msg_d1(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 D1 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xD1;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_12(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], int seq)
{
/* 68 A0 ... A5 68 12 05 DI0 ... DI3 SEQ CS 16 */
msg[DLT645_TX_TYPE] = 0x12;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
msg[DLT645_TX_START_BODY] = seq;
dlt645_finalise_tx_message(port, msg, 5, address);
}
void dlt645_send_msg_92(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], const uint8_t n[], int m)
{
/* 68 A0 ... A5 68 92 L DI0 ... DI3 N1 ... NM SEQ CS 16 */
msg[DLT645_TX_TYPE] = 0x92;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
memcpy(&msg[DLT645_TX_START_BODY + 4], n, m);
dlt645_finalise_tx_message(port, msg, 4 + m, address);
}
void dlt645_send_msg_b2(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], const uint8_t n[], int m)
{
/* 68 A0 ... A5 68 B2 L DI0 ... DI3 N1 ... NM SEQ CS 16 */
msg[DLT645_TX_TYPE] = 0xB2;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
memcpy(&msg[DLT645_TX_START_BODY + 4], n, m);
dlt645_finalise_tx_message(port, msg, 4 + m, address);
}
void dlt645_send_msg_d2(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 D2 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xD2;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_14(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], const uint8_t p[4], const uint8_t c[4], const uint8_t n[], int m)
{
/* 68 A0 ... A5 68 14 L DI0 ... DI3 PA P0 P1 P2 C0 ... C3 N1 ... NM CS 16 */
msg[DLT645_TX_TYPE] = 0x14;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
memcpy(&msg[DLT645_TX_START_BODY + 4], p, 4);
memcpy(&msg[DLT645_TX_START_BODY + 8], c, 4);
memcpy(&msg[DLT645_TX_START_BODY + 12], n, m);
dlt645_finalise_tx_message(port, msg, 12 + m, address);
}
void dlt645_send_msg_94(int port, uint8_t msg[], const uint8_t address[6])
{
/* 68 A0 ... A5 68 94 00 CS 16 */
msg[DLT645_TX_TYPE] = 0x94;
dlt645_finalise_tx_message(port, msg, 0, address);
}
void dlt645_send_msg_d4(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 D4 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xD4;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_13(int port, uint8_t msg[])
{
static const uint8_t address[6] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
msg[DLT645_TX_TYPE] = 0x13;
dlt645_finalise_tx_message(port, msg, 0, address);
}
void dlt645_send_msg_93(int port, uint8_t msg[], const uint8_t address[6], const uint8_t addressx[])
{
/* 68 A0 ... A5 68 93 06 A0 ... A5 CS 16 */
msg[DLT645_TX_TYPE] = 0x93;
dlt645_insert_address(&msg[DLT645_TX_START_BODY], addressx);
dlt645_finalise_tx_message(port, msg, 6, address);
}
void dlt645_send_msg_15(int port, uint8_t msg[], const uint8_t address[6], const uint8_t addressx[])
{
/* 68 A0 ... A5 68 15 06 A0 ... A5 CS 16 */
msg[DLT645_TX_TYPE] = 0x15;
dlt645_insert_address(&msg[DLT645_TX_START_BODY], addressx);
dlt645_finalise_tx_message(port, msg, 6, address);
}
void dlt645_send_msg_95(int port, uint8_t msg[], const uint8_t address[6])
{
/* 68 A0 ... A5 68 95 00 CS 16 */
msg[DLT645_TX_TYPE] = 0x95;
dlt645_finalise_tx_message(port, msg, 0, address);
}
void dlt645_send_msg_08(int port, uint8_t msg[], const uint8_t address[6], rtc_t date)
{
/ 68 A0 ... A5 68 08 06 ss mm hh DD MM YY CS 16 */
msg[DLT645_TX_TYPE] = 0x08;
dlt645_insert_date(&msg[DLT645_TX_START_BODY], date, 6);
dlt645_finalise_tx_message(port, msg, 6, address);
}
void dlt645_send_msg_16(int port, uint8_t msg[], const uint8_t address[6], rtc_t date)
{
/ 68 A0 ... A5 68 16 04 mm hh DD MM CS 16 */
msg[DLT645_TX_TYPE] = 0x16;
dlt645_insert_date(&msg[DLT645_TX_START_BODY], date, 4);
dlt645_finalise_tx_message(port, msg, 4, address);
}
void dlt645_send_msg_16_999999(int port, uint8_t msg[], rtc_t *date)
{
static const uint8_t address[6] = {0x99, 0x99, 0x99, 0x99, 0x99, 0x99};
msg[DLT645_TX_TYPE] = 0x16;
dlt645_insert_date(&msg[DLT645_TX_START_BODY], date, 4);
dlt645_finalise_tx_message(port, msg, 4, address);
}
void dlt645_send_msg_96(int port, uint8_t msg[], const uint8_t address[6])
{
/* 68 A0 ... A5 68 96 00 CS 16 */
msg[DLT645_TX_TYPE] = 0x96;
dlt645_finalise_tx_message(port, msg, 0, address);
}
void dlt645_send_msg_d6(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 D6 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xD6;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_17(int port, uint8_t msg[], const uint8_t address[6], int z)
{
/* 68 A0 ... A5 68 17 01 Z CS 16 */
msg[DLT645_TX_TYPE] = 0x17;
msg[DLT645_TX_START_BODY] = z;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_97(int port, uint8_t msg[], const uint8_t address[6], int z)
{
/* 68 A0 ... A5 68 97 01 Z CS 16 */
msg[DLT645_TX_TYPE] = 0x97;
msg[DLT645_TX_START_BODY] = z;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_d7(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 D7 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xD7;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_18(int port, uint8_t msg[], const uint8_t address[6], const uint8_t di[4], const uint8_t p[4], const uint8_t pn[4])
{
/* 68 A0 ... A5 68 18 0C DI0 .. DI3 PA0 PO0 P10 P20 PAN P0N P1N P2N CS 16 */
msg[DLT645_TX_TYPE] = 0x18;
dlt645_insert_di(&msg[DLT645_TX_START_BODY], di);
memcpy(&msg[DLT645_TX_START_BODY + 4], p, 4);
memcpy(&msg[DLT645_TX_START_BODY + 8], pn, 4);
dlt645_finalise_tx_message(port, msg, 12, address);
}
void dlt645_send_msg_98(int port, uint8_t msg[], const uint8_t address[6], const uint8_t p[4])
{
/* 68 A0 ... A5 68 98 04 PAN P0N P1N P2N CS 16 */
msg[DLT645_TX_TYPE] = 0x98;
memcpy(&msg[DLT645_TX_START_BODY], p, 4);
dlt645_finalise_tx_message(port, msg, 4, address);
}
void dlt645_send_msg_d8(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 D8 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xD8;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_19(int port, uint8_t msg[], const uint8_t address[6], const uint8_t p[4], const uint8_t c[4])
{
/* 68 A0 ... A5 68 19 08 PA P0 P1 P2 C0 .. C3 CS 16 */
msg[DLT645_TX_TYPE] = 0x19;
memcpy(&msg[DLT645_TX_START_BODY], p, 4);
memcpy(&msg[DLT645_TX_START_BODY + 4], c, 4);
dlt645_finalise_tx_message(port, msg, 8, address);
}
void dlt645_send_msg_99(int port, uint8_t msg[], const uint8_t address[6])
{
/* 68 A0 ... A5 68 99 00 CS 16 */
msg[DLT645_TX_TYPE] = 0x99;
dlt645_finalise_tx_message(port, msg, 0, address);
}
void dlt645_send_msg_d9(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 D9 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xD9;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_1a(int port, uint8_t msg[], const uint8_t address[6], const uint8_t p[4], const uint8_t c[4])
{
/* 68 A0 ... A5 68 1A 08 PA P0 P1 P2 C0 ... C3 CS 16 */
msg[DLT645_TX_TYPE] = 0x1A;
memcpy(&msg[DLT645_TX_START_BODY], p, 4);
memcpy(&msg[DLT645_TX_START_BODY + 4], c, 4);
dlt645_finalise_tx_message(port, msg, 8, address);
}
void dlt645_send_msg_9a(int port, uint8_t msg[], const uint8_t address[6])
{
/* 68 A0 ... A5 68 9A 00 CS 16 */
msg[DLT645_TX_TYPE] = 0x9A;
dlt645_finalise_tx_message(port, msg, 0, address);
}
void dlt645_send_msg_da(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 DA 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xDA;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_send_msg_1bx(int port, uint8_t msg[], const uint8_t address[6], const uint8_t p[4], const uint8_t c[4])
{
static const uint8_t di[4] =
{
0xFF, 0xFF, 0xFF, 0xFF
};
msg[DLT645_TX_TYPE] = 0x1B;
memcpy(&msg[DLT645_TX_START_BODY], p, 4);
memcpy(&msg[DLT645_TX_START_BODY + 4], c, 4);
dlt645_insert_di(&msg[DLT645_TX_START_BODY + 8], di);
dlt645_finalise_tx_message(port, msg, 12, address);
}
void dlt645_send_msg_1b(int port, uint8_t msg[], const uint8_t address[6], const uint8_t p[4], const uint8_t c[4], const uint8_t di[4])
{
/* 68 A0 ... A5 68 1B 0C PA P0 P1 P2 C0 ... C3 FF DI1 DI2 DI3 CS 16 */
msg[DLT645_TX_TYPE] = 0x1B;
memcpy(&msg[DLT645_TX_START_BODY], p, 4);
memcpy(&msg[DLT645_TX_START_BODY + 4], c, 4);
dlt645_insert_di(&msg[DLT645_TX_START_BODY + 8], di);
dlt645_finalise_tx_message(port, msg, 12, address);
}
void dlt645_send_msg_9b(int port, uint8_t msg[], const uint8_t address[6])
{
/* 68 A0 ... A5 68 9B 00 CS 16 */
msg[DLT645_TX_TYPE] = 0x9B;
dlt645_finalise_tx_message(port, msg, 0, address);
}
void dlt645_send_msg_db(int port, uint8_t msg[], const uint8_t address[6], int err)
{
/* 68 A0 ... A5 68 DB 01 ERR CS 16 */
msg[DLT645_TX_TYPE] = 0xDB;
msg[DLT645_TX_START_BODY] = err;
dlt645_finalise_tx_message(port, msg, 1, address);
}
void dlt645_log_di(const uint8_t di[4])
{
printf("DI = %02X %02X %02X %02X", di[0], di[1], di[2], di[3]);
}
void dlt645_log_date(const uint8_t date[4], int n)
{
switch (n)
{
case 4:
printf("Date = %02d/%02d %02d:%02d", date[3], date[2], date[1], date[0]);
break;
case 5:
printf("Date = %04d/%02d/%02d %02d:%02d", date[4] + 2000, date[3], date[2], date[1], date[0]);
break;
case 6:
printf("Date = %04d/%02d/%02d %02d:%02d:%02d", date[5] + 2000, date[4], date[2], date[1], date[0]);
break;
}
}
void dlt645_log_n(const uint8_t n[4], int m)
{
int i;
printf("N =");
for (i = 0; i < m; i++)
printf(" %02X", n[i]);
}
void dlt645_log_p(const uint8_t p[4])
{
printf("P = %02X %02X %02X %02X", p[0], p[1], p[2], p[3]);
}
void dlt645_log_c(const uint8_t c[4])
{
printf("C = %02X %02X %02X %02X", c[0], c[1], c[2], c[3]);
}
void dlt645_log_address(const uint8_t address[6])
{
printf("Address = %02X %02X %02X %02X %02X %02X", address[0], address[1], address[2], address[3], address[4], address[5]);
}

中断接收DLT645处理


/* This routine is called from within UART port interrupts, so it must be kept lean and mean. */
void dlt645_rx_byte(int port, uint8_t c)
{
int i;
int sum;
if (ports[port].rx_frame_pending)
return;
ports[port].rx_msg.inter_char_timeout = SAMPLES_PER_10_SECONDS/200;
if (ports[port].rx_msg.ptr == 0)
{
if (c == 0x68)
{
ports[port].rx_msg.buf.uint8[ports[port].rx_msg.ptr++] = c;
ports[port].rx_msg.len = 12 + MAX_DLT645_MSG_BODY;
}
}
else
{
if (ports[port].rx_msg.ptr == 9)
{
if (c <= MAX_DLT645_MSG_BODY)
ports[port].rx_msg.len = 12 + c;
else
ports[port].rx_msg.ptr = 0;
}
ports[port].rx_msg.buf.uint8[ports[port].rx_msg.ptr++] = c;
if (ports[port].rx_msg.ptr == ports[port].rx_msg.len)
{
if (ports[port].rx_msg.buf.uint8[ports[port].rx_msg.len - 1] == 0x16)
{
sum = ports[port].rx_msg.buf.uint8[0];
for (i = 1; i < ports[port].rx_msg.len - 2; i++)
sum += ports[port].rx_msg.buf.uint8[i];
if (ports[port].rx_msg.buf.uint8[ports[port].rx_msg.len - 2] == (sum & 0xFF))
{
ports[port].rx_frame_pending = true;
}
}
ports[port].rx_msg.ptr = 0;
}
}
}
核心代码



然后判断这个标志位进行接收处理

这里我们进行电能赋值为0X12345678

打开出口助手和DLT645上位机


串口上电数据为


满足性能要求
DLT645上位机初始数据为空白

接下来我开始发查询命令

发送:(07:55:12 716) FE FE FE FE 68 99 99 99 99 99 99 68 11 04 33 33 33 33 47 16
串口助手上接收到的数据

68 99 99 99 99 99 99 68 11 04 33 33 33 33 47 16
DLT645软件上接收到的数据
FE FE FE FE 68 99 99 99 99 99 99 68 11 04 33 33 33 33 47 16
串口助手上忽略了4个前导码0XFE,只提取有效数据
68 99 99 99 99 99 99 68 11 04 33 33 33 33 47 16

可以看到读取的值为123456.78KWH,
同理读取下面的其它数据

可以看到都能正确读取数值,
至此DLT645-2007协议破解完成
详情请看视屏