Страница 1 из 4

Программный I2C

Добавлено: Пт апр 25, 2014 11:28:05
Demetros
Доброго времени суток!
Столкнулся с проблемой при реализации программного I2C. Суть такова: микроконтроллер PIC16F876A работает в паре с DS1307. Это нечто вроде будильника. Я задаю время(в программе это 00:00:00), часы тикают и при достижении заданного времени (5 секунд) зажигается, например, светодиод (на самом деле проект куда более серьезный, данный пример лишь упрощение). I2C повесил на RC6 и RC7. Все работает стабильно, прием и передача идет, но проблема в том, что на порт С больше ничего повесить нельзя. После того как зажигается светодиод, сбивается прием/передача. Перепроверял много раз, нигде в коде весь порт не участвует, оперирую только отдельными пинами. Помогите, пожалуйста, найти ошибку и освободить оставшиеся пины порта С. Программу на си и проект в Proteus 7.10 SP0 прилагаю.
Заранее благодарен.

Re: Программный I2C

Добавлено: Пт апр 25, 2014 13:46:08
cahek80
можно вопрос? а зачем скобки в (RC2=1) в строке if (sec==5) (RC2=1);

Re: Программный I2C

Добавлено: Пт апр 25, 2014 15:17:09
Demetros
В принципе они там действительно не нужны, это наверно моя привычка с QBasica и Pascal'а брать все в операторные скобки.

Re: Программный I2C

Добавлено: Пт апр 25, 2014 15:19:02
ARV
не может это быть связано с тем, что для вывода сигналов и2ц вы пишите в регистр TRISC, а светодиод зажигаете совсем не так?

P.S. как все эти нестандартные возможности "якобы Си" затрудняют понимание программы!

Re: Программный I2C

Добавлено: Пт апр 25, 2014 15:24:45
cahek80
Demetros писал(а):В принципе они там действительно не нужны, это наверно моя привычка с QBasica и Pascal'а брать все в операторные скобки.
немного оффтоп, но как-то впервые встречаю подобные скобки еще с кубасика и паскалей... ))

и еще немного неясно, пока не на чем прошагать - SDA_IN Вы нигде в 0 не выставляете?

Re: Программный I2C

Добавлено: Пт апр 25, 2014 16:51:17
Demetros
ARV: По всем симптомам так и есть, будто в какой-то момент программы происходит управление всем портом, но в программе я оперирую TRISC6 и TRISC7 (направлением 6 и 7-й ножки), по идее остальные ноги остаются работать "на выход".

cahek80: В паскале вместо "()" используется "Begin End". Прошу прощения за кривой код, на скорую руку урезал ненужные части программы. На самом деле там стояла не одна функция "RC2=1", а несколько других, они и были объединены скобками.
По поводу SDA_IN, я вроде единожды выставляю в 0 при инициализации и больше не трогаю SDA_IN. Дальнейшее "общение" идет за счет изменения направления работы ножки и подтягивающих резисторов (если я конечно не ошибаюсь).

Re: Программный I2C

Добавлено: Пт апр 25, 2014 17:08:23
cahek80
begin end, хм тогда уж {}, а не () :)
про TRIS* и SDA_IN да, я понял, сам когда-то так рулил тоже. Но работало без сбоев. хз.

Re: Программный I2C

Добавлено: Пт апр 25, 2014 19:15:51
Аlex
но в программе я оперирую TRISC6 и TRISC7 (направлением 6 и 7-й ножки)
А как Вы думаете, после перенаправления бита порта, что будет находится в защёлке ? Откуда такая уверенность, что там будет то, что у Вас на уме ? :)


ЗЫ: Курим -
http://www.microchip.ru/files/d-sheets-rus/pic16_9.pdf
http://www.microchip.ru/lit/?mid=1x0

Re: Программный I2C

