Обсуждаем контроллеры компании Atmel.
Ответить

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Сб авг 10, 2019 05:40:49

kras писал(а):Но что еще не понравилось. Если на передаче
outgoingBuffer[5] = 0xff0034fe;
outgoingBuffer - однобайтное, не зачем туда впихивать 0xff0034fe.
kras писал(а):огда в таком порядке они и приходят, но вместо 0хf0ss 0xfass .... я наблюдаю

FFFFFFF0ss FFFFFFFAss FFFFFFFBss FFFFFFFCss FFFFFFFDss FFFFFFFEss
Измените
Код:
char c = Wire.read();    // получаем байт (как символ)
на
Код:
unsigned char c = Wire.read();    // получаем байт (как символ)

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Сб авг 10, 2019 12:01:40

Встало на места, спасибо большое! Единственное, почему тогда остаток заполняется 1-ми, а не нулями. Я ставил DEC вместо HEX, были отрицательные числа. Пока я могу понять это только так, что по умолчанию просто все принятое - это единицы. И если я отправляю FE, то получу не 254, а отрицательное число, если не обнулю все лишнее кроме FE. Короче, я эту логику не понял)

Добавлено after 51 minute 50 seconds:
Помогите, пожалуйста, еще последнюю ошибку найти. Я установил в TWI.C порты на I2C PB0 и PB2. А PB1 сделал для кнопки. То есть нажатие на кнопку - и программа один раз инкрементирует значение count. Я решил, что это значение будет передаваться также, как в уже разобранном примере, то есть мы просто раз в секунду будем видеть, сработал счетчик по кнопке или нет. Проблема в том, что я отдельно то программу кнопки с прерыванием и задержкой от дребезга попробовал, она работает. А вот когда я включил это в программу Слейва, то получилось немного неожиданно: когда нажимаю на кнопку, данные перестают передаваться, но передается пустота. Это из-за того, что CLK на I2C идет?

Сначала, до этого, вообще компилятор выдавал ошибку, потому что в TWI и в коде, как я понимаю, использовался один и тот же номер прерывания INT0. Я решил поставить INT1 на кнопку и заработало, но вот что тут не так? Ведь не считает в итоге. Ну вообще я понял, почему передача останавливается при нажатии на кнопку - она же уходит на прерывание. Но затем почему тогда count не инкрементируется? Светодиод тоже не зажигается.

Спойлер#include <avr/io.h>
#include <avr/interrupt.h>
#include "TWI.h"


#define InvBit(reg, bit) reg ^= (1<<(bit))
#define ClearBit(reg, bit) reg &= (~(1<<(bit)))
#define SetBit(reg, bit) reg |= (1<<(bit))
#define BitIsSet(reg, bit) ((reg & (1<<bit)) != 0)

#define InvBit(reg, bit) reg ^= (1<<(bit))
#define ClearBit(reg, bit) reg &= (~(1<<(bit)))
#define SetBit(reg, bit) reg |= (1<<(bit))
#define BitIsSet(reg, bit) ((reg & (1<<bit)) != 0)

#define LED PB4

long int count = 1;

extern volatile unsigned char outgoingBuffer[6];

//volatile uint32_t value1 = 0x00;

//SIGNAL(INT0_vect)
SIGNAL(SIG_INTERRUPT1)
{
if (bit_is_set(PINB,PB1))
{
count=count+1;
PORTB ^= (1<<LED); //Change PB4 State
}
else
count=count+1;
}


int main( void )
{
// Светодиод
DDRB |= (1<<LED); // конфигурируем пин как выход
PORTB &= ~(1<<LED); // по умолчанию светодиод выключен


GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
MCUCR = 0b00000001; // при любом перепаде

sei(); //!< Enable global interrupts.

twi_slave_init();
twi_slave_enable();

int i;

for(i=0; i<6; outgoingBuffer[i++]=0) {} // очистка передающего буфера

while (1)
{

outgoingBuffer[5] = count;
outgoingBuffer[4] = 0xfd;
outgoingBuffer[3] = 0xfc;
outgoingBuffer[2] = 0xfb;
outgoingBuffer[1] = 0xfa;
outgoingBuffer[0] = 0xf0;

}


}

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Сб авг 10, 2019 13:35:48

