Имеется STM32F103 и стоит задача сделать устройство MODBUS slave
Реализовал так:
Создал структуру:
Код: Выделить всё
typedef struct {
uint8_t update; // флаг того что данные обновились
uint8_t rx_buffer_uart[256]; // буфер по максимальному размеру пакета MODBUS
uint8_t size; // размер принятных данных
} receive_data;Код: Выделить всё
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*)receive_data_slave.rx_buffer_uart, BUFFER_SIZE); // разрешить ожидание приёма пакета
Код: Выделить всё
while (1)
{
if (receive_data_slave.update == 1) // если данные обновились
{
uint8_t response[256] = {0}; // создать пустой массив для ответа
process_receive_slave(&receive_data_slave, &slave_hold_reg, &response); // передать в обработчик полученные данные, регистры для чтения/записи, указатель на массив для ответа
if (response[0] != 0) // если массив для ответа не пустой
while(HAL_UART_Transmit_DMA(&huart1, (uint8_t*)response, sizeof(response)) == HAL_BUSY); // отправить ответ
receive_data_slave.update = 0; // данные обработаны, снимаю флаг обновления
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*)receive_data_slave.rx_buffer_uart, BUFFER_SIZE); // разрешаю приём следующих данных
}
}Код: Выделить всё
void process_receive_slave (receive_data* data, uint16_t *reg, uint8_t *response)
{
if (data->rx_buffer_uart[0] != SLAVE_ADDRESS) // если данные не для нашего адреса - сразу выходим
return;
int crc;
crc = crc_chk(data->rx_buffer_uart, (data->size)-2);
if ((data->rx_buffer_uart[(data->size)-1] == (crc & 0xFF00) >> 8) && //проверка чек-суммы пакета
(data->rx_buffer_uart[(data->size)-2] == (crc & 0x00FF)))
{
uint16_t addr_reg, quantity;
addr_reg = ((data->rx_buffer_uart[2]) << 8) + (data->rx_buffer_uart[3]); // определение адреса регистра указанного в пакете
switch(data->rx_buffer_uart[1]) {
case 3: // если команда на чтение
quantity = ((data->rx_buffer_uart[4]) << 8) + (data->rx_buffer_uart[5]); // сколько запрошено регистров считать
response[0] = SLAVE_ADDRESS; // далее формирование ответа
response[1] = 0x03; // команда
response[2] = quantity * 2;
uint8_t i = 0;
uint8_t j = 3;
while(i < quantity)
{
response[j] = (reg[addr_reg-SLAVE_REG_START+i] & 0xFF00) >> 8;
j++;
response[j] = reg[addr_reg-SLAVE_REG_START+i] & 0x00FF;
j++;
i++;
}
crc = crc_chk(response, j);
response[j] = crc & 0x00FF;
j++;
response[j] = (crc & 0xFF00) >> 8;
break;
case 6: // если команда на запись
reg[addr_reg-SLAVE_REG_START] = ((data->rx_buffer_uart[4]) << 8) + (data->rx_buffer_uart[5]); // записать данные в регистр
for (int i=0; i < data->size; i++) // сформировать ответ - копия запроса
{
response[i] = data->rx_buffer_uart[i];
}
break;
default:
break;
}
}
}Но есть проблема, при попытке записи (командой 01 06 00 01 01 F4 D8 1D) (при этом чтение идёт всё также с периодом 100 мс) я иногда получаю ответ состоящий из всех нулей либо на команду записи, либо на команду чтения, следующую за командой записи.
Подскажите, пожалуйста, откуда берутся эти нули?
Ведь стоит защита от оправки пустого ответа и ожидание освобождения передатчика:
Код: Выделить всё
if (response[0] != 0)
while(HAL_UART_Transmit_DMA(&huart1, (uint8_t*)response, sizeof(response)) == HAL_BUSY);Заранее благодарю за помощь
