STM32 - отправляет нули в UART

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
aeroshin
Родился
Сообщения: 1
Зарегистрирован: Сб дек 03, 2022 20:20:38

STM32 - отправляет нули в UART

Сообщение aeroshin »

Всем добрый день!
Имеется 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;
		}
	}
}
Читаю 100 регистров разом с периодом 100 мс - всё ОК. (командой 01 03 00 01 00 64 15 E1)
Но есть проблема, при попытке записи (командой 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);
Ошибка возникает только при чтении с небольшим периодом или быстрой последовательной записи. Если редко читать и редко писать - ошибки не возникает

Заранее благодарю за помощь
Реклама
tonyk
Это не хвост, это антенна
Сообщения: 1309
Зарегистрирован: Вт ноя 19, 2019 06:10:18

Re: STM32 - отправляет нули в UART

Сообщение tonyk »

uint8_t rx_buffer_uart[256];
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*)receive_data_slave.rx_buffer_uart, BUFFER_SIZE);
Так не хорошо, или везде число, или- имя, что гораздо лучше.
uint8_t response[256] = {0}; // создать пустой массив для ответа
Зачем ещё один массив? Если не собираешься передавать пакеты из RTU-сегмента в TCP/UDP-сегмент, то достаточно одного массива.
while(HAL_UART_Transmit_DMA(&huart1, (uint8_t*)response, sizeof(response)) == HAL_BUSY);
То есть тупо стоим и жгём время, пока посылка не уйдёт? А ведь могли бы заниматься чем-то полезным.
crc = crc_chk(data->rx_buffer_uart, (data->size)-2);
Считай КС _всего_ пакета. В целом пакете она будет 0. Нет?

Я ХАЛом не пользуюсь, но не вижу управления направлением приёма-передачей у трансивера. Или Tx и Rx в физической линии разделены?
я иногда получаю ответ состоящий из всех нулей
В чём смотришь? Я пользовался Termit. Покажи весь ответ.
Реклама
Ответить

Вернуться в «ARM»