Модуль modbus.h
Modbus RTU Master: holding-регистры
#include <modbus.h> предоставляет синхронный Modbus RTU Master для чтения и записи holding-регистров через порт Master контроллера. Для начала работы нужен успешный mbInit(). Вызовы ждут завершения транзакции и задерживают остальные callback планировщика C. Не используйте одновременно разных владельцев одного последовательного порта.
Параметры и коды результата
Параметры устройства: addr=1..248 по проверке текущей прошивки (для стандартных устройств используйте 1..247; 248 не является обычным адресом Modbus). Broadcast с адресом 0 этот C API не принимает. start — нулевой 16-битный адрес регистра, а не обозначение 40001: регистру 40001 обычно соответствует start=0, но адрес уточняйте в документации ведомого устройства.
values указывает на массив uint16_t минимум из count элементов. NULL запрещён. Требуется start + count <= 65536; переход за конец адресного пространства отклоняется.
Константы ответа:
- MB_ERR_OK = 0 — успех.
- MB_ERR_INIT = -1 — нет инициализации; -1 также возможен при остановке сценария и отказе mbInit().
- MB_ERR_PARAM_FUNC = -2 — параметры транзакции.
- MB_ERR_FORMAT_SEND = -3 — формат исходящего кадра.
- MB_ERR_TIMEOUT_SEND = -4 — тайм-аут передачи.
- MB_ERR_TIMEOUT_RECEIVE = -5 — тайм-аут ответа.
- MB_ERR_PDU_CRC = -6 — CRC ответа.
- MB_ERR_PDU_FORMAT = -7 — формат ответа.
- MB_ERR_PDU_ERR = -8 — исключение ведомого устройства.
mbInit() может возвращать собственный код низкоуровневой инициализации; этот список относится прежде всего к mbRead()/mbWrite(). Диагностика транзакций выводится в /txt?log.
mbInit
int mbInit(uint32_t baudrate, uint8_t databits, uint8_t stopbits, uint8_t parity, uint8_t answerDelay);
baudrate — от 1200 до 230400; databits — 8 или 9; stopbits — 1 или 2; parity — MB_PARITY_NONE (0), MB_PARITY_EVEN (1), MB_PARITY_ODD (2). Убедитесь в соответствии настройкам ведомого устройства; аппаратная интерпретация числа бит зависит от режима parity. answerDelay — дополнительная задержка в миллисекундах, которая на порту квантуется в тики по 750 мкс; отдельной проверки диапазона здесь нет. Для Master её влияние зависит от нижнего уровня, поэтому это не замена timeout чтения. Не используйте большие значения без проверки на своей прошивке: результат пересчёта хранится в uint8_t. Возвращает 0 при успехе. Инициализация сбрасывает счётчики успешных чтений/записей.
Ограничение нечётного parity
В текущем C-заголовке MB_PARITY_ODD равен 2, но драйвер USART APM32 использует значение 3 для нечётной чётности. Порт выполняет прямое приведение без преобразования, поэтому режим ODD сейчас не соответствует заявленному. Передать 3 через C API нельзя: проверка mbInit отклонит значение больше 2. До исправления порта не рассчитывайте на нечётную чётность; успешный mbInit сам по себе не подтверждает правильную конфигурацию ODD. Это установлено сверкой исходников, аппаратная проверка линии с parity не выполнялась.
mbRead
int mbRead(uint8_t addr, uint16_t start, uint16_t count, uint16_t * values, uint16_t timeout);
Читает holding-регистры функцией 0x03. timeout задаёт ожидание ответа в миллисекундах и допускается от 1 до 1000. В текущей конфигурации count от 1 до 125. Возвращает 0 либо отрицательный код; используйте результат массива только при успехе.
mbWrite
int mbWrite(uint8_t addr, uint16_t start, uint16_t count, uint16_t * values);
Записывает holding-регистры функцией 0x10. В текущей конфигурации count от 1 до 123. Отдельного аргумента timeout у C-функции нет: используется RECEIVING_TIMEOUT нижнего уровня, сейчас 500 мс. Адрес устройства передаётся явно. Возвращает 0 либо отрицательный код.
Пределы вычисляются из размера буфера прошивки: чтение min(125, (MB_BUFF_LEN-5)/2), запись min(123, (MB_BUFF_LEN-9)/2). Здесь MB_BUFF_LEN=255. Для чтения это максимум 250 байт данных, для записи — 246 байт. Большой прикладной массив разбивайте на несколько транзакций.
mbGetCountRead
uint32_t mbGetCountRead(void);
Возвращает uint32_t-счётчик только успешно завершённых операций соответствующего вида после последней инициализации. Ошибочные транзакции его не увеличивают. Новый C-сценарий должен заново вызвать mbInit().
mbGetCountWrite
uint32_t mbGetCountWrite(void);
Возвращает uint32_t-счётчик только успешно завершённых операций соответствующего вида после последней инициализации. Ошибочные транзакции его не увеличивают. Новый C-сценарий должен заново вызвать mbInit().
Пример
Пример перенастраивает порт Master и выполняет реальную транзакцию. Укажите параметры своего стенда.
#include <dev.h>
#include <modbus.h>
#include <stdio.h>
int main(void) {
if (mbInit(9600, 8, 1, MB_PARITY_NONE, 0) != 0) {return 1;}
uint16_t values[2];
int result = mbRead(1, 0, 2, values, 200);
if (result != MB_ERR_OK) {
printf("Modbus error: %d\n", result);
return 1;
}
printf("Registers: %u, %u\n", (unsigned int)values[0], (unsigned int)values[1]);
return 0;
}