Перейти к содержанию

Отправка строки в UART в stm32f030


User_1

Рекомендуемые сообщения

23 минуты назад, snn_krs сказал:

Если довавить еще одну букву,

 

23 минуты назад, snn_krs сказал:

Чтение с 7-го байта вызовет ошибку.

Ну, вот, договорились до ручки! То есть, получается в слове "Hello" программа букву 'H' может прочитать, а следующую 'e' уже не может, потому что эта 'e' расположена по некратному адресу? :)

Процессор 32-битный, и все его регистры тоже 32-битные. Процессор читает из ППЗУ сразу 4 байта "Hell" в регистр, а потом уже начинает суетиться и разбивать прочитанное значение на байты и пользовать их по-байтно. Но эта внутренняя кухня уже не видна так очевидно.

А компилятор сам подровняет нужное число нулей в конце строки, чтобы следующее значение в ППЗУ начиналось с кратного 4-м адреса. Вон, не зря же в примере выше в конце "Hello World!" стоят аж 4 байта нулей, а не один только байт.

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Чем это SPL лучше HAL? и при чем тут Keil.

5 минут назад, Yurkin2015 сказал:

Процессор 32-битный, и все его регистры тоже 32-битные. Процессор читает из ППЗУ сразу 4 байта "Hell" в регистр, а потом уже начинает суетиться и разбивать прочитанное значение на байты и пользовать их по-байтно. Но эта внутренняя кухня уже не видна так очевидно.

Не пишите глупости

Товарищи при доступе к байтам ничего выравнивать не нужно, это ваши фантазии.

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

44 минуты назад, Yurkin2015 сказал:

А компилятор сам подровняет нужное число нулей в конце строки

Вот содержимое памяти когда передаю строку (Send_to_UART("Hello World!");):2018-09-21_21-17-48.png.7c0a3000b2a87a09293ca46f3e44703f.png

А вот содержимое памяти, когда передаю в функцию массив

(char hello[] = {"Hello World!"};

Send_to_UART(hello);):

2018-09-21_21-15-26.png.6c3bd37559a83ee5c8dde3f9866a4b52.png

Верхний вариант не работает, нижний - работает

Изменено пользователем User_1
Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Странные эти ф0...

7 минут назад, User_1 сказал:

Верхний вариант не работает,

Дописывать программно ноли , если сумма символов не делится на 4.

Вот примерно так:

if(Chr%4!=0)

{ for()...}

И т.д. 

Пишу с телефона , поэтому неудобно полностью написать.

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

12 часа назад, User_1 сказал:

Почему-то этот код работает: 

Проблема в использовании указателя в сыром виде (*string). В этом случае читается всё что начинается с адреса string, это может быть один байт - если он старший, и все 4 байта - если он окажется младшим. Вместо этого нужно читать явно: while( string[0] ),   data = string[0].

Второе: указатель принимает адрес константы, + этот адрес находится в параметре функции - операции c подобными переменными дурной тон. Необходимо создать новый указатель в самой функции, и менять его как хочется. Функция не должна менять внешний указатель в своём параметре. В противном случае повторное использование функции может дать весёлый результат.

Ссылка на комментарий
Поделиться на другие сайты

12 минуты назад, AVI-crak Home сказал:

В противном случае повторное использование функции может дать весёлый результат.

это разве что выдавать два раза одну и ту же строку подряд с максимальной оптимизацией. А так по идее ничего страшного и нет.

Ссылка на комментарий
Поделиться на другие сайты

.

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

	char data = 0;
	while(*string)
	{
		while(!(USART_GetFlagStatus(USART1, USART_FLAG_TXE)));
		data = *string;
		USART1->TDR = data;
		string++;
	}

Зачем тут ещё одна переменная (data) ? 
Достаточно :

	while(*string)
	{
		while(!(USART_GetFlagStatus(USART1, USART_FLAG_TXE)));
		USART1->TDR = *string++;
	}

И проблема, вероятнее всего, именно в этом.
Компилятор под переменную выделяет целый регистр, просто работает потом с отдельной его частью (байтом). И чтение целого регистра по невыровненному адресу (через указатель) вызывает системное исключение.
Хотя, могу ошибаться. Проверить свои мысли нет возможности.
 

8 часов назад, MasterElectric сказал:

А так по идее ничего страшного и нет.

Речь, скорее всего, шла о правиле хорошего тона.
Если функция не модифицирует данные по указателю-аргументу, он должен быть объявлен с квалификатором "const". Это нужно изначально "зарубать на носу". Ибо в дальнейшем могут повалиться ошибки при, например, попытке передачи в функцию указателя на константу. А человек, пишущий программу, будет в недоумении - с какого хера он меня материт за то, что я объявил объект константным и передаю его указатель в функцию, которая не должна менять мои данные, а просто куда-нибудь их выводить ...

Ссылка на комментарий
Поделиться на другие сайты

10 hours ago, MasterElectric said:

Все нормально работает

Можете показать как вы написали?

(это я же, только из дома)

У меня тоже всё работает, если использовать хал. Но хотелось бы сделать всё используя SPL

Ссылка на комментарий
Поделиться на другие сайты

CMSIS

// передаем 1 байт
void USART_RxReset(void)
{
  USART_Rx_Cnt = 0;
  USART1->CR1 |= USART_CR1_RE;
}

void USART_Transmit(USART_TypeDef *tUSART, uint8_t Data)
{
  while(!(tUSART->ISR & USART_ISR_TC));
  tUSART->TDR = Data;
}

// передаем буфер
void USART_TransmitBuff(USART_TypeDef *tUSART, uint8_t *tData, uint32_t tCnt)
{
  while(tCnt--) USART_Transmit(tUSART, *tData++);
  USART_Status &= ~(USART_STATUS_RXCMPL | USART_STATUS_RXERR);
  USART_RxReset();
}

void USART_TransmitString(USART_TypeDef *tUSART, const char *tData)
{
  while(*tData) USART_Transmit(tUSART, *tData++);
  USART_Status &= ~(USART_STATUS_RXCMPL | USART_STATUS_RXERR);
  USART_RxReset();
}

//*******************************************************************************
  USART_TxBuff[0] = 0;
  USART_TxBuff[1] = 1;
  USART_TxBuff[2] = 2;
  USART_TxBuff[3] = 3;
  USART_TxBuff[4] = 4;
  USART_TxBuff[5] = 5;

  USART_TransmitBuff(USART1, USART_TxBuff, 6);
  USART_TransmitString(USART1, "123456 ");
  USART_TransmitString(USART1, "123456789 ");
  USART_TransmitString(USART1, "12345 ");
  USART_TransmitString(USART1, "123 ");
  USART_TransmitString(USART1, "12 ");

без прерываний и ДМА, тупо в лоб. Позже сделаю нормально не работал особо с F0.
void Usart1_Init(void)
{
  RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
  RCC->APB2ENR |= RCC_APB2ENR_USART1EN;

  TGPIO::SetMode(PA2, (gpAlternateMode | gpSpeedHigh | gpAF1));
  TGPIO::SetMode(PA3, (gpAlternateMode | gpSpeedHigh | gpAF1));

  USART1->BRR =(APBCLK + BAUDRATE/2)/BAUDRATE;
  USART1->RTOR= 100;
  USART1->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE | USART_CR1_RTOIE;
  USART1->CR2 |= USART_CR2_RTOEN;

  USART1->CR1 |= USART_CR1_UE;

  USART_Status = 0;

  NVIC_SetPriority(USART1_IRQn, 0);
  NVIC_EnableIRQ(USART1_IRQn);
}
/* USART */
uint8_t    USART_RxBuff[40];
uint8_t    USART_TxBuff[40];
uint8_t    USART_Rx_Cnt;
uint8_t    USART_Tx_Cnt;
uint32_t   USART_Status;

#define    USART_STATUS_RXCMPL           (1 << 0)
#define    USART_STATUS_RXERR            (1 << 1)
#define    USART_STATUS_TXCMPL           (1 << 2)

а еще прием:

// прерывание от USART1
void USART1_IRQHandler(void)
{
  if(USART1->ISR & USART_ISR_RXNE)
  {// пришли данные по юарту
   if(USART_Rx_Cnt < sizeof(USART_RxBuff))
   {
	USART_RxBuff[USART_Rx_Cnt++] = USART1->RDR;
   }
   else
   {// переполнение буфера

   }
  }

  if(USART1->ISR & USART_ISR_RTOF)
  {
   USART1->CR1 &= ~USART_CR1_RE;
   USART_Status |= USART_STATUS_RXCMPL;
   USART1->ICR|=USART_ICR_RTOCF;
  }
}

потом  в общем цикле нужно опрашивать флаги юарта:

  while(1)
  {
   /* СОБЫТИЯ USART */
   if(USART_Status & USART_STATUS_RXCMPL)
   {// приняли пакет
    ...
    USART_Status &= ~USART_STATUS_RXCMPL;
   }


  }     
     

 

Изменено пользователем MasterElectric
Ссылка на комментарий
Поделиться на другие сайты

Интересно

Передача по сути точно так же реализована. В понедельник тупо скопирую и проверю. Спасибо)

 

Кстати, а почему все пишут отдельную функцию для передачи одного байта и из функции для передачи строки для каждого байта вызывают эту первую функцию? Это же медленнее

Ссылка на комментарий
Поделиться на другие сайты

6 часов назад, User_0 сказал:

Кстати, а почему все пишут отдельную функцию для передачи одного байта и из функции для передачи строки

Так удобнее и меньше занимает ресурсов , если эта функция часто вызывается .

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

Вот мой пример приема символов:

https://drive.google.com/file/d/14cOYggEWX-_MqzywETzumDk3S6Y3qVBe/view?usp=drivesdk

Есть пример где через калбэк функцию принимаются символы и загружаются в массив . Но там особого отличия нет.

Только что, artos5 сказал:

USART работает исключительно с DMA как на прием, так и на передачу.

На передачу оправдано , а на прием - не понятно как это использовать, там передается либо половина буфера либо целый , а у меня всегда размер буфера разный . И на передачу часто камень вешается , поэтому я использую через прерывания . 

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

Там где новая версия USART есть Receiver timeout, когда произошел останавливаем прием. ДМА настраиваем на макс. размер буфера если достигли все это переполнение. Там где нет  использую IDLE но там фиксированная длина в 1.5 символа иногда это слишком мало. В тех что постарше (F4) хочу попробовать сделать прием на 2 каналах ДМА. второй канал для таймера. Но зато все работает в фоне.

Ссылка на комментарий
Поделиться на другие сайты

В общем получить ассемблерный листинг прямо из CoIDE мне не удалось, однако, сравнивая получаемые в результате компиляции бинарники (приложил) увидел кое-какие отличия. Я сравнивал варианты когда в функцию передаю массив (вариант 1) и строку (вариант 2). Единственным существенным отличием оказалась команда по адресу 0х724. В варианте с массивом там была команда C4 0D 00 08, а в варианте со строкой - D1 0D 00 08. Что это за команды и что они делают я не знаю, но если в мк залить прошивку с передачей в функцию строки, а потом с помощью ST-Link Utility изменить один этот байт - мк оживает, отладка работает нормально, "Hello World!" передаётся. Выходит, проблема в компиляторе (у меня версия 5.4 2016q2) или в самом кококсе (у меня версия 1.7.8). Возможно, само ядро микроконтроллера некорректно обрабатывает эту команду.

Проект тоже приложил в архиве, если кому интересно - попробуйте. Вдруг у вас другая версия CoIDE при той же версии компилятора или наоборот.

 

Файлы в приложении:

В архиве сам проект

Array.bin - файл, полученный при компиляции версии, где в функцию передаётся массив

String.bin - файл, полученный при компиляции версии, где в функцию передаётся строка (непосредственно то, что выдаёт компилятор)

String_ok.bin - файл String.bin, но в нём я вручную заменил команду D1 0D 00 08 на C4 0D 00 08.

Каждый из этих файлов можно залить в мк и увидеть, что первый и третий работают, второй - нет. Так же легко увидеть, что второй и третий отличаются всего на один байт (как раз та команда). Юарт здесь настроен на скорость 19200

Напомню, проект для камня STM32F030F4P6

String_ok.bin

Array.bin

String.bin

STM32F030_USART.rar

Ссылка на комментарий
Поделиться на другие сайты

21 минуту назад, Oxford сказал:

в KEIL программировать надо

Keil стоит неоправданно дорого, а пользоваться пиратским софтом совесть не позволяет

давайте не будем разводить дискуссии на тему какая среда лучше

Ссылка на комментарий
Поделиться на другие сайты

2 минуты назад, Oxford сказал:

Ключ для F0/L0 бесплатно

Это первый коммерческий проект на F0, в основном использую F105 (там два модуля CAN) и присматриваюсь к F40х.

32кб хватит чтобы попробовать среду, для серьёзных проектов этого мало

Ссылка на комментарий
Поделиться на другие сайты

Ну KEIL деньги берет не просто так. Если нужен ключ для KEIL, могу активировать до проф версии.

Изменено пользователем Oxford
Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...