Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
0 / 0 / 1
Регистрация: 14.11.2012
Сообщений: 227
1

Прием по UART STM32F103

23.05.2019, 22:03. Просмотров 3684. Ответов 9
Метки нет (Все метки)

Здравствуйте. Тема заезженная, знаю- прием по ЮАРТу. Прежде чем сюда писать по изучал 3-4 статьи и темы на этом форуме, делал все по примерам и советам, но все равно ошибка почти везде типичная- хочу получить в терминальную программу то, что отправил, а получаю бред (приложил скрин). Строки и символы, прописанные в коде, получаю исправно. Пишу в IAR, терминалы- Realterm tcomu10 (результат везде один и тот же). Может кто-то сталкивался с подобным или заметит ошибку. А то вроде код проще некуда, а сдвинуться не могу. Заранее спасибо.
C
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
#include "misc.h"
#include <string.h>
#include <stdio.h>
 
unsigned  char RXc, t;
 
void usart_init(void)
{
    /* Enable USART1 and GPIOA clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
 
    /* NVIC Configuration */
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the USARTx Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
 
    /* Configure the GPIOs */
    GPIO_InitTypeDef GPIO_InitStructure;
 
    /* Configure USART1 Tx (PA.09) as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
    /* Configure USART1 Rx (PA.10) as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
    /* Configure the USART1 */
    USART_InitTypeDef USART_InitStructure;
 
    /* USART1 configuration ------------------------------------------------------*/
    /* USART1 configured as follow:
        - BaudRate = 115200 baud
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
        - USART Clock disabled
        - USART CPOL: Clock is active low
        - USART CPHA: Data is captured on the middle
        - USART LastBit: The clock pulse of the last data bit is not output to
            the SCLK pin
     */
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
 
    USART_Init(USART1, &USART_InitStructure);
 
    /* Enable USART1 */
    USART_Cmd(USART1, ENABLE);
 
    /* Enable the USART1 Receive interrupt: this interrupt is generated when the
        USART1 receive data register is not empty */
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
 
void USART1_IRQHandler(void)
{
    if ((USART1->SR & USART_FLAG_RXNE) != (u16)RESET)
    {
            t=1;
            RXc = USART_ReceiveData(USART1);       
    }
}
 
void USARTSend(unsigned char *pucBuffer)
{
    while (*pucBuffer)
    {
        USART_SendData(USART1, *pucBuffer++);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        {
        }
    }
}
 
 
int main(void)
{
    // Initialize USART
    usart_init();
    USARTSend(" Hello.\r\nUSART1 is ready.\r\n");
 
    while (1)
    {
      if (t==1)
      {t=0;
      USART_SendData(USART1, RXc);}
    }
 }
0
Миниатюры
Прием по UART STM32F103  
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.05.2019, 22:03
Ответы с готовыми решениями:

UART и STM32F103
Здравствуйте, уважаемые! Начал тут заниматься STM32, перейдя на него с AtMega. Возник вопрос - как...

STM32F103, проблема с UART на скорости 9600
Столкнулся с такой проблемой, плата с установленным STM32F103VBT по RS485 передает данные на...

STM32F103 + DMA + UART отправка данных с прерыванием
Всем доброго дня. Прошу помощи , а то уже сломал мозг. Нужно отправить данные через DMA1 USORT2 с...

STM32F103 I2C прием не определенного количества байт.
Здравствуйте. Тема I2C в STM32 вроде обсосана и может есть где ответ на мой вопрос, но не нашел...

9
Эксперт .NET
7078 / 4655 / 1114
Регистрация: 25.05.2015
Сообщений: 14,227
Записей в блоге: 14
24.05.2019, 06:19 2
Цитата Сообщение от Turgenev Посмотреть сообщение
хочу получить в терминальную программу то, что отправил, а получаю бред (приложил скрин). Строки и символы, прописанные в коде, получаю исправно
Так бред или всё-таки исправно?

Добавлено через 39 секунд
Осциллограф есть в доступности?
0
2671 / 1593 / 342
Регистрация: 09.09.2017
Сообщений: 6,516
24.05.2019, 08:52 3
Цитата Сообщение от Turgenev Посмотреть сообщение
RXc = USART_ReceiveData(USART1);
Переменные, используемые в прерывании и основном коде, стоит объявлять как volatile.
1
2671 / 1593 / 342
Регистрация: 09.09.2017
Сообщений: 6,516
24.05.2019, 09:03 4
Еще, сравнивая со своим кодом, не увидел у вас разрешения RCC_APB2ENR_AFIOEN.
.
Вдруг пригодится мой код для UART'ов на stm32f103 во вложении
C
1
2
3
4
5
6
#define USART 1 //номер UART'a (с ремапом не возился, так что только 1, 2, 3)
#define F_APB2 72000000 //частота APB2, поскольку UART1 тактируется оттуда. Если надо UART2, 3 - укажите F_APB1
#include "uart.h"
...
UART_init(USART, 115200);
UART_puts(USART, "\r\nUART test\r\n");
0
Вложения
Тип файла: txt uart.txt (7.9 Кб, 9 просмотров)
Тип файла: txt pinmacro.txt (2.2 Кб, 3 просмотров)
0 / 0 / 1
Регистрация: 14.11.2012
Сообщений: 227
24.05.2019, 23:49  [ТС] 5
Цитата Сообщение от Rius Посмотреть сообщение
Так бред или всё-таки исправно?
Получаю бред, когда хочу получить то, что сам отправил с терминала на компьютере.
Получаю исправно то, что зашил в МК и не отправляю сам.

Цитата Сообщение от Rius Посмотреть сообщение
Осциллограф есть в доступности?
На работе если только. Могу в понедельник отнести. Посмотреть в двоичном коде что отправляю и что принимаю осциллографом?

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Переменные, используемые в прерывании и основном коде, стоит объявлять как volatile.
Спасибо, учту и на всякий случай сделал- не помогло.

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Еще, сравнивая со своим кодом, не увидел у вас разрешения RCC_APB2ENR_AFIOEN.
Добавил строчку
C
1
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
после включения тактирования ЮАРТа и порта А- не помогло. В вашем коде пытаюсь разобраться...
0
834 / 509 / 167
Регистрация: 30.07.2015
Сообщений: 1,665
25.05.2019, 00:27 6
Turgenev, ну правильно, что получаете ерунду вы складываете принятый символ в переменную unsigned char, а в функцию отправки пишете указатель на unsigned char. Причем передаете туда вы все равно unsigned char, а не указатель я подозреваю что компилятор на это дело должен ругнуться хотя бы варнингом.
И далее вы пытаетесь применить метод который работает со строками, перебирает со стартового указателя до нуля:
C++
1
2
3
4
5
6
7
    while (*pucBuffer)
    {
        USART_SendData(USART1, *pucBuffer++);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        {
        }
    }
Но у вас то совсем не строка, а фиг пойми что по фиг пойми какому адресу, и совсем не обязательно что заканчивается нулем.
Если вы хотите простое эхо по одному символу, то исправьте функцию отправки на такую:
C++
1
2
3
4
5
6
7
void USARTSend(unsigned char c)
{
        USART_SendData(USART1, c);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        {
        }
    }
И все заработает.
Или же набирайте в буфер и отправляйте потом буфер.
1
834 / 509 / 167
Регистрация: 30.07.2015
Сообщений: 1,665
26.05.2019, 12:59 7
Turgenev, Мой косяк, не заметил что отправляете символ через стандартную функцию USART_SendData, а не через свою void USARTSend

Добавлено через 1 минуту
А отладчик, что говорит в прерывании? какой символ приходит?
0
0 / 0 / 1
Регистрация: 14.11.2012
Сообщений: 227
26.05.2019, 13:12  [ТС] 8
Цитата Сообщение от _SayHello Посмотреть сообщение
ну правильно, что получаете ерунду вы складываете принятый символ в переменную unsigned char, а...
C указателями у меня действительно путаница, но эхо у меня реализовано функцией из SPL библиотеки:
C
1
USART_SendData(USART1, RXc);
А функция с запутанными адресами, используется только для отправки одной "постоянной" строки и с ней проблем не было, ну кроме той, что никак въехать в эти указатели не могу:
C
1
USARTSend(" Hello.\r\nUSART1 is ready.\r\n");
То есть в процессе приема отправленного байта функция, в которой используются указатели не участвует.

Но проблему я решил. Настерегло, что у меня не нашли глупых ошибок в коде и спустя тучу часов борьбы с этой проблемой я наконец решил поменять юсб порт, контроллер, провода иии... преобразователь интерфейса. После замены последнего все заработало- есть 2 одинаковых преобразователя от 2х разных продавцов с АЛИ. Отличие только в том, что у одного на микросхеме есть маркировка, а другого нет. Угадайте, какой из них не рабочий?))

