这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
icore4t_45 [2020/09/26 19:46] zgf 创建 |
icore4t_45 [2022/04/01 10:54] (当前版本) sean |
||
---|---|---|---|
行 1: | 行 1: | ||
+ | | **银杏科技有限公司旗下技术文档发布平台** |||| | ||
+ | |技术支持电话|**0379-69926675-801**||| | ||
+ | |技术支持邮件|Gingko@vip.163.com||| | ||
+ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
+ | | V1.0 | 2020-9-26 | zgf | 初次建立 | | ||
+ | ===== 实验四十五:Modbus TCP通信实验——电源监控 ===== | ||
- | 实验四十五:Modbus TCP通信实验——电源监控 | + | ==== 一、 实验目的与意义 ==== |
- | 一、 实验目的与意义 | + | |
- | 1、 了解Modbus TCP通讯协议 | + | - 了解Modbus TCP通讯协议; |
- | 2、 了解Modbus TCP与TCP协议的关系 | + | - 了解Modbus TCP与TCP协议的关系; |
- | 3、 掌握Modbus Poll的使用方法 | + | - 掌握Modbus Poll的使用方法; |
- | 4、 掌握KEIL MDK 集成开发环境使用方法 | + | - 掌握KEIL MDK 集成开发环境使用方法。 |
- | 二、 实验设备及平台 | + | ==== 二、 实验设备及平台 ==== |
- | 1、 iCore4T 双核心板及底板 | + | |
- | 2、 JLINK(或相同功能)仿真器 | + | - iCore4T 双核心板及底板; |
- | 3、 以太网通讯线缆 | + | - JLINK(或相同功能)仿真器; |
- | 4、 Keil MDK 开发平台 | + | - 以太网通讯线缆; |
- | 5、 装有WIN XP(及更高版本)系统的计算机 | + | - Keil MDK 开发平台; |
- | 三、 实验原理 | + | - 装有WIN XP(及更高版本)系统的计算机。 |
- | 1. Modbus _TCP简介 | + | ==== 三、 实验原理 ==== |
- | Modbus通信协议由Modicon公司于1979年发明的,是全球最早用于工业现场的总线规约。它是一种主从通讯方式,采用服务器和客户机的模式记性通讯。Modbus通信协议具有多个变种,其具有支持串口(主要是RS-485总线),以太网多个版本,其中最著名的是Modbus RTU,Modbus ASCII和Modbus TCP三种。本实验主要针对Modbus TCP进行的一个数据通讯实验。 | + | |
- | Modbus TCP协议基于TCP协议实现,其数据帧包含于TCP数据之中,本文以数据读取及其应答为例对Modbus TCP进行读取。数据读取请求报文格式如表1所示。 | + | === 1.Modbus _TCP简介 === |
- | 表1 Modbus TCP数据读取请求报文 | + | |
- | 事务处理标识 协议标识 报文长度 设备标识 功能码 起始地址 寄存器数量 | + | * Modbus通信协议由Modicon公司于1979年发明的,是全球最早用于工业现场的总线规约。它是一种主从通讯方式,采用服务器和客户机的模式记性通讯。Modbus通信协议具有多个变种,其具有支持串口(主要是RS-485总线),以太网多个版本,其中最著名的是Modbus RTU,Modbus ASCII和Modbus TCP三种。本实验主要针对Modbus TCP进行的一个数据通讯实验。 |
- | 2byte 2byte 2byte 1byte 1byte 2 byte 2 byte | + | * Modbus TCP协议基于TCP协议实现,其数据帧包含于TCP数据之中,本文以数据读取及其应答为例对Modbus TCP进行读取。数据读取请求报文格式如表1所示。 |
- | 事务处理标识符:两个字节,一般每次通讯后将加1,从而区别不同的通讯数据报文。 | + | * 表1 Modbus TCP数据读取请求报文 |
- | 协议标识符:两个字节,Modbus TCP标识符为0x0000。 | + | |
- | 数据长度:两个字节,标识后面的数据量的大小,数据长度以字节为单位。 | + | |事务处理标识 |协议标识 |报文长度 |设备标识 |功能码 |起始地址 |寄存器数量| |
- | 设备标识:用以标识连接在串行线或者网络上的远程服务端的地址。 | + | |2byte |2byte |2byte |1byte |1byte |2 byte |2 byte| |
- | 功能码:一般为读取的寄存器的类型。 | + | |
- | 起始地址:寄存器的起始地址。 | + | * 事务处理标识符:两个字节,一般每次通讯后将加1,从而区别不同的通讯数据报文。 |
- | 寄存器数量:要读取寄存器的数量。 | + | * 协议标识符:两个字节,Modbus TCP标识符为0x0000。 |
- | 数据读取应答报文格式如表2所示。 | + | * 数据长度:两个字节,标识后面的数据量的大小,数据长度以字节为单位。 |
- | 表2 Modbus TCP数据读取应答报文 | + | * 设备标识:用以标识连接在串行线或者网络上的远程服务端的地址。 |
- | 事务处理标识 协议标识 报文长度 设备标识 功能码 数据长度 数据 | + | * 功能码:一般为读取的寄存器的类型。 |
- | 2byte 2byte 2byte 1byte 1byte 1byte n byte | + | * 起始地址:寄存器的起始地址。 |
- | 事务处理标识符:两个字节,与请求标识一致。 | + | * 寄存器数量:要读取寄存器的数量。 |
- | 协议标识符:两个字节,与请求标识一致。 | + | |
- | 数据长度:两个字节,指示后面的数据量的大小,数据长度以字节为单位。 | + | * 数据读取应答报文格式如表2所示。 |
- | 设备标识:用以标识连接在串行线或者网络上的远程服务端的地址。 | + | * 表2 Modbus TCP数据读取应答报文 |
- | 功能码:一般为读取的寄存器的地址,与请求标识一致。 | + | |
- | 数据长度:传输的数据长度。 | + | |事务处理标识 |协议标识 |报文长度 |设备标识 |功能码 |数据长度 |数据| |
- | 数据:寄存器的数据。 | + | |2byte |2byte |2byte |1byte |1byte |1byte |n byte| |
- | 四、 实验程序 | + | |
- | 本实验主要基于TCP通讯和ADC电源监控两部分实现,本文对这两个方面不做过多描述。 | + | * 事务处理标识符:两个字节,与请求标识一致。 |
- | 1. 主函数 | + | * 协议标识符:两个字节,与请求标识一致。 |
- | + | * 数据长度:两个字节,指示后面的数据量的大小,数据长度以字节为单位。 | |
+ | * 设备标识:用以标识连接在串行线或者网络上的远程服务端的地址。 | ||
+ | * 功能码:一般为读取的寄存器的地址,与请求标识一致。 | ||
+ | * 数据长度:传输的数据长度。 | ||
+ | * 数据:寄存器的数据。 | ||
+ | ==== 四、 实验程序 ==== | ||
+ | |||
+ | * 本实验主要基于TCP通讯和ADC电源监控两部分实现,本文对这两个方面不做过多描述。 | ||
+ | 1.主函数 | ||
+ | <code c> | ||
+ | int main(void) | ||
+ | { | ||
+ | /* USER CODE BEGIN 1 */ | ||
+ | int cnt; | ||
+ | short data; | ||
+ | /* USER CODE END 1 */ | ||
+ | /*MCU Configuration------------------------------------*/ | ||
+ | HAL_Init(); | ||
+ | /* USER CODE BEGIN Init */ | ||
+ | |||
+ | /* USER CODE END Init */ | ||
+ | /* Configure the system clock */ | ||
+ | SystemClock_Config(); | ||
+ | /* USER CODE BEGIN SysInit */ | ||
+ | i2c.initialize(); | ||
+ | axp152.initialize(); | ||
+ | axp152.set_dcdc1(3500);//[ARM & FPGA BK1/2/6 &OTHER] | ||
+ | axp152.set_dcdc2(1200);//[FPGA INT & PLL D] | ||
+ | axp152.set_aldo1(2500);//[FPGA PLL A] | ||
+ | axp152.set_dcdc4(3300);//[POWER_OUTPUT] | ||
+ | axp152.set_dcdc3(3300);//[FPGA BK4][Adjustable] | ||
+ | axp152.set_aldo2(3300);//[FPGA BK3][Adjustable] | ||
+ | axp152.set_dldo1(3300);//[FPGA BK7][Adjustable] | ||
+ | axp152.set_dldo2(3300);//[FPGA BK5][Adjustable] | ||
+ | /* USER CODE END SysInit */ | ||
+ | |||
+ | /* Initialize all configured peripherals */ | ||
+ | MX_GPIO_Init(); | ||
+ | MX_ADC1_Init(); | ||
+ | MX_ADC3_Init(); | ||
+ | MX_ETH_Init(); | ||
+ | |||
+ | /* USER CODE BEGIN 2 */ | ||
+ | //LWIP初始化 | ||
+ | NETMPU_Config(); | ||
+ | lwip.initialize(); | ||
+ | eth_tcps.initialize(); | ||
+ | /* USER CODE END 2 */ | ||
+ | |||
+ | /* Infinite loop */ | ||
+ | /* USER CODE BEGIN WHILE */ | ||
+ | while (1) | ||
+ | { | ||
+ | /* USER CODE END WHILE */ | ||
+ | |||
+ | /* USER CODE BEGIN 3 */ | ||
+ | if((cnt ++ / 800000) % 2){ | ||
+ | LED_RED_ON; | ||
+ | }else{ | ||
+ | LED_RED_OFF; | ||
+ | } | ||
+ | lwip.periodic_handle(); | ||
+ | //根据定时器计数标志,每隔一秒,读取一次ADC的值 | ||
+ | if(adc_read_flag ==1) | ||
+ | { | ||
+ | adc_read_flag = 0; | ||
+ | my_adc.read(0); | ||
+ | my_adc.read_mux(); | ||
+ | } | ||
+ | |||
+ | //将ADC采集的计算值,放大1000倍便于观察数据的正确性。计算公式请参考adc部分例程。 | ||
+ | data = my_adc.value[0]*6000; | ||
+ | hold_reg[0] = data >> 8; | ||
+ | hold_reg[1] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[1] * 2000; | ||
+ | hold_reg[2] = data >> 8; | ||
+ | hold_reg[3] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[2]*2000; | ||
+ | hold_reg[4] = data >> 8; | ||
+ | hold_reg[5] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[3]*2000; | ||
+ | hold_reg[6] = data >> 8; | ||
+ | hold_reg[7] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[4]*2000; | ||
+ | hold_reg[8] = data >> 8; | ||
+ | hold_reg[9] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[5]*500;·· | ||
+ | hold_reg[10] = data >> 8; | ||
+ | hold_reg[11] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[6]*1000; | ||
+ | hold_reg[12] = data >> 8; | ||
+ | hold_reg[13] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[7]*2000; | ||
+ | hold_reg[14] = data >> 8; | ||
+ | hold_reg[15] = data & 0xff; | ||
+ | |||
+ | data = my_adc.value[8]*2000; | ||
+ | hold_reg[16] = data >> 8; | ||
+ | hold_reg[17] = data & 0xff; | ||
+ | |||
+ | if(eth_tcps.receive_ok_flag == 1){ | ||
+ | eth_tcps.receive_ok_flag = 0; | ||
+ | modbus_tcp.process(eth_tcps.receive_buffer); | ||
+ | } | ||
+ | } | ||
+ | /* USER CODE END 3 */ | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | 2.TCP数据发送函数 | ||
+ | * 基于TCP中的服务器代码数据发送函数进行函数封装,设计一个发送指定数量数据的函数。 | ||
+ | <code c> | ||
+ | int send(struct tcp_pcb *tpcb,unsigned char *data,int len) | ||
+ | { | ||
+ | int ret_err; | ||
+ | struct tcp_server_struct *es; | ||
+ | memcpy(eth_tcps.send_buffer,data,len); | ||
+ | es = tpcb->callback_arg; | ||
+ | if(es != NULL){ //连接处于空闲可以发送数据 | ||
+ | es->p = pbuf_alloc(PBUF_TRANSPORT,len,PBUF_POOL);//申请内存 | ||
+ | pbuf_take(es->p,(char*)eth_tcps.send_buffer,len);//将eth_tcps.send_buffer[]中的数据拷贝到es->p_tx中 | ||
+ | tcp_server_senddata(tpcb,es); //将eth_tcps.send_buffer[]里面复制给pbuf的数据发送出去 | ||
+ | if(es->p)pbuf_free(es->p); //释放内存 | ||
+ | ret_err=ERR_OK; | ||
+ | }else{ | ||
+ | tcp_abort(tpcb); //终止连接,删除pcb控制块 | ||
+ | ret_err=ERR_ABRT; | ||
+ | } | ||
+ | return ret_err; | ||
+ | } | ||
+ | |||
+ | </code> | ||
- | 2. TCP数据发送函数 | + | 3.Modbus TCP协议处理 |
- | 基于TCP中的服务器代码数据发送函数进行函数封装,设计一个发送指定数量数据的函数。 | + | * Modbus TCP的协议处理由多个子函数组成,函数代码如下。 |
- | + | <code c> | |
- | + | int err; | |
- | 3. Modbus TCP协议处理 | + | char discrete_input[32] = {0x55,0x55,0x55}; |
- | Modbus TCP的协议处理由多个子函数组成,函数代码如下。 | + | char coil[32] = {0x55,0x55,0x55}; |
- | + | char input_reg[20] = {0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10}; | |
- | + | char hold_reg[512] = {0x01,0x02,0x03}; | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | 五、 实验步骤 | + | |
- | 1、 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); | + | |
- | 2、 把iCore4T通过以太网线与计算机相连,为iCore4T供电; | + | |
- | 3、 设置电脑IP地址(见附录1); | + | |
- | 4、 打开Keil MDK 开发环境,并打开本实验工程; | + | |
- | 5、 烧写程序到iCore4T上; | + | |
- | 6、 打开Modbus Poll软件建立连接(见附录2),读取hold寄存器中的数据值,观察核心板返回的数据值。 | + | |
- | 六、 实验现象 | + | |
- | Modbus Poll软件可看到核心板电源数据的检测值。 | + | |
- | + | ||
+ | //--------------------------- Function --------------------------// | ||
+ | static int process(unsigned char *modbus_recvbuf) | ||
+ | { | ||
+ | unsigned char receive_buffer_temp[100]; | ||
+ | memcpy(receive_buffer_temp,modbus_recvbuf,12); | ||
+ | memset(modbus_recvbuf,0,12); | ||
+ | mb_rsq_pdu(receive_buffer_temp,12); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | static int mb_rsq_pdu(unsigned char *receive_buffer_temp,int counter_temp) | ||
+ | { | ||
+ | if(receive_buffer_temp[0 + 6] == 0x01){ | ||
+ | switch(receive_buffer_temp[1 + 6]){ | ||
+ | case 1: | ||
+ | function_1(receive_buffer_temp); | ||
+ | break; | ||
+ | case 2: | ||
+ | function_2(receive_buffer_temp); | ||
+ | break; | ||
+ | case 3: | ||
+ | function_3(receive_buffer_temp); | ||
+ | break; | ||
+ | case 4: | ||
+ | function_4(receive_buffer_temp); | ||
+ | break; | ||
+ | case 5: | ||
+ | function_5(receive_buffer_temp,counter_temp); | ||
+ | break; | ||
+ | case 6: | ||
+ | function_6(receive_buffer_temp,counter_temp); | ||
+ | break; | ||
+ | default : | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,1); | ||
+ | break; | ||
+ | } | ||
+ | }else if(receive_buffer_temp[0 + 6] == 0){ | ||
+ | broadcast(receive_buffer_temp); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | static int function_1(unsigned char *receive_buffer_temp) | ||
+ | { | ||
+ | int i; | ||
+ | unsigned short cnt; | ||
+ | unsigned short coil_num; | ||
+ | unsigned short start_address; | ||
+ | int temp = 0; | ||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
+ | coil_num = receive_buffer_temp[4 + 6] << 8| receive_buffer_temp[5 + 6]; | ||
+ | if((start_address + coil_num) > 255){ | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,2); | ||
+ | return 1; | ||
+ | } | ||
+ | receive_buffer_temp[2 + 6] = ((coil_num % 8 )? (coil_num / 8 + 1) : (coil_num / 8)); | ||
+ | cnt = receive_buffer_temp[2 + 6] + 5 - 2; | ||
+ | if(coil_num % 8){ | ||
+ | if(coil_num < 8){ | ||
+ | for(i = 0;i < coil_num;i ++)temp |= 1 << i; | ||
+ | receive_buffer_temp[3 + 6] = ((coil[start_address / 8]) >> (start_address % 8) | (coil[start_address / 8 + 1]) << (8 - (start_address % | ||
+ | 8))) & temp; | ||
+ | }else { | ||
+ | for(i = 0;i < receive_buffer_temp[2 + 6] - 1;i++)receive_buffer_temp[3 + i + 6] = (coil[i + start_address / 8]) >> (start_address % 8) | (coil[i + start_address / 8 + 1]) << (8 - (start_address % 8)); | ||
+ | receive_buffer_temp[3 + i + 6] = (coil[i + start_address / 8] << ((8 - (coil_num % 8 - start_address % 8) % 8)) & 0xff) >> (8 - (coil_num % 8)); | ||
+ | } | ||
+ | }else { | ||
+ | for(i = 0;i < receive_buffer_temp[2 + 6];i++)receive_buffer_temp[3 + i + 6] = (coil[i + start_address / 8]) >> (start_address % 8) | (coil[i + start_address / 8 + 1]) << (8 - (start_address % 8)); | ||
+ | } | ||
+ | receive_buffer_temp[4] = (cnt & 0xff00) >> 8; | ||
+ | receive_buffer_temp[5] = (cnt & 0x00ff); | ||
+ | cnt = cnt + 6; | ||
+ | eth_tcps.send(eth_tcps.tcppcbnew,receive_buffer_temp,cnt); | ||
+ | return 0; | ||
+ | } | ||
+ | static int function_2(unsigned char *receive_buffer_temp) | ||
+ | { | ||
+ | int i; | ||
+ | unsigned short cnt; | ||
+ | unsigned short discrete_num; | ||
+ | unsigned short start_address; | ||
+ | int temp = 0; | ||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
- | + | discrete_num = receive_buffer_temp[4 + 6] << 8| receive_buffer_temp[5 + 6]; | |
- | 附录1:电脑IP设置 | + | |
- | 打开控制面板->网络和 Internet->网络连接,选择对应的网卡,右键点击属性,设置IPV4的IP地址,如图所示、 | + | if((start_address + discrete_num) > 255){ |
- | + | mb_excep_rsq_pdu(receive_buffer_temp,2); | |
- | + | return 1; | |
- | + | } | |
- | 附录2:Modbus Poll软件建立连接 | + | receive_buffer_temp[2 + 6] = ((discrete_num % 8 )? (discrete_num / 8 + 1) : (discrete_num / 8)); |
- | 打开Modbus Poll,点击Connet,设置协议类型、IP地址和端口号,点击OK开始进行连接。 | + | cnt = receive_buffer_temp[2 + 6] + 5 - 2; |
- | + | if(discrete_num % 8){ | |
+ | if(discrete_num < 8){ | ||
+ | for(i = 0;i < discrete_num;i ++)temp |= 1 << i; | ||
+ | receive_buffer_temp[3 + 6] = ((discrete_input[start_address / 8]) >> (start_address % 8) | (discrete_input[start_address / 8 + 1]) << (8 - (start_address % 8))) & temp; | ||
+ | }else { | ||
+ | for(i = 0;i < receive_buffer_temp[2 + 6] - 1;i++)receive_buffer_temp[3 + i + 6] = (discrete_input[i + start_address / 8]) >> (start_address % 8) | (discrete_input[i + start_address / 8 + 1]) << (8 - (start_address % 8)); | ||
+ | receive_buffer_temp[3 + i + 6] = (discrete_input[i + start_address / 8] << ((8 - (discrete_num % 8 - start_address % 8) % 8)) & 0xff) >> (8 - (discrete_num % 8)); | ||
+ | } | ||
+ | }else { | ||
+ | for(i = 0;i < receive_buffer_temp[2 + 6];i++)receive_buffer_temp[3 + i + 6] = (discrete_input[i + start_address / 8]) >> (start_address % 8) | (discrete_input[i + start_address / 8 + 1]) << (8 - (start_address % 8)); | ||
+ | } | ||
+ | |||
+ | receive_buffer_temp[4] = (cnt & 0xff00) >> 8; | ||
+ | receive_buffer_temp[5] = (cnt & 0x00ff); | ||
+ | cnt = cnt + 6; | ||
+ | |||
+ | eth_tcps.send(eth_tcps.tcppcbnew,receive_buffer_temp,cnt); | ||
+ | return 0; | ||
+ | } | ||
+ | static int function_3(unsigned char *receive_buffer_temp) | ||
+ | { | ||
+ | int i; | ||
+ | int cnt = 0; | ||
+ | unsigned short int start_address; | ||
+ | |||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
+ | |||
+ | receive_buffer_temp[2 + 6] = receive_buffer_temp[5 + 6] * 2; | ||
+ | |||
+ | if(receive_buffer_temp[2 + 6] > 48){ | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,2); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | if((start_address * 2 + receive_buffer_temp[2]) > 512){ | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,2); | ||
+ | return 1; | ||
+ | } | ||
+ | cnt = receive_buffer_temp[2 + 6] + 5 - 2; | ||
+ | for(i = 0;i < receive_buffer_temp[2 + 6];i++){ | ||
+ | receive_buffer_temp[i + 3 + 6] = hold_reg[start_address * 2 + i]; | ||
+ | } | ||
+ | |||
+ | receive_buffer_temp[4] = (cnt & 0xff00) >> 8; | ||
+ | receive_buffer_temp[5] = (cnt & 0x00ff); | ||
+ | cnt = cnt + 6; | ||
+ | |||
+ | eth_tcps.send(eth_tcps.tcppcbnew,receive_buffer_temp,cnt); | ||
+ | return 0; | ||
+ | } | ||
+ | static int function_4(unsigned char *receive_buffer_temp) | ||
+ | { | ||
+ | int i; | ||
+ | int cnt; | ||
+ | unsigned short int start_address; | ||
+ | |||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
+ | |||
+ | receive_buffer_temp[2 + 6] = receive_buffer_temp[5 + 6] * 2; | ||
+ | |||
+ | if((start_address * 2 + receive_buffer_temp[2 + 6]) > 20){ | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,2); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | cnt = receive_buffer_temp[2 + 6] + 5 - 2; | ||
+ | for(i = 0;i < receive_buffer_temp[2 + 6];i++)receive_buffer_temp[i + 3 + 6] = input_reg[start_address * 2 + i]; | ||
+ | |||
+ | receive_buffer_temp[4] = (cnt & 0xff00) >> 8; | ||
+ | receive_buffer_temp[5] = (cnt & 0x00ff); | ||
+ | cnt = cnt + 6; | ||
+ | |||
+ | eth_tcps.send(eth_tcps.tcppcbnew,receive_buffer_temp,cnt); | ||
+ | return 0; | ||
+ | } | ||
+ | static int function_5(unsigned char *receive_buffer_temp,int counter_temp) | ||
+ | { | ||
+ | unsigned short start_address; | ||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
+ | |||
+ | if(start_address > 255){ | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,2); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | if((receive_buffer_temp[4 + 6] == 0xff) && (receive_buffer_temp[5 + 6] == 0x00)){ | ||
+ | coil[(start_address / 8)] |= 1 << start_address % 8; | ||
+ | }else if((receive_buffer_temp[4 + 6] == 0x00) && (receive_buffer_temp[5 + 6] == 0x00)){ | ||
+ | coil[(start_address / 8)] &= ~(1 << start_address % 8); | ||
+ | }else { | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,3); | ||
+ | } | ||
+ | |||
+ | receive_buffer_temp[4] = (6 & 0xff00) >> 8; | ||
+ | receive_buffer_temp[5] = (6 & 0x00ff); | ||
+ | |||
+ | eth_tcps.send(eth_tcps.tcppcbnew,receive_buffer_temp,counter_temp); | ||
+ | return 0; | ||
+ | } | ||
+ | static int function_6(unsigned char *receive_buffer_temp,int counter_temp) | ||
+ | { | ||
+ | unsigned short start_address; | ||
+ | |||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
+ | |||
+ | if(start_address > 255){ | ||
+ | mb_excep_rsq_pdu(receive_buffer_temp,2); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | hold_reg[start_address * 2] = receive_buffer_temp[4 + 6]; | ||
+ | hold_reg[start_address * 2 + 1] = receive_buffer_temp[5 + 6]; | ||
+ | |||
+ | receive_buffer_temp[4] = (6 & 0xff00) >> 8; | ||
+ | receive_buffer_temp[5] = (6 & 0x00ff); | ||
+ | eth_tcps.send(eth_tcps.tcppcbnew,receive_buffer_temp,counter_temp); | ||
+ | return 0; | ||
+ | } | ||
+ | static int mb_excep_rsq_pdu(unsigned char *receive_buffer_temp,int error_code) | ||
+ | { | ||
+ | receive_buffer_temp[1 + 6] |= 0x80; | ||
+ | switch(error_code) { | ||
+ | case 1: | ||
+ | receive_buffer_temp[2 + 6] = 1; | ||
+ | break; | ||
+ | case 2: | ||
+ | receive_buffer_temp[2 + 6] = 2; | ||
+ | break; | ||
+ | case 3: | ||
+ | receive_buffer_temp[2 + 6] = 3; | ||
+ | break; | ||
+ | case 4: | ||
+ | receive_buffer_temp[2 + 6] = 4; | ||
+ | break; | ||
+ | default : | ||
+ | break; | ||
+ | } | ||
+ | receive_buffer_temp[4] = (3 & 0xff00) >> 8; | ||
+ | receive_buffer_temp[5] = (3 & 0x00ff); | ||
+ | |||
+ | eth_tcps.send(eth_tcps.tcppcbnew,receive_buffer_temp,9); | ||
+ | return 0; | ||
+ | } | ||
+ | static int broadcast(unsigned char *receive_buffer_temp) | ||
+ | { | ||
+ | int start_address; | ||
+ | switch(receive_buffer_temp[1 + 6]){ | ||
+ | case 5: | ||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
+ | if(start_address > 255){ | ||
+ | return 1; | ||
+ | } | ||
+ | if((receive_buffer_temp[4 + 6] == 0xff) && (receive_buffer_temp[5 + 6] == 0x00)){ | ||
+ | coil[(start_address / 8)] |= 1 << start_address % 8; | ||
+ | }else if((receive_buffer_temp[4 + 6] == 0x00) && | ||
+ | (receive_buffer_temp[5 + 6] == 0x00)){ | ||
+ | coil[(start_address / 8)] &= ~(1 << start_address % 8); | ||
+ | } | ||
+ | break; | ||
+ | case 6: | ||
+ | start_address = (receive_buffer_temp[2 + 6] << 8) | receive_buffer_temp[3 + 6]; | ||
+ | if(start_address > 255){ | ||
+ | return 1; | ||
+ | } | ||
+ | hold_reg[start_address * 2] = receive_buffer_temp[4 + 6]; | ||
+ | hold_reg[start_address * 2 + 1] = receive_buffer_temp[5 + 6]; | ||
+ | break; | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | ==== 五、 实验步骤 ==== | ||
+ | |||
+ | - 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); | ||
+ | - 把iCore4T通过以太网线与计算机相连,为iCore4T供电; | ||
+ | - 设置电脑IP地址(见附录1); | ||
+ | - 打开Keil MDK 开发环境,并打开本实验工程; | ||
+ | - 烧写程序到iCore4T上; | ||
+ | - 打开Modbus Poll软件建立连接(见附录2),读取hold寄存器中的数据值,观察核心板返回的数据值。 | ||
+ | ==== 六、 实验现象 ==== | ||
+ | |||
+ | * Modbus Poll软件可看到核心板电源数据的检测值。 | ||
+ | {{ :icore4t:icore4t_arm_hal_45_1.png?direct |}} | ||
+ | ==== 附录1:电脑IP设置 ==== | ||
+ | |||
+ | * 打开控制面板->网络和 Internet->网络连接,选择对应的网卡,右键点击属性,设置IPV4的IP地址,如图所示: | ||
+ | {{ :icore4t:icore4t_arm_hal_45_2.png?direct |}} | ||
+ | {{ :icore4t:icore4t_arm_hal_45_3.png?direct |}} | ||
+ | ==== 附录2:Modbus Poll软件建立连接 ==== | ||
+ | |||
+ | * 打开Modbus Poll,点击Connet,设置协议类型、IP地址和端口号,点击OK开始进行连接。 | ||
+ | {{ :icore4t:icore4t_arm_hal_45_4.png?direct |}} | ||
+ | {{ :icore4t:icore4t_arm_hal_45_5.png?direct |}} |