Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.54/79: Рейтинг темы: голосов - 79, средняя оценка - 4.54
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
1

Принцип работы с периферией на прерываниях.

14.08.2015, 07:31. Показов 15021. Ответов 39
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте. Attiny85, Atmel Studyo 6, язык C, Пинборд 2.

Мучаюсь с велосипедом. Переключаемый I2C\SPI на базе USI с тактированием от счетчика.

Тактирование от счетчика принципиально, а не по нужде.

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

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

И вот оно начинается — передаем или уже закончили, а дальше что делать, а что приняли, а ACK отдали, 2ой старт сделали уже или нет? а это вообще прием или передача?

Я пока написал 30-40% от задуманого, потратив 6 часов. В голове прикидывается, что это выльется в пару-тройку кейз функций и столько же фоновых процессов(можно сократить если еще раз в кейз кинуть). А так же с пару-тройку глобальных переменных не считая структуры с флагами.

Посмотрев на все это, я задался вопросом, может я что то делаю не так?
Этот вопрос я и адресую вам. Спасибо.

Код не выкладываю ибо там сейчас первичный бульон и врятли будет понятно.

Если вопрос сформулировать более кратко:

"Делая драйвер для периферии на прерываниях, знатные кейз функции, куча глобальных переменных с флаговыми автоматами и шлфоновыми процессами, это нормально?"

Всегда старался их избегать, а тут сразу и много..
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
14.08.2015, 07:31
Ответы с готовыми решениями:

Cобытийность. Принцип использования и принцип работы событий в jQ и GCT
Добрый день. Подготавливаюсь к собеседованию по чеклисту и не могу найти ответ на вопрос:...

Принцип работы
Можете объяснить подробно как работает программа. 1 var n,m,x,y: integer; r: real; begin ...

Принцип работы
Я нашёл программу очень похожую на ту которая мне нужна. Прошу объяснить принцип её работы кому...

Принцип работы ОУ в DC-DC
Подскажите как работает нижний по схеме ОУ. А то не как не пойму. Светодиоды по моему вообще...

39
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
15.08.2015, 23:08 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от RiosomX
...
Модульность программы.
Конечные автоматы вам в помощь. Иначе никак.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
15.08.2015, 23:15 22
Цитата Сообщение от dymyurk1978
Цитата Сообщение от RiosomX
...
Модульность программы.
Конечные автоматы вам в помощь. Иначе никак.

Дак, в правильном направлении я двигаюсь? Конечные автоматы у меня и так в ней процветают, хотя и по минимуму, боюсь их обилия.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
15.08.2015, 23:19 23
Конечных автоматов не нужно бояться. Дело не в кол-ве, а в целесообразности применения в том или ином случае. Вообще советую, сесть, самому себе составить ТЗ. И писать, рисовать на бумажке то, что ты хотел бы получить. Когда ты четко составишь ТЗ и изложишь на буниге, тебе останется только лишь писать код по бумажкам.
0
0 / 0 / 0
Регистрация: 28.01.2012
Сообщений: 499
15.08.2015, 23:33 24
Цитата Сообщение от RiosomX
А это я и не писал.
Это выше писал vt340, я его и процитировал относительно моего вопроса.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
16.08.2015, 02:04 25
Вообщем так ничего и не придумал, кроме как разветвить функцию на синхронный и асинхронный режим.

Так как посоветовали начать с API, с него и начал писать.

Вот код, посоветуйте по его оптимизации и его грамотности, буду очень благодарен.

Инициализация переменных
Код
// Internal USI Structure defymitions
#define ACK      1
#define NoACK   0
#define REC      1
#define NoREC   0

// Internal USI Structure initiotyzotion
struct cl_intUSI
{
byte FlagACK:1;
byte FlagREC:1;
byte Step;
byte DataCounter;
voidFuncVector NextAction;
} intUSI = {ACK};

// External USI Structure defymitions
#define Frii      0x00
#define INT_Awoyt   0x01
#define I2C_Busy   0x02
#define SPI_Busy   0x03
#define DataReady   0x04

// External USI Structure initiotyzotion
struct cl_extUSI
{
byte BusStatus;
byte IC_Address;
byte CELL_Address;
voidFuncVector AfterExchange;
byte Data[MaxData];
} extUSI = {Frii};
Главная функция
Код
#define I2C_WRITE   0x00
#define I2C_READ   0x01
#define I2C_WRITE_A   0x02
#define I2C_READ_A   0x03
#define SPI_READ   0x04
#define SPI_WRITE   0x05

