扩展库使用说明——modbus主机
本帖最后由 fangyan123 于 2021-11-30 17:03 编辑在这里Modbus主要指Modbus-RTU协议,下面的说明均以Modbus-RTU协议进行说明。如果对Modbus协议不了解,建议先下载最下方的“Modbus协议.pdf”文档熟悉该协议。
1-协议简介
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。
2-硬件连接
Modbus协议实际应用一般基于RS485物理层,下图为RS485模块接线图:
在测试协议时,可以通过串口与电脑上位机软件通信进行测试,下面的测试程序都是直接通过电脑上位机进行测试。
3-图形块说明在这里会挑一些重要或者特殊的进行说明。1.读线圈
输入参数:1.超时时间:主机发送数据后,堵塞等待从机响应的最长时间。
2.buf:读回来的线圈值,为无符号8位整数的数组。
返回参数:从机响应超时返回0,不正确类型返回-1,成功返回1。
2.读输入寄存器
输入参数:1.buf:读回来的输入寄存器值,为无符号8位整数类型的数组,也就是会将输入寄存器的16位数据拆分 为2个8位的数据,高位在前低位在后。
3.写多个保持寄存器
输入参数:1.buf:读回来的输入寄存器值,为无符号8位整数类型的数组,也就是会将输入寄存器的16位数据拆分 为2个8位的数据,高位在前低位在后。
4.读保持寄存器
输入参数:1.buf:读回来的输入寄存器值,为无符号8位整数类型的数组,也就是会将输入寄存器的16位数据拆分 为2个8位的数据,高位在前低位在后。
5.读写多个保持寄存器
输入参数:1.buf:该语句会将buf中的数据写入从机,并将从机读取回来的数据又写回buf中,为无符号8位整数类 型的数组,也就是会将输入寄存器的16位数据拆分为2个8位的数据,高位在前低位在后。
6.定时回调函数
需要使用定时器每隔100us调用一次。
4-范例代码
1.读取线圈
图形块以及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
if(mbMaster.ReqReadCoils(1,1,9,buf,500)){
spi_tft.clear((0x67FF));
spi_tft.set_cursor(34,0);
spi_tft.draw_hanzi_12("读线圈测试");
spi_tft.set_cursor(0,15);
spi_tft.println((String("buf:") + String(buf[(int)(0)])));
spi_tft.println((String("buf:") + String(buf[(int)(1)])));
delay(1000);
}
}
return 1;
}
效果展示:
2.读离散量输入
图形块以及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
if(mbMaster.ReqReadDiscreteInputs(1,1,9,buf,500)){
spi_tft.clear((0x67FF));
spi_tft.set_cursor(34,0);
spi_tft.draw_hanzi_12("读线圈测试");
spi_tft.set_cursor(0,15);
spi_tft.println((String("buf:") + String(buf[(int)(0)])));
spi_tft.println((String("buf:") + String(buf[(int)(1)])));
delay(1000);
}
}
return 1;
}
效果展示:
3.读输入寄存器
图形块及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
if(mbMaster.ReqReadInputRegister(1,1,1,buf,500)){
spi_tft.clear((0x67FF));
spi_tft.set_cursor(34,0);
spi_tft.draw_hanzi_12("读输入测试");
spi_tft.set_cursor(0,15);
spi_tft.println((String("buf:") + String(buf[(int)(0)])));
spi_tft.println((String("buf:") + String(buf[(int)(1)])));
delay(1000);
}
}
return 1;
}
效果展示:
4.读保持寄存器
图形块及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
if(mbMaster.ReqReadHoldingRegister(1,1,1,buf,500)){
spi_tft.clear((0x67FF));
spi_tft.set_cursor(16,0);
spi_tft.draw_hanzi_12("读保持寄存器测试");
spi_tft.set_cursor(0,15);
spi_tft.println((String("buf:") + String(buf[(int)(0)])));
spi_tft.println((String("buf:") + String(buf[(int)(1)])));
delay(1000);
}
}
return 1;
}
效果展示:
5.写单个线圈
图形块及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
spi_tft.clear((0x67FF));
spi_tft.set_cursor(0,10);
if(mbMaster.ReqWriteCoil(1,1,0,500)){
spi_tft.draw_hanzi_12("写线圈成功");
}
else{
spi_tft.draw_hanzi_12("写线圈失败");
}
delay(1000);
spi_tft.clear((0x67FF));
spi_tft.set_cursor(0,22);
if(mbMaster.ReqWriteCoil(1,1,1,500)){
spi_tft.draw_hanzi_12("写线圈成功");
}
else{
spi_tft.draw_hanzi_12("写线圈失败");
}
delay(1000);
}
return 1;
}
效果展示:
无
6.写多个线圈
图形块及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
spi_tft.clear((0x67FF));
spi_tft.set_cursor(0,10);
buf[(int)(0)] = 0xff;
if(mbMaster.ReqWriteCoil_S(1,1,6,buf,500)){
spi_tft.draw_hanzi_12("写线圈成功");
}
else{
spi_tft.draw_hanzi_12("写线圈失败");
}
delay(1000);
spi_tft.clear((0x67FF));
spi_tft.set_cursor(0,22);
buf[(int)(0)] = 0;
if(mbMaster.ReqWriteCoil_S(1,1,6,buf,500)){
spi_tft.draw_hanzi_12("写线圈成功");
}
else{
spi_tft.draw_hanzi_12("写线圈失败");
}
delay(1000);
}
return 1;
}
效果展示:
7.写单个保持寄存器
图形块及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
spi_tft.clear((0x67FF));
spi_tft.set_cursor(0,10);
if(mbMaster.ReqWriteHoldingRegister(1,1,0x1234,500)){
spi_tft.draw_hanzi_12("写寄存器成功");
}
else{
spi_tft.draw_hanzi_12("写寄存器失败");
}
delay(1000);
}
return 1;
}
效果展示:
8.写多个保持寄存器
图形块及字符代码#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
buf[(int)(0)] = 0x12;
buf[(int)(1)] = 0x34;
buf[(int)(2)] = 0x56;
buf[(int)(3)] = 0x78;
spi_tft.clear((0x67FF));
spi_tft.set_cursor(0,10);
if(mbMaster.ReqWriteHoldingRegister_S(1,1,2,buf,500)){
spi_tft.draw_hanzi_12("写寄存器成功");
}
else{
spi_tft.draw_hanzi_12("写寄存器失败");
}
delay(1000);
}
return 1;
}
效果展示:
7.读写多个保持寄存器
图形块及字符代码
#define MBMASTER_USART1 1
#include <CH32V103.h>
#include "myLib/CH32V_ST7735S.h"
#include "mylib/MB_Master.h"
#include "CH32V_TIM.h"
uint8_t buf;
SPITFT spi_tft(128,128,PC5,PA2,PA4);
MBMaster mbMaster(USART1,9600,USART_Parity_No);
void TIM_attachInterrupt_2() {
mbMaster.TimerCallback();
}
int main(void)
{
CH32_Init();
spi_tft.init();
spi_tft.set_direction(2);
spi_tft.clear((0x67FF));
mbMaster.Init();
TIM_attachInterrupt(TIM2, 100, TIM_attachInterrupt_2);
while(1){
buf[(int)(0)] = 0x12;
buf[(int)(1)] = 0x34;
buf[(int)(2)] = 0x56;
buf[(int)(3)] = 0x78;
spi_tft.clear((0x67FF));
spi_tft.set_cursor(0,10);
if(mbMaster.ReqReadWriteHoldingRegister_S(1,3,2,1,2,buf,500)){
spi_tft.draw_hanzi_12("写寄存器成功");
spi_tft.set_cursor(0,27);
spi_tft.println((String("buf:") + String(buf[(int)(0)])));
spi_tft.println((String("buf:") + String(buf[(int)(1)])));
}
else{
spi_tft.draw_hanzi_12("写寄存器失败");
}
delay(1000);
}
return 1;
}
效果展示:
附件:
您好,使用STC8H1K08,测试modbus读保持寄存器功能时,无法正常读取数值。经过检查,发现发送数据modbus的采集命令正常,回复也正常。但是判断接收时为错误。
#define ModBus_Master_UART UART_2
#include <STC8HX.h>
uint32 sys_clk = 24000000;//设置PWM、定时器、串口、EEPROM频率参数
#include "lib/twen_board.h"
#include "mylib/MB_Master.h"
#include "lib/UART.h"
uint8 mylist={0,0,0,0};
void Timer0Init(void) //100微秒@24.000MHz
{
AUXR &= 0x7f; //定时器时钟12T模式
TMOD &= 0xf0; //设置定时器模式
TL0 = 0x38; //设定定时初值
TH0 = 0xff; //设定定时初值
}
void T_IRQ0(void) interrupt 1 using 1{
MBMasterTimerCallback();
}
void setup()
{
twen_board_init();//天问51初始化
Timer0Init();
MBMasterInit(UART_2, UART2_RX_P10, UART2_TX_P11, 9600, TIM_2, MB_M_PAR_NONE);
uart_init(UART_1, UART1_RX_P30, UART1_TX_P31, 9600, TIM_1);//初始化串口
}
void loop()
{
mylist[(int)(0)] = 1;
mylist[(int)(1)] = 2;
mylist[(int)(2)] = 0;
mylist[(int)(3)] = 1;
if(MBMasterReqWriteHoldingRegister_S(1,1,1,mylist,500)){
}
if(MBMasterReqReadHoldingRegister(1,2,1,mylist,500)){
}
uart_putchar(UART_1, mylist[(int)(0)]);//串口单个字符输出
uart_putchar(UART_1, mylist[(int)(1)]);//串口单个字符输出
uart_putchar(UART_1, mylist[(int)(2)]);//串口单个字符输出
uart_putchar(UART_1, mylist[(int)(3)]);//串口单个字符输出
}
void main(void)
{
setup();
while(1){
loop();
}
}
图形例程方便打包发上来吗?? 从机的使用方法有空也发一下吧:) #include "mylib/MB_Master.h"老大这个文件有么 天问Block软件,文件--项目中心--最新项目,搜:modbus modbus从机程序有问题呀,有完整的吗?可以付费 可以直接用到stc32G芯片上吗
大神有微信吗?我这里有个485问题求助 大师,如果两个主串口应该怎么排列呢,谢谢
页:
[1]