modbus_app.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include "board.h"
  2. #include "poweroff_save_app.h"
  3. #include "modbus_encoder.h"
  4. #include "modbus_slave.h"
  5. #include "modbus_master.h"
  6. #include "variable.h"
  7. #include "SEGGER_RTT.h"
  8. #include "encrypt_md5.h"
  9. #include "encrypt_xxtea.h"
  10. #include "modbus_app.h"
  11. #include <string.h>
  12. #define MODBUS_APP_NUMBER 3
  13. typedef struct
  14. {
  15. unsigned char uart_no; //串口号
  16. unsigned char modbus_dir; //modbus方向,0是从机,1是主机
  17. //当做为从机时,master_or_slave保存modbus_slave_t 对象指针
  18. //当做为主机时,master_or_slave保存modbus_master_t 对象指针
  19. void *master_or_slave; //主站信息
  20. unsigned char count;
  21. unsigned char step; //状态步
  22. unsigned char rx_buffer[1024];
  23. unsigned char tx_buffer[512];
  24. } modbus_status_t;
  25. //modbus主站对象信息
  26. modbus_master_t master1;
  27. static modbus_slave_t slaves[2];
  28. void servo_on_respone(modbus_master_cmd_t *cmd, unsigned char *respone, int length);
  29. //modbus协议的一些状态信息
  30. static modbus_status_t modbus_status[MODBUS_APP_NUMBER] = {
  31. { 0, 0, &slaves[0] ,1}, //组0,ID2,串口2,从站
  32. { 2, 0, &slaves[0] ,2}, //组0,ID2,串口2,从站
  33. { 1, 0, &slaves[0] ,2} //组1,ID1,串口3主站
  34. };
  35. /**
  36. * 系统默认的回调函数
  37. *
  38. * @author lxz (2019/6/12/周三)
  39. *
  40. * @param address
  41. * @param number
  42. */
  43. static void slave1_on_comm(unsigned char id, unsigned char cmd, unsigned short address, unsigned short number)
  44. {
  45. //通知软件需要退出进入bootloader
  46. if (cmd == 0x23)
  47. {
  48. extern void app_save_parameter(void);
  49. //先保存参数
  50. app_save_parameter();
  51. //设置标志位
  52. //Stm32_Clock_DeInit();
  53. //设置标志
  54. hw_noinit_write(0, 0xA5A5A5A5);
  55. //设置ID
  56. hw_noinit_write(3, id);
  57. hw_noinit_write(2, 115200);
  58. hw_noinit_write(4, 115200);
  59. hw_noinit_write(6, 115200);
  60. hw_board_reboot();
  61. }
  62. }
  63. /**
  64. * modbus应用环境的初始化,包括了一些数据域的初始化注册
  65. *
  66. * @author lxz (2019/5/17/周五)
  67. */
  68. void mosbus_app_init(void)
  69. {
  70. modbus_slave_t *slave = &slaves[0];
  71. //保存ID码,保证bootloader会同步回来
  72. hw_noinit_write(1, 1);
  73. hw_noinit_write(3, 1);
  74. hw_noinit_write(5, 1);
  75. //从站初始化
  76. memset(&slaves[0], 0, sizeof(slaves));
  77. slave->id = 1; //设置从站ID
  78. slave->on_comm = slave1_on_comm; //设置从站通讯的回调函数
  79. //添加从站有效的数据域信息
  80. modbus_slave_add_dataarea(slave,
  81. 0x01, //数据类型为位
  82. 0, //映射开始地址为0
  83. MIDDLE_COILS_NUMBER, //数据单位个数
  84. (unsigned char *)&middle_coils[0] //数据所在地址
  85. );
  86. modbus_slave_add_dataarea(slave,
  87. 0x01, //数据类型为位
  88. 0x0800, //映射开始地址为0x800,用于兼容台达DVP协议的M码地址
  89. MIDDLE_COILS_NUMBER, //数据单位个数
  90. (unsigned char *)&middle_coils[0] //数据所在地址
  91. );
  92. modbus_slave_add_dataarea(slave,
  93. 0x03, //数据类型为16位数值
  94. 0, //映射开始地址为0
  95. USER_DATA_NUMBER, //数据单位个数
  96. (unsigned char *)&user_datas[0] //数据所在地址
  97. );
  98. modbus_slave_add_dataarea(slave,
  99. 0x03, //数据类型为16位数值
  100. 0x1000, //映射开始地址为0x1000,用于兼容台达DVP协议的D码地址
  101. USER_DATA_NUMBER, //数据单位个数
  102. (unsigned char *)&user_datas[0] //数据所在地址
  103. );
  104. //升级系统必须的命令
  105. modbus_slave_add_dataarea(slave,
  106. 0xFE, //数据类型为系统定制,升级时使用
  107. 0, //映射开始地址为0
  108. 512, //数据单位个数
  109. 0 //数据所在地址
  110. );
  111. //WIFI一些对应的通讯缓冲
  112. slave = &slaves[1];
  113. slave->id = 0x7F;
  114. modbus_slave_add_dataarea(slave,
  115. 0x01, //数据类型为系统定制,升级时使用
  116. 0x00, //映射开始地址为0
  117. 24, //数据单位个数
  118. (unsigned char *)&middle_coils[1000 >> 3] //数据所在地址
  119. );
  120. modbus_slave_add_dataarea(slave,
  121. 0x03, //数据类型为系统定制,升级时使用
  122. 0x00, //映射开始地址为0
  123. 128, //数据单位个数
  124. (unsigned char *)&user_datas[1600] //数据所在地址
  125. );
  126. #if 1
  127. //初始化主站环境
  128. modbus_master_init();
  129. //初始化主站信息
  130. memset(&master1, 0, sizeof(master1));
  131. master1.encoder_type = MODBUS_ENCODER_RTU; //RTU模式
  132. master1.interval = 10000; //10ms的命令间隔
  133. master1.one_byte_time = 1000; //一个字节的时间为1ms
  134. master1.retry = 3; //命令的重试次数为3次
  135. #endif
  136. }
  137. /**
  138. * modbus 从台应用代码
  139. *
  140. * @author lxz (2019/5/17/周五)
  141. *
  142. * @param status
  143. */
  144. static void modbus_slave_app(modbus_status_t *status)
  145. {
  146. int length;
  147. int index = 0;
  148. modbus_encoder_t *encoder;
  149. switch (status->step)
  150. {
  151. case 0:
  152. hw_dma_uart_begin_read(status->uart_no, &status->rx_buffer[0], 1024);
  153. status->step++;
  154. break;
  155. case 1:
  156. length = hw_dma_uart_read_finish(status->uart_no);
  157. if (length > 0)
  158. {
  159. status->step = 0;
  160. encoder = modbus_encoder_match(status->rx_buffer, length);
  161. if (encoder != (void *)0)
  162. {
  163. length = encoder->decode(&status->rx_buffer[0], &status->rx_buffer[0], length);
  164. if (length > 0)
  165. {
  166. while (index < status->count)
  167. {
  168. length = modbus_slave_run(
  169. &((modbus_slave_t *)status->master_or_slave)[index],
  170. &status->tx_buffer[0],
  171. &status->rx_buffer[0]);
  172. if (length > 0)
  173. {
  174. length = encoder->encode(&status->tx_buffer[0], &status->tx_buffer[0], length);
  175. if (length > 0)
  176. {
  177. hw_dma_uart_begin_write(status->uart_no, (const char *)&status->tx_buffer[0], length);
  178. status->step = 2;
  179. }
  180. break;
  181. }
  182. index++;
  183. }
  184. }
  185. }
  186. }
  187. break;
  188. case 2:
  189. if (hw_dma_uart_write_finish(status->uart_no))
  190. {
  191. status->step = 0;
  192. }
  193. break;
  194. }
  195. }
  196. /**
  197. * 主站应用代码
  198. *
  199. * @author lxz
  200. *
  201. * @param status
  202. */
  203. static void modbus_master_app(modbus_status_t *status)
  204. {
  205. int length;
  206. switch (status->step)
  207. {
  208. case 0:
  209. //判断是否有包需要处理
  210. length = hw_dma_uart_read_finish(status->uart_no);
  211. //将接收信息提供给主站,并获取主站输出
  212. length = modbus_master_run(
  213. (modbus_master_t *)status->master_or_slave,
  214. status->tx_buffer,
  215. status->rx_buffer,
  216. length);
  217. if (length > 0)
  218. {
  219. //主站有需要输出时进行输出
  220. hw_dma_uart_begin_write(status->uart_no, (const char *)&status->tx_buffer[0], length);
  221. status->step++;
  222. }
  223. break;
  224. case 1:
  225. //等待输出完毕
  226. if (hw_dma_uart_write_finish(status->uart_no))
  227. {
  228. status->step = 0;
  229. hw_dma_uart_begin_read(status->uart_no, &status->rx_buffer[0], 1024);
  230. }
  231. break;
  232. }
  233. }
  234. /**
  235. * modbus应用的循环运行函数,根据自己需求编写
  236. *
  237. * @author lxz (2019/5/17/周五)
  238. *
  239. * @param void
  240. */
  241. void modbus_app_proc(void)
  242. {
  243. int index = 0;
  244. while (index < MODBUS_APP_NUMBER)
  245. {
  246. if (modbus_status[index].modbus_dir == 0)
  247. {
  248. modbus_slave_app(&modbus_status[index]);
  249. } else
  250. {
  251. modbus_master_app(&modbus_status[index]);
  252. }
  253. index++;
  254. }
  255. /*
  256. if (sw_timer_expire(&timer))
  257. {
  258. //500ms发一次
  259. sw_timer_start(&timer, 0, 500000);
  260. user_datas[11] += 1;
  261. modbus_master_add_once_cmd(
  262. &master1,
  263. 1,
  264. 0x06,
  265. 11,
  266. 1,
  267. (unsigned char *)&user_datas[11],
  268. 1000,
  269. 0
  270. );
  271. }
  272. */
  273. }