当前位置: 首页 > news >正文

上海网站制作网站制作公司海南网站运营公司

上海网站制作网站制作公司,海南网站运营公司,设计新颖的兰州h5制作,网站建设需要注册42类吗———————————————————————————————————— ⏩ 大家好哇#xff01;我是小光#xff0c;嵌入式爱好者#xff0c;一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子#xff0c;使用STM32CUBEMX做了很多驱动#x…———————————————————————————————————— ⏩ 大家好哇我是小光嵌入式爱好者一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子使用STM32CUBEMX做了很多驱动包括ADC、UART、RS485、EEPROM(IIC)、FLASH(SPI)、modbus等等。 ⏩本篇文章对STM32CUBEMX在RS485通信的基础上做modbus通信做一个详细的使用教程。 ⏩感谢你的阅读不对的地方欢迎指正。 ———————————————————————————————————— modbuspoll 工具下载modbus协议简介Modbus协议类型Modbus-Rtu协议Modbus功能码 STM32CUBEMX配置RS485配置定时器配置 驱动代码测试结果XCOM串口调试助手作为主机测试modbus poll作为主机测试 总结 工具下载 Modbus Poll是一个模拟Modbus协议主机的上位机软件主要用于模拟测试跟其他从机设备通信的过程。与之成套存在的另一个软件–Modbus Slave则是模拟Modbus协议从机的上位机软件。该软件内部封装标准Modbus协议栈通过图形化界面使得操作更为简便。目前软件支持01、02、03、04、05、06、15、16功能码异常报文检测原始报文查看数据记录等功能是调试Modbus协议栈的好帮手。 下载链接: 链接百度网盘下载链接modbus poll 7.0.1 提取码lft0 modbus协议简介 参考 值得收藏 Modbus RTU 协议详解 详解Modbus通信协议—清晰易懂 Modbus协议类型 串行端口存在多个版本的Modbus协议而最常见的是下面四种 Modbus-Rtu 远程终端控制系统 CRC16校验Modbus-Ascii Ascii码表示数据 LRC校验Modbus-Tcp TCP三种报文类型 无校验ModbusPlus 我们这里使用Modbus-Rtu进行编写代码和测试。 Modbus-Rtu协议 Modbus功能码 Modbus规定了多个功能那么为了方便的使用这些功能我们给每个功能都设定一个功能码也就是指代码。 既然搞清楚了原理那么后面我们开始程序讲解 STM32CUBEMX配置 RS485配置 参考我之前的文章 STM32CUBUMX配置RS485(中断接收)–保姆级教程 一定要根据这个文章把RS485调通 定时器配置 首先我们要知道modbus通信的一帧数据是通过每一帧数据之间的间隔时间来确认的。 当bps19200时超时时间是大于3.5个字节时间。当bps19200时超时时间是大于1750us 例如 bps 9600 传输一个字节的时间是1/9600*10 10.4ms3.5个字节时间就是3.5ms bps 115200超时时间就是17500 定时器定时时间计算可以参考我之前的文章 STM32CUBEMX配置 定时器中断 下面进行定时器配置 我们配置的PSC 27500-1 ARR 50-1 TIM3的时钟是275Mhz 所以定时时间 T 27500 * 50/275 * 10^6 0.00005s 50us 定时器计数35次也就是1800 刚好大于1750us 符合modbus协议 开启定时器中断优先级需要比串口中断更低 驱动代码 modbus.h #ifndef MODBUS_H_ #define MODBUS_H_#include stm32H7xx_hal.h //HAL库文件声明 #include gpio.h #include usart.h#define BUFFER_SIZE 600 //最大数据帧typedef struct {uint8_t myadd;//从机设备地址uint8_t timrun;//定时器uint8_t slave_add;//主机要匹配的从机地址本设备作为主机时uint8_t reflag;//接收完成标志位1完成 0未完成uint8_t Host_time_flag;//发送数据标志uint8_t recount;//接收到的字节数unsigned char rcbuf[BUFFER_SIZE];//接受数据帧unsigned char sendbuf[BUFFER_SIZE];//发送数据帧uint32_t timout;//超时时间 单位msuint32_t Host_Sendtime;//发送完上一帧后的时间计数 单位ms}MODBUS;// Modbus初始化函数 void Modbus_Init(void); void Modbus_Event(void); void Modbus_Func3(void); void Modbus_Func6(void); void Modbus_Func16(void);void Modbus_Send_Byte( uint8_t ch );int Modbus_CRC16(uint8_t buff[],int len); #endifmodbus.c #include modbus.h MODBUS modbus; uint16_t Reg[] {0x0001,0x0012,0x0013,0x0004,0x0025,0x0036,0x0007,0X0008,};//reg是提前定义好的寄存器和寄存器数据要读取和改写的部分内容// Modbus初始化函数void Modbus_Init(void){modbus.myadd 0x01; //从机设备地址为2modbus.timrun 0; //modbus定时器停止计算modbus.slave_add0x02;//主机要匹配的从机地址本设备作为主机时modbus.reflag 0;//无数据包处理modbus.Host_time_flag 0;//发送数据标志modbus.recount 0;//接收到的字节数modbus.timout 0;//超时时间 单位msmodbus.Host_Sendtime 0;//发送完上一帧后的时间计数 单位ms}// Modbus事件处理函数void Modbus_Event(void){uint16_t crc,rccrc;//crc和接收到的crc//没有收到数据包if(modbus.reflag 0) //如果接收未完成则返回空{return;}//收到数据包(接收完成)//通过读到的数据帧计算CRC//参数1是数组首地址参数2是要计算的长度除了CRC校验位其余全算crc Modbus_CRC16(modbus.rcbuf[0],modbus.recount-2); //获取CRC校验位// 读取数据帧的CRCrccrc modbus.rcbuf[modbus.recount-2]*256modbus.rcbuf[modbus.recount-1];//计算读取的CRC校验位//等价于下面这条语句//rccrcmodbus.rcbuf[modbus.recount-1]|(((uint16_t)modbus.rcbuf[modbus.recount-2])8);//获取接收到的CRCif(crc rccrc) //CRC检验成功 开始分析包{ if(modbus.rcbuf[0] modbus.myadd) // 检查地址是否时自己的地址{switch(modbus.rcbuf[1]) //分析modbus功能码{case 0: break;case 1: break;case 2: break;case 3: Modbus_Func3();break;//这是读取寄存器的数据case 4: break;case 5: break;case 6: Modbus_Func6(); break;//这是写入单个寄存器数据case 7: break;case 8: break;case 9: break;case 16: Modbus_Func16(); break;//写入多个寄存器数据}}else if(modbus.rcbuf[0] 0) //广播地址不予回应{} } modbus.recount 0;//接收计数清零modbus.reflag 0; //接收标志清零}/*********************************************************************************主机0301 03 00 01 00 01 D5 CA 从地址01开始读读取一个寄存器的数据内容ID 功能码 起始地址 读取寄存器的个数从机返回01 03 02 00 03 F8 45 返回了两个字节的数据数据是00 03ID 功能码 几个字节 返回的数据内容*********************************************************************************/// Modbus 3号功能码函数// Modbus 主机读取寄存器值void Modbus_Func3(void){uint16_t Regadd,Reglen,crc;uint8_t i,j; //得到要读取寄存器的首地址Regadd modbus.rcbuf[2]*256modbus.rcbuf[3];//读取的首地址//得到要读取寄存器的数据长度Reglen modbus.rcbuf[4]*256modbus.rcbuf[5];//读取的寄存器个数//发送回应数据包i 0;modbus.sendbuf[i] modbus.myadd; //ID号发送本机设备地址modbus.sendbuf[i] 0x03; //发送功能码modbus.sendbuf[i] ((Reglen*2)%256); //返回字节个数for(j0;jReglen;j) //返回数据{//reg是提前定义好的16位数组模仿寄存器modbus.sendbuf[i] Reg[Regaddj]/256;//高位数据modbus.sendbuf[i] Reg[Regaddj]%256;//低位数据}crc Modbus_CRC16(modbus.sendbuf,i); //计算要返回数据的CRCmodbus.sendbuf[i] crc/256;//校验位高位modbus.sendbuf[i] crc%256;//校验位低位//数据包打包完成// 开始返回Modbus数据RS485DIR_TX;//这是开启485发送for(j0;ji;j)//发送数据{Modbus_Send_Byte(modbus.sendbuf[j]); }RS485DIR_RX;//这里是关闭485发送}// Modbus 6号功能码函数// Modbus 主机写入寄存器值void Modbus_Func6() {uint16_t Regadd;//地址16位uint16_t val;//值uint16_t i,crc,j;i0;Regaddmodbus.rcbuf[2]*256modbus.rcbuf[3]; //得到要修改的地址 valmodbus.rcbuf[4]*256modbus.rcbuf[5]; //修改后的值要写入的数据Reg[Regadd]val; //修改本设备相应的寄存器//以下为回应主机modbus.sendbuf[i]modbus.myadd;//本设备地址modbus.sendbuf[i]0x06; //功能码 modbus.sendbuf[i]Regadd/256;//写入的地址modbus.sendbuf[i]Regadd%256;modbus.sendbuf[i]val/256;//写入的数值modbus.sendbuf[i]val%256;crcModbus_CRC16(modbus.sendbuf,i);//获取crc校验位modbus.sendbuf[i]crc/256; //crc校验位加入包中modbus.sendbuf[i]crc%256;//数据发送包打包完毕RS485DIR_TX;;//使能485控制端(启动发送) for(j0;ji;j){Modbus_Send_Byte(modbus.sendbuf[j]);}RS485DIR_RX;//失能485控制端改为接收}//这是往多个寄存器器中写入数据//功能码0x10指令即十进制16void Modbus_Func16(){uint16_t Regadd;//地址16位uint16_t Reglen;uint16_t i,crc,j;Regaddmodbus.rcbuf[2]*256modbus.rcbuf[3]; //要修改内容的起始地址Reglen modbus.rcbuf[4]*256modbus.rcbuf[5];//读取的寄存器个数for(i0;iReglen;i)//往寄存器中写入数据{//接收数组的第七位开始是数据Reg[Regaddi]modbus.rcbuf[7i*2]*256modbus.rcbuf[8i*2];//对寄存器一次写入数据}//写入数据完毕接下来需要进行打包回复数据了//以下为回应主机内容//内容接收数组的前6位两位的校验位modbus.sendbuf[0]modbus.rcbuf[0];//本设备地址modbus.sendbuf[1]modbus.rcbuf[1]; //功能码 modbus.sendbuf[2]modbus.rcbuf[2];//写入的地址modbus.sendbuf[3]modbus.rcbuf[3];modbus.sendbuf[4]modbus.rcbuf[4];modbus.sendbuf[5]modbus.rcbuf[5];crcModbus_CRC16(modbus.sendbuf,6);//获取crc校验位modbus.sendbuf[6]crc/256; //crc校验位加入包中modbus.sendbuf[7]crc%256;//数据发送包打包完毕RS485DIR_TX;;//使能485控制端(启动发送) for(j0;j8;j){Modbus_Send_Byte(modbus.sendbuf[j]);}RS485DIR_RX;//失能485控制端改为接收}void Modbus_Send_Byte( uint8_t ch ){/* 发送一个字节数据到USART2 */HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xff); //while(__HAL_UART_GET_FLAG(huart1,UART_FLAG_TC)!SET); //等待发送结束}int Modbus_CRC16(uint8_t buff[],int len) {unsigned short tmp 0xffff;unsigned short ret1 0;for(int n 0; n len; n) //此处的6 -- 要校验的位数为6个{tmp buff[n] ^ tmp;for(int i 0;i 8;i) //此处的8 -- 指每一个char类型又8bit每bit都要处理{if(tmp 0x01){tmp tmp 1;tmp tmp ^ 0xA001;}else{tmp tmp 1;}}}ret1 tmp 8; //将CRC校验的高低位对换位置ret1 ret1 | (tmp 8);return ret1; }目前只写了03读寄存器、06写一个寄存器、16写多个寄存器三个功能 stm32_h7xx_it.c extern MODBUS modbus;void USART1_IRQHandler(void) {/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(huart1);/* USER CODE BEGIN USART1_IRQn 1 */if( modbus.reflag1) //有数据包正在处理{return ;} modbus.rcbuf[modbus.recount] USART1_aRxBuffer[0];modbus.timout 0;if(modbus.recount 1) //已经收到了第二个字符数据{modbus.timrun 1; //开启modbus定时器计时}HAL_UART_Receive_IT(huart1, (uint8_t *)USART1_aRxBuffer,1); //添加的一行代码/* USER CODE END USART1_IRQn 1 *//* USER CODE END USART1_IRQn 1 */ }/******************************************************************************* 函数名 HAL_TIM_PeriodElapsedCallback* 功 能 定时器超时中断回调函数* 参 数 htim 定时器名 * 返回值 无******************************************************************************/ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if (htim-Instance TIM3) {if(modbus.timrun ! 0)//运行时间0表明{modbus.timout;if(modbus.timout 35)//大于1750us{modbus.timrun 0;modbus.reflag 1;//接收数据完毕modbus.timout 0;USART1_RX_STA|0x8000;}}modbus.Host_Sendtime;//发送完上一帧后的时间计数if(modbus.Host_Sendtime1000)//距离发送上一帧数据1s了{//1s时间到modbus.Host_time_flag1;//发送数据标志位置1}} }上面写了RS485串口中断处理函数和定时器中断处理函数 main.c HAL_TIM_Base_Start_IT(htim3); //启动定时器TIM3Modbus_Init();//本机作为从机使用时初始化RS485DIR_RX;//拉低PB5更改RS485模式为接收while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */Modbus_Event();//本机作为从机使用时}/* USER CODE END 3 */ } 主函数只需要写一个初始化在循环中调用Modbus_Event()函数循环查询就可以了。 测试结果 XCOM串口调试助手作为主机测试 主机发送解析 01 03 00 00 00 04 44 09 01从机地址 03功能码读寄存器 00 00读的起始地址 00 04要读的数据的个数 44 09校验码从机返回解析 01 03 08 00 01 00 12 00 13 00 04 CD 12 01从机地址 03功能码读寄存器 08数据的位数8个字节 00 01 00 12 00 13 00 04接收到四个数据0001001200130004 CD 12校验码校验方式是CRC16 我们可以计算出来从机返回的数据是没有问题的然后我们后面使用modbus poll作为主机进行测试 modbus poll作为主机测试 1.打开modbus pollSetup-read/write defination: 2.Connection-connect 3.查看结果 开始显示的不是16进制可以选中这些数据 Display-Hex - Ascall这样就是16进制显示了可以看到读取了我们程序中写的数据。 点击这个可以查看发送和返回的数据包 可以看到和我们刚才串口调试的是一样的结果。 总结 本次实验我们在RS485通信的基础上实现了modbus-RTU协议当然只写了03、06、16功能码测试都是没有问题的图方便我只放上了03的测试你们可以把这个都测试一遍甚至可以把他的功能写全面。
http://wiki.neutronadmin.com/news/405956/

