uart波特率为9600,modbus帧间隔3.5个字符即3.5ms,开启一个4ms的定时器,在uart接收中断中刷新4ms定时器,定时器超时则表示连续4ms没有接收到数据,认为一帧结束,
mb_frame_end_flag
= 1;
/* 寄存器映射表 */
struct reg_map_table {
u16 start_addr;
u16 count;
u16 *p_reg_struct;
};
typedef struct {
u16 cell_vol1;
u16 cell_vol2;
u16 cell_vol3;
u16 cell_vol4;
s16 current;
s16 temp1;
s16 temp2;
......
}bms_info_st;
typedef struct {
u16 over_vol;
s16 over_cur;
s16 over_temp;
......
}protect_para_st;
typedef struct {
u16 hw_ver[10];
u16 sw_ver[10];
u16 sys_sn[10];
......
}sys_para_st;
typedef struct {
u16 vol_gain;
s16 cur_offset;
s16 cur_gain;
u16 temp_offset;
......
}cali_para_st;
/* 4组寄存器 */
extern bms_info_st g_bms_info; //采集的数据,只读
extern protect_para_st g_protect_para; //设置的保护参数,可读可写入flash
extern sys_para_st g_sys_para;
extern cali_para_st g_cali_para;
extern u8 mb_buf[256];
extern u16 mb_cnt;
extern u8 mb_frame_end_flag;
extern void modbus_task(void);
#include "modbus.h"
const u8 mb_salve_addr = 0x01; //modbus从机地址
u16* p_reg; //寄存器映射指针
u8 mb_buf[256] = {0}; //uart接收缓冲
u16 mb_cnt = 0; //uart接收一帧的长度
u8 mb_frame_end_flag = 0; //帧结束标志
bms_info_st g_bms_info; //运行数据
protect_para_st g_protect_para; //保护参数
sys_para_st g_sys_para; //系统参数
cali_para_st g_cali_para; //校准参数
struct reg_map_table mb_reg_map_table[4] = {
{ 0, sizeof(g_bms_info)/2, &g_bms_info},
{256, sizeof(g_protect_para)/2, &g_protect_para},
{512, sizeof(g_sys_para)/2, &g_sys_para},
{768, sizeof(g_sys_para)/2, &g_cali_para},
};
/* modbus CRC16 */
u16 mb_crc16(u8 *buf, u16 len)
{
u16 crc = 0xffff;
u16 i = 0, j = 0;
for (i = 0; i < len; i++)
{
crc ^= buf[i];
for (j = 0; j < 8; j++)
{
if (crc & 0x01)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return (crc);
}
/* 地址映射寄存器(结构体), 返回错误码 */
u8 mb_reg_map(u16 addr, u16 count)
{
u8 i = 0;
for (i = 0; i < 4; i++)
{
if ((addr >= mb_reg_map_table[i].start_addr)
&& (addr <= mb_reg_map_table[i].start_addr + mb_reg_map_table[i].count))
{
if ((addr + count) <= (mb_reg_map_table[i].start_addr + mb_reg_map_table[i].count))
{
p_reg = mb_reg_map_table[i].p_reg_struct + addr - mb_reg_map_table[i].start_addr;
return 0;
}
else
{
return 0x03; //请求的数据长度错误
}
}
}
return 0x02; //起始地址错误
}
/* 错误响应帧:
* 1byte 从机地址
* 1byte 功能码 + 0x80
* 1byte 错误码:
* 0x01->不支持的功能码
* 0x02->起始地址错误
* 0x03->请求的数据长度错误
* 0x04->数据读写失败
* 2bytes CRC16
*/
void mb_err_ack(u8 op_code, u8 err_code)
{
u8 mb_txbuf[5];
u16 crc16;
mb_txbuf[0] = mb_salve_addr;
mb_txbuf[1] = op_code | 0x80;
mb_txbuf[2] = err_code;
crc16 = mb_crc16(mb_txbuf, 3);
mb_txbuf[3] = crc16 >> 8;
mb_txbuf[4] = crc16;
uart2_tx(mb_txbuf, 5);
}
//0x03: 读寄存器指令
/* 1byte 从机地址
* 1byte 功能码:0x03
* 2bytes 起始寄存器地址
* 2bytes 寄存器个数N
* 2bytes CRC16
*/
//响应: 地址 + 0x03 + 字节数(1B) + N*寄存器值 + CRC16
void mb_read_reg(u16 reg_addr, u16 count)
{
u16 crc16;
u8 i = 0;
u8 err_code = 0;
/* 映射寄存器 */
err_code = mb_reg_map(reg_addr, count);
if (err_code)
{
mb_err_ack(0x03, err_code);
return;
}
mb_buf[0] = mb_salve_addr;
mb_buf[1] = 0x03;
mb_buf[2] = 2*count;
for (i = 0; i < count; i++)
{
mb_buf[2*i + 3] = p_reg[i] >> 8;
mb_buf[2*i + 4] = p_reg[i];
}
crc16 = mb_crc16(mb_buf, 2*count + 3);
mb_buf[3 + 2*count] = crc16 >> 8;
mb_buf[4 + 2*count] = crc16;
uart2_tx(mb_buf, 5 + 2*count);
}
//0x06: 写单个寄存器
/* 1byte 从机地址
* 1byte 功能码:0x06
* 2bytes 寄存器地址
* 2bytes 寄存器值
* 2bytes CRC16
*/
//响应: 同接收
void mb_write_reg(u16 addr, u16 val)
{
u8 i = 0;
u16 VPackTemp = 0;
s16 cur_temp = 0;
/* 映射寄存器 */
u8 err_code = mb_reg_map(addr, 0);
if (err_code)
{
mb_err_ack(0x06, err_code);
return;
}
*p_reg = val;
switch (addr)
{
case 0x0300:
g_bms_info.pack_v = val >> 8 | val << 8;
for(i=ucCellNumOffset; i<(ucCellNumOffset+ucCellNum); i++)
{
VPackTemp += AFE.uiCell[i];
}
E2uiVPackGain = (U32)CALIPACKVOL*VPackTemp / val;
break;
case 0x0301:
E2siCadcOffset = AFE.siCurr;
break;
case 0x0302:
cur_temp = val >> 8 | val << 8;
E2siCadcGain = (S32)CALICUR * (AFE.siCurr - E2siCadcOffset) / cur_temp;
break;
}
uart2_tx(mb_buf, 8);
}
//0x10: 写多个寄存器
/* 1byte 从机地址
* 1byte 功能码:0x10
* 2bytes 寄存器起始地址
* 2bytes 寄存器个数 N
* 1byte 字节数 2*N
* 2*N bytes 2*N 要写入寄存器的值
* 2bytes CRC16
*/
//响应: 地址 + 0x10 + 寄存器起始地址 + 寄存器个数N + CRC16
void mb_write_multi_reg(u16 addr, u16 count, u16* val)
{
u16 crc16;
u8 i = 0;
/* 映射寄存器 */
u8 err_code = mb_reg_map(addr, count);
if (err_code)
{
mb_err_ack(0x10, err_code);
return;
}
my_memcpy((u8*)val, (u8*)p_reg, 2 * count);
mb_buf[0] = mb_salve_addr;
mb_buf[1] = 0x10;
mb_buf[2] = addr >> 8;
mb_buf[3] = addr;
mb_buf[4] = count >> 8;
mb_buf[5] = count;
crc16 = mb_crc16(mb_buf, 6);
mb_buf[6] = crc16 >> 8;
mb_buf[7] = crc16;
uart2_tx(mb_buf, 8);
}
/* crc16校验 */
static u8 mb_crc16_check(void)
{
u16 recv_crc16 = 0;
u16 calc_crc16 = 0;
recv_crc16 = mb_buf[mb_cnt - 1] | mb_buf[mb_cnt - 2] << 8;
calc_crc16 = mb_crc16(mb_buf, mb_cnt - 2);
return (calc_crc16 == recv_crc16);
}
/* 上位机读取数据前,更新modbus协议的数据 */
static void mb_get_data(void)
{
//禁止uart接收中断
my_memset(0);
g_bms_info.cell_vol1 = 采集的电压1;
g_bms_info.cell_vol2 = 采集的电压2;
......
......
//使能uart接收中断
}
/* 上位机下发设置参数后,写入flash */
static void mb_set_data(void)
{
//禁止uart接收中断
E2uiOVvol = g_protect_para.over_vol;
E2uiOCcur = g_protect_para.over_cur;
......
......
write_flash_flag = 1;
//使能uart接收中断
}
/* 解析帧数据 */
void mb_parse_cmd(void)
{
u8 slave_addr = 0;
u8 op_code = 0;
u16 reg_addr = 0;
u16 reg_cnt = 0;
u16 reg_val = 0;
u16* p_val = NULL;
slave_addr = mb_buf[0];
reg_addr = mb_buf[2] << 8 | mb_buf[3];
reg_cnt = mb_buf[4] << 8 | mb_buf[5];
reg_val = mb_buf[4] << 8 | mb_buf[5];
p_val = (u16*)&mb_buf[7];
if (slave_addr == mb_salve_addr)
{
op_code = mb_buf[1];
switch (op_code)
{
case 0x03:
mb_get_data();
mb_read_reg(reg_addr, reg_cnt);
break;
case 0x06:
mb_get_data();
mb_write_reg(reg_addr, reg_val);
mb_set_data();
break;
case 0x10:
mb_get_data();
mb_write_multi_reg(reg_addr, reg_cnt, p_val);
mb_set_data();
break;
default:
mb_err_ack(op_code, 0x01); /* 不支持的op_code */
break;
}
}
else
{
return;
}
}
void modbus_task(void)
{
if (mb_frame_end_flag == 1)
{
mb_frame_end_flag = 0;
if (mb_crc16_check())
{
mb_parse_cmd(); /* 解析协议 */
}
else
{
goto frame_err;
}
frame_err:
// memset(mb_buf, mb_cnt, 0);
mb_cnt = 0;
}
}
while(1)
{
modbus_task();
if (write_flash_flag)
{
write_flash_flag = 0;
//TODO: 写flash
}
}