User_1

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

63 сообщения в этой теме

User_1    4

Всем привет!

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


void Send_to_UART(char* string)
{
	char data = 0;
	while(*string)
	{
		while(!(USART_GetFlagStatus(USART1, USART_FLAG_TXE)));
		data = *string;
		USART1->TDR = data;
		string++;
	}
	while(!(USART_GetFlagStatus(USART1, USART_FLAG_TXE)));
	USART_SendData(USART1, 0x0D);
	while(!(USART_GetFlagStatus(USART1, USART_FLAG_TXE)));
	USART_SendData(USART1, 0x0A);
	while(!(USART_GetFlagStatus(USART1, USART_FLAG_TC)));
}

char hello[13] = {'H','e','l','l','o',' ','W','o','r','l','d','!'};

int main (void)
{
	Init_Clock();
	Init_USART1();
	Send_to_UART(hello);
	while(1);
}

А если написать вот так:


int main (void)
{
	Init_Clock();
	Init_USART1();
	Send_to_UART("Hello World!");
	while(1);
}

то не просто не работает - микроконтролер зависает даже до входа в main().

В Си ведь, насколько я понимаю, строка - это тот же массив символов

Объясните, пожалуйста, что я делаю не так?

Камень stm32f030, среда CooCox CoIDE

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    290

Допиши , string*+=0;

В функции sendtouart()

И ещё что за непонятный цикл while() в конце?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
5 минут назад, artos5 сказал:

Допиши , string*+=0;

И ещё что за непонятный цикл while() в конце?

Не совсем понял: string*+=0 - Sintax error

Если написать *string+=0; - ничего не изменяется

while(); - просто бесконечный пустой цикл

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    290

Я щас скину рабочий пример , который работает на всех stm32

У меня пример для HAL
Но где то был и пример работы с регистрами напрямую , надо поискать.

void TFT_RS422_uart1(char *str) // display interface
{
	int x=0;
	str+=0;
  while(str[x])
  {
   x++;
  }	
if(x) HAL_UART_Transmit(&huart1,str,x,1000);
}

 

Вот нашел в закромах, работа с регистрами:

void Usart1_Send_symbol(uint8_t data) 
{
  while(!(USART1->SR & USART_SR_TC)); 
  USART1->DR = data; 
}


void Usart1_Send_String(char* str)
{
  uint8_t i=0;
  str+=0;
  while(str[i])
  {
    Usart1_Send_symbol(str[i]);
    i++;
  }
  Usart1_Send_symbol('\n');
  Usart1_Send_symbol('\r');
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
41 минуту назад, artos5 сказал:

Я щас скину рабочий пример

Переписал всё точно так же - и ничего не изменилось, если передать Send_to_UART(hello) - работает, а если Send_to_UART("hello") - зависает

Причём при компиляции ни ошибок ни предупреждений нет

str+=0 - это же просто прибавление нуля к указателю, какой смысл в этой операции?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    290

Ну так str+=0 , дописывает 0 , где он проверяется в цикле , если этого не сделать будет зависать как раз.

У меня два данных примера работают и не зависают.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
4 минуты назад, artos5 сказал:

Ну так str+=0 , дописывает 0 , где он проверяется в цикле , если этого не сделать будет зависать как раз.

Не совсем так, я в отладчике ставлю breakpoint перед вызовом функции Send_to_UART(), сразу после инициализации - но даже инициализация не выполняется, микроконтроллер сразу попадает вот сюда:


.size Reset_Handler, .-Reset_Handler

/**
 * @brief  This is the code that gets called when the processor receives an
 *         unexpected interrupt.  This simply enters an infinite loop, preserving
 *         the system state for examination by a debugger.
 *
 * @param  None
 * @retval : None
*/
    .section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
  b Infinite_Loop
  .size Default_Handler, .-Default_Handler

(скопировал с описанием, чтобы нагляднее было)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    290

Значит с инициализацией что то напутано  . Могу весь код скинуть , но он к f103

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
4 минуты назад, artos5 сказал:

Могу весь код скинуть , но он к f103

От него мало пользы, тут инициализация немного иначе выполняется

Но, странно, если просто массив передавать - всё же нормально работает. Пробовал на разных скоростях - всё работает без нареканий

 

Ладно, чуть позже попробую бинарники сравнить, может там что увижу. Интересно посмотреть как хранятся в памяти массив и эта строка (должно же быть одинаково?) 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 373
2 часа назад, User_1 сказал:

В Си ведь, насколько я понимаю, строка - это тот же массив символов

Объясните, пожалуйста, что я делаю не так?

ага.,

char hello[] = переменная, живет в ОЗУ

"Hello Word" = константа, живет ППЗУ

void Send_to_UART(char* string) = стучится в ОЗУ

или нет?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
29 минут назад, IMXO сказал:

void Send_to_UART(char* string) = стучится в ОЗУ

Насколько я понимаю (поправьте, если ошибаюсь), в функцию же должен передаваться указатель на адрес первого элемента массива(строки). В стм32 единое адресное пространство, должно быть без разницы

 

Поэкспериментировал и пришёл к интересному результату:

Если вызываю функцию вот так:  Send_to_UART("ABCDEF"); - мк зависает, как и было раньше

Но если вызвать её вот так:  Send_to_UART("ABCDEFG"); - всё нормально, строка передаётся. То есть любая строка содержащая больше шести символов.

Сравнивал полученные при компиляции бинарники (прикрепил бинарники с 6- и 7-символьной строкой) - разница только в самой строке, других отличий нет

ABCDEF.bin

ABCDEFG.bin

 

UPD

Интересно, что если написать как раньше   Send_to_UART("Hello World!"); - не работает, а если без пробела - работает

(пробел же в хексе 0x20, не 0х00)

Аналогично "ABCDEFG" работает, а "ABC DEFG" - нет

UPD2

Посмотрел отладчиком на примере строки без пробела - string хранит вполне правильный адрес во флеше. Считываю содержимое камня с помощью ST-Link Utility - этот адрес как раз соответствует началу массива, который я передал в функцию

Изменено пользователем User_1
Исправил очепятку

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    290
1 час назад, IMXO сказал:

void Send_to_UART(char* string) = стучится в ОЗУ

или нет?

Эта функция принимает строку , и не важно в ОЗУ она или ПЗУ . У меня и так и так работает и ничего не виснет .

Я как раз так и использую:

Send_to_UART("Test string");

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Yurkin2015    320
2 часа назад, IMXO сказал:

или нет?

У этих процессоров память ППЗУ и ОЗУ расположены в одном адресном пространстве. ППЗУ начинается с адреса 0х0000000, а ОЗУ начинается с адреса 0х20000000. Можно обращаться и читать любое место по любому адресу, без разницы.

Другое дело, как в программе добавлять 0 к строке, которая константа и прошита в ППЗУ навечно !?!

Да и не надо ничего добавлять, компилятор сам добавит 0 в конце строки-константы при компиляции и в ППЗУ эта строка будет уже с нулём на конце.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
35 минут назад, Yurkin2015 сказал:

компилятор сам добавит 0 в конце строки-константы при компиляции

Так и есть, вот он, ноль в конце строки

2018-09-21_17-00-22.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 373

и все таки попробуйте для константы сделать как положено:

void Send_to_UART(const char* string)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
6 минут назад, IMXO сказал:

и все таки попробуйте для константы сделать как положено:

void Send_to_UART(const char* string)

Это не для константы, const означает, что функция может читать данные, на которые указывает передаваемый ей указатель, но не может изменять их.

Пробовал, никакой разницы

Если в коде, с которым мк зависает, закомментировать вызов функции USART_Init() - мк не зависает (но юарт не работает, понятное дело). Инициализация простейшая, тут почти все значения по умолчанию:


	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	USART_InitTypeDef USART_InitStructure;

	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_Init(USART1, &USART_InitStructure);

	USART_Cmd(USART1, ENABLE);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    290

Соберите в кубе проект и примените мой первый пример , уверен что все заведется сразу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 419

интересно так. В функцию должен быть передан указатель на строку. Когда он передается (hello  неявно передается как указатель, ибо он массив) то все работает. А когда передается строка (а это далеко не указатель, даже не явно) то все виснет. И это от чего то вызывает удивление. Кмк надо просто вспомнить базовый Си, и не важно где именно хранится константа. Важно как она обьявлена и как передается. Возможно надо просто для строк написать перезагружаемую функцию с аргументом другого типа и все будет работать.

прототип должен выглядеть так

void Send_to_UART(const char message[]);

и все будет нормуль

а уже в самой функции передачи можно явно переопределить аргумент как (uint8_t*)message

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
snn_krs    46

Совсем недавно этот вопрос обсуждался в ветке "STM для чайников". В М0 в ПЗУ хранятся только не упакованные данные.

Поэтому если строка с конечным 0 кратна 4-м все работает. Если не кратна то ошибка доступа к памяти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 419

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
1 час назад, mail_robot сказал:

А когда передается строка (а это далеко не указатель, даже не явно) то все виснет

Просто насколько я понимаю, строка в Си - это тот же массив символов и когда я вот так передаю строку - передаётся указатель на первый элемент этого массива. Для строк определённой длины ((4xN)+3) работает же. Если дело в кратности длины строки четырём байтам - звучит убедительно

 

Всё несколько иначе: он не успевает ничего передать просто потому что даже инициализацию не проходит. То есть я ставлю breakpoint на самом входе в main(), даже до инициализации, включаю отладку - и он зависает не дойдя до этой точки. И, повторюсь: если передать "Hello World!" - ничего не работает, а если "HelloWorld!" (то есть без пробела) - всё работает, а содержимое памяти мк отличается ровно на один байт - как раз этот пробел (но дело не именно в пробеле, если написать Hello_World! или HelloWWorld! - тоже не работает)

 

В хале всё работает, но код ровно вдвое больше)

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
snn_krs    46

