- #include "at32l021_clock.h"
- #include "at32l021_board.h"
- #include "modbus_slave.h"
- #include "bsp_dma.h"
- #include "bsp_usart.h"
- #include "bsp_time.h"
- #include "crc16.h"
- //定时器3中断服务函数 处理Modbus主任务
- void TMR3_GLOBAL_IRQHandler(void)//1ms中断
- {
- if (tmr_flag_get(TMR3, TMR_OVF_FLAG) == SET)
- {
- MODBUS_SLAVE_Pool();
- tmr_flag_clear(TMR3, TMR_OVF_FLAG);
- }
- }
- //定时器6中断服务函数 计算帧间隔超时计数
- void TMR6_GLOBAL_IRQHandler(void)//50us中断
- {
- if (tmr_flag_get(TMR6, TMR_OVF_FLAG) == SET)
- {
- timer_record.timer_counter++;
- tmr_flag_clear(TMR6, TMR_OVF_FLAG);
- }
- }
- //串口2中断服务函数 串口发送完成中断,用于判断报文发送完成从而开启接收
- void USART2_IRQHandler(void)
- {
- if(usart_interrupt_flag_get(USART2, USART_TDC_FLAG) != RESET)
- {
- RS485_RX_EN();//接收使能
- dma_channel_enable(DMA1_CHANNEL5, TRUE); //DMA接收使能
- usart_interrupt_enable(USART2, USART_TDC_INT, FALSE);//关闭串口发送完成中断
- }
- }
- crm_clocks_freq_type clocks_struct;
- int main(void)
- {
- system_clock_config();
- crm_clocks_freq_get(&clocks_struct);
-
- rs485_send_init();//MAX485使能引脚初始化
- bsp_usart_init();//串口2初始化
-
- bsp_dma_uart_tx_init(modbus_slave.tx_buf,TX_LEN_MAX);//初始化串口发送dma
- bsp_dma_uart_rx_init(modbus_slave.rx_buf,RX_LEN_MAX);//初始化串口接收dma
-
- bsp_timer3_init();//1ms
- bsp_timer6_init();//50us
- /*报文接收时间间隔 由于此处使用115200波特率
- ModbusRTU协议规定 大于19200 bps时,帧间隔超时时间为1.75ms
- 1.75ms = 1750us 1750/50 = 35*/
- timer_record.overtime = 35;
- while(1)
- {
- ;
- }
- }
由于内容限制,这里只展示从站主要源码,程序实现Modbus功能码 01 02 03 04 05 06 0F 10:
- /************************************************************************/
- /* “文件包含”处理 */
- /************************************************************************/
- #include "modbus_slave.h"
- #include "bsp_dma.h"
- #include "bsp_time.h"
- #include "bsp_usart.h"
- #include "crc16.h"
- /************************************************************************/
- /* 全局变量定义 */
- /************************************************************************/
- Modbus_Slave_t modbus_slave = {0};
- uint16_t test_hold_reg[3] = {0};// 03 06 10 功能码使用
- uint8_t test_led[15] = {0};// 01 05 功能码使用
- uint8_t test_adc[5] = {0x66, 0x77};// 04 功能码使用
- /************************************************************************/
- /* 函数声明 */
- /************************************************************************/
- static void MODBUS_SLAVE_FunctionCodeHandle(void);
- static void MODBUS_SLAVE_01H(void);// 01功能码通过修改test_led[15]数组的值
- static void MODBUS_SLAVE_02H(void);// 02功能码通过函数MODBUS_SLAVE_BSP_GetKeyState 返回值
- static void MODBUS_SLAVE_03H(void);// 03功能码通过读取test_hold_reg[3]数组的值
- static void MODBUS_SLAVE_04H(void);// 04功能码通过读取test_adc[5]数组的值
- static void MODBUS_SLAVE_05H(void);// 05功能码通过修改test_led[15]数组的值
- static void MODBUS_SLAVE_06H(void);// 06功能码通过修改test_hold_reg[3]数组的值
- static void MODBUS_SLAVE_10H(void);// 10功能码通过修改多个test_hold_reg[3]数组的值
- static void MODBUS_SLAVE_0FH(void);// 0F功能码通过修改多个test_led[15]数组的值
- void MODBUS_SLAVE_SendAckErr(uint8_t ErrCode);
- //Modbus主程序
- void MODBUS_SLAVE_Pool(void)
- {
- uBit16 addr;
- uBit16 crc1;
-
- modbus_slave.curr_dma_cnt = dma_data_number_get(DMA1_CHANNEL5);//获取当前串口接收DMA传输计数器中的值
- if (timer_record.timer_start_flag == 0 && modbus_slave.curr_dma_cnt != RX_LEN_MAX)
- {
- timer_record.timer_start_flag = 1;//表示开始接收了
- timer_record.StartTime = timer_record.timer_counter; // 记录开始时间
-
- modbus_slave.last_dma_cnt = modbus_slave.curr_dma_cnt;
- }
- if (timer_record.timer_start_flag == 1)
- {
- if (modbus_slave.curr_dma_cnt == modbus_slave.last_dma_cnt)
- {
- timer_record.Currvalue = timer_record.timer_counter - timer_record.StartTime;//获取经过的时间
- if (timer_record.Currvalue > timer_record.overtime)//判断是否超时
- {
- timer_record.timer_start_flag = 0;//清除接收标志
- modbus_slave.recv_len = RX_LEN_MAX - modbus_slave.curr_dma_cnt;//已经接收的字节数
-
- //成功接收到一帧报文
- bsp_dma_uart_rx_init(modbus_slave.rx_buf,RX_LEN_MAX);//初始化串口接收DMA
- dma_channel_enable(DMA1_CHANNEL5, FALSE);//接收DMA失能
- RS485_TX_EN();//发送使能
-
- if (modbus_slave.recv_len < 4) /* 接收到的数据小于4个字节就认为错误 */
- {
- RS485_RX_EN();//接收使能
- dma_channel_enable(DMA1_CHANNEL5, TRUE); //DMA接收使能
- goto err_ret;
- }
-
- /* 计算CRC校验和 */
- crc1 = CRC16_Modbus(modbus_slave.rx_buf, modbus_slave.recv_len);
- if (crc1 != 0)
- {
- RS485_RX_EN();//接收使能
- dma_channel_enable(DMA1_CHANNEL5, TRUE); //DMA接收使能
- goto err_ret;
- }
- /* 站地址 (1字节) */
- addr = modbus_slave.rx_buf[0]; /* 第1字节 站号 */
- if (addr != SADDR485) /* 判断主机发送的命令地址是否符合 */
- {
- RS485_RX_EN();//接收使能
- dma_channel_enable(DMA1_CHANNEL5, TRUE); //DMA接收使能
- goto err_ret;
- }
-
- //功能码处理
- MODBUS_SLAVE_FunctionCodeHandle();
- }
- }
- else
- {
- // 如果 DMA 接收计数值发生变化,则更新计数
- timer_record.StartTime = timer_record.timer_counter; // 更新开始时间
- }
- modbus_slave.last_dma_cnt = modbus_slave.curr_dma_cnt;//更新此次DMA值
- }
- err_ret:
- memset(modbus_slave.rx_buf, 0, modbus_slave.recv_len);
- modbus_slave.recv_len = 0;/* 必须清零计数器,方便下次帧同步 */
- }
- //Modbus功能码处理
- static void MODBUS_SLAVE_FunctionCodeHandle(void)
- {
- switch (modbus_slave.rx_buf[1]) /* 第2个字节 功能码 */
- {
- case 0x01: /* 读取线圈状态(此例程用led代替)*/
- MODBUS_SLAVE_01H();
- break;
- case 0x02: /* 读取输入状态(按键状态)*/
- MODBUS_SLAVE_02H();
- break;
-
- case 0x03: /* 读取保持寄存器*/
- MODBUS_SLAVE_03H();
- break;
-
- case 0x04: /* 读取输入寄存器(ADC的值)*/
- MODBUS_SLAVE_04H();
- break;
-
- case 0x05: /* 强制单线圈(设置led)*/
- MODBUS_SLAVE_05H();
- break;
-
- case 0x06: /* 写单个保存寄存器*/
- MODBUS_SLAVE_06H();
- break;
-
- case 0x10: /* 写多个保存寄存器*/
- MODBUS_SLAVE_10H();
- break;
-
- case 0x0F: /* 写多个线圈寄存器*/
- MODBUS_SLAVE_0FH();
- break;
- default:
- modbus_slave.RTU_response_code = RSP_ERR_CMD;
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 告诉主机命令错误 */
- break;
- }
- }
- //将两字节转换为16位
- uBit16 MODBUS_SLAVE_BEBufToUint16(uBit8 *_pBuf)
- {
- return (((uBit16)_pBuf[0] << 8) | _pBuf[1]);
- }
- //串口发送
- void MODBUS_SLAVE_UartSend(uBit8 *buf, uBit16 len)
- {
- //发送函数
- bsp_dma_uart_tx_init(modbus_slave.tx_buf, len);//初始化dma,重置传输计数器
- dma_channel_enable(DMA1_CHANNEL4, TRUE); /* usart2 tx begin dma transmitting */
- usart_flag_clear(USART2, USART_TDC_FLAG);
- usart_interrupt_enable(USART2, USART_TDC_INT, TRUE);
- }
- //发送加crc
- void MODBUS_SLAVE_SendWithCRC(uint8_t *buf, uint8_t len)
- {
- uint16_t crc;
-
- crc = CRC16_Modbus(buf, len);
- buf[len++] = crc >> 8;
- buf[len++] = crc;
-
- MODBUS_SLAVE_UartSend(buf, len);
- }
- //发送错误应答 ErrCode : 错误代码
- void MODBUS_SLAVE_SendAckErr(uint8_t ErrCode)
- {
- modbus_slave.send_len = 0;
-
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[0]; /* 485地址 */
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[1] | 0x80; /* 异常的功能码 */
- modbus_slave.tx_buf[modbus_slave.send_len++] = ErrCode; /* 错误代码(01,02,03,04) */
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- //判断LED指示灯是否已经点亮
- uint8_t MODBUS_SLAVE_BSPIsLedOn(uint8_t num)
- {
- if (num == 1)
- {
- if (test_led[0])
- {
- return 1;
- }
- return 0;
- }
- else if (num == 2)
- {
- if (test_led[1])
- {
- return 1;
- }
- return 0;
- }
- else if (num == 3)
- {
- if (test_led[2])
- {
- return 1;
- }
- return 0;
- }
- else if (num == 4)
- {
- if (test_led[3])
- {
- return 1;
- }
- return 0;
- }
- return 0;
- }
- //读线圈状态功能码 01H
- static void MODBUS_SLAVE_01H(void)
- {
- uBit16 reg;
- uBit16 num;
- uBit16 i;
- uBit16 m;
- uBit8 status[10];
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len != 8)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; // 数据值域错误
- return;
- }
-
- reg = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[2]); // 寄存器号
- num = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); // 寄存器个数
- m = (num + 7) / 8;
- if ((reg >= REG_D01) && (num > 0) && (reg + num <= REG_DXX + 1))
- {
- for (i = 0; i < m; i++)
- {
- status[i] = 0;
- }
- for (i = 0; i < num; i++)
- {
- if (MODBUS_SLAVE_BSPIsLedOn(i + 1 + reg - REG_D01)) // 读LED的状态,写入状态寄存器的每一位
- {
- status[i / 8] |= (1 << (i % 8));
- }
- }
- }
- else
- {
- modbus_slave.RTU_response_code = RSP_ERR_REG_ADDR; // 寄存器地址错误
- }
- if (modbus_slave.RTU_response_code == RSP_OK) // 正确应答
- {
- modbus_slave.send_len = 0;
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[0];
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[1];
- modbus_slave.tx_buf[modbus_slave.send_len++] = m; // 返回字节数
- for (i = 0; i < m; i++)
- {
- modbus_slave.tx_buf[modbus_slave.send_len++] = status[i];
- }
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); // 告诉主机命令错误
- }
- }
- //02读取输入状态
- uint8_t MODBUS_SLAVE_BSP_GetKeyState(uint8_t _ucKeyID)
- {
- return 1;//此处应该返回按键按下状态,这里模拟都为1
- }
- //读取输入状态功能码 02H
- static void MODBUS_SLAVE_02H(void)
- {
- uint16_t reg;
- uint16_t num;
- uint16_t i;
- uint16_t m;
- uint8_t status[10];
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len != 8)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- return;
- }
- reg = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[2]); /* 寄存器号 */
- num = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); /* 寄存器个数 */
- m = (num + 7) / 8;
- if ((reg >= REG_T01) && (num > 0) && (reg + num <= REG_TXX + 1))
- {
- for (i = 0; i < m; i++)
- {
- status[i] = 0;
- }
- for (i = 0; i < num; i++)
- {
- if (MODBUS_SLAVE_BSP_GetKeyState(reg - REG_T01 + i))
- {
- status[i / 8] |= (1 << (i % 8));
- }
- }
- }
- else
- {
- modbus_slave.RTU_response_code = RSP_ERR_REG_ADDR; /* 寄存器地址错误 */
- }
- if (modbus_slave.RTU_response_code == RSP_OK) /* 正确应答 */
- {
- modbus_slave.send_len = 0;
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[0];
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[1];
- modbus_slave.tx_buf[modbus_slave.send_len++] = m; /* 返回字节数 */
- for (i = 0; i < m; i++)
- {
- modbus_slave.tx_buf[modbus_slave.send_len++] = status[i]; /* T01-02状态 */
- }
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 告诉主机命令错误 */
- }
- }
- //读取保持寄存器的值
- uint8_t MODBUS_SLAVE_ReadRegValue(uint16_t reg_addr, uint8_t *reg_value)
- {
- uint16_t value;
- switch (reg_addr) /* 判断寄存器地址 */
- {
- case SLAVE_REG_P01:
- value = test_hold_reg[0];
- break;
- case SLAVE_REG_P02:
- value = test_hold_reg[1]; /* 将寄存器值读出 */
- break;
- default:
- return 0; /* 参数异常,返回 0 */
- }
- reg_value[0] = value >> 8;
- reg_value[1] = value;
- return 1; /* 读取成功 */
- }
- //读取保持寄存器功能码 03H
- static void MODBUS_SLAVE_03H(void)
- {
- uint16_t reg;
- uint16_t num;
- uint16_t i;
- uint8_t reg_value[64];
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len != 8) /* 03H命令必须是8个字节 */
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- reg = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[2]); /* 寄存器号 */
- num = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); /* 寄存器个数 */
- if (num > sizeof(reg_value) / 2)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- for (i = 0; i < num; i++)
- {
- if (MODBUS_SLAVE_ReadRegValue(reg, ®_value[2 * i]) == 0) /* 读出寄存器值放入reg_value */
- {
- modbus_slave.RTU_response_code = RSP_ERR_REG_ADDR; /* 寄存器地址错误 */
- break;
- }
- reg++;
- }
- err_ret:
- if (modbus_slave.RTU_response_code == RSP_OK) /* 正确应答 */
- {
- modbus_slave.send_len = 0;
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[0];
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[1];
- modbus_slave.tx_buf[modbus_slave.send_len++] = num * 2; /* 返回字节数 */
- for (i = 0; i < num; i++)
- {
- modbus_slave.tx_buf[modbus_slave.send_len++] = reg_value[2*i];
- modbus_slave.tx_buf[modbus_slave.send_len++] = reg_value[2*i+1];
- }
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len); /* 发送正确应答 */
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 发送错误应答 */
- }
- }
- //读取输入寄存器功能码 04H
- static void MODBUS_SLAVE_04H(void)
- {
- uint16_t reg;
- uint16_t num;
- uint16_t i;
- uint16_t status[10];
- memset(status, 0, 10);
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len != 8)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- reg = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[2]); /* 寄存器号 */
- num = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); /* 寄存器个数 */
- if ((reg >= REG_A01) && (num > 0) && (reg + num <= REG_AXX + 1))
- {
- for (i = 0; i < num; i++)
- {
- switch (reg)
- {
- /* 测试参数 */
- case REG_A01:
- status[i] = test_adc[0];
- break;
-
- default:
- status[i] = 0;
- break;
- }
- reg++;
- }
- }
- else
- {
- modbus_slave.RTU_response_code = RSP_ERR_REG_ADDR; /* 寄存器地址错误 */
- }
- err_ret:
- if (modbus_slave.RTU_response_code == RSP_OK) /* 正确应答 */
- {
- modbus_slave.send_len = 0;
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[0];
- modbus_slave.tx_buf[modbus_slave.send_len++] = modbus_slave.rx_buf[1];
- modbus_slave.tx_buf[modbus_slave.send_len++] = num * 2; /* 返回字节数 */
- for (i = 0; i < num; i++)
- {
- modbus_slave.tx_buf[modbus_slave.send_len++] = status[i] >> 8;
- modbus_slave.tx_buf[modbus_slave.send_len++] = status[i] & 0xFF;
- }
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 告诉主机命令错误 */
- }
- }
- //强制单线圈功能码 05H
- static void MODBUS_SLAVE_05H(void)
- {
- uint16_t reg;
- uint16_t value;
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len != 8)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- reg = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[2]); /* 寄存器号 */
- value = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); /* 数据 */
- if ((value>>8) != 0x00 && (value>>8) != 0xFF)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- //此处处理可以优化
- if (value>>8)//右移8位为0xFF 则值1 表示打开
- value = 1;
- else//右移8位为0x00 则值0 表示关闭
- value = 0;
-
- if (reg == REG_D01)
- {
- test_led[0] = value;//模拟LED状态
- }
- else if (reg == REG_D02)
- {
- test_led[1] = value;
- }
- else if (reg == REG_D03)
- {
- test_led[2] = value;
- }
- else if (reg == REG_D04)
- {
- test_led[3] = value;//模拟LED状态
- }
- else
- {
- modbus_slave.RTU_response_code = RSP_ERR_REG_ADDR; /* 寄存器地址错误 */
- }
- err_ret:
- if (modbus_slave.RTU_response_code == RSP_OK) /* 正确应答 */
- {
- //此命令码应答报文与请求报文一致
- memcpy(modbus_slave.tx_buf, modbus_slave.rx_buf, modbus_slave.recv_len - 2);//不复制crc位
- modbus_slave.send_len = (modbus_slave.recv_len - 2);//不复制crc位
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 告诉主机命令错误 */
- }
- }
- //读取保持寄存器的值
- uint8_t MODBUS_SLAVE_WriteRegValue(uint16_t reg_addr, uint16_t reg_value)
- {
- switch (reg_addr) /* 判断寄存器地址 */
- {
- case SLAVE_REG_P01:
- test_hold_reg[0] = reg_value; /* 将值写入保存寄存器 */
- break;
-
- case SLAVE_REG_P02:
- test_hold_reg[1] = reg_value; /* 将值写入保存寄存器 */
- break;
-
- default:
- return 0; /* 参数异常,返回 0 */
- }
- return 1; /* 读取成功 */
- }
- //写单个寄存器功能码 06H
- static void MODBUS_SLAVE_06H(void)
- {
- uint16_t reg;
- uint16_t value;
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len != 8)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- reg = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[2]); /* 寄存器号 */
- value = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); /* 寄存器值 */
- if (MODBUS_SLAVE_WriteRegValue(reg, value) == 1) /* 该函数会把写入的值存入寄存器 */
- {
- ;
- }
- else
- {
- modbus_slave.RTU_response_code = RSP_ERR_REG_ADDR; /* 寄存器地址错误 */
- }
- err_ret:
- if (modbus_slave.RTU_response_code == RSP_OK) /* 正确应答 */
- {
- //此命令码应答报文与请求报文一致
- memcpy(modbus_slave.tx_buf, modbus_slave.rx_buf, modbus_slave.recv_len - 2);//不复制crc位
- modbus_slave.send_len = (modbus_slave.recv_len - 2);//不复制crc位
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 告诉主机命令错误 */
- }
- }
- //写多个寄存器功能码 10H
- static void MODBUS_SLAVE_10H(void)
- {
- uint16_t reg_addr;
- uint16_t reg_num;
- uint8_t byte_num;
- uint8_t i;
- uint16_t value;
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len < 11)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- reg_addr = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[2]); /* 寄存器号 */
- reg_num = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); /* 寄存器个数 */
- byte_num = modbus_slave.rx_buf[6]; /* 后面的数据体字节数 */
- if (byte_num != 2 * reg_num)
- {
- ;
- }
- for (i = 0; i < reg_num; i++)
- {
- value = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[7 + 2 * i]); /* 寄存器值 */
- if (MODBUS_SLAVE_WriteRegValue(reg_addr + i, value) == 1)
- {
- ;
- }
- else
- {
- modbus_slave.RTU_response_code = RSP_ERR_REG_ADDR; /* 寄存器地址错误 */
- break;
- }
- }
- err_ret:
- if (modbus_slave.RTU_response_code == RSP_OK) /* 正确应答 */
- {
- //此命令码应答报文与请求报文一致
- memcpy(modbus_slave.tx_buf, modbus_slave.rx_buf, 6);//不复制crc位
- modbus_slave.send_len = 6;//不复制crc位
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 告诉主机命令错误 */
- }
- }
- //写多个线圈
- uint8_t MODBUS_SLAVE_BSPSetLed(uint8_t num, uint8_t value)
- {
- static uint8_t last, last_flag;
- if (num / 8)
- {
- num = 8;
- last++;
- }
- else
- {
- num %= 8;
- last_flag = 1;
- }
- for (uint16_t i = 0; i < num; i++)
- {
- if (last_flag == 0)
- {
- test_led[i+((last - 1) * 8)] = (value & (0x01 << i)) >> i;
- }
- if (last_flag == 1)
- {
- test_led[i + (last * 8)] = (value & (0x01 << i)) >> i;
- }
-
- }
-
- if (last_flag)
- {
- last_flag = 0;
- last = 0;
- }
- return 0;
- }
- //写多个线圈功能码 0FH
- static void MODBUS_SLAVE_0FH(void)
- {
- uint16_t reg_num;
- uint8_t byte_num;
- uint8_t i;
- uint16_t value;
- modbus_slave.RTU_response_code = RSP_OK;
- if (modbus_slave.recv_len < 10)
- {
- modbus_slave.RTU_response_code = RSP_ERR_VALUE; /* 数据值域错误 */
- goto err_ret;
- }
- reg_num = MODBUS_SLAVE_BEBufToUint16(&modbus_slave.rx_buf[4]); /* 寄存器个数 */
- byte_num = modbus_slave.rx_buf[6]; /* 后面的数据体字节数 */
- //判断寄存器数量与字节数是否对应
- if (reg_num % 8)//寄存器数量不是整数字节,需要+1之后比较
- {
- if (byte_num != ((reg_num / 8) + 1))
- {
- ;
- }
- }
- else//寄存器数量是整数字节直接进行比较
- {
- if (byte_num != (reg_num / 8))
- {
- ;
- }
- }
-
- for (i = 0; i < byte_num; i++)
- {
- value = modbus_slave.rx_buf[7 + i];/* 寄存器值 */
- MODBUS_SLAVE_BSPSetLed(reg_num, value);
- reg_num -= 8;
- }
- err_ret:
- if (modbus_slave.RTU_response_code == RSP_OK) /* 正确应答 */
- {
- //此命令码应答报文与请求报文一致
- memcpy(modbus_slave.tx_buf, modbus_slave.rx_buf, 6);//不复制crc位
- modbus_slave.send_len = 6;//不复制crc位
- MODBUS_SLAVE_SendWithCRC(modbus_slave.tx_buf, modbus_slave.send_len);
- }
- else
- {
- MODBUS_SLAVE_SendAckErr(modbus_slave.RTU_response_code); /* 告诉主机命令错误 */
- }
- }
- #ifndef _MODBUS_SLAVE_H_
- #define _MODBUS_SLAVE_H_
- /************************************************************************/
- /* “文件包含”处理 */
- /************************************************************************/
- #include "data_types.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- /************************************************************************/
- /* 宏定义 */
- /************************************************************************/
- #define SADDR485 (1) // 从机地址
- #define RX_LEN_MAX (255) // 报文接收缓冲区大小
- #define TX_LEN_MAX (255) // 报文发送缓冲区大小
- /* 01H 读强制单线圈 */
- /* 05H 写强制单线圈 */
- #define REG_D01 0x1000
- #define REG_D02 0x1002
- #define REG_D03 0x1003
- #define REG_D04 0x1004
- #define REG_DXX REG_D04
- /* 02H 读取输入状态 */
- #define REG_T01 0x2001
- #define REG_T02 0x2002
- #define REG_T03 0x2003
- #define REG_TXX REG_T03
- /* 03H 读保持寄存器 */
- /* 06H 写保持寄存器 */
- /* 10H 写多个保存寄存器 */
- #define SLAVE_REG_P01 0x3001
- #define SLAVE_REG_P02 0x3002
- /* 04H 读取输入寄存器(模拟信号) */
- #define REG_A01 0x4001
- #define REG_AXX REG_A01
- /* RTU 应答代码 */
- #define RSP_OK (0) // 成功
- #define RSP_ERR_CMD (0x01) // 不支持的功能码
- #define RSP_ERR_REG_ADDR (0x02) // 寄存器地址错误
- #define RSP_ERR_VALUE (0x03) // 数据值域错误
- #define RSP_ERR_WRITE (0x04) // 写入失败
-
- /************************************************************************/
- /* 类型定义 */
- /************************************************************************/
- typedef struct
- {
- uBit8 rx_buf[RX_LEN_MAX]; // 报文接收处理缓冲区
- uBit8 tx_buf[TX_LEN_MAX]; // 报文发送处理缓冲区
- uBit16 curr_dma_cnt; // 表示当前DMA传输计数器中的值
- uBit16 last_dma_cnt; // 表示上次DMA传输计数器中的值
- uBit16 recv_len; // 接收的字节数
- uBit16 send_len; // 发送的字节数
- uBit8 RTU_response_code; // RTU应答码
- }Modbus_Slave_t;
- /************************************************************************/
- /* 全局变量声明 */
- /************************************************************************/
- extern Modbus_Slave_t modbus_slave;
- /************************************************************************/
- /* 函数声明 */
- /************************************************************************/
- void MODBUS_SLAVE_Pool(void);
- #ifdef __cplusplus
- }
- #endif
- #endif
七、效果展示(由于篇幅限制只展示部分功能码)
01功能码:
05功能码:
0F功能码: