Встало на места, спасибо большое! Единственное, почему тогда остаток заполняется 1-ми, а не нулями. Я ставил DEC вместо HEX, были отрицательные числа. Пока я могу понять это только так, что по умолчанию просто все принятое - это единицы. И если я отправляю FE, то получу не 254, а отрицательное число, если не обнулю все лишнее кроме FE. Короче, я эту логику не понял)
Добавлено after 51 minute 50 seconds: Помогите, пожалуйста, еще последнюю ошибку найти. Я установил в TWI.C порты на I2C PB0 и PB2. А PB1 сделал для кнопки. То есть нажатие на кнопку - и программа один раз инкрементирует значение count. Я решил, что это значение будет передаваться также, как в уже разобранном примере, то есть мы просто раз в секунду будем видеть, сработал счетчик по кнопке или нет. Проблема в том, что я отдельно то программу кнопки с прерыванием и задержкой от дребезга попробовал, она работает. А вот когда я включил это в программу Слейва, то получилось немного неожиданно: когда нажимаю на кнопку, данные перестают передаваться, но передается пустота. Это из-за того, что CLK на I2C идет?
Сначала, до этого, вообще компилятор выдавал ошибку, потому что в TWI и в коде, как я понимаю, использовался один и тот же номер прерывания INT0. Я решил поставить INT1 на кнопку и заработало, но вот что тут не так? Ведь не считает в итоге. Ну вообще я понял, почему передача останавливается при нажатии на кнопку - она же уходит на прерывание. Но затем почему тогда count не инкрементируется? Светодиод тоже не зажигается.
На практике можно не успеть сделать того, что можно хорошо обосновать в теории. Но без практики теория может отдаляться от нее, и когда они встретятся снова - не узнает даже неприкосновенное шампанское профессора в лаборатории. Моя практика: robofeya.ru
Добавлено after 23 minutes 30 seconds: А. и без прерывания мне никак по счетчику. Там быстро считать надо. Когда появляются импульсы на входном порту счетчика, передачу надо в идеале остановить и считать импульсы. Поэтому опрос порта в теле программы не подойдет, мне нужно понять, что не так у меня с прерываниями.
Кстати, и я немного сообразил, но как ни странно, I2C то у меня работал при коде, который показал последним. PB2 - там же нет прерывания INT0. Но тогда I2C не должен работать, а мне кажется, что PB0 как раз необходимо прерывание, а PB1 в I2C можно повесить и на другой порт, но вот из-за этого, наверное, я и плаваю в данном вопросе.
Если я оставлю PB0, PB1 и INT0 под I2c, то мне нужно кнопку повесить на PB2, я так понимаю, для нее должно срабатывать INT2. Но все таки я не совсем сообразил, как это написать надо.
На практике можно не успеть сделать того, что можно хорошо обосновать в теории. Но без практики теория может отдаляться от нее, и когда они встретятся снова - не узнает даже неприкосновенное шампанское профессора в лаборатории. Моя практика: robofeya.ru
заработало! А как сделать защиту от дребезга? Кажется, delay как то неправильно работает, я добавил
Спойлер#include <util/delay.h> // Подключаем библиотеку функций задержки
ISR(PCINT0_vect) { /*-обработка кнопки-*/
if (BitIsClear(PINB,KN)) { count++; PORTB ^= (1<<LED); //Change PB4 State _delay_ms (500); } }
и у меня обнуляется переменная count, когда мне это не надо. Главное, что считает быстрее, чем сейчас для теста надо, нужна защита от дребезга) Видимо, это потому происходит, что то же самое прерывание на delay используется. Может что-то другое поставить, а не delay?
if (BitIsClear(PINB,KN)) { count++; //_delay_ms (500); PORTB ^= (1<<LED); //Change PB4 State int i; for(i=0; i<20000; i++) { count1++; } }
}
Как то странно у меня работает.
С длиной count поразбираюсь сам) Действительно, смысл делать long, если передается только 8 бит. А как лучше сделать, разбить переменную на 6 байт, или передавать сразу 32 бита, например?
На практике можно не успеть сделать того, что можно хорошо обосновать в теории. Но без практики теория может отдаляться от нее, и когда они встретятся снова - не узнает даже неприкосновенное шампанское профессора в лаборатории. Моя практика: robofeya.ru
kras писал(а):А как сделать защиту от дребезга? Кажется, delay как то неправильно работает, я добавил
Нельзя в прерывание лепить всякие там _delay_ms (500); и тем более for(i=0; i<20000; i++) { count1++;}. Поэкспериментируйте с конденсатором, начните с 1n 10n 100n.
kras писал(а):Действительно, смысл делать long, если передается только 8 бит. А как лучше сделать, разбить переменную на 6 байт, или передавать сразу 32 бита, например?
А может вам для начала почитать вот это Типы данных
А может вам для начала почитать вот это Типы данных
Так мне длинную переменную надо передать. Вроде вы удобно показали, что можно смещать просто на то количество битов, на которое нужно. Но я намека не понимаю, как я long int могу передать в виде 8 бит данных? Тут можно только разбить на несколько байт, не?
На практике можно не успеть сделать того, что можно хорошо обосновать в теории. Но без практики теория может отдаляться от нее, и когда они встретятся снова - не узнает даже неприкосновенное шампанское профессора в лаборатории. Моя практика: robofeya.ru
kras писал(а):Но я намека не понимаю, как я long int могу передать в виде 8 бит данных? Тут можно только разбить на несколько байт, не?
Я же вроде показал как это сделать.
uint32_t - это без знаковый целый тип, гарантирующий размерность ("ширину") переменной 32 бита. unsigned int, unsigned long - так сказать, language-specific, просто без знаковый целый тип, "ширина" которого может отличаться от платформы
Да и long int не существует такого, это не означает что у вас переменная вдруг станет 32+16=48бит. Ведь специально выше дал ссылку
Таким образом, получаются следующие типы: unsigned char – число от 0 до 255 signed char – число от -127 до 127 unsigned int – число от 0 до 65535 signed int – число от -32767 до 32764 unsigned long – число от 0 до 4294967295 signed long – число от -2147483648 до 2147483648
Сори, я дурак, Вы же и показали сразу разбиение побайтово переменной типа uint32_t)
Добавлено after 24 minutes 18 seconds: Вроде все ок. Единственное, если импульсы идут сильно быстро, у меня такое чувство, что они не успевают считаться. Хотя это странно, ведь сейчас все время считаются данные, кроме того момента, когда происходит непосредственно передача. Я так понимаю, что прерывание на передачу может конфликтовать с прерыванием на счетчик, когда нужно быстро посчитать ~500 импульсов в секунду.
Я думал, что могу это избежать, просто увеличив delay() на мастере с 500 мс на ~5000 мс. Но тогда, как я наблюдаю, Слейв вообще не считает, а полностью занят прерыванием на I2C!!
Какая точно ерунда происходит: после некоторого времени, допустим, счетчик насчитал EF. А я жду переполнение. Так вот, внезапно счет начинает идти дольше. Зависает на одном и том же числе по 2-3 секунды. Я просто меандр на кнопку посылаю с периодом 80 мс (12.5 Гц или 12.5 периодов в секунду).
Что может быть не так?
Ну есть возможность упростить - передавать мне надо раз в 10 минут вообще. Возможно, можно и таймер поставить, который будет считать. А нужно ли? Ну для теста можно передавать раз в 30 секунд...
На практике можно не успеть сделать того, что можно хорошо обосновать в теории. Но без практики теория может отдаляться от нее, и когда они встретятся снова - не узнает даже неприкосновенное шампанское профессора в лаборатории. Моя практика: robofeya.ru
А можно подробнее, где прочитать про таймер. Проблема в том, что действительно устройство начинает подвисать. Такое ощущение, что счет не в приоритете получается по сравнению с прерыванием на передачу, это так?
А подсчет импульсов нельзя сделать в приоритете в данном примере? Так то вроде немного разобрался, спасибо огромное! Но вот этот момент немного портит цельное понимание картины по прерываниям)
Потому что дальше вопрос с таймером, мне кажется - отдельная история. Я бы использовал внутренний, но можно, пожалуй, подключить внешний таймер и вывести еще одно прерывание, по которому бы происходила передача данных.
На практике можно не успеть сделать того, что можно хорошо обосновать в теории. Но без практики теория может отдаляться от нее, и когда они встретятся снова - не узнает даже неприкосновенное шампанское профессора в лаборатории. Моя практика: robofeya.ru
kras писал(а):А можно подробнее, где прочитать про таймер.
Даташит читаем на контроллер.
kras писал(а):Проблема в том, что действительно устройство начинает подвисать. Такое ощущение, что счет не в приоритете получается по сравнению с прерыванием на передачу, это так?
А подсчет импульсов нельзя сделать в приоритете в данном примере? Так то вроде немного разобрался, спасибо огромное! Но вот этот момент немного портит цельное понимание картины по прерываниям)
Приоритет прерываний работает по принципу «кто первый встал тот и ходит в тапках». Остальные запрещены аппаратно.
kras писал(а):Потому что дальше вопрос с таймером, мне кажется - отдельная история.
Отнюдь, три строчки кода.
kras писал(а):Я бы использовал внутренний, но можно, пожалуй, подключить внешний таймер и вывести еще одно прерывание, по которому бы происходила передача данных.
Неа, все таки сложно догадаться до решения. Раз три строчки, я не хочу пока ставить внешние часы а хочу добавить сторожевой (?) таймер микроконтроллера. Окей, два прерывания и их противодействие это все таки зло. Кстати, а зачем в I2C прерывание?
И не совсем понял. Получается, что таймер лучше тем, что он, хотя тоже работает по прерыванию, но считает независимо от основной программы микроконтроллера, то есть таймер запустил счет и будет считать параллельно с МК, так? Ну вроде это понятно.
Однако, а как таймер будет работать по входному сигналу с порта PB2?
Если все ок, то получается да, мне нужно добавить эти 3 строчки в код и удалить счет импульсов по прерыванию на PB2. Можете подсказать?)
На практике можно не успеть сделать того, что можно хорошо обосновать в теории. Но без практики теория может отдаляться от нее, и когда они встретятся снова - не узнает даже неприкосновенное шампанское профессора в лаборатории. Моя практика: robofeya.ru
И не совсем понял. Получается, что таймер лучше тем, что он, хотя тоже работает по прерыванию, но считает независимо от основной программы микроконтроллера, то есть таймер запустил счет и будет считать параллельно с МК, так? Ну вроде это понятно.
Все верно. В отличии от предложенного вами решения с кнопкой, прерывание таймера будет срабатывать раз в 256 импульсов, а не два раза за импульс как с кнопкой.
kras писал(а):Однако, а как таймер будет работать по входному сигналу с порта PB2?
Вход внешнего сигнала таймера/счетчика T0.
kras писал(а):Если все ок, то получается да, мне нужно добавить эти 3 строчки в код и удалить счет импульсов по прерыванию на PB2.
Все верно, вам лучше использовать какой нибудь генератор начального кода, к примеру AvrWiz, я пользуюсь такимСпойлер