[RISC-V MCU 创新应用比赛] CH32V307 ModbusTCP&RTU物联网型智能空调控制器

[复制链接]
 楼主| forgot 发表于 2023-2-27 14:18 | 显示全部楼层 |阅读模式
本帖最后由 forgot 于 2023-2-27 14:20 编辑

#申请原创#
CH32V307 ModbusTCP&RTU物联网型智能空调控制器创新设计

实现功能:
1、该方案是通过以外网络TCP和串行总线两种方式分别以ModbusTCP和ModbusRTU的标准协议对CH32V307主板进行访问实现各类寄存器读写功能,包括线圈寄存器、离散输入寄存器、保持寄存器等;
2、通过CH32V307主板进行modbus协议解析,通过串口对红外模块进行控制以实现空调进行学习、开机、关机、制热、制冷、除湿、风速、风量、定时等功能;
3、OLED液晶会对系统进行信息展示,如灯光状态、空调状态等,远程管理主机以PC机上的MThings及modbuspoll来替代完成;

架构及外设组成:
结构.png

环境搭建:
all.png

硬件组成:
PC机:通过MThings及modbuspoll来模拟空调远程管理主机。
CH32V307开发板:实现ModbusTCP_slave及ModbusRTU_slave的系统主要功能。
红外自学习模块:实现学习空调红外指令,并可以通过指令地址完成进行相关指令发送。
OLED液晶:显示系统工作状态及空调当前状态。
LED灯:对应寄存器0x1001灯光控制
v307.jpg

软件说明:
  以CH32V307开发主板为系统核心,基于Peripheral库和NetLib,
通过WCHNET库与TIM2实现TCP Client功能,采用free modbus协议栈实现ModbusTCP读写功能;
通过USART标准库与TIM3实现串口2通讯,采用中断的方式,以TIM3实现串口全帧检测,采用free modbus协议栈实现ModbusRTU读写功能;
通过USART标准库实现串口3对红外学习模块控制指令发送;
通过GPIO模拟时序,实现OLED信息显示。串口1作为打印口实现调试打印功能。
通过GPIO基本控制,实现LED灯光控制。

主要功能函数说明:
main函数://MB_RTU或者MB_TCP
  1. <font size="3" face="Arial">//MB_RTU或者MB_TCP
  2. char Curr_Mod = MB_TCP;

  3. /*********************************************************************
  4. MOD:  USART2  TX-->A.2   RX-->A.3
  5. AIR:  USART3  TX-->B.10  RX-->B.11
  6. OLED:        CLK-->A.4  SDA-->A.6
  7. LED:         A.0
  8. *********************************************************************/

  9. int main(void)
  10. {
  11.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  12.     Delay_Init();
  13.     LED_Configuration();
  14.     OLED_Configuration();
  15.     OLED_Init();
  16.     OLED_Poweron();
  17.     USART_AIR_Init(9600);                               //air空调发射器串口初始化->串口3
  18.     USART_Printf_Init(9600);                            //usart打印初始化->串口1
  19.     if (Curr_Mod == MB_RTU) {
  20.         eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_NONE);    //modbus_rtu初始化-> 串口2+定时器3
  21.     } else if(Curr_Mod == MB_TCP){
  22.         WCETH_Init();                                   //eth网卡初始化-> 网口+定时器2
  23.         eMBTCPInit(0);                                  //modbus_tcp
  24.     }
  25.     eMBEnable();
  26.     while(1){
  27.         if (Curr_Mod == MB_TCP) {
  28.             WCHNET_MainTask();
  29.         }
  30.         eMBPoll();
  31.         AIR_Process();
  32.         OLED_Show();
  33.     }
  34. }</font>