Добавлено: Пт апр 25, 2014 19:25:06
HHIMERA
Demetros писал(а): I2C повесил на RC6 и RC7. Все работает стабильно, прием и передача идет, но проблема в том, что на порт С больше ничего повесить нельзя. После того как зажигается светодиод, сбивается прием/передача. Перепроверял много раз, нигде в коде весь порт не участвует, оперирую только отдельными пинами.
Смотрите в сторону RMW... "оперирую только отдельными пинами" в этих ПИКах на самом деле является операцией с портом...
В последующих ПИках поэтому и ввели регистры LATx... У Микрочипа есть апнота на эту тему...

Re: Программный I2C

Добавлено: Пт апр 25, 2014 19:58:05
urry
ну да, согласен с Химерой - RMW.
Я уже всегда в мк, в которых нет LAT, выделяю регистр, обзываю его LATX и меняю битики в нем, а его уже - целиком выдаю в порт.
Да, дольше, зато спишь спокойно.

Re: Программный I2C

Добавлено: Пт апр 25, 2014 20:02:06
ARV
urry писал(а):Я уже всегда в мк, в которых нет LAT, выделяю регистр, обзываю его LATX и меняю битики в нем, а его уже - целиком выдаю в порт.
я так понимаю, если бы было написано традиционно PORTC |= 1<<PC7; то никаких проблем не возникло бы? я с PIC-ами никогда в жизни дел не имел

Re: Программный I2C

Добавлено: Пт апр 25, 2014 20:12:43
HHIMERA
ARV писал(а):если бы было написано традиционно PORTC |= 1<<PC7; то никаких проблем не возникло бы?
Это и есть Read-Modify-Write...
Как сказал уже Юрий... лучше юзать "фантомный регистр" и через XOR...

Re: Программный I2C

Добавлено: Пт апр 25, 2014 21:04:59
ARV
Юрий сказал, что правильно - это когда считываем в промежуточную переменную, модифицируем и выводим обратно - так?

что написал я, так это то же самое! это сокращенная запись PORTC = PORTC | (1<<PB7); то есть в промежуточную переменную (ее компилятор должен создать сам - автоматические переменные обычно бывают как раз регистровыми) считывается порт, над ним выполняется операция модификации, а затем результат записывается обратно в порт.

что не так?

Re: Программный I2C

Добавлено: Пт апр 25, 2014 21:30:52
Аlex
ARV писал(а):PORTC = PORTC | (1<<PB7); то есть в промежуточную переменную (ее компилятор должен создать сам - автоматические переменные обычно бывают как раз регистровыми) считывается порт, над ним выполняется операция модификации, а затем результат записывается обратно в порт.
что не так?
Оптимизатор убьёт эти все предположения и вставит единственную команду bsf (установка бита в регистре).
У ТС'а проблема в другом. Я уже пытался ему намекнуть, ссылочку кинул, чтобы он почитал хоть немного и покумекал. Но тут некоторые не выдержали и открыли тайну напрямую :)

Re: Программный I2C

Добавлено: Пт апр 25, 2014 21:40:05
ARV
Аlex писал(а):Оптимизатор убьёт эти все предположения и вставит единственную команду bsf (установка бита в регистре).
если PORTC определен, как volatile-переменная, оптимизатор не имеет на это права. но если это так - я пас, к PIC-ам ни рукой ни ногой :)))

Re: Программный I2C

Добавлено: Пт апр 25, 2014 22:02:30
HHIMERA
Угу... "Гложут меня смутные сомнения!"(С)
AVR Studio 4.18... Mega16A...

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

23:       asm("nop");
+000000CE:   0000        NOP                      No operation
25:       PORTC = PORTC | (1<<PB7); 
+000000CF:   9AAF        SBI       0x15,7         Set bit in I/O register
27:       asm("nop");
+000000D0:   0000        NOP                      No operation
29:       PORTC |= (1<<PB7); 
+000000D1:   9AAF        SBI       0x15,7         Set bit in I/O register

Re: Программный I2C

