X T iny Mod bus 는 리 소 스가 제한 된 임 베 디 드 시스템을 위해 설계 된 경 량 C 언어 임 베 디 드 Mod bus 프로토 콜 스 택 입니다 . Mod bus R TU 및 Mod bus AS C II 전송 모 드를 지원 하며 마스터 및 슬 레이 브 기능을 제공합니다 .이 문서 에서는 X T iny Mod bus 의 아 키 텍 처 특성 , API 인터페 이스 , 마이 그레이 션 방법 및 전체 마스터 슬 레이 브 샘플 소 스 코드를 자세히 설명 합니다 .
X T iny Mod bus 개 요
X T iny Mod bus 는 최소 리 소 스 소비 로 완전한 Mod bus 프로토 콜 기능을 제공하기 위해 설계 되었습니다 .순 수한 C 언어로 작성 되었으며 운영 체 제에 의존 하지 않으며 51 MC U , AV R , S TM 32, MS P 430 및 기타 임 베 디 드 플랫폼 으로 쉽게 이 식 할 수 있습니다 .
1. 1 핵심 특징
- 超轻量级
- 主从站一体
- 双协议支持
- 无操作系统依赖
- 功能码完整
- 可裁剪配置
- 中断驱动
- CRC check
1. 2 자원 사용 량
| 资源 | |||
|---|---|---|---|
| Flash(代码) | |||
| RAM(全局变量) | |||
| 栈空间 | |||
| 接收缓冲区 | |||
| 发送缓冲区 |
2. 문서 구조
X T iny Mod bus /
- - x t iny _ mod bus . h / / 마스터 헤 더 파일 , API 선언 및 구성 매 크 로
- - x t iny _ mod bus . c / / 핵심 프로토 콜 구현
- - x t iny _ mod bus _ port . h 플랫폼 포 팅 인터페 이스 (사 용 자 구현)
- - x t iny _ mod bus _ conf ig . h / / 프로 파 일 (기 능 자 르기)
예 제 / ex amples
- - - slave _ demo . c / / 슬 레이 브 예 제
- - master _ demo . c / / 기본 스테 이션 예 제
st m 32 _ port . c S TM 32 마이 그레이 션 예 제
III . 구성 옵션
xt iny _ mod bus _ conf ig . h 에서 매 크 로를 통해 구성 기능을 정의 합니다 .
/ / 마스터 기능 활성화 (주 석 이 제거 되면 슬 레이 브 만 컴 파 일)
# define X MB _ en ab le _ MAS TER 1
/ / 슬 레이 브 기능 활성화
# define X MB _ EN AB LE _ S LA VE 1
프로토 콜 모 드 : 1 = R TU , 0 = AS C II
# define X MB _ R TU _ MO DE 1
/ / 버 퍼 크기
# define X MB _ BU F _ S IZ E 64
/ / 슬 레이 브 주소 (1 - 24 7)
# define X MB _ S LA VE _ AD DR 1
지원 되는 기능 코드 (필 요한 주 석을 제거 하면 코드 볼 륨 을 줄 일 수 있음)
# define X MB _ FC _ READ _ CO IL S 1 // 0 x 01
# define X MB _ FC _ READ _ IN PU TS 1 // 0 x 02
# define X MB _ FC _ READ _ H OL D ING S 1 // 0 x 03
# define X MB _ FC _ READ _ IN P UT _ REG ETS 1 // 0 x 04
X MB _ FC _ W R ITE _ CO IL 정의 1 // 0 x 05
# define X MB _ FC _ W R ITE _ REG IS TER 1 // 0 x 06
# define X MB _ FC _ W R ITE _ CO IL S 1 // 0 x 0 f
# define X MB _ FC _ W R ITE _ REG IS TER S 1 0 x 10
/ / 데이터 영역 크기
# define X mb _ co ils _ num 16 / / 코 일 수
# define X mb _ input _ num 16 / / 단 속 입력 수 량
# define X MB _ H OL D ING S _ N UM 32 / / 레 지 스터 수 를 유지 합니다 .
# define X MB _ IN P UT _ REG S _ N UM 16 / / 입력 레 지 스터 수
프레 임 시간 초 과 시간 (문 자 간 격 , ms)
# define X MB _ FR AME _ TIM EO UT 5
플랫폼 이 식 인터페 이스
X T iny Mod bus 는 콜 백 함 수를 통해 하드 웨어 플랫폼 과 분리 되어 사용자는 다음 인터페 이 스를 구현 할 수 있습니다 .
x t iny _ mod bus _ port . h
직 렬 포 트 초기 화 (바 트 속도 , 데이터 비트 , 중지 비트 , 체크 비트)
vo id x mb _ port _ u art _ init (u int 32 _ t baud rate);
/ / 바 이트 를 보내 다
vo id x mb _ port _ u art _ send _ by te (u int 8 _ t by te);
/ / 수신 인터 럽 트 사용 가능 / 사용 안 함
vo id x mb _ port _ u art _ r x _ enable (u int 8 _ t enable);
/ / 전송 완료 인터 럽 트 활성화 / 비 활 성 화
vo id x mb _ port _ u art _ tx _ enable (u int 8 _ t enable);
/ / 시스템 밀 리 초 카운 트 가져 오 기 (타 임 초 과 감지 용)
u int 32 _ t x mb _ port _ get _ ti ck (vo id);
/ / 임 계 영역 으로 들어가 기 (중 단 끄 기)
vo id x mb _ port _ enter _ critical (vo id);
/ / 임 계 영역 종료 (개 인 인터 럽 트)
vo id x mb _ port _ exit _ critical (vo id);
/ / RS 48 5 송 수 신 제어 (1 = 전송 , 0 = 수신)
vo id x mb _ port _ rs 48 5 _ dir (u int 8 _ t tx);
4. 1 S TM 32 마이 그레이 션 예
< code>// stm32_port.c
#include "stm32f10x.h"
#include "xtiny_modbus.h"
static volatile uint32_t sys_tick = 0;
// SysTick中断,1ms一次
void SysTick_Handler(void) {
sys_tick++;
}
void xmb_port_uart_init(uint32_t baudrate) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// TX: PA9 复用推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// RX: PA10 浮空输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// RS485方向控制: PA8
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitStruct.USART_BaudRate = baudrate;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStruct);
// 使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
USART_Cmd(USART1, ENABLE);
}
void xmb_port_uart_send_byte(uint8_t byte) {
USART_Send데이터(USART1, byte);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
void xmb_port_uart_rx_enable(uint8_t enable) {
if (enable) USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
else USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
}
void xmb_port_uart_tx_enable(uint8_t enable) {
if (enable) USART_ITConfig(USART1, USART_IT_TC, ENABLE);
else USART_ITConfig(USART1, USART_IT_TC, DISABLE);
}
uint32_t xmb_port_get_tick(void) {
return sys_tick;
}
void xmb_port_enter_critical(void) {
__disable_irq();
}
void xmb_port_exit_critical(void) {
__enable_irq();
}
void xmb_port_rs485_dir(uint8_t tx) {
if (tx) GPIO_SetBits(GPIOA, GPIO_Pin_8);
else GPIO_초기화Bits(GPIOA, GPIO_Pin_8);
}
// 串口中断服务程序
void USART1_IRQHandler(void) {
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
uint8_t byte = USART_Receive데이터(USART1);
xmb_uart_rx_isr(byte); // 交给协议栈处理
}
if (USART_GetITStatus(USART1, USART_IT_TC) != RESET) {
USART_지우기ITPendingBit(USART1, USART_IT_TC);
xmb_uart_tx_isr(); // 通知协议栈发送完成
}
}
五、从站模式完整示例
// slave_demo.c
#include "xtiny_modbus.h"
#include <stdint.h>
// 应用数据区(用户可直接读写)
uint8_t coils[XMB_COILS_NUM]; // Coil status
uint8_t inputs[XMB_INPUTS_NUM]; // 离散输入
uint16_t holdings[XMB_HOLDINGS_NUM]; // 保持寄存器
uint16_t input_regs[XMB_INPUT_REGS_NUM]; // 输入寄存器
int main(void) {
// 初始化系统时钟、GPIO等
SystemInit();
SysTick_Config(SystemCoreClock / 1000); // 1ms SysTick
// 初始化Modbusslave
xmb_slave_init(9600, XMB_SLAVE_ADDR);
// 注册数据区回调(或直接使用全局数组)
xmb_slave_set_coils(coils);
xmb_slave_set_inputs(inputs);
xmb_slave_set_holdings(holdings);
xmb_slave_set_input_regs(input_regs);
// 初始化一些数据
holdings[0] = 100; // temperature
holdings[1] = 50; // 湿度
while (1) {
// 主循环中调用协议栈处理
xmb_slave_poll();
// 用户应用代码
// 例如:读取传感器更新到input_regs
// input_regs[0] = read_adc();
// 更新线圈状态到实际输出
// for (i=0; i<8; i++) set_relay(i, coils[i]);
}
}
// 写线圈回调(可选,用于执行实际动作)
void xmb_callback_write_coil(uint16_t addr, uint8_t value) {
// 当主站写线圈时调用
// 例如:控制继电器
// set_relay(addr, value);
}
// 写寄存器回调(可选)
void xmb_callback_write_register(uint16_t addr, uint16_t value) {
// 当主站写保持寄存器时调用
// 例如:更新设定值
// if (addr == 0) set_temperature(value);
}
六、主站模式完整示例
// master_demo.c
#include "xtiny_modbus.h"
#include <stdio.h>
int main(void) {
uint8_t coils[8];
uint16_t regs[10];
int16_t rc;
SystemInit();
SysTick_Config(SystemCoreClock / 1000);
// 初始化Modbusmaster
xmb_master_init(9600);
while (1) {
// 读取从站1的8个线圈状态
rc = xmb_master_read_coils(1, 0, 8, coils);
if (rc == XMB_OK) {
printf("读取成功:");
for (int i = 0; i < 8; i++) printf("%d ", coils[i]);
printf("\n");
} else {
printf("Read failed,错误码:%d\n", rc);
}
// 读取从站1的10个保持寄存器
rc = xmb_master_read_holdings(1, 0, 10, regs);
if (rc == XMB_OK) {
printf("register:");
for (int i = 0; i < 10; i++) printf("%d ", regs[i]);
printf("\n");
}
// write single coil:控制第1路继电器吸合
rc = xmb_master_write_coil(1, 0, 1);
if (rc == XMB_OK) printf("写线圈成功\n");
// write single register
rc = xmb_master_write_register(1, 0, 1234);
if (rc == XMB_OK) printf("写寄存器成功\n");
// write multiple coils
uint8_t coil_vals[4] = {1, 0, 1, 0};
xmb_master_write_coils(1, 0, 4, coil_vals);
// write multiple registers
uint16_t reg_vals[3] = {100, 200, 300};
xmb_master_write_registers(1, 0, 3, reg_vals);
// 延时1秒
delay_ms(1000);
}
}
// 错误码说明
// XMB_OK = 0 成功
// XMB_ERR_TIMEOUT = -1 超时
// XMB_ERR_CRC = -2 CRC check오답
// XMB_ERR_EXCEPT = -3 从站异常响应
// XMB_ERR_ADDR = -4 地址不匹配
// XMB_ERR_BUSY = -5 总线忙
七、51单片机移植要点
- 缓冲区大小:51单片机RAM有限,建议将XMB_BUF_SIZE设为32
- number of registers:线圈和寄存器数量不宜过多,建议各16个
- 晶振选择:使用11.0592MHz晶振保证9600bps准确
- 中断优先级:串口中断优先级设为最高,避免丢字节
- 帧超时:51单片机无SysTick,可用定时器0实现1ms计时
- 变量存储:大数组定义为x데이터或i데이터,避免占用直接寻址区
- CRC表:CRC16查表法占用256字节ROM,51单片机可接受
7.1 51单片机定时器实现ms计时
// 51单片机1ms定时器(11.0592MHz)
static uint16_t xmb_tick = 0;
void timer0_init(void) {
TMOD |= 0x01; // 定时器0模式1
TH0 = 0xFC; // 1ms初值
TL0 = 0x67;
ET0 = 1; // 使能定时器0中断
TR0 = 1; // 启动定时器0
EA = 1;
}
void timer0_isr(void) interrupt 1 {
TH0 = 0xFC;
TL0 = 0x67;
xmb_tick++;
}
uint32_t xmb_port_get_tick(void) {
return xmb_tick;
}
八、common problems
- 通讯无响应:检查从站地址、Baud rate、校验位是否一致,A/B线是否接反
- CRC오답:确认晶振频率准确,串口配置正确,检查是否有干扰
- 只能收不能发:检查RS485方向控制引脚,ConfirmDE/RE接在一起
- 数据丢包:增大缓冲区,提高串口中断优先级,减少关中断时间
- 主站超时:增加超时时间,确认从站响应速度,检查总线负载
- 多从站冲突:确保每个从站地址唯一,总线两端接120Ω终端电阻
- 编译报错:确认配置宏定义正确,移植인터페이스全部实现
九、与其他Modbus协议栈对比
| 协议栈 | 代码体积 | RAM占用 | master | slave | 适用平台 |
|---|---|---|---|---|---|
| XTinyModbus | ~5KB | ~120B | 支持 | td> | |
| FreeModbus | |||||
| uModbus | |||||
| libmodbus | |||||
| mnModbus |
X T iny Mod bus 는 매우 적은 자원 소비 와 간 결 한 API 설계 로 51 MC U 와 같은 매우 제한 된 자 원을 가진 임 베 디 드 시스템에 특히 적합 합니다 . X T Mod iny bus 는 매우 작은 하드 웨어 에서 Mod bus 통신 을 구현 해야 하는 프로젝트에 이상 적입니다 .이 문서 에서 제공 되는 코 드는 프로젝트 개발 에 직접 사용할 수 있으며 실제 제품에 통합 하기 전에 테스트 보 드 에서 통신 을 검 증 하는 것이 좋습니다 .
Leave a Reply