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_SendData(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_ResetBits(GPIOA, GPIO_Pin_8);
}
// シリアルポート中断服务程序
void USART1_IRQHandler(void) {
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
uint8_t byte = USART_ReceiveData(USART1);
xmb_uart_rx_isr(byte); // 交给プロトコルスタック処理
}
if (USART_GetITStatus(USART1, USART_IT_TC) != RESET) {
USART_ClearITPendingBit(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 checkError
// 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计时
- 变量存储:大配列定义为xdata或idata,避免占用直接寻址区
- 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线是否接反
- CRCError:確認晶振频率准确,シリアルポート設定正确,チェックありますか?干渉
- 只能收不能发:チェック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