void usi(byte Mode, byte IC_Address, byte CELL_Address)//Функция
{
if((extUSI.BusStatus!=Frii)&(Mode<I2C_READ))      //Если шина занята и возможен асинхорнный режим .
{                                       //Становимся в очередь
//usiQueue(); Заглушка                     //
}                                       //
else
{
do                                    //Если асинхронный режим не возможен, то в
{                                    //бесконечном цикле ждем освобождения шины.
}                                    //
while(extUSI.BusStatus!=Frii);               //

switch(Mode)
{
case I2C_READ:
case I2C_WRITE:
case I2C_READ_A:
case I2C_WRITE_A:
extUSI.BusStatus = I2C_Busy;               //Занимаем шину
IC_Address = (IC_Address<1)|(0b00000001&Mode);   //Скрещиваем 128 байтовый адрес с RW получаем 1ый пакет для вызова ИС.
extUSI.IC_Address = IC_Address;               //
extUSI.CELL_Address = CELL_Address;
USIControl = I2C_Mode|CLK_Mode;               //Инициализация USI

if(Mode<I2C_READ)                        //Если синхронный режим
{
I2C_SyncOperations();
}

briok;

case SPI_READ:
briok;
case SPI_WRITE:
briok;
}
}

}
Функция регистрация данных для передачи
Код
void usiDataToSend(byte Data)
{
for(byte Counter = (intUSI.DataCounter-1); Counter--; Counter != 0xFF)   //Сдвиг массива вправо и запись байта в 0й индекс.
{
extUSI.Data[intUSI.DataCounter] = extUSI.Data[Counter];
}
extUSI.Data[0] = Data;
intUSI.DataCounter++;
}
По поводу регистрации данных, сначала думал сделать какую нибудь дикость с приведением типов, а потом подумал, а нахрена оно надо? Легче разбивать в цикле там где надо и регистрировать по байтам.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
16.08.2015, 02:27 26
Цитата Сообщение от RiosomX
...
В код вникать не стал, так как мне неизвестно ваше ТЗ. Состояния лучше определять enum-ом. Меньше ошибок в дальнейшем.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
16.08.2015, 04:36 27
Цитата Сообщение от dymyurk1978
Цитата Сообщение от RiosomX
...
Состояния лучше определять enum-ом. Меньше ошибок в дальнейшем.

Изучил. Крутая штука, если бы GCC выдавал хотя бы ворнинги.

Как он от ошибок спасти может?

Цитата Сообщение от dymyurk1978
В код вникать не стал, так как мне неизвестно ваше ТЗ
А я бы был рад, пытаюсь максимально наглядно писать. =\

А ТЗ у меня - навелосипедить драйвер USI с динамическим переключением между I2C и SPI, тактируемый от TC0 и по возможности максимально использующий прерывания.

Тем самым приобрести опыт и знание работы с периферией на прерываниях.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
20.08.2015, 02:39 28
В софте заработало. Но сожрало это чудовище 1кб ПЗУ и 50б ОЗУ, и это без реализации SPI и микрух с 2 байтовым адресом. Но выполнялось относительно быстро лол.

Кончено это супер быдлокод и можно пожать даже моими усилиями. Но даже 500б на обслуживание интерфейса это многовато для микросхемы с ПЗУ в 2кб.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
22.08.2015, 05:01 29
Чтобы не забивать форум, спрошу здесь.

Решил я сделать I2C по гайду.

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

Где в 7 строке получается гарантированное замкание SCL на питание.
Код
// Генерируем состояние Старт (или ПовСтарт)
sbi(sdaport,sda);         // на всякий случай выставляем в исходное состояние sda
sbi(sclport,scl);         // тоже с SCL
cbi(sclportd,scl);         // ВАЖНО!!! отключаем SCL от выходного буфера интерфейса
USISR = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0x0<<USICNT0);    //сбрасываем USISR
cbi(sdaport,sda);         // переводим  SDA в 0 пока SCL в 1
dummyloop(USI_DELAY);         // тупим нашу задержку
sbi(sclportd,scl);         // ВАЖНО!!! подключаем SCL обратно к выходному буферу интерфейса
cbi(sclport,scl);          // переводим SCL в 0
sbi(sdaport,sda);          // освобождаем линию SDA для последующей передачи/приема данных
dummyloop(USI_DELAY);          // еще раз тупим задержку
Помня статью DI
Ни в коем случае нельзя переключать вывод микроконтроллера в OUT и дергать ногу на +5. Можно запросто словить КЗ и пожечь либо контроллер либо какой-нибудь девайс на шине. Мало ли кто там линию придавит.
Я обеспокоился сием обстоятельством. Выразил обеспокоенность в коментах. И сделал по своему. Ведь старт можно сгенерировать оперируя лишь DDRами.
И сделал.
Код
      DDRB &= ~(_BV(PB2));
DDRB &= ~(_BV(PB0));

_delay_ms(1);
DDRB |= _BV(PB0);

