реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> stm32 uart rs485, описание прерывания на прием в буфер (и на передачу)
dimka2001
сообщение Apr 20 2012, 15:57
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 129
Регистрация: 6-11-05
Пользователь №: 10 508



ситуация такая, нужно написать прерывание на прием в буфер и в зависимости от значения первого байта в ответ отправить другой буфер (около 20 байт). ниже кусок прерывания для одного байта. как его переделать для буфера??? помогите!!!


Код
void USART1_IRQHandler(void)
{
    //Receive Data register not empty interrupt
      if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
   {
       rx=1;
       USART_ClearITPendingBit(USART1, USART_IT_RXNE);
       tmp=USART_ReceiveData (USART1);

   }
      //Transmission complete interrupt
      if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)
      {
          USART_ClearITPendingBit(USART1, USART_IT_TC);
          tx_end=1;
      }
Go to the top of the page
 
+Quote Post
ohmjke
сообщение Apr 21 2012, 10:11
Сообщение #2


Частый гость
**

Группа: Участник
Сообщений: 116
Регистрация: 27-01-10
Из: СПб
Пользователь №: 55 094



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

CODE
#define USART1_BUF_SIZE (64)
#define USART1_BUF_MASK (USART1_BUF_SIZE - 1)

typedef struct {
uint8_t buf [USART1_BUF_SIZE];
uint8_t in;
uint8_t out;
uint8_t count;
} usart1_buf_t;

volatile static usart1_buf_t usart1_rx, usart1_tx;

extern void usart1_putchar (uint8_t symb) {
if ((USART1->SR & USART_SR_TXE) && !usart1_tx.count) {
USART1->DR = symb;
} else if (usart1_tx.count < USART1_BUF_SIZE) {
usart1_tx.buf [usart1_tx.in++] = symb;
usart1_tx.count++;
usart1_tx.in &= USART1_BUF_MASK;
};
};

extern uint8_t usart1_getchar (void) {
uint8_t symb;
if (usart1_rx.count > 0) {
symb = usart1_rx.buf [usart1_rx.out++];
usart1_rx.count--;
usart1_rx.out &= USART1_BUF_MASK;
return symb;
};
return 0;
};

void USART1_IRQHandler (void) {
if (USART1->SR & USART_SR_TC) {
USART1->SR &= ~USART_SR_TC;
if (usart1_tx.count > 0) {
USART1->DR = usart1_tx.buf [usart1_tx.out++];
usart1_tx.count--;
usart1_tx.out &= USART1_BUF_MASK;
};
} else if (USART1->SR & USART_SR_RXNE) {
USART1->SR &= ~USART_SR_RXNE;
if (usart1_rx.count < USART1_BUF_SIZE) {
usart1_rx.buf [usart1_rx.in++] = USART1->DR;
usart1_rx.in &= USART1_BUF_MASK;
usart1_rx.count++;
};
};
};


Сообщение отредактировал ohmjke - Apr 21 2012, 10:15
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 21 2012, 11:08
Сообщение #3


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



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


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
ohmjke
сообщение Apr 21 2012, 11:16
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 116
Регистрация: 27-01-10
Из: СПб
Пользователь №: 55 094



Ну, вообще да, изначально было сделано для AVR.
А почему неразумно для 32-х битных МК? Насколько я знаю, CM3 нормально работает с невыровненными данными. В же чем тогда "неправильность"?
Go to the top of the page
 
+Quote Post
dimka2001
сообщение Apr 21 2012, 15:00
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 129
Регистрация: 6-11-05
Пользователь №: 10 508



Цитата(ohmjke @ Apr 21 2012, 13:11) *
Не уверен, что верно понял, что Вам нужно. Но я использую два кольцевых буфера, на прием и передачу.

CODE
#define USART1_BUF_SIZE (64)
#define USART1_BUF_MASK (USART1_BUF_SIZE - 1)

typedef struct {
uint8_t buf [USART1_BUF_SIZE];
uint8_t in;
uint8_t out;
uint8_t count;
} usart1_buf_t;

volatile static usart1_buf_t usart1_rx, usart1_tx;

extern void usart1_putchar (uint8_t symb) {
if ((USART1->SR & USART_SR_TXE) && !usart1_tx.count) {
USART1->DR = symb;
} else if (usart1_tx.count < USART1_BUF_SIZE) {
usart1_tx.buf [usart1_tx.in++] = symb;
usart1_tx.count++;
usart1_tx.in &= USART1_BUF_MASK;
};
};

extern uint8_t usart1_getchar (void) {
uint8_t symb;
if (usart1_rx.count > 0) {
symb = usart1_rx.buf [usart1_rx.out++];
usart1_rx.count--;
usart1_rx.out &= USART1_BUF_MASK;
return symb;
};
return 0;
};

void USART1_IRQHandler (void) {
if (USART1->SR & USART_SR_TC) {
USART1->SR &= ~USART_SR_TC;
if (usart1_tx.count > 0) {
USART1->DR = usart1_tx.buf [usart1_tx.out++];
usart1_tx.count--;
usart1_tx.out &= USART1_BUF_MASK;
};
} else if (USART1->SR & USART_SR_RXNE) {
USART1->SR &= ~USART_SR_RXNE;
if (usart1_rx.count < USART1_BUF_SIZE) {
usart1_rx.buf [usart1_rx.in++] = USART1->DR;
usart1_rx.in &= USART1_BUF_MASK;
usart1_rx.count++;
};
};
};



не понятно когда вызывается прерывание на передачу буфера (ну или как запустить передачу буфера) и зачем нужны функции extern void usart1_putchar (uint8_t symb) и extern uint8_t usart1_getchar (void) . прием осуществляется по прерыванию, т.е. каждый байт по прерыванию, я думал что нужно один байт принять по прерыванию а остальные по проверке флага...
Go to the top of the page
 
+Quote Post
ohmjke
сообщение Apr 21 2012, 15:06
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 116
Регистрация: 27-01-10
Из: СПб
Пользователь №: 55 094



Цитата(dimka2001 @ Apr 21 2012, 19:00) *
ну или как запустить передачу буфера

Вызывать в цикле функцию usart1_putchar(); Данные из Вашего буфера попадут в передающий кольцевой буфер, а затем уже передадутся по usart'y.
Данные принимаются без всяких функций, они складываются в приемный буфер, для этого нужен лишь обработчик прерывания по завершению приема. А вот usart1_getchar (); - чтение байта из приемного кольцевого буфера.
Go to the top of the page
 
+Quote Post
dimka2001
сообщение Apr 21 2012, 16:11
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 129
Регистрация: 6-11-05
Пользователь №: 10 508



Цитата(ohmjke @ Apr 21 2012, 18:06) *
Вызывать в цикле функцию usart1_putchar(); Данные из Вашего буфера попадут в передающий кольцевой буфер, а затем уже передадутся по usart'y.
Данные принимаются без всяких функций, они складываются в приемный буфер, для этого нужен лишь обработчик прерывания по завершению приема. А вот usart1_getchar (); - чтение байта из приемного кольцевого буфера.


