你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

关于类ModBus协议的例程分享

[复制链接]
cuyebiren 发布时间:2020-8-15 17:25
哎,长久不玩,基本的ADC、Time模块都不会用了。。。
大家应该遇到过类似:头、地址、命令、数据长度、数据、校验 这种格式的协议,比如 刷卡器模块、电表模块、串口屏等基本都是采用这种格式的协议——我称之为类ModBus协议,因为它不是严格的ModBus协议

本例程所用开发板:普中PZ6806L
本例程功能:通过UART控制数码管显示 0~9
本例程所用的协议:
协议格式:head     address    cmd     length    datas    check
bytes     :      1           1           1           1          n          1
说明:
1、length = datas 的长度,本历程固定为 1
2、check  = address、 cmd、length、datas 的异或值
3、cmd 取值范围:0,1,2,3, ... 10,
      对应功能分别为:cmd = 0, 显示字符 0、cmd = 1,显示字符 1、。。。cmd = 9,显示字符 9,cmd = 10,循环显示 字符 0~9,间隔500ms
4、datas 字段未使用,可为任意值
5、一般接收到报文后,应当返回应答信息,本例程为报文原样返回

CubeMx配置过程:
配置过程附件里也有

1.JPG 2.JPG 3.JPG 4.JPG 6.JPG

5.JPG 7.JPG 8.JPG 9.JPG


编写测试代码:
这里主要说两点:
1、HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
12.JPG

   我发现,使用HAL库按标准库的方式处理UART通信也是可以的,这里把 Size 设为 1 即可,然后需要在UART回调函数中重复调用此函数;——我没有经过长时间大数据测试,不能保证这样做没有问题。
2、善用 状态机。
  个人感觉 C语言 的难点就这4个:结构体、指针、状态机、软件寄存器(位域)
  接收状态机:
   2640509f7e3037aeaa32da80832b1ef.jpg
  1. switch(uart_rec.state) // 状态机-接收协议处理
  2. {            // 协议格式: head(1byte)/address(1byte)/cmd(1byte)/length(1byte)/datas(length byte)/check(1byte)
  3. case UART_Idle:
  4.   if (uart_rec_tmp == uart_rec.head) // UART_Idle ==> UART_Head
  5.    uart_rec.state = UART_Head;
  6.   break;
  7. case UART_Head:
  8.   if (uart_rec_tmp == uart_rec.addr) // UART_Head ==> UART_Addr
  9.    uart_rec.state = UART_Addr;
  10.   else if (uart_rec_tmp != uart_rec.head) // UART_Head ==> UART_Idle
  11.    uart_rec.state = UART_Idle;
  12.   break;
  13. case UART_Addr:
  14.   if (isValidCMD(uart_rec_tmp)) // UART_Addr ==> UART_CMD
  15.   {
  16.    uart_rec.cmd = uart_rec_tmp;
  17.    uart_rec.state = UART_CMD;
  18.   }
  19.   else if (uart_rec_tmp == uart_rec.head) // UART_Addr ==> UART_Head
  20.    uart_rec.state = UART_Head;
  21.   else             // UART_Addr ==> UART_Idle
  22.    uart_rec.state = UART_Idle;
  23.   break;
  24. case UART_CMD:
  25.   if (isValidLen(uart_rec_tmp))
  26.   {
  27.    uart_rec.len = uart_rec_tmp;
  28.    uart_rec.cnt = 0;
  29.    
  30.    if (uart_rec_tmp == 0)  // UART_CMD ==> UART_Datas
  31.     uart_rec.state = UART_Datas;
  32.    else           // UART_CMD ==> UART_Len
  33.     uart_rec.state = UART_Len;
  34.   }
  35.   else if (uart_rec_tmp == uart_rec.head) // UART_CMD ==> UART_Head
  36.    uart_rec.state = UART_Head;
  37.   else             // UART_CMD ==> UART_Idle
  38.    uart_rec.state = UART_Idle;
  39.   break;
  40. case UART_Len:
  41.   uart_rec.buf[uart_rec.cnt] = uart_rec_tmp;
  42.   uart_rec.cnt++;
  43.   
  44.   if (uart_rec.cnt == uart_rec.len)  // UART_Len ==> UART_Datas
  45.    uart_rec.state = UART_Datas;
  46.   break;
  47. case UART_Datas:
  48.   if (uart_rec_tmp == checkUartBuf(&uart_rec)) // UART_Datas ==> UART_Complete
  49.    uart_rec.state = UART_Complete;
  50.   else if (uart_rec_tmp == uart_rec.head) // UART_Datas ==> UART_Head
  51.    uart_rec.state = UART_Head;
  52.   else                // UART_Datas ==> UART_Idle
  53.    uart_rec.state = UART_Idle;
  54.   break;
  55. case UART_Complete:  // 在 uart_recHandle() 中 UART_Complete ==> UART_Idle
  56.   break;
  57. default: uart_rec.state = UART_Idle; break;
  58. }
复制代码

测试:(测试视频请查看附件)
13.JPG


奉上全部工程和文件:
modbus_fake.rar (18.69 MB, 下载次数: 72)
2 收藏 2 评论2 发布时间:2020-8-15 17:25

举报

2个回答
mfc4143 回答时间:2020-8-17 08:19:44
赞一个
lee00120 回答时间:2020-10-29 20:50:09
顶一个

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版