А я думаю это как раз тот случай. "HelloWorld!" + 0 = 12 символов и работает. Добавите еще 4 символа и снова будет работать.

На картинке выше видно, если слово из 4-х букв например "Hell",  то они располагаются в обратном порядке с 3-го по 0-й байт. Если довавить еще одну букву, то она будет не в 4-м а в 7-м байте.

Чтение ПЗУ возможно с 0-го, 4-го и т.д. адресов. Чтение с 7-го байта вызовет ошибку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
User_1    4
2 минуты назад, snn_krs сказал:

Чтение ПЗУ возможно с 0-го, 4-го и т.д. адресов. Чтение с 7-го байта вызовет ошибку

Спасибо)

А есть способ это обойти средствами SPL или вручную?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
artos5    290
2 минуты назад, User_1 сказал:

А есть способ это обойти

Программно дописывать ноли например чтобы сумма символов делилась на 4

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
LiVit    8

Охренеть.

Вот сейчас сотни человек юзающих KEIL и посылающих не просто helloworld-ы по UART, а что-то более осмысленное, да и зачастую генерящееся "на лету", смотрят на всё это с недоумением...

Граждане, завязывайте с кубами и кокосами.
Берите SPL, кейл и пишите. И всё будет работать. Я с кокоса, к примеру, спрыгнул после полугода использования, о чем не жалею.

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

Поделиться сообщением


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

Ваша публикация должна быть проверена модератором

Гость
Вы не авторизованы. Если у вас есть аккаунт, пожалуйста, войдите.
Ответить в тему...

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

  Разрешено не более 75 смайлов.

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

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

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

Загрузка...

  • Похожие публикации

    • Автор: DmitryDDDD
      Здравствуйте, имеется задача передачи данных от stm32 на ПК и от ПК в stm по UART. Имеется stm32f411e-disco, созданная программа на пк в Qt creator. UART передатчик - CH340. Программа для stm - Keil, настройка в cubeMX.
      Основные выдержки из кода Qt (mainwindow.cpp):
       
      C++ (Qt)Выделить код
      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
      // Настройка UART      serial = new QSerialPort(this);      serial->setPortName("com4");      serial->setBaudRate(QSerialPort::Baud115200);      serial->setDataBits(QSerialPort::Data8);      serial->setParity(QSerialPort::NoParity);      serial->setStopBits(QSerialPort::OneStop);      serial->setFlowControl(QSerialPort::NoFlowControl);      serial->open(QIODevice::ReadWrite);      /*serial->write("ok*");  */                                                          connect(serial, SIGNAL(readyRead()), this, SLOT(serialReceived()));   // Запись принятых даннх в текстовое окно void MainWindow::serialReceived() {     QByteArray ba;     ba=serial->readAll();     ui->label->setText(ba);     qDebug()<<ba; }   // Отправка "1" и "2" в зависимости от нажатой кнопки void MainWindow::on_pushButton_clicked() {   serial->write("1"); }   void MainWindow::on_pushButton_2_clicked() {   serial->write("2"); }
      Настроен UART на прием и передачу. При нажатии какой-либо кнопки по UART передаётся 1 или 2ка. Так же принятая информация отображается в текстовом окне label. При замыкании RX и TX у CH340 отправленная 1 или 2 тут же принимаются программой.

      Программный код для stm создан в CubeMX. Там подключено два UART, один на приём, другой на передачу (можно настроить один для работы в 2 направления).
      Основные выдержки из кода Keil (main.c):
      //Настройка UART
      serial = new QSerialPort(this);
      serial->setPortName("com4");
      serial->setBaudRate(QSerialPort::Baud115200);
      serial->setDataBits(QSerialPort::Data8);
      serial->setParity(QSerialPort::NoParity);
      serial->setStopBits(QSerialPort::OneStop);
      serial->setFlowControl(QSerialPort::NoFlowControl);
      serial->open(QIODevice::ReadWrite);
      /* serial->write("ok*"); */ // Transmiting "ок" to COM Port
      connect(serial, SIGNAL(readyRead()), this, SLOT(serialReceived()));
       
      // Отображение принятых данных в текстовом меню label
      void MainWindow::serialReceived()
      {
      QByteArray ba;
      ba=serial->readAll();
      ui->label->setText(ba);
      qDebug()<<ba;
      }
       
      // Отправка 1 или 2 в зависимости от нажатой кнопки
      void MainWindow::on_pushButton_clicked()
      {
      serial->write("1");
      }
       
      void MainWindow::on_pushButton_2_clicked()
      {
      serial->write("2");
      }
       
      Выдержки из кода в Keil (main.c):
       
      // Настройка UART
      static void MX_USART1_UART_Init(void)
      {
        huart1.Instance = USART1;
        huart1.Init.BaudRate = 115200;
        huart1.Init.WordLength = UART_WORDLENGTH_8B;
        huart1.Init.StopBits = UART_STOPBITS_1;
        huart1.Init.Parity = UART_PARITY_NONE;
        huart1.Init.Mode = UART_MODE_TX_RX;
        huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
        huart1.Init.OverSampling = UART_OVERSAMPLING_16;
        if (HAL_UART_Init(&huart1) != HAL_OK)
        {
          _Error_Handler(__FILE__, __LINE__);
        }
      }
      // 2 массива для принятия и отправки данных
        uint8_t strTX[1];
          uint8_t strRX[1];
      // Попытка сделать что-то адекватное
              int strTX = 1;
      while(1) {        
              HAL_UART_Transmit_IT(&huart2, (uint8_t*) strTX, 1);
            HAL_UART_Receive_IT(&huart2, (uint8_t*) strTX, 1);
      Код в keil явно кривой, в Qt вроде всё работает. Получается передать из stm в Qt, но из Qt в stm нет. 
      Нужно получить следующее: нажимаем в Qt одну из двух кнопок, отправляется в stm либо 1, либо 2 в зависимости от выбранной кнопки. Stm принимает, обрабатывает, если 1, то загорается один светодиод, если 2, то другой. Дальше stm отправляет обратно в Qt информацию о том, какой светодиод загорелся. 

      P.S: довольно далек от программирования, но стараюсь разобраться. Буду благодарен любой помощти, некоторые скриншоты прилагаю.



    • Автор: LiVit
      Приветствую, коллеги!
      Ситуация такая: есть серия устройств на STM32F030R8, на некоторых время от времени начинает греться микроконтроллер. 
      Вся логика работает, всё вроде в порядке, кроме потребления в 250мА. И перегретого корпуса микроконтроллера.
      В прошивке изначально отсутствовала инициализация неиспользуемых ног, кроме того, проц сначала старается завести внешний кварц, и только потом переходит на внутренний генератор.
      Нога BOOT0 притянута к земле напрямую, без резистора.
      На проце который уже начал перегреваться, я сделал инициализацию всех ног на вход, с подтяжкой ног к земле. Сразу завожу внутренний тактовый генератор.
      К сожалению, ему уже ничего не помогает, - даже будучи стертым, он жрет 200 мА. Как я понимаю, тут мои полномочия всё.
      Хотелось бы услышать от коллег, что именно могло вызвать такую странную неисправность проца? Может кто сталкивался? В Errata ничего подобного не нашел.
    • Гость Andrey-Docent
      Автор: Гость Andrey-Docent
      Всем привет! Планируется сделать на базе arduino устройство, ведущее обмен данными с переферийным устройством по интерфейсу rs-232 и также необходимо контролировать работу arduino с помощью компьютера тоже посредством интерфейса rs-232. Но у arduino только один такой порт. Первая мысль в связи с этим - сделать ещё один порт и вывести линии RX и TX на другие (например цифровые) ножки порта. Можно ли как-то это сделать? Нет ли готовых библиотек для этого (на данный момент не нашёл таковых в интернете)? Может есть ещё какой-нибудь обходной путь? Заранее спасибо.
    • Гость Максим
      Автор: Гость Максим
      Всем светлым и умным головам привет!

      Никак не могу найти информацию о данном прерывании TIM1_BRK_UP_TRG_COM.
      Вопрос 1: Что это за стек или система прерываний? 
      Вопрос 2: Когда будет вызываться обработчик прерывания TIM1_BRK_UP_TRG_COM_IRQHandler, если также есть обработчик прерывания TIM1_CC_IRQHandler?
      Вопрос 3: период переполнения таймера равен 100 мкс. Сколько раз будет вызываться обработчик прерывания TIM1_BRK_UP_TRG_COM_IRQHandler до обработчика прерывания TIM1_CC_IRQHandler? По логике вещей, предполагаю, что 100 раз?
      Заранее благодарен!

      Всем радости))
    • Автор: User_1
      Доброго времени суток!
      Вкратце: нужно после того, как я записал байт данных в SPI1->DR, отменить передачу этого байта и вместо него отправить 0х00
      Подробно: Смысл вот в чём: некий контроллер, с которым я пытаюсь наладить общение по SPI, запрашивает произвольный участок массива байт и считывает их сплошным потоком. Ну примерно как считывается микросхема EEPROM: задаёшь начальный адрес, а потом просто шлёшь сплошные 0xFF, а она сама инкрементирует адрес и прямо непрерывным потоком байт выдаёт содержимое памяти. Только тут в роли этой микросхемы мой stm32f030 и мне нужно следующий байт отправлять в SPI1->DR сразу после отправки предыдущего. Но когда поток заканчивается (а он каждый раз разной длины и длина эта заранее неизвестна), один байт остаётся не переданным и отправится первым при следующем запросе. А мне нужно, чтобы первым байтом всегда отправлялся 0х00
      Пином (ну то есть битом) NSS управляю программно, его выставление в единичку и снова в ноль, очевидно, не помогает вообще никак. Пока решил проблему так: деинициализирую модуль SPI и выключаю его тактирование, затем включаю тактирование и снова инициализирую. Работает, скорости хватает. Но должно же быть менее костыльное решение?)
      Может кто сталкивался с такой проблемой?
      Курение даташита, reference manual и результатов поиска в гугле, не особо помогло.