#include "b6x.h" #include "drvs.h" #include "dbg.h" #include "sftmr.h" #include "app_modbus.h" #include "CRCxx.h" #include "app_ota.h" #include "sys_config.h" #define ModbusCRC16_EN 0 #define DEBUG_MODBUS 1 #if DEBUG_MODBUS #define DEBUG(fmt, args...) debug("[modbus]" fmt, ##args) #else #define DEBUG(fmt, args...) #endif #define MODBUS_MAX_LEN 64 static uint8_t MODBUS_ReceCount =0; static uint8_t MODBUS_Rece_BUF[MODBUS_MAX_LEN]; static uint8_t MODBUS_Sent_BUF[MODBUS_MAX_LEN]; // 需掉电不丢失数据12*2字节//40027-40030//40514-40520 uint16_t MODBUS_FLASH_DAT[12] ={ [0]=1,//MODBUS从机地址 [1]=1,// 出厂模式状态 //写入 1,设备将重置进入出厂模式 [2]=100,// 固件版本 [3]=1,// 硬件版本 [4]=30,//30*100ms // 代码过期时间 [5]=30,//30*100ms// 输出继电器的关闭时间 [6]=100,//100*100ms// Led 激活时间 [7]=10,//10*10ms// 蜂鸣器激活时间 [8]=0x001f,// Led 键盘颜色//RGB565 格式 [9]=0xf800,// Led Mifare 读卡颜色//RGB565 格式 [10]=0x07E0,// Led 状态灯0颜色//RGB565 格式 [11]=0x07ff,// Led 状态灯1颜色//RGB565 格式 }; bool app_modbus_CheckData(uint8_t *dat , uint8_t len); //发送数据并计算CRC void app_modbus_SendData(uint8_t *dat ,uint8_t len){ if(0 == len){ return; } uint16_t CRC16=crc16_modbus(dat ,len); dat[len++] =CRC16 & 0xff;// CRC低字节在前 dat[len++] =CRC16 >> 8; uart_send(UART1_PORT ,len ,dat); while(len){//清空发送数据缓存 dat[--len] =0; } } // 01 功能码 void FunctionalCode_01(uint16_t reg_addr){//ID寄存器地址//返回7字节 uint8_t len_count=0; // DEBUG("FuncCode_01:0x%X\n",reg_addr); MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR; MODBUS_Sent_BUF[len_count++] =0x01; switch(reg_addr){ case 0x0005: break; default: len_count =0; break; } } // 03 功能码 # 读 - 保持寄存器 // 06 功能码 # 写 - 单个寄存器 void FunctionalCode_03_06(uint8_t CMDCode, uint16_t reg_addr , uint16_t reg_val_num){//寄存器地址//返回8字节或15字节 uint8_t len_count=0; // DEBUG("FuncCode_03:0x%X\n",reg_addr); MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR; MODBUS_Sent_BUF[len_count++] =CMDCode; if(CMDCode == 0x03){//寄存器个数计数 MODBUS_Sent_BUF[2] =0; len_count++; }else if(CMDCode == 0x06){ MODBUS_Sent_BUF[len_count++] =(reg_addr >> 8) & 0xff; MODBUS_Sent_BUF[len_count++] =reg_addr & 0xff; } switch(reg_addr){ case 0x0001: // 设备的 Modbus地址 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =0x00; MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ MODBUS_ADDR =reg_val_num & 0xff; MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR >> 8; MODBUS_Sent_BUF[len_count++] =MODBUS_ADDR & 0xff; break; } { // 0x0101-0x0002 case 0x0101: // // 读写系统配置 if(CMDCode == 0x03){ // # 读 - 保持寄存器 break; }else if(CMDCode == 0x06){ // # 写 - 单个寄存器 write_cfg(&sys_conf); //保存写入配置 break; } case 0x0102: // 管理员模式油门极限寄存器(Unit:%) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_conf.Manager_sLim =reg_val_num & 0xff; MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Manager_sLim & 0xff; break; } case 0x0103: // 游客模式油门极限寄存器(Unit:%) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_conf.Tourist_sLim =reg_val_num & 0xff; MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Tourist_sLim & 0xff; break; } case 0x0104: // 减速油门极限寄存器(Unit:%)(自动减速时油门极限) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_conf.Speed_Cut_sLim =reg_val_num & 0xff; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_sLim & 0xff; break; } case 0x0105: // 刹车距离寄存器(前进)(Unit:mm) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_conf.Brake_DLimit =reg_val_num; MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit & 0xff; break; } case 0x0106: // 减速距离寄存器(Unit:mm) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_conf.Speed_Cut_DLimit =reg_val_num; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit & 0xff; break; } case 0x0107: // 刹车距离极限寄存器(后退)(Unit:mm) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_conf.Brake_DLimit_B =reg_val_num; MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Brake_DLimit_B & 0xff; break; } case 0x0108: // 减速距离极限寄存器(Unit:mm) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_conf.Speed_Cut_DLimit_B =reg_val_num; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B >> 8; MODBUS_Sent_BUF[len_count++] =sys_conf.Speed_Cut_DLimit_B & 0xff; break; } } { // 0x0109-0x010D case 0x0201: //PAD模式寄存器 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_sta.Pmode >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.Pmode & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_sta.Pmode =reg_val_num & 0xff; MODBUS_Sent_BUF[len_count++] =sys_sta.Pmode >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.Pmode & 0xff; break; } case 0x0202: //系统模式寄存器(只读) if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_sta.Smode >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.Smode & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ // sys_sta.Smode =reg_val_num & 0xff; // MODBUS_Sent_BUF[len_count++] =sys_sta.Smode >> 8; // MODBUS_Sent_BUF[len_count++] =sys_sta.Smode & 0xff; break; } case 0x0203: //输入输出状态寄存器 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){// 输入输出状态寄存器可写 // sys_sta.I_STA =reg_val_num & 0xff;//输入寄存器不可写 sys_sta.IO_STA =reg_val_num & 0xff; MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.IO_STA & 0xff; break; } case 0x0204: //输入状态寄存器 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ // sys_sta.I_STA =reg_val_num & 0xff;//输入寄存器不可写 MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.I_STA & 0xff; break; } case 0x0205: //0 关闭12V输出//1 开启12V输出 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ sys_sta.O_12V =reg_val_num & 0xff; MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V >> 8; MODBUS_Sent_BUF[len_count++] =sys_sta.O_12V & 0xff; break; } } { // 0x0201-0x0203 case 0x0301: // 电池状态 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_STA >> 8; MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_STA & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ break; } case 0x0302: // 电池电压 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Voltage >> 8; MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Voltage & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ break; } case 0x0303: // 电池电量 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Percent >> 8; MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Percent & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ break; } case 0x0304: // 剩余充电时间 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Remain_Time >> 8; MODBUS_Sent_BUF[len_count++] =BAT_Message.Bat_Remain_Time & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ break; } case 0x0305: // 雷达距离信息 if(CMDCode == 0x03){ MODBUS_Sent_BUF[len_count++] =radar_data.distance >> 8; MODBUS_Sent_BUF[len_count++] =radar_data.distance & 0xff; MODBUS_Sent_BUF[2] +=2; if(0 == --reg_val_num){ break; } }else if(CMDCode == 0x06){ break; } } default: len_count =0; break; } if(len_count == 0){ return; } app_modbus_SendData(MODBUS_Sent_BUF ,len_count); } bool app_modbus_CheckData(uint8_t *dat , uint8_t len){//检查数据 uint16_t CRC16; // DEBUG("len:%d\n",len); if(len > 8){ len = 8; } if(dat[0] ==MODBUS_ADDR){//验证从机地址 CRC16 =crc16_modbus(dat ,len-2);//计算CRC DEBUG("CRC16:0x%X\n",CRC16); #if !ModbusCRC16_EN CRC16 =((uint16_t)(dat[len-1])<<8) + dat[len-2]; #endif if(CRC16 ==((uint16_t)(dat[len-1])<<8) + dat[len-2]){//CRC低字节在前 switch(dat[1]){//功能码 case 0x01:// 功能码 01 FunctionalCode_01(((uint16_t)dat[2]<<8) + dat[3]); break; case 0x03:// 功能码03 # 读 - 保持寄存器 FunctionalCode_03_06(0x03,((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]); // FunctionalCode_03(((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]); break; case 0x06:// 功能码06 # 写 - 单个寄存器 FunctionalCode_03_06(0x06,((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]); // FunctionalCode_06(((uint16_t)dat[2]<<8) + dat[3] ,((uint16_t)dat[4]<<8) + dat[5]); break; default: break; } return true; } } return false; } #if !defined(Modbus_RBUF_SIZE) #define Modbus_RBUF_SIZE 0x100 #endif #define Modbus_FIFO_RXTL 8 #undef RBUF_SIZE #define RBUF_SIZE Modbus_RBUF_SIZE #include "rbuf.h" /// RingBuffer for modbus1 static rbuf_t ModbusRbRx; void app_modbus_Rb_Reset(void){ rbuf_init(&ModbusRbRx); } uint16_t app_modbus_Rb_Len(void){ return rbuf_len(&ModbusRbRx); } uint16_t app_modbus_Rb_Read(uint8_t *buff, uint16_t max){ return rbuf_gets(&ModbusRbRx, buff, max); } #define Rx_timeout _MS(20) // 接收超时时间 static tmr_tk_t Rx_timeout_id=0; static tmr_tk_t Rx_timeout_handler(tmr_id_t id){ (void)(id); MODBUS_ReceCount = app_modbus_Rb_Read(&MODBUS_Rece_BUF[0], MODBUS_MAX_LEN); DEBUG("RC:%d\n",MODBUS_ReceCount); app_PAD_CheckData(MODBUS_Rece_BUF, MODBUS_ReceCount);//PAD数据解析 app_modbus_CheckData(MODBUS_Rece_BUF, MODBUS_ReceCount);//modbus数据解析 app_otas_rxd(MODBUS_ReceCount ,MODBUS_Rece_BUF);//otas数据解析 while(MODBUS_ReceCount){ MODBUS_Rece_BUF[--MODBUS_ReceCount] = 0; } return 0; } void app_modbus_Init(uint32_t baudrate, uint8_t io_tx, uint8_t io_rx){ uart_init(UART1_PORT, io_tx, io_rx); uart_conf(UART1_PORT, BRR_BAUD(baudrate), LCR_BITS(8, 1, none)); // 使能FIFO 接收8字节时触发、使能超过20字节触发超时中断 uart_fctl(UART1_PORT, FCR_FIFOEN_BIT | FCR_RXTL_8BYTE, 20/*bits_rto*/, UART_IR_RXRD_BIT | UART_IR_RTO_BIT); // empty buffer rbuf_init(&ModbusRbRx); DEBUG("MODBUS init success!\n"); NVIC_EnableIRQ(UART1_IRQn); Rx_timeout_id =sftmr_start(10, Rx_timeout_handler); } void UART1_IRQHandler(void){ uint32_t state = UART1->IFM.Word; // UART1->RIF.Word; if (state & 0x01){ //(BIT_RXRD) UART1->IDR.RXRD = 1; // Disable RXRD Interrupt for (uint8_t i = 0; i < Modbus_FIFO_RXTL; i++){ rbuf_putc(&ModbusRbRx, UART1->RBR); } sftmr_Refresh(Rx_timeout_id ,Rx_timeout); UART1->ICR.RXRD = 1; // Clear RXRD Interrupt Flag UART1->IER.RXRD = 1; // Enable RXRD Interrupt } if (state & 0x10){ //(BIT_RTO) UART1->IDR.RTO = 1; // Disable RTO Interrupt while (UART1->SR.RFNE){ rbuf_putc(&ModbusRbRx, UART1->RBR); if(0 ==UART1->SR.RFNE){ sftmr_Refresh(Rx_timeout_id ,Rx_timeout); } } UART1->ICR.RTO = 1; // Clear RTO Interrupt Flag UART1->IER.RTO = 1; // Enable RTO Interrupt } }