_delay_ms(1);
USISR |= 0b11110000;   // Flag drop/counter clear mask
DDRB |= _BV(PB2);
_delay_ms(1);
Все бы хорошо. В протеусе Старт\стоп отрабатывались на ура. SCL был, хороший такой. Ток данные из USIDR не вываливались, регистр не сдвигался, SDA висела в 0.
Если тактировать от ТС0, то USIDR сдвигался, но данных один фиг на SDA не было.
А в режиме SPI все работало! Я даже думал забить и сделать на основе SPI всю канитель...

Как то так (отправка 0xAA)
https://www.cyberforum.ru/savedimages/2015/08/22/jxkjfvgbgnjgz7epwgux.jpg

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

Проблема оказалась в том, что я не оперировал регистром PORT. И если в SDA PORT записать единицу, то все фурычит на ура. ПРИ ЭТОМ линяя SCL и режим SPI этого совершенно не требуют.

Добавил в код
Код
      DDRB &= ~(_BV(PB2));
DDRB &= ~(_BV(PB0));

_delay_ms(1);
DDRB |= _BV(PB0);

_delay_ms(1);
USISR |= 0b11110000;   // Flag drop/counter clear mask
DDRB |= _BV(PB2);
_delay_ms(1);

>>>>>>>>>PORTB |= _BV(PB0);<<<<<<<<<<<
И получилось (отправка 0xAA)
https://www.cyberforum.ru/savedimages/2015/08/22/fxuxvbaggmz8xvevmg.jpg

Я не нашел упоминания об этом ни в даташите, ни в статьях-гайдах.

В статье выше это даже косвенно опровергалось в коментах.
Сорри, опечатался. И в статье тоже. Не может быть выхода с подтяжкой…
Вобщем для включения выходного драйвера сигналов SCL и SDA надо установить соответствующий бит регистра DDRх в 1. Выдача сигнала в соответствующий бит регистра PORTх нужна для того, чтобы линия находилась в исходном состоянии (т.е. в 1).
Я что то не понимаю, что я сделал не так, что привело к этой проблеме? И где я что то упустил?
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
22.08.2015, 05:15 30
Пины для SPI (выходы) работают в режиме двухтактный выход. То есть DDRx = 1. На выход. PORTx рулим.
I2C - монтажное и. Подключение по схеме с открытым коллектором-стоком. У AVR этот режим работает при PORTx = 0. Рулим DDRx. В этом случае при PORTx = 0 и DDRx = 1 открыт нижний транзистор. То есть низкий уровень. При PORTx = 0 и DDRx = 0 пин висит в воздухе, а за счет резистора осуществляется подтяжка к + Uпит. То есть высокий уровень.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
22.08.2015, 05:23 31
Цитата Сообщение от dymyurk1978
Пины для SPI (выходы) работают в режиме двухтактный выход. То есть DDRx = 1. На выход. PORTx рулим.
I2C - монтажное и. Подключение по схеме с открытым коллектором-стоком. У AVR этот режим работает при PORTx = 0. Рулим DDRx. В этом случае при PORTx = 0 и DDRx = 1 открыт нижний транзистор. То есть низкий уровень. При PORTx = 0 и DDRx = 0 пин висит в воздухе, а за счет резистора осуществляется подтяжка к + Uпит. То есть высокий уровень.
Спасибо за ответ в столь поздний час!

Я и пытался сделать как вы сейчас описали.
Но пока в PORTx SDA не запишешь единицу, USI толкать байты в него не будет. Как только это случается SDA становится равен 7му биту USIDR.

Вот 2 строчки для Tiny85
Код
#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>

void usiI2C()   // Init USI like I2C wyth software clock
{
USICR = 0b00101010;      // I2C/Soft clock mask
}

inline void usiI2C_Start()
{
DDRB &= ~(_BV(PB2));
DDRB &= ~(_BV(PB0));

_delay_ms(1);
DDRB |= _BV(PB0);

_delay_ms(1);
USISR |= 0b11110000;   // Flag drop/counter clear mask
DDRB |= _BV(PB2);
_delay_ms(1);

//PORTB |= _BV(PB0); << пока не раскоментишь не заработает.

}

int main(void)
{

_delay_ms(10);
usiI2C();
usiI2C_Start();
USIDR = 0b10101010;
_delay_ms(1);

for(int A = 0; A < 8; A++)
{
USICR |= _BV(USITC);
_delay_ms(1);
USICR |= _BV(USITC);
_delay_ms(1);
}

while(1)
{
volatile int A;
A++;
}
}
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
22.08.2015, 05:34 32
Наконец то нашел, что я упустил в даташите... успокоился. Могли бы и выделить.