Добавлено: Пт апр 25, 2014 22:03:21
Аlex
ARV писал(а):не имеет на это права
Мне кажется, Вы заблуждаетесь.
volatile тут совсем не причём. Ну не убьёт компилятор совсем эту строку, если посчитает нужным, но никак не будет создавать ещё переменную. С какой радости ? :)

ЗЫ: Не путайте с языком java. Там строки, типа a=a+1; и a+=1; не эквивалентны. Для Си - это одно и тоже...

Re: Программный I2C

Добавлено: Пт апр 25, 2014 22:17:27
ARV
Аlex писал(а):Мне кажется, Вы заблуждаетесь.
volatile тут совсем не причём. Ну не убьёт компилятор совсем эту строку, если посчитает нужным, но никак не будет создавать ещё переменную. С какой радости ? :)

ЗЫ: Не путайте с языком java. Там строки, типа a=a+1; и a++; не эквивалентны. Для Си - это одно и тоже...
а мне кажется - вы заблуждаетесь :) что касается java - то я знаю ее (или его?) на уровне "смотрю в книгу - вижу фигу".

если переменная объявлена как volatile, то компилятор не имеет права выкинуть любое обращение к ней.

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

int var; 
volatile int vol;

var;
vol;
здесь обращение к var компилятор имеет право выкинуть, а обращение на чтение к vol - не имеет. соответственно в операторе vol |= 1; произойдет обязательное считывание содержимого переменной в промежуточную переменну, а затем модифицированный результат промежуточной переменной запишется обратно. более того, если написать var = vol + vol + vol; то компилятор не будет иметь права заменить это на var = vol * 3; - он так и будет трижды считывать vol!!!

но это в нормальных компиляторах Си так, как там в PIC-антном компиляторе - я не в курсе... может, он и не адекватный восе...

Re: Программный I2C

Добавлено: Пт апр 25, 2014 22:27:32
Аlex
Ну я даже и не знаю что сказать...

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

int main(int argc, char **argv) {
int a;
volatile int b;

while(1){

	a = a | (1<<7);
	a |= (1<<7);

	b = b | (1<<7);
	b |= (1<<7);
}
}

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

29        	a = a | (1<<7);
080002f6:   ldr r3, [r7, #12]
080002f8:   orr.w r3, r3, #128      ; 0x80
080002fc:   str r3, [r7, #12]
30        	a |= (1<<7);
080002fe:   ldr r3, [r7, #12]
08000300:   orr.w r3, r3, #128      ; 0x80
08000304:   str r3, [r7, #12]
32        	b = b | (1<<7);
08000306:   ldr r3, [r7, #8]
08000308:   orr.w r3, r3, #128      ; 0x80
0800030c:   str r3, [r7, #8]
33        	b |= (1<<7);
0800030e:   ldr r3, [r7, #8]
08000310:   orr.w r3, r3, #128      ; 0x80
08000314:   str r3, [r7, #8]
IDE - CooCox. компилятор, как я понял, - arm-none-eabi.
:dont_know:

Re: Программный I2C

Добавлено: Пт апр 25, 2014 22:41:10
ARV
пока и я не вижу, что вы хотели сказать :)

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

а вот вам примерчик для AVR:

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

   PORTB = var + var + var;
  7c:	90 91 61 00 	lds	r25, 0x0061
  80:	89 2f       	mov	r24, r25
  82:	88 0f       	add	r24, r24
  84:	89 0f       	add	r24, r25
  86:	88 bb       	out	0x18, r24	; 24
   PORTB = vol + vol + vol;
  88:	20 91 60 00 	lds	r18, 0x0060
  8c:	80 91 60 00 	lds	r24, 0x0060
  90:	90 91 60 00 	lds	r25, 0x0060
  94:	82 0f       	add	r24, r18
  96:	89 0f       	add	r24, r25
  98:	88 bb       	out	0x18, r24	; 24
как видите, в первом случае считывание в регистр было 1 раз, а потом этот регистр плюсовался к исходному, а во втором случае считывание переменной сделано трижды :)))