相关文章:

  • 网站的衡量标准室内设计网页版
  • 网站建设包括哪几个方面广西建设银行行号查询网站
  • 做网站优化排名wordpress建站免费吗
  • 邯郸网站开发公司系部网站建设需求分析运行需求
  • 制作网站后台教程公司做完网站怎么搜不到
  • 网站推广优化设计方案专业建设网站制作
  • 织梦 网站地图销售培训主要培训内容
  • 哪个网站能买到做披萨的芝士正宗公司网站建设网络推广
  • 网站违规词处罚做网站的门店做网站有没有必要
  • 论坛网站开发成本电脑网站你懂我意思正能量
  • 企业网站总结体育西网站开发设计
  • 做网站运营如何提升用户粘度网站开发 团队协作
  • 网站开发公司经营范围营销型网站套餐
  • 沭阳奥体小区做网站男的怎么做直播网站
  • 农业信息网站建设概念济南营销型网站建设
  • 青岛网站建设技术外包天津河东网站建设公司
  • 成都网站建设十强企业网站建设费属哪个费用
  • 网站建设 中标discuz网站搬家教程
  • 给城市建设提议献策的网站html5新增标签
  • 网站做等保备案网站建设与网页设计入门
  • 乐清网站制作哪家好网页设计师要求什么专业
  • 河北做网站的网络营销方案的传播
  • 网站的提交重置按钮怎么做上海网站建设基础
  • 源码怎么做成网站网站建设验收合同模板
  • a 朝扬网络网站建设wordpress收用户邮件
  • 深圳附近做个商城网站找哪家公司好免费网页制作成品下载
  • 做网站域名不备案会怎么样网站模块设计软件
  • 网站制作从零开始WordPress文章不置顶
  • php mysql的网站开发开发人员公众号
  • 网易建站模板wordpress主题汉化版免费下载