не понятно в функции usart1_putchar() байт записывается в uart и в прерывании
if ((USART1->SR & USART_SR_TXE) && !usart1_tx.count) {
USART1->DR = symb;

и в прерывании
USART1->DR = usart1_tx.buf [usart1_tx.out++];

и что такое кольцевой буфер???
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Apr 21 2012, 16:33
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(dimka2001 @ Apr 21 2012, 19:11) *
не понятно в функции usart1_putchar() байт записывается в uart и в прерывании

Видимо, не в прерывании записывается первый байт посылки (при условии что буфер пуст и буфер USART также пустой).
Остальные байты пишутся по прерыванию освобождения буфера USART.

Цитата(dimka2001 @ Apr 21 2012, 19:11) *
и что такое кольцевой буфер???

Кольцевой буфер - стандартный прием ортанизации приёма/передачи и тп
Спросите гугла. Он знает.
Go to the top of the page
 
+Quote Post
ohmjke
сообщение Apr 21 2012, 16:39
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 116
Регистрация: 27-01-10
Из: СПб
Пользователь №: 55 094



Цитата(dimka2001 @ Apr 21 2012, 20:11) *
не понятно в функции usart1_putchar() байт записывается в uart
if ((USART1->SR & USART_SR_TXE) && !usart1_tx.count) {
USART1->DR = symb;

Это происходит лишь в том случае, если закончена передача предыдущего байта и данных в кольцевом передающем буфере нет. Т.е., это сделано для того, чтобы не использовать буфер без надобности - нет лишних операций.
Цитата(dimka2001 @ Apr 21 2012, 20:11) *
и в прерывании
USART1->DR = usart1_tx.buf [usart1_tx.out++];

Здесь же производится запись байта в регистр данных usart'a из буфера.
Про кольцевой буфер можно почитать здесь - http://microsin.ru/content/view/1098/44/
Go to the top of the page
 
+Quote Post
SSerge
сообщение Apr 21 2012, 18:34
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Идея правильная, а в реализации есть несколько неприятных ошибок.

Переменная usart1_tx.count модифицируется в двух местах: в функции usart1_putchar и в обработчике прерывания.
Аналогично и с usart1_rx.count, она также модифицируется в функции usart1_getchar и в обработчике прерывания.
А ведь прерывание может случится как раз между чтением этих переменных из памяти и записью в память изменённого значения. После этого значение счётчика будет неправильным и никакой volatile от этого не спасает.

Самое простое решение - запрещать прерывания в функциях usart1_putchar и usart1_getchar непосредственно перед модификацией счётчиков и разрешать сразу после.
Если отказаться от использования счётчиков, а оперировать только индексами буферов (или указателями в буфер) то можно обойтись без запрета/разрешения прерываний.

И ещё, прерывания от передатчика логичнее разрешить от флага TXE, он для этого и придуман.
Флаг ТС при работе черех RS-485 тоже понадобится, но только один раз на каждый пакет, он нужен чтобы узнать что передача последнего байта пакета закончилась и можно переключать драйвер RS-485 с передачи на приём.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
ohmjke
сообщение Apr 21 2012, 18:53
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 116
Регистрация: 27-01-10
Из: СПб
Пользователь №: 55 094



Мне пока что usart нужен лишь для того, чтобы посылать кое-какую инфу на комп во время отладки. С этой задачей данная реализация справляется без проблем.
Но за советы спасибо, возможно, когда-нибудь они и пригодятся.
И кстати, насчет модификации счетчиков - а что если применить bit-banding?
Go to the top of the page
 
+Quote Post
SSerge
сообщение Apr 21 2012, 19:28
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(ohmjke @ Apr 22 2012, 01:53) *
И кстати, насчет модификации счетчиков - а что если применить bit-banding?

а как? Через этот механизм можно только логические операции с битами производить, зато атомарно. Инкремент/декремент так не сделать.
С другой стороны, зачем вообще нужны эти счётчики, если работать с индексами массивов получается ничуть не хуже.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
ohmjke
сообщение Apr 21 2012, 19:59
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 116
Регистрация: 27-01-10
Из: СПб
Пользователь №: 55 094



Цитата(SSerge @ Apr 21 2012, 23:28) *
а как? Через этот механизм можно только логические операции с битами производить, зато атомарно. Инкремент/декремент так не сделать.
С другой стороны, зачем вообще нужны эти счётчики, если работать с индексами массивов получается ничуть не хуже.

Ой, да, чет я вообще тупость какую-то сморозил wacko.gif
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 22 2012, 03:04
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(SSerge @ Apr 22 2012, 01:28) *
С другой стороны, зачем вообще нужны эти счётчики, если работать с индексами массивов получается ничуть не хуже.

Чуть-чуть хуже - ёмкость буфера уменьшится на 1 элемент, станет == USART1_BUF_SIZE - 1 sm.gif
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 23 2012, 07:13
Сообщение #15


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(ohmjke @ Apr 21 2012, 14:16) *
Ну, вообще да, изначально было сделано для AVR.
А почему неразумно для 32-х битных МК? Насколько я знаю, CM3 нормально работает с невыровненными данными. В же чем тогда "неправильность"?

В скорости и количестве исполняемого кода.
Попробуйте заменить uint8_t на uint_fast8_t и посмотрите...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 16:33
Рейтинг@Mail.ru


Страница сгенерированна за 0.01507 секунд с 7
ELECTRONIX ©2004-2016