Но раз уж зашла тема про указатели. Будьте добры, разъясните один момент (статьи из интернета не помогли).
В примере на сайте avislab:
C
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
...
#define RX_BUF_SIZE 80
volatile char RX_BUF[RX_BUF_SIZE] = {'\0'};
volatile char RXc;
...
void USART1_IRQHandler(void)
{
...
  RXc = USART_ReceiveData(USART1);
  RX_BUF[RXi] = RXc;
...    
}
...
void USARTSend(const unsigned char *pucBuffer)
{
    while (*pucBuffer)
    {
        USART_SendData(USART1, *pucBuffer++);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        {
        }
    }
...
int main(void) {
...
USARTSend(RX_BUF);
...
}
Если начать собирать, то компилятор выдаст ошибку на строку USARTSend(RX_BUF):
Error[Pe167]: argument of type "char volatile *" is incompatible with parameter of type "unsigned char const *"

Если исправить тип указателя pucBuffer на тот же тип, что и у переменной, адрес которой берет pucBuffer в функции USARTSend:
C
1
void USARTSend(char volatile *pucBuffer)
То все нормально, кроме warning на строку RX_BUF[RXi] = RXc:
Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
Который исправляется изменением типа переменной RXc с volatile char на просто char.

Судя по тому, что это пример работы с ЮАРТом и в комментариях к этой статье ни у кого подобных ошибок не было, значит что-то я не понимаю, хоть и программа работает исправно после всех этих изменений. Не подскажете почему вылезает ошибка и как в этом случае правильно работать с указателем?
0
834 / 509 / 167
Регистрация: 30.07.2015
Сообщений: 1,665
26.05.2019, 13:35 9
Лучший ответ Сообщение было отмечено Turgenev как решение

Решение

Turgenev, volatile ключевое слово для компилятора, чтобы он не принимал никаких решений по поводу этой переменной самостоятельно и обязательно читать данную переменную перед использованием. В данной строке
C++
1
RX_BUF[RXi] = RXc;
Компилятор просто не может сам разобраться в порядке действий, так как ему самому думать запрещено, ведь массив это указатель и там еще прибавится операция разыменовывания и сложения.
Не всегда и не все надо помечать volatile.
К примеру попробуйте объявить так:
C++
1
2
char RX_BUF[RX_BUF_SIZE] = {'\0'};
volatile char RXc;
C++
1
2
3
4
5
6
7
8
9
10
void USARTSend(const char *pucBuffer)
{
    while (*pucBuffer)
    {
        USART_SendData(USART1, *pucBuffer++);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        {
        }
    }
}
Проверьте будут ли ошибки.

volatile переменные стоит использовать , когда они используются в обработчиках прерываний и при этом не используются в main
1
0 / 0 / 1
Регистрация: 14.11.2012
Сообщений: 227
26.05.2019, 21:12  [ТС] 10
Заработало, только у RXi еще volatile убрал. Спасибо большое.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.05.2019, 21:12

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

STM32F103 подключение через UART-RS485 счетчик Modbus RTU не отзывается
Электрически все подключается через UART2-&gt;конвертер-RS485-&gt;счетчик 1. Проверка счетчика через...

Не работает прием по UART
Отладочная плата stm32vlDyscovery. Контроллер не получает данные, прерывание не происходит при...

STM32F4xx + DMA + прием по UART
Добрый день. Возникла тут одна задачка, думаю вот как правильней будет её решить. Ситуация такая,...

Прием данных по UART с прерыванями
Всем привет! У меня проблема пи работе с UART. Если отправить данные в терминал получается...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.