Не трогайте INT0, PB0 и PB1.
Код:
// Interrupt on any change on pins PCINT0-5: On
GIMSK |= (1<<PCIE);
PCMSK |= (0<<PCINT5) | (0<<PCINT4) | (0<<PCINT3) | (1<<PCINT2) | (0<<PCINT1) | (0<<PCINT0);   // PCINT2 - PB2 PCINT3 - PB3 PCINT4 - PB4
GIFR  |= (1<<PCIF);


ISR(PCINT0_vect) {
-обработка кнопки-
}
лучше опрос кнопки сделать в основном цикле.

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Сб авг 10, 2019 18:00:19

Не совсем понял. Тогда какой код будет?

Добавлено after 23 minutes 30 seconds:
А. и без прерывания мне никак по счетчику. Там быстро считать надо. Когда появляются импульсы на входном порту счетчика, передачу надо в идеале остановить и считать импульсы. Поэтому опрос порта в теле программы не подойдет, мне нужно понять, что не так у меня с прерываниями.

Кстати, и я немного сообразил, но как ни странно, I2C то у меня работал при коде, который показал последним. PB2 - там же нет прерывания INT0. Но тогда I2C не должен работать, а мне кажется, что PB0 как раз необходимо прерывание, а PB1 в I2C можно повесить и на другой порт, но вот из-за этого, наверное, я и плаваю в данном вопросе.

Если я оставлю PB0, PB1 и INT0 под I2c, то мне нужно кнопку повесить на PB2, я так понимаю, для нее должно срабатывать INT2. Но все таки я не совсем сообразил, как это написать надо.

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Сб авг 10, 2019 21:20:13

kras писал(а):Но все таки я не совсем сообразил, как это написать надо.
Плохо.
Код мастер
Спойлер
Код:
#include <Wire.h>

#define adres 0x5C>>1
volatile uint32_t count = 0x00;

volatile unsigned char incomingBuffer[6];

void setup()
{
   Wire.begin();        // подключение к шине i2c
   Serial.begin(9600);  // запуск последовательного порта
   delay(2000);            // пауза
}

void loop()
{
   unsigned char c=0;
   Wire.requestFrom(adres, 6);    // запрос 6 байт от слейва #2

   while(Wire.available())    // пока есть, что читать
   {
   incomingBuffer[c] = Wire.read();    // получаем байт (как символ)
   c++;
   }
   count = 0x00;
   count += (uint32_t) incomingBuffer[3] << 8;
   count += (uint32_t) incomingBuffer[2] << 8;
   count += (uint32_t) incomingBuffer[1] << 8;
   count += (uint32_t) incomingBuffer[0] ;
   Serial.print(count, DEC);         // печатает в порт
   Serial.print("\n\r");
   delay(500);
}
Код Slave
Спойлер
Код:
#include <avr/interrupt.h>
#include "TWI.h"

#define InvBit(reg, bit)   reg ^= (1<<(bit))
#define ClearBit(reg, bit)       reg &= (~(1<<(bit)))
#define SetBit(reg, bit)          reg |= (1<<(bit))
#define BitIsSet(reg, bit)       ((reg & (1<<bit)) != 0)
#define BitIsClear(reg, bit)    ((reg & (1<<(bit))) == 0)

extern volatile unsigned char incomingBuffer[8];
extern volatile unsigned char  outgoingBuffer[6];

volatile uint32_t count = 0x00; //

#define LED PB4
#define KN PB2

ISR(PCINT0_vect) {
/*-обработка кнопки-*/

if (BitIsClear(PINB,KN))
{
count++;
PORTB ^= (1<<LED); //Change PB4 State
}

}

int main( void )


// Светодиод
DDRB |= (1<<LED); // конфигурируем пин как выход
PORTB &= ~(1<<LED); // по умолчанию светодиод выключен

// Кнопка
DDRB &= ~(1<<KN); // конфигурируем пин как вход
PORTB |= (1<<KN); // включаем подтяжку

// Interrupt on any change on pins PCINT0-5: On
GIMSK |= (1<<PCIE);
PCMSK |= (0<<PCINT5) | (0<<PCINT4) | (0<<PCINT3) | (1<<PCINT2) | (0<<PCINT1) | (0<<PCINT0);   // PCINT2 - PB2 PCINT3 - PB3 PCINT4 - PB4
GIFR  |= (1<<PCIF);

  sei();   //!< Enable global interrupts.

  twi_slave_init();
  twi_slave_enable();
 

   for(int i=0; i<6; outgoingBuffer[i++]=0) {}            // очистка передающего буфера
   
   
   while (1)
  {
   
outgoingBuffer[3] = (count & 0xff000000) >> 24;
outgoingBuffer[2] = (count & 0x00ff0000) >> 16;
outgoingBuffer[1] = (count & 0x0000ff00) >> 8;
outgoingBuffer[0] = (count & 0x000000ff);

 
  }
 
 
}

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Вс авг 11, 2019 08:31:09

заработало! А как сделать защиту от дребезга? Кажется, 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?

Ну колхоз мне пока не решил проблему:

Код:
ISR(PCINT0_vect) {
/*-обработка кнопки-*/

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 бита, например?

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Вс авг 11, 2019 09:18:31

kras писал(а):А как сделать защиту от дребезга? Кажется, delay как то неправильно работает, я добавил
Нельзя в прерывание лепить всякие там _delay_ms (500); и тем более for(i=0; i<20000; i++) { count1++;}.
Поэкспериментируйте с конденсатором, начните с 1n 10n 100n.
kras писал(а):Действительно, смысл делать long, если передается только 8 бит. А как лучше сделать, разбить переменную на 6 байт, или передавать сразу 32 бита, например?
А может вам для начала почитать вот это Типы данных

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Вс авг 11, 2019 15:02:08

А может вам для начала почитать вот это Типы данных

Так мне длинную переменную надо передать. Вроде вы удобно показали, что можно смещать просто на то количество битов, на которое нужно. Но я намека не понимаю, как я long int могу передать в виде 8 бит данных? Тут можно только разбить на несколько байт, не?

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Вс авг 11, 2019 16:59:03

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
ну откуда здесь взялся long int?????

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Вс авг 11, 2019 17:33:51

Сори, я дурак, Вы же и показали сразу разбиение побайтово переменной типа uint32_t)

Добавлено after 24 minutes 18 seconds:
Вроде все ок. Единственное, если импульсы идут сильно быстро, у меня такое чувство, что они не успевают считаться. Хотя это странно, ведь сейчас все время считаются данные, кроме того момента, когда происходит непосредственно передача. Я так понимаю, что прерывание на передачу может конфликтовать с прерыванием на счетчик, когда нужно быстро посчитать ~500 импульсов в секунду.

Я думал, что могу это избежать, просто увеличив delay() на мастере с 500 мс на ~5000 мс. Но тогда, как я наблюдаю, Слейв вообще не считает, а полностью занят прерыванием на I2C!!

Какая точно ерунда происходит: после некоторого времени, допустим, счетчик насчитал EF. А я жду переполнение. Так вот, внезапно счет начинает идти дольше. Зависает на одном и том же числе по 2-3 секунды. Я просто меандр на кнопку посылаю с периодом 80 мс (12.5 Гц или 12.5 периодов в секунду).

Что может быть не так?

Ну есть возможность упростить - передавать мне надо раз в 10 минут вообще. Возможно, можно и таймер поставить, который будет считать. А нужно ли? Ну для теста можно передавать раз в 30 секунд...

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Пн авг 12, 2019 08:35:28

kras писал(а):Что может быть не так?
Что-то сразу не доглядел
Код:
   count = 0x00;
   count += (uint32_t) incomingBuffer[3] << 24;
   count += (uint32_t) incomingBuffer[2] << 16;
   count += (uint32_t) incomingBuffer[1] << 8;
   count += (uint32_t) incomingBuffer[0] ;
   Serial.print(count, DEC);         // печатает в порт
   Serial.print("\n\r");
kras писал(а):когда нужно быстро посчитать ~500 импульсов в секунду.
Используйте таймер, благо таймер выходит на вывод PB2.

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Пн авг 12, 2019 08:39:56

А можно подробнее, где прочитать про таймер. Проблема в том, что действительно устройство начинает подвисать. Такое ощущение, что счет не в приоритете получается по сравнению с прерыванием на передачу, это так?

А подсчет импульсов нельзя сделать в приоритете в данном примере? Так то вроде немного разобрался, спасибо огромное! Но вот этот момент немного портит цельное понимание картины по прерываниям)

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

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Пн авг 12, 2019 13:11:45

kras писал(а):А можно подробнее, где прочитать про таймер.
Даташит читаем на контроллер.
kras писал(а):Проблема в том, что действительно устройство начинает подвисать. Такое ощущение, что счет не в приоритете получается по сравнению с прерыванием на передачу, это так?

А подсчет импульсов нельзя сделать в приоритете в данном примере? Так то вроде немного разобрался, спасибо огромное! Но вот этот момент немного портит цельное понимание картины по прерываниям)
Приоритет прерываний работает по принципу «кто первый встал тот и ходит в тапках». Остальные запрещены аппаратно.
kras писал(а):Потому что дальше вопрос с таймером, мне кажется - отдельная история.
Отнюдь, три строчки кода.
kras писал(а):Я бы использовал внутренний, но можно, пожалуй, подключить внешний таймер и вывести еще одно прерывание, по которому бы происходила передача данных.
Интересно про внешний таймер узнать, это как?

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Вт авг 13, 2019 10:17:07

https://soltau.ru/index.php/arduino/ite ... -k-arduino

Добавлено after 1 hour 35 minutes 25 seconds:
Отнюдь, три строчки кода.


Неа, все таки сложно догадаться до решения. Раз три строчки, я не хочу пока ставить внешние часы а хочу добавить сторожевой (?) таймер микроконтроллера.
Окей, два прерывания и их противодействие это все таки зло. Кстати, а зачем в I2C прерывание?

В общем, начал читать про таймер для подсчета импульсов с этого: http://integrator.adior.ru/index.php/proshivki/430
Затем полистал код здесь https://forum.cxem.net/index.php?/topic ... %BD%D0%B4/

И не совсем понял. Получается, что таймер лучше тем, что он, хотя тоже работает по прерыванию, но считает независимо от основной программы микроконтроллера, то есть таймер запустил счет и будет считать параллельно с МК, так? Ну вроде это понятно.

Однако, а как таймер будет работать по входному сигналу с порта PB2?

Если все ок, то получается да, мне нужно добавить эти 3 строчки в код и удалить счет импульсов по прерыванию на PB2. Можете подсказать?)

Re: I2C на Attiny 13 - Попытка сквозь времена:)

Вт авг 13, 2019 19:04:30

kras писал(а):Кстати, а зачем в I2C прерывание?
Так как I2C программный, то прерывание нужно для регистрации события на шине.
kras писал(а):В общем, начал читать про таймер для подсчета импульсов с этого: http://integrator.adior.ru/index.php/proshivki/430
Затем полистал код здесь https://forum.cxem.net/index.php?/topic ... %BD%D0%B4/

И не совсем понял. Получается, что таймер лучше тем, что он, хотя тоже работает по прерыванию, но считает независимо от основной программы микроконтроллера, то есть таймер запустил счет и будет считать параллельно с МК, так? Ну вроде это понятно.
Все верно. В отличии от предложенного вами решения с кнопкой, прерывание таймера будет срабатывать раз в 256 импульсов, а не два раза за импульс как с кнопкой.
kras писал(а):Однако, а как таймер будет работать по входному сигналу с порта PB2?
Вход внешнего сигнала таймера/счетчика T0.
kras писал(а):Если все ок, то получается да, мне нужно добавить эти 3 строчки в код и удалить счет импульсов по прерыванию на PB2.
Все верно, вам лучше использовать какой нибудь генератор начального кода, к примеру AvrWiz, я пользуюсь таким
СпойлерИзображение
Ответить