Смешно то, что по даташиту без единицы в PORTx, SCL то же не должна работать... но работает.


https://www.cyberforum.ru/savedimages/2015/08/22/wmttjburmghx6xwm.jpg
0
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
23.08.2015, 00:02 33
Чего смешного , если так и должно быть
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
23.08.2015, 02:26 34
Цитата Сообщение от YTYOUT
Чего смешного , если так и должно быть
When the SCL pin output dryver is enabtid the SCL line will be forced low if th coressponding bit in the PORTB rikystir is zero.
Я перевел как.

Когда SCL подключен к USI (DDRx - 1) SCL будет прижат к земле, если соответствующий пин в PORTB установлен в 0.
Однако линия SCL прекрасно работает без каких либо манипуляций с PORTB.

Поясните.
0
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
23.08.2015, 02:49 35
Управление идет не через PORT, а через DDR . Ключевые слова - Tri-state, Open - collector
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
28.08.2015, 04:47 36
Не стал создавать новую тему для мелкого вопроса.

Как работает ADC в режиме Analog Comparator trigger source.

Что должен компаратор сделать? Прерывание или просто изменение ACO?

Обязательно ли включать компаратору прерывания?

Что то в даташите вообще мало этому уделено. А в тренингах упоминается максимум, что он есть.

Нужно для реализации 3х кнопок на 1ой ноге. (Подсмотрел в одном телевизоре).
МК делает свои дела, на PBx висит 5В. 3 кнопки при нажатии замыкают разные комбинации резисторов. Деля напряжение на ноге.
Как только напруга падает ниже 5В, просыпается ADC, начинает мерить ее и вызывает прерывание.
0
0 / 0 / 0
Регистрация: 24.12.2011
Сообщений: 2,752
28.08.2015, 09:45 37
Порты у компаратора и ADC одни и те же. Если я правильно понял, сначала они настроены на компаратор, после срабатывания должны перепрограммироваться на ADC и измерить напряжение? Затем перепрограммироваться обратно. Зачем такие сложности? Компаратор здесь лишний.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
28.08.2015, 19:14 38
Цитата Сообщение от omokost
Порты у компаратора и ADC одни и те же. Если я правильно понял, сначала они настроены на компаратор, после срабатывания должны перепрограммироваться на ADC и измерить напряжение? Затем перепрограммироваться обратно. Зачем такие сложности? Компаратор здесь лишний.
Ну я вообще инфы по этому не нашел.

ADTS2..0 = 001 — запуск АЦП от аналогового компаратора. Удобно блин. Например, чтобы не замерять постоянно входную величину, а запрограммировать компаратор на то, что как только у него вылезет что-либо выше порога, так тут же захватывать это дело на АЦП.
Я так понимаю. Что и AC и ADC работают одновременно, настроенные на одну и ту же ногу. ADC ожидает сигнала от AC, который выдает его при изменении уровня. После получения сигнала, ADC начинает измерение и выдает прерывание по готовности данных.

Т.е. от самого контроллера с момента инициализации AC/ADC до прерывания о готовности данных от ADC никаких действий не требуется.

НО это то, как понял я. Как это работает на самом деле, я и пытаюсь выяснить.
0
0 / 0 / 0
Регистрация: 24.12.2011
Сообщений: 2,752
28.08.2015, 20:44 39
Цитата Сообщение от RiosomX
... пытаюсь выяснить.
Выяснять нужно на макетке, желательно с JTAG. Т.к. применение извращенное, прямого и ясного ответа вы едва ли дождетесь. ИМХО.
0
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
29.08.2015, 17:45 40
Цитата Сообщение от omokost
Цитата Сообщение от RiosomX
... пытаюсь выяснить.
Выяснять нужно на макетке, желательно с JTAG. Т.к. применение извращенное, прямого и ясного ответа вы едва ли дождетесь. ИМХО.

Нашел на забугорном форуме.

Все автотриггеры АЦП срабатывают по нарастающему фронту их флага прерывания.
Что и оказалось правдой.
0
29.08.2015, 17:45
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.08.2015, 17:45
Помогаю со студенческими работами здесь

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

Подскажите принцип работы
Ребята, я не знаю,что писать в поиске при таком вопросе. Собственно вопрос: я часто играю в игры,...

Принцип работы Service
Здравствуйте, господа. Не могу понять, что еще может Service, кроме перегружаемых методов? При...

Принцип работы видеокарты
Расскажите принцип работы видеокарт что происходит при построении изображения и в какой...

Принцип работы MVC
Добрый вечер! Уже часов 8 пытаюсь понять технологию MVC (Model-View-Controller). Прочитал много...

Основы C# принцип работы
Гении помогите !!??Я только учусь, объясните принцип работы С# ?

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


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru