Асинхронная работа с I2C

Обсуждаем контроллеры компании Atmel.
Ответить
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Добрый день, в общем появилась идея перетащить больную часть периферии на I2C, это пара термодатчиков и расширитель порта к которому подключается LCD идикатор, кнопки и светодиоды. В принципе я уже это реализовал, но тут мне не нравится 2 вещи.
Асинхронность тут заключается в том что бы во время вывода символов на LCD, (через символ) происходила работа остальной периферии.

1) Переделывал из последовательного кода и во всех задержках (и ожидания флагов) сделал сохранение текущего состояния и выход(на КА) . Из за этого получилось, что для каждого опроса флага готовности, надо пройти несколько вложений функций. Для устранения этого недостатка, думаю применить Callback функции, но тут не понятно как сохранить модульность проекта.

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

PS: Применение Rtos и тд не предлагать.
Реклама
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

pokk писал(а):Применение Rtos и тд не предлагать.
А что тогда предлагать ? И что за "и тд" ? - всё остальное не предлагать ? :)
Как раз, таки, ОСью решатся Ваши проблемы на раз-два...
Реклама
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

И что за "и тд" ?
Другие разновидности ОС.
Как раз, таки, ОСью решатся Ваши проблемы на раз-два...
Как именно это там решается? Особенно меня интересует второй вопрос.
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

pokk писал(а):Как именно это там решается? Особенно меня интересует второй вопрос.
Распараллеливанием задач. Это касается и первого вопроса тоже.
Вам не хочется вызывать функцию и не из прерываний (из программного таймера), и не из главного цикла по флагу. Какие ещё пути Вы видите ? Я, например, их не вижу. Кроме геморного - возврат из прерывания не в ту точку, из которой туда пришли. Но Вы прекрасно понимаете, чем чреваты такие выкрутасы.
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Вам не хочется вызывать функцию и не из прерываний (из программного таймера), и не из главного цикла по флагу.
Не не из главного цикла пусть вызывается, я не хочу проверять флаг готовности этой функции с частотой главного цикла, если период вызова функции большой(секунды или минуты)
....Какие ещё пути Вы видите ?......
Пока подумываю в главном цикле сделать диспетчер который будет брать из очереди функции и запускать их.
А в прерывании они будут добавляться в буфер. Но с реализацией этого варианта, пока что темный лес.
Реклама
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

pokk писал(а):я не хочу проверять флаг готовности этой функции с частотой главного цикла, если период вызова функции большой(секунды или минуты)
Не вижу никаких проблем. Или проверка флага занимает много процессорного времени ?
pokk писал(а):Пока подумываю в главном цикле сделать диспетчер который будет брать из очереди функции и запускать их.
А в прерывании они будут добавляться в буфер. Но с реализацией этого варианта, пока что темный лес.
Вы изобретаете велосипед. Всё это уже реализовано, и называется это - ОСРВ.
Но, почему-то, Вы не хотите, чтобы Вам её предлагали... :dont_know:
Реклама
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Не вижу никаких проблем. Или проверка флага занимает много процессорного времени ?
Нет, но если по смотреть сколько "накопится" за период опроса будет прилично.
Но, почему-то, Вы не хотите, чтобы Вам её предлагали... :dont_know:
1) Начальство против.
2) Свой велосипед починить легче. :)
3) Свой велосипед доработать проще( реализовать 1-wire).
4) Ну и возможно ОСРВ избыточно, а тут всё под конкретную задачу.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

pokk писал(а):я не хочу проверять флаг готовности этой функции с частотой главного цикла
а чем вы собираетесь заниматься в главном цикле? он как бы для опроса всяких вещей подходит лучше всего...

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

только принципиально это не отличается от метода, который вам не нравится... но других я и придумать не могу :(
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

могу предложить вам сделать систему программных счетчиков: один таймер по прерыванию отслеживает массив счетчиков, уменьшает их и ставит соответствующий флаг, если какой-то счетчик обнулился. в главном цикле вы смотрите на эти флаги, и, как только появился соответствующий, выполняете нужную вам функцию и снова устанавливаете нужный счетчик...
Ну пока такое и использую одно прерывание всегда настроено на миллисекунды, и там все временные счетчики инкрементируются.
т.е. если опрос датчика делается раз в 2 секунды, вы ставите таймер на 2 секунды и только по его истечению вызываете функцию опроса датчика...
В смысле сделать один таймер перенастраиваемый? т.е под каждую новую задержку изменять период срабатывания таймера?
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

pokk писал(а):Нет, но если по смотреть сколько "накопится" за период опроса будет прилично.
Ну и пусть копиться, основной цикл для этого и существует, чтобы в нём выполнялось всё громозкое и низкоприоритетное.
pokk писал(а): 1) Начальство против.
2) Свой велосипед починить легче. :)
3) Свой велосипед доработать проще( реализовать 1-wire).
4) Ну и возможно ОСРВ избыточно, а тут всё под конкретную задачу.
1. А ему не без разницы ли, как Вы будете реализовывать задачу ?
2. Да, но он и ломаться будет чаще уже изобретённого и проверенного временем. Если второй будет вообще ломаться.
3. Не вижу никакой связи. 1-wire никак не относится к распараллеливанию задач.
4. Ошибочное мнение. А для Вашего случая, вообще, - наоборот.
Друг Кота
Аватара пользователя
Сообщения: 15672
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Первый подвох -
не закончив обмен (протокол предусматривает определенную последовательность команд-данных) с одним из устройств нельзя обратиться к другому - какая тут "асинхронность"-то?
А распределив по времени обращение к каждому из присутствующих на шине устройств и заморачиваться "распараллеливанием" не прийдется. "Попридержать" один (несколько) из процессов до завершения текущего обмена вполне можно.
8)
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Первый подвох -
не закончив обмен (протокол предусматривает определенную последовательность команд-данных) с одним из устройств нельзя обратиться к другому - какая тут "асинхронность"-то?
В первом же сообщении писал
Асинхронность тут заключается в том что бы во время вывода символов на LCD, (через символ) происходила работа остальной периферии.
Хотя да асинхронность тут слабая главное что бы I2c не мешало другой периферии, spi, usart и тд.

В принципе, я нашёл то что меня устраивает
http://www.avrfreaks.net/forum/i2c-state-machine
Осталось только разобраться как это работает.
Друг Кота
Аватара пользователя
Сообщения: 15672
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

И чего же в том сложного-то?
"диспетчер вывода" всего - у каждого абонента шины своя очередь и отметка о выполнении очередного шага.
Обычный LCD индикатор имеет свой контроллер, которому только соответствующие данные/команды пересылать надо (и возможность переключения полей отображения) - предзагрузка одной части, затем команда смены полей отображения (сдвиг) ежли уж очень охота быстро все заменить.
Ну уж если слишком припрет - использовать аппаратный модуль I2C самого МК - только и тогда распределение по времени делать прийдется для разных устройств.
Выигрыш по времени весьма сомнителен - ибо при каждой передаче команд/данных потребуется заголовочную часть с адресом устройства вводить вместо передачи массива в одном пакете и с одним заголовком.
:roll:
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Выигрыш по времени весьма сомнителен - ибо при каждой передаче команд/данных потребуется заголовочную часть с адресом устройства вводить вместо передачи массива в одном пакете и с одним заголовком.
Тут смысл переключения в том, что бы кнопки не тормозили пока на индикатор данные выводятся. Ну и остальную периферию опросить, хотя период срабатывания маленький, так что в основном кнопки.
Друг Кота
Аватара пользователя
Сообщения: 15672
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Это кнопки при выводе на индикатор - то "тормозят"? :))
Самая медленная обработка при динамической индикации на светодиодных матрицах - и то "выше крыши" по завпсу времени.
Чей-то в Вашем алгоритме "не то" делается...
:roll:
Родился
Сообщения: 11
Зарегистрирован: Пт янв 06, 2017 14:03:22

Сообщение kvadrats »

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

Код: Выделить всё

/*
 * minim.c
 *
 * Created: 01.03.2017 17:46:32
 *  Author: Администратор
 */ 


#include <avr/io.h>
#define CPU_F              8000000UL // 4МГц
#define SCL_F               400000UL  // 100кГц, 400кГц - максимум для twi
#define TW_START                    0x08
#define TW_MT_SLA_ACK               0x18
#define TW_MT_DATA_ACK              0x28
#define TW_REP_START                0x10
#define TW_MR_SLA_ACK               0x40
#define TW_MR_DATA_NACK             0x58  //Ведущий принял данные и не передал подтверждение

void twi_Init(void)
{
	TWBR = ( ( (CPU_F)/(SCL_F)-16 ) /2 ) ;
	TWSR = 0; //Очищаются биты TWPS0 и TWPS1
}

void start ()
{
	TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
	 if((TWSR & 0xF8) == TW_START)
	 {
		 PORTB|=(1<<0); //есть старт 
	 }
}

void ID_forread(unsigned char data)
{
	TWDR =data ;
	TWCR=(1<<TWINT)|(1<<TWEN);
	 while(!(TWCR & (1<<TWINT)));
	 if ((TWSR & 0xF8) == TW_MT_SLA_ACK)
	 {
		PORTB|=(1<<1); //есть ответ 
	 }
}

void transf_addr(unsigned char data)
{
	TWDR=(data);
	TWCR=(1<<TWINT)|(1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
	if((TWSR & 0xF8) == TW_MT_DATA_ACK)
	{
		PORTB|=(1<<2); //есть ответ
	}
}



void restart()
{
	TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
	/*Проверяем статус. Условие повтора начала передачи (0x10=TW_REP_START) должно подтвердиться*/
	if((TWSR & 0xF8) == TW_REP_START)
	{
		PORTB|=(1<<3);
	}
}

void prov_read_id(data)
{
	/*Записываем адрес ведомого (7 битов) и в конце бит чтения (1)*/
	//TWDR=0b1010’000’1;
	TWDR = data;
	
	//Отправляем..
	TWCR=(1<<TWINT)|(1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
	
	/*Проверяем, нашелся ли ведомый с адресом 1010’000 и готов ли он работать на чтение*/
	if((TWSR & 0xF8) == TW_MR_SLA_ACK)
	{
		PORTB|=(1<<4);
	}
	
}

unsigned char read()
{	unsigned char data;
	 TWCR=(1<<TWINT)|(1<<TWEN);
	 
	 //Ждем окончания приема..
	 while(!(TWCR & (1<<TWINT)));
	 
	 /*Проверяем статус. По протоколу, прием данных должен оканчиваться без подтверждения со стороны ведущего (TW_MR_DATA_NACK = 0x58)*/
	 if((TWSR & 0xF8) != TW_MR_DATA_NACK)
	 PORTB|=(1<<5);
	 data=TWDR;
	 
	 /*Устанавливаем условие завершения передачи данных (СТОП)*/
	 TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	 
	 //Ждем установки условия СТОП
	 while(TWCR & (1<<TWSTO));
	 return data;
}

int main(void)
{   
	DDRB=0xff;
	DDRD=0xff;
		twi_Init();
     start ();
	 ID_forread(0b11010110); //передаем адрес гироскопа с битом записи
	 transf_addr(0x0F); //записываем адрес регистра для чтения без инкремента 
	 //здесь мы записали адрес регистра для чтения, теперь переходим в режим чтения
	 restart();
	 prov_read_id(0b11010111);
	 PORTD=read();
	 PORTB|=(1<<6);
	while(1)
    {
        //TODO:: Please write your application code 
    }
}
Ответить

Вернуться в «AVR»