modbus协议eMBPoll函数:
  1. <font size="3" face="Arial">eMBErrorCode
  2. eMBPoll( void )
  3. {
  4.     static UCHAR   *ucMBFrame;
  5.     static UCHAR    ucRcvAddress;
  6.     static UCHAR    ucFunctionCode;
  7.     static USHORT   usLength;
  8.     static eMBException eException;

  9.     int             i;
  10.     eMBErrorCode    eStatus = MB_ENOERR;
  11.     eMBEventType    eEvent;

  12.     /* 协议栈准备完成 */
  13.     if( eMBState != STATE_ENABLED ) {
  14.         return MB_EILLSTATE;
  15.     }
  16.     /* 获取事件 RTU采用发送消息事件,TCP采用xMBPortTCPPool轮询信号*/
  17.     if( xMBPortEventGet( &eEvent ) == TRUE ) {
  18.         /* 判断事件类型 */
  19.         switch ( eEvent ) {
  20.         case EV_READY:
  21.             break;

  22.         /* 接收完成事件 */
  23.         case EV_FRAME_RECEIVED:
  24.             /* modbus接收函数,获取地址、PDU指针、PDU长度 */
  25.             eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );//pdu:功能码+数据
  26.             if( eStatus == MB_ENOERR ) {
  27.                 /* 判断地址是否吻合 */
  28.                 if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) ) {
  29.                     /* 发送执行事件 */
  30.                     ;
  31.                     ( void )xMBPortEventPost( EV_EXECUTE );
  32.                 }
  33.             }else {
  34.                 ;
  35.                 ( void )xMBPortEventPost( EV_READY );
  36.             }
  37.             break;
  38.         /* 执行事件 */
  39.         case EV_EXECUTE:
  40.             /* 功能码 */
  41.             ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
  42.             eException = MB_EX_ILLEGAL_FUNCTION;
  43.             /* 遍历所有支持的功能码 */
  44.             for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) {
  45.                 if( xFuncHandlers[i].ucFunctionCode == 0 ) {
  46.                     break;
  47.                 } else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) {
  48.                     /*调用相关处理函数*/
  49.                     eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
  50.                     break;
  51.                 }
  52.             }
  53.             /*不是广播*/
  54.             if(ucRcvAddress != MB_ADDRESS_BROADCAST) {
  55.                 /*异常*/
  56.                 if( eException != MB_EX_NONE ) {
  57.                     usLength = 0;
  58.                     ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
  59.                     ucMBFrame[usLength++] = eException;
  60.                 }
  61.                 if( ( eMBCurrentMode == MB_ASCII ) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS ) {
  62.                     vMBPortTimersDelay( MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );
  63.                 }
  64.                 /*发送响应函数*/
  65.                 eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
  66.             }
  67.             break;

  68.         case EV_FRAME_SENT:
  69.             break;
  70.         }
  71.     }
  72.     return MB_ENOERR;
  73. }</font>

寄存器红外控制:
  1. <font size="3" face="Arial">void Air_Ctrl_Fun(uint16_t *cmd)
  2. {
  3.     uint16_t reg = 0;//寄存器地址

  4.     reg = *cmd;
  5.     if(reg) {
  6.         switch(reg) {
  7.         case 0x1001:
  8.             Air_1001_Reg(usRegHoldingBuf[Rey_Ctl_Pos]);
  9.             break;
  10.         case 0x1002:
  11.             Air_1002_Reg(usRegHoldingBuf[INT_LRN_Pos]);
  12.             break;
  13.         case 0x1003:
  14.             Air_1003_Reg(usRegHoldingBuf[OUT_LRN_Pos]);
  15.             break;
  16.         case 0x1004:
  17.             Air_1004_Reg(usRegHoldingBuf[Air_Mod_Pos]);
  18.             break;
  19.         case 0x1005:
  20.             Air_1005_Reg(usRegHoldingBuf[Fan_Spd_Pos]);
  21.             break;
  22.         case 0x1006:
  23.             Air_1006_Reg(usRegHoldingBuf[Fan_Dir_Pos]);
  24.             break;
  25.         case 0x1007:
  26.             Air_1007_Reg(usRegHoldingBuf[Air_Tim_Pos]);
  27.             break;
  28.         default:
  29.             break;
  30.         }
  31.     }
  32.     *cmd = 0;
  33. }</font>

液晶显示:
  1. void OLED_Show(void)

  2. {

  3.     FINE_STR(LAST_CMD);

  4.     if(need_show){

  5.         if (Curr_Mod == MB_RTU){

  6.             OLED_CLS();

  7.             OLED_ShowStr(0,0,(unsigned char*)"IoT Air CTRLer",2);

  8.             OLED_ShowStr(0,2,(unsigned char*)"Modbus-RTU",2);

  9.             if(usRegHoldingBuf[1]){

  10.                 OLED_ShowStr(0,4,(unsigned char*)"LED_STA:ON",2);

  11.             }else {

  12.                 OLED_ShowStr(0,4,(unsigned char*)"LED_STA:OFF",2);

  13.             }

  14.             OLED_ShowStr(0,6,(unsigned char*)show_buff1,2);

  15.         }else if(Curr_Mod == MB_TCP){

  16.             OLED_CLS();

  17.             OLED_ShowStr(0,0,(unsigned char*)"IoT Air CTRLer",2);

  18.             OLED_ShowStr(0,2,(unsigned char*)"Modbus-TCP",2);

  19.             if(usRegHoldingBuf[1]){

  20.                 OLED_ShowStr(0,4,(unsigned char*)"LED_STA:ON",2);

  21.             }else {

  22.                 OLED_ShowStr(0,4,(unsigned char*)"LED_STA:OFF",2);

  23.             }

  24.             OLED_ShowStr(0,6,(unsigned char*)show_buff1,2);

  25.         }

  26.         need_show = 0;

  27.     }

  28. }

寄存器地址分布说明:
0x1001:灯光控制;
0x1002:进入学习;
0x1003:退出学习;
0x1004:各类模式控制;
0x1005:各类风速控制;
0x1006:各类风向控制;
0x1007:各类定时控制;

RTU配置并连接:
RTU.png

TCP配置并连接:
TCP.png

连接成功:
rtutcp.png

制冷25°:
cool on.jpg

视频以动图代替:
开机:
kaiji.gif

制冷:
FormatFactoryPart1.gif

gitee代码托管
托管.png

https://gitee.com/fankas-dream/forgot-gitee.git
需要的自己下载。


yeates333 发表于 2023-6-10 11:42 | 显示全部楼层
modbus RTU主要作用是什么?

评论

通讯啊  发表于 2023-6-10 12:15
jackcat 发表于 2023-6-10 15:57 | 显示全部楼层
ModbusTCP是一种基于Modbus协议的通信方式,它使用TCP/IP协议作为传输层,可以实现在不同设备之间进行数据通信和控制。
maudlu 发表于 2023-6-10 16:06 | 显示全部楼层
CH32V307单片机作为下位机如何实现modbus通讯
pl202 发表于 2023-6-10 16:36 | 显示全部楼层
相比于传统的串口Modbus协议,ModbusTCP具有传输速度快、可靠性高、距离远等优点,在现代工业控制系统中被广泛采用。
tifmill 发表于 2023-6-10 16:58 | 显示全部楼层
ModbusRTU通信,怎么设置通道?

评论

啥通道,串口通道吗  发表于 2023-6-11 09:46
vivilyly 发表于 2023-6-10 17:48 | 显示全部楼层
modbus tcp 比modbus rtu 速度快吗

评论

是的  发表于 2023-6-14 08:27
就是串口的通讯速率,115200 9600波特率都可以的  发表于 2023-6-11 09:46
yorkbarney 发表于 2023-6-13 21:20 | 显示全部楼层
如何移植UPNP协议到stm32
beacherblack 发表于 2023-6-13 22:34 | 显示全部楼层
modbus tcp和modbus rtu的区别是什么?

评论

一个是网络通讯,一个是 串口通讯,看名字就看得出来  发表于 2023-6-14 08:27
pl202 发表于 2023-6-13 23:06 | 显示全部楼层
Modbus-rtu,用什么工具调试,如何调试

评论

用串口工具或者是modbuspoll来调试就好,都很好用  发表于 2023-6-14 08:26
claretttt 发表于 2023-6-14 09:51 | 显示全部楼层
modbus RTU和modbus TCP能同时使用么
 楼主| forgot 发表于 2023-6-14 10:23 | 显示全部楼层
claretttt 发表于 2023-6-14 09:51
modbus RTU和modbus TCP能同时使用么

可以同时用,要看怎么设计好
robertesth 发表于 2023-6-14 10:42 | 显示全部楼层
modbus接收的数据怎么处理              
abotomson 发表于 2023-6-14 10:48 | 显示全部楼层
Modbus RTU最大通信速率有多少?
 楼主| forgot 发表于 2023-6-14 10:50 | 显示全部楼层
robertesth 发表于 2023-6-14 10:42
modbus接收的数据怎么处理

按照寄存器读写方式进行数据获取,实现自己读取数据的目的
 楼主| forgot 发表于 2023-6-14 10:50 | 显示全部楼层
abotomson 发表于 2023-6-14 10:48
Modbus RTU最大通信速率有多少?

实际使用上,一般以9600BPS8E1为多,这也是MODBUS RTU建议的默认出厂设置值,另外还有默认19200的,但再高也只有允许设置到115200的,再高就没有见过了。实际上115200的速率,通讯距离会大大的缩短,可靠性也会有所下降。
ingramward 发表于 2023-6-14 11:26 | 显示全部楼层
modbus从站地址怎么设?               
 楼主| forgot 发表于 2023-6-14 11:33 | 显示全部楼层
ingramward 发表于 2023-6-14 11:26
modbus从站地址怎么设?

在配置modbus的参数的时候设置,如果是TCP那就是IP地址
pentruman 发表于 2023-6-14 11:53 | 显示全部楼层
CH32V307 怎么支持RS485接口和MODBUS通信协议
 楼主| forgot 发表于 2023-6-14 11:56 | 显示全部楼层
pentruman 发表于 2023-6-14 11:53
CH32V307 怎么支持RS485接口和MODBUS通信协议

硬件上通过串口接到RS485驱动芯片,软件部分加上freemodbus协议栈,轻松实现
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2064

主题

14488

帖子

59

粉丝
快速回复 在线客服 返回列表 返回顶部

2064

主题

14488

帖子

59

粉丝
快速回复 在线客服 返回列表 返回顶部