Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Параллельная работа на AVR(UART,ПЗУ,UART)  (Прочитано 17531 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
pokk
Помогающий

ru
Offline Offline

« : 24-06-2014 09:57 » 

Здравствуйте, в качестве изучения новых алгоритмов поставил себе такую задачу
На микроконтроллере AVR без использования прерываний сделать параллельную работу:
1) Передачи данных по UART в режиме запрос ответ. (примерно период опроса 1с)
2) запись в ПЗУ.
3) Выдавать по UART отладочную информацию (прохождения контрольных точек)

С первым и вторым пунктом проблем нету его уже реализовал почти в двух вариантах =))
с третьим соответственно загвоздка так как параллельно это с первым не как не сделаешь тут думаю  главное что бы всё передалось и не перепуталось (часть ответа часть отладочной информации)

В принципе приведённый код ниже будет работать, но мне не совсем нравится что те действия которые выполняются редко  типа контрольных точек будут непонятно когда отправляться.
Можно ли сделать это так что бы они отправлялись однозначно (не перепутались)  и по мере прохождения (ответ,точка1,точка2 )  ?


Код:
void main(void)
{
//Инициализация
resive=WAIT;
while(1){
//---------Передачи данных по UART------------------------------
// Приёмника в виде конечных автоматов у меня нету
//по этому пусть будет пока так
switch(resive){
case WAIT:{
if (!(UCSR1A & (1<<RXC1))==0){resive=SEND;} // Если что-то пришло (типа запрос)
break;
}
case SEND:{
temp=usart_sender_test(5,"13456");   // Отправляем ответ
if(temp==SEND_END){resive=WAIT;}// отправили все 5 байт ждём  приёма
break;
}
}
//---------Запись в ПЗУ-------------------------------
writer(5,"тест1");
//----------Контрольные точки--------------------------
//  time1,time2 эти переменные инкрементируются в таймере по 1 секунде

//if(time1==1){usart_sender_test(36,"контрольна точка 1(прошла 1 секунда)")} 
//if(time2==5){usart_sender_test(35,"контрольна точка 2(прошло 5 секунд)")}

// хотелось бы видеть это как выше но как сделать что бы оно входило туда где законило работу я не придумал.
switch(point){
case TIMEOUT:{
if(time1==1){point=send;}
break;
}
case SEND:{
temp=usart_sender_test(36,"контрольна точка 1(прошла 1 секунда)");
if(temp==SEND_END){
time=0;
point=TIMEOUT;
}
}
}
switch(point1){
case TIMEOUT:{
if(time1==5){point1=send;}
break;
}
case SEND:{
temp=usart_sender_test(35,"контрольна точка 2(прошло 5 секунд)");
if(temp==SEND_END){
time1=0;
point1=TIMEOUT;
}
}
}
}
}

unsigned char usart_sender_test(unsigned char len_send,unsigned char* usart_send_buffer){
  static unsigned char manager_usart=USART_INIT;
  static unsigned char index_usart;
  static unsigned char len;
  unsigned char counter=1;
  unsigned char temp=USART_ERR;
     
  while(counter){       
      switch(manager_usart){
        case USART_OFF:{break;}
        case USART_INIT:{
            len=len_send;
            manager_usart=USART_START;
            break;
        }
        case USART_START:{
                if(len!=0){
                    manager_usart=USART_FLAG;
                }
                else{
                    index_usart=0; 
                    manager_usart=USART_INIT;
                    Usart_resive=ON;
                    counter=0;
                    temp=SEND_END;               
                }   
            break;
        }
        case USART_FLAG:{
            if (!(UCSR1A & (1<<UDRE1))==0){
                // заходим суда если регистр UDR1 пуст и готов к передачи
                UDR1=usart_send_buffer[index_usart];
                len--;
                index_usart++;
                manager_usart=USART_START;               
            }else{
                counter=0; // выход из функции
                temp=WAIT_FLAG;
            }
            break;
        }       
      }
  }
  return temp;
}       
//-----------------------------------------------------------------------------



Блок схема функции usart_sender_test();


* Блок схема.png (23.95 Кб - загружено 2078 раз.)
Записан
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 24-06-2014 12:58 » 

А где здесь параллельная работа?
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
pokk
Помогающий

ru
Offline Offline

« Ответ #2 : 24-06-2014 13:26 » 

В место ожидания WAIT происходит выход из функции usart_sender_test  с параметром завершения передачи,в процессе либо в ошибке. В коде это отраженно а вот в блок схеме  нет.  Соответственно функция  writer(5,"тест1"); работает аналогичным образом только там проверяется другой флаг.
Записан
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 24-06-2014 14:46 » 

Цитата
На микроконтроллере AVR без использования прерываний сделать параллельную работу:
Как ты себе это мыслишь?

Если

Цитата
В место ожидания WAIT происходит выход из функции usart_sender_test  с параметром завершения передачи,в процессе либо в ошибке.

Ну... тут еще нужно перевести эту фразу
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 24-06-2014 18:28 » 

в качестве изучения новых алгоритмов поставил себе такую задачу

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

Цитата
На микроконтроллере AVR без использования прерываний сделать параллельную работу:
Как ты себе это мыслишь?

В принципе можно организовать кооперативную мультизадачность в виде взаимодействующих сопрограмм, одна из которых будет опрашивать бит готовности UART и при необходимости производить обмен данными. Но разделяю недоумение Sla: зачем это городить, если все уже заложено в аппаратуре (как только взведется бит готовности, подпрограмма обслуживания соответствующего прерывания выполнится автоматически с гораздо меньшими задержками). Нужна веская причина для такого выбора.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #5 : 25-06-2014 00:47 » 

Цитата
Не понял, какие конкретно алгоритмы изучаются в данном топике.
Те которые позволяют не "зависать"  на время ожидания флага или выдержки времени.
Изначально это я делал на условиях if  потом сделал на  case  а потом смотрю что это очень похожее на  Автоматное программирование.  
Цитата
В принципе можно организовать кооперативную мультизадачность в виде взаимодействующих сопрограмм,...
не в курсе что это  но уже читаю  https://forum.shelek.ru/index.php/topic,25760.0.html

Цитата
Нужна веская причина для такого выбора.
Что бы в дальнейшем можно было организовать параллельное выполнение кода там где нету прерываний.
К примеру программная реализация какого-либо протокола.  или подключение LCD дисплея. Вместо ожидания времени(флага) в цикле while()  можно продолжать работать.
 
Цитата
Ну... тут еще нужно перевести эту фразу
А что тут не понятно ?

первый вход в функцию usart_sender_test  сохранит что и откуда передавать  и изменит состояния с INIT на  START после в состоянии  START проверится длинна отправляемого массива если больше 0  то  перейдём в состоянии  WAIT   где проверится флаг готовности UART если он готов  то всё ок (байт сразу отправляется) если нет то выходим из функции и возвращаем  статус "В процессе передачи" после этого идём дальше по главному  циклу и выполняем   Запись в ПЗУ(таким же образом по этому он там не зависает на мили секунды)  и достаточно быстро возвращаемся обратно к первой функции usart_sender_test  после её вызова уже сразу попадаем в последнее состояние которое было  т.е  WAIT. Там опять опять опрашиваем флаг готовности UART и так до тех пор пока  UART не будет готов и  весь массив не отправится после этого переходим в состояние  INIT и готовые принимать новые данные.        
« Последнее редактирование: 25-06-2014 00:50 от pokk » Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 25-06-2014 06:17 » 

не в курсе что это  но уже читаю  https://forum.shelek.ru/index.php/topic,25760.0.html

Эта статья больше подходит для ознакомления с самой идеей сопрограмм, если раньше не доводилось с ними сталкиваться. Для практической работы, возможно, лучше почитать https://forum.shelek.ru/index.php/topic,26526.msg284766.html#msg284766

К примеру ... подключение LCD дисплея. Вместо ожидания времени(флага) в цикле while()  можно продолжать работать.

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

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #7 : 25-06-2014 09:07 » 

Цитата
Для практической работы, возможно, лучше почитать https://forum.shelek.ru/index.php/topic,26526.msg284766.html#msg284766
Пробовал работать с протококками но что-то не пошло.

В общем то что хотел сделал я примерно в следующем виде. в главном цикле крутится  SENDER где опрашивается буфер(очередь) на наличие данных.  когда нам надо что-то передать мы просто  ложем в этот буфер(добавляем в очередь) и  далее как дойдёт до  SENDER он и отправит.   
Записан
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 25-06-2014 09:07 » 

У... как все запущенно...

Тогда немного ликбеза
Рисовать ничего не буду, только на пальцах

Параллельность понимает работу нескольких процессов в своей области видимости  переменных, и независимости от других процессов.
Это как два человека копающих траншею. Вроде копают на одной земле, а на самом деле не зависят друг от друга.

На однопрцессорных системах это сделать невозможно.

Можно добиться "псевдопараллельности" Для этого и придуманы прерывания.
Т.е. создается некий пул процессов, который выполняется в заданные промежутки времени.
Управляет таким процессами - системный таймер, именно он задает приоритеты, тайминги, и выделяет процессорное время.

В твоем случае - возможно псевдопараллельность, или как ты назвал автоматное программирование.

Т.е. вход в процедуру обработки в зависимости от состояния автомата.

Итак
Основной цикл
   Процедура1 - область видимости переменных состояния
   Процедура2 - область видимости переменных состояний
Конец цикла.

Работа с внешними устройствами (uart) организована на системном (железном) уровне.
Нужно выдать данные и уйти на обработку основного цикла. При этом не обязательно проверять где-то готовность приемопередатчика.

Что такое Процедура с состояниями?

В твоем случае, ты сделал анализ Состояний кейсом, но могут быть и другие способы.
Могут быть переходы по адресу, например запоминается не состояние, а запоминается адрес следующего обработчика, который в свою очередь установит другое состояние (адрес)

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


зы... была у меня как-то задача, когда не хватало системных таймеров  формировать посылку для последовательной передачи...

Ну и была система с вычисляемым  приоритетом...

Т.е.
Выполнять в каждом цикле, каждый второй, каждый 7-й раз. 
Но тогда ПО писалось руками, было критично ко времени выполнения, каждая процедура выравнивалась по количеству машинных циклов. Не... больше такого не хочу...
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 25-06-2014 09:33 » new

Пробовал работать с протококками но что-то не пошло.

Про это тоже есть небольшая статья.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #10 : 01-07-2014 02:56 » 

...
Работа с внешними устройствами (uart) организована на системном (железном) уровне.
Нужно выдать данные и уйти на обработку основного цикла. При этом не обязательно проверять где-то готовность приемопередатчика.
...
Ага я так и сделал в выше сообщении написал.
Цитата
В общем то что хотел сделал я примерно в следующем виде. в главном цикле крутится  SENDER где опрашивается буфер(очередь) на наличие данных.  когда нам надо что-то передать мы просто  ложем в этот буфер(добавляем в очередь) и  далее как дойдёт до  SENDER он и отправит.   

Соответственно запись в ПЗУ сделал так же. А как сделать чтение из ПЗУ  аналогичным образом ?  Тут уже временным буфером не как не обойтись надо в каждой процедуре выделять состояние ожидание чтения и выходить из неё пока ПЗУ не готово ?
Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 01-07-2014 05:10 » 

Читать всегда проще, чем писать, особенно если синхронно. Есть же в datasheet примеры чтения из EEPROM от производителя:

Код: (Text) С
unsigned char EEPROM_read(unsigned int uiAddress)
{
  /* Wait for completion of previous write */
  while(EECR & (1<<EEPE));
  /* Set up address register */
  EEAR = uiAddress;
  /* Start eeprom read by writing EERE */
  EECR |= (1<<EERE);
  /* Return data from Data Register */
  return EEDR;
}
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
pokk
Помогающий

ru
Offline Offline

« Ответ #12 : 01-07-2014 07:57 » 

Естественно я имел ввиду без вот этого  "подвисания"   
Код:
while(EECR & (1<<EEPE));

Записан
Dale
Блюзмен
Модератор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #13 : 01-07-2014 08:19 » 

Если не хотите застревать в цикле ожидания, в случае неготовности устройства нужно просто передавать управление планировщику потоков. Как его реализовать - взять готовую RTOS, разбить задачу на протопотоки или написать собственноручно, - решать вам.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines