Миландр

Ключевым подразделением нашей компании
является Центр Проектирования интегральных микросхем
Текущее время: 2020-мар-29 18:43

Часовой пояс: UTC+03:00




Начать новую тему  Ответить на тему  [ 17 сообщений ]  На страницу « 1 2
Автор Сообщение
 Заголовок сообщения: Re: Почему Keil "недоволен"?
СообщениеДобавлено: 2019-ноя-20 15:10 
Не в сети

Зарегистрирован: 2009-июл-21 14:13
Сообщения: 1454
Откуда: Тула
vladh писал(а):
Роман, а может Вы мне порекомендуете как сделать красиво. Дело в том, что у меня идет общение по модбас с ведущим. Все данные, которые я принимаю и отправляю хранятся в двухбайтовом массиве. А связь производится байтами. Так вот как лучше(проще) мне разделять двухбайтовую переменную на однобайтовые и как однобайтовые соединять в двухбайтовую?
Это зависит от задачи, т.е. для чего нужно разделять.
Например, если Вам нужно побайтно принять или передать данные из массива uint16_t buf[], то можно объявить указатель на байт и воспользоваться им:
extern uint16_t buf[]

void rx_data() {
  uint8_t *ptr = (uint8_t *)buf;
  ptr[0] = uart->dr;
}
в общем случае указатель может указывать не на первый элемент массива, что в протоколах обмена часто полезно:
  uint32_t *ptr = (uint32_t *) &buf[3];
ptr[0] // это байты с 3 по 6
ptr[1] // это байты с 7 по 10 
Подобным образом можно преобразовывать что угодно во что угодно (строку в число с плавающей точкой, например).

Если же Вам всегда нужно чтобы весь массив был представлен и байтами и словами (16 разрядными данными), можете воспользоваться структурами и объединениями:
union my_data_u {
  uint16_t word;
  struct byte {
    uint8_t low;
    uint8_t hi;
  };
};

union my_data_u buf1[BUF_SIZE];

typedef union my_data_u my_data_t;
my_data_t buf2[BUF_SIZE]; // то же самое 

buf1[i].byte.low = buf2[j].byte.hi; 
buf2[k].word = 12345;
С инициализацией, правда, в этом случае будет поинтереснее - зависит и от стандарта (Си/Си++), и от версии стандарта и от компилятора.

Так же, часто бывает полезно объявить структуру данных формата обмена (или несколько штук).
Для MODBUS напимер:
struct modbus_frame_s { // структура заголовка сообщения 
  uint8_t address;
  uint8_t function;
  uint8_t data[];
};

// на примере одной ф-ции чтения регистров
struct modbus_read_input_registers_request_s { // запрос на чтение 
  //uint16_t starting_address;  // так работать не будет, т.к. мобдас допотопный 
  //uint16_t quantity;         // и работает с "обратным" относительно "1986ве..." порядка байтов 
  uint8_t  start_adr_hi;
  uint8_t  start_adr_lo;
  uint8_t  quantity_hi;
  uint8_t  quantity_lo;
};

struct mb_rir_response_s { // ответ с данными
  uint8_t byte_count;
  uint16_t data[];          // а тут уж как договоритесь, бывает и "Сишный" порядок
};

struct mb_error_s { // ответ с ошибкой
  uint8_t exception_code;
};
Тогда Вы сможете удобно оперировать данными не задумываясь о том, как удобнее объявлять массив - в байтах или в словах...
uint8_t mb_buffer[256], mb_buf_len; // а принято объявлять в байтах ;)
enum { MY_MB_ADDRESS = 77 };
enum {
  ... ,
  MB_Read_Input_Registers = 0x04,
  MB_Write_Single_Register = 0x06,
  ...
};
uint16_t mb_calc_crc16(uint8_t data[], uint8_t data_size);

void mb_send(uint8_t func_code, uint8_t data[], uint8_t data_size)
{
  uint i;
  struct modbus_frame_s *frame = (struct modbus_frame_s *)mb_buffer;

  frame->address = MY_MB_ADDRESS;
  frame->function = func_code;
  for(i=0; i<data_size; ++i) {
    frame->data[i] = data[i];
  }
  // играем с указателем и записываем CRC после поля данных
  *( (uint16_t *) &mb_buffer[2+data_size]) = mb_calc_crc16(mb_buffer, 2+data_size);

  mb_buf_len = 2+data_size+2;
  uart_send(mb_buffer, mb_buf_len);
}

void mb_rir_req(uint16_t starting_address, uint16_t quantity)
{
  struct modbus_read_input_registers_request_s  req;

  req.start_adr_hi = starting_address>>8;
  req.start_adr_lo = starting_address;
  req.quantity_hi = quantity>>8;
  req.quantity_lo = quantity;

  mb_send(MB_Read_Input_Registers, (uint8_t *) &req,  sizeof(struct modbus_read_input_registers_request_s) );
}

main()
{
  ...
  mb_rir_req(1000, 33); // считать с адреса 1000  33 регистра ввода
  ...
  if(uart_modbus_recieve_finished) { // по таймауту приёма или ещё как...
    mb_rx_handler(); // в итоге будет вызвана ф-ция обработки принятых данных 
                   // process_input_register_data(uint16_t data)
                   // или ф-ция обработки исключения модбас
                   // mb_exception_handler( struct mb_error_s * e);
  }
  ...
}

void mb_rx_handler()
{
  struct modbus_frame_s *frame = (struct modbus_frame_s *)mb_buffer;

  if(frame->address != MY_MB_ADDRESS) return;
  if(mb_calc_crc16(mb_buffer, mb_buf_len) != 0) return;

  if(farme->func & 0x80) {
    mb_exception_handler( (struct mb_error_s *) frame->data );
    return;
  }

  switch(frame->func) {
    case MB_Read_Input_Registers:
      mb_rir_response( (struct mb_rir_response_s *) frame->data );
      break;
    case MB_Write_Single_Register:
      mb_wrs_response( (struct mb_wrs_response_s *) frame->data );
      break;
    default:
      // неподдерживаемая ф-ция...
  }
}

void mb_rir_response( struct mb_rir_response_s * resp )
{
  for(int i = 0; i < resp->byte_count/2; ++i) {
    process_input_register_data( resp->data[i] );
  }
}

PS: пока писал написали четыре ответа)))

_________________
сочувствующий…


Вернуться к началу
 Заголовок сообщения: Re: Почему Keil "недоволен"?
СообщениеДобавлено: 2019-ноя-25 10:10 
Не в сети

Зарегистрирован: 2017-авг-09 12:38
Сообщения: 147
Организация: НПФ "Авангард"
Всем большое спасибо за оказанную помощь.


Вернуться к началу
Показать сообщения за:  Поле сортировки  
Начать новую тему  Ответить на тему  [ 17 сообщений ]  На страницу « 1 2

Часовой пояс: UTC+03:00


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Перейти: 

Создано на основе phpBB® Forum Software © phpBB Limited
Русская поддержка phpBB