vit007 писал(а):поправил аппаратное - один в один пример шита
В студии не про симмулировать же...
У Вас не совсем верно делается настройка.
Для начала, забудьте про конструкции вида
- Код:
sbi PORTB,2 // Вывод SS на +5
sbi PORTB,4 // На MISO подключаем подтягивающий резистор
ldi temp0,0b11010001 // Настраиваем SPI, SPIE и SPE = 1 это разрешит прерывания и
Гораздо лучше написать вот так:
- Код:
.equ SS=2
.equ MISO=4
...
sbi PORTB,SS
sbi PORTB,MISO
ldi temp,((1<<SPIE)|(1<<SPE)|(1<<MSTR)|(1<<SPR0))
out SPCR,temp
В такой записи Вы никогда не ошибетесь в установке бит, и с первого взгляда понятно, что делается в команде.
Обработчик прерывания SPI_STC у Вас записан неправильно. Зачем в прерывании ждать установки флага SPIF, если сам обработчик вызывается только после установки этого флага? Флаг SPIF очищается аппаратно при выполнении обработчика. Я не помню, очищается флаг при вызове обработчика или при выходе из него (скорее всего, первое). В первом случае Вы будете бесконечно "висеть" в цикле опроса этого флага внутри обработчика прерывания, ожидая установки только что сброшенного перед этим флага SPIF, который не установится никогда. Во втором случае Вы внутри обработчика проверяете флаг, который и так установлен и выходите из обработчика, не взяв полученные данные. Ради чего тогда обмен затевался?
Смотрите - логика работы SPI такова: перед началом обмена в регистре SPDR слейва находится какое-то число (если не инициализировали регистр SPDR слейва, то там мусор). Когда мастер помещает передаваемое число в свой регистр SPDR, то его аппаратный блок SPI автоматически начинает передачу, генерируя импульсы на выходе SCK, на каждом импульсе побитно выдвигая содержимое своего регистра SPDR (старший бит) в регистр SPDR слейва (в младший бит), одновременно с этим старший бит регистра SPDR слейва выдвигается в младший бит регистра SPDR мастера, как показано на картинке из даташита
- spi.jpg
- (36.68 KiB) Скачиваний: 693
Таким образом, длительность цикла обмена - 8 тактов на SCK, после завершения обмена содержимое регистра SPDR мастера переносится в регистр SPDR слейва, и наоборот. То есть в одном цикле обмена мастер и слейв меняются содержимым своих регистров SPDR.
Поэтому в обработчике прерывания SPI_STC мастер должен прочитать содержимое своего регистра SPDR, чтобы определить, что же послал ему слейв, а потом, если необходимо продолжить обмен, занести в регистр SPDR новое передаваемое число и выйти из обработчика. После завершения передачи этого числа вновь будет вызван обработчик прерывания SPI_STC.
Таким образом, если мастер хочет получить от слейва один байт данных, обмен должен состоять из двух циклов и строиться так:
Вначале (в первом цикле) мастер должен занести в свой SPDR число-команду, которая сообщит слейву, какие именно данные от него требуются, после завершения первого цикла передачи мастер получит то содержимое SPDR слейва, которое было там при инициализации, эти данные мастеру не интересны. Одновременно с этим, после завершения первого цикла передачи у слейва тоже вызовется обработчик SPI_STC, в котором слейв должен прочитать свой SPDR, взяв оттуда полученную от мастера число-команду, указывающую, какие данные запрашивает мастер, выбрать нужные мастеру данные, поместить их в свой SPDR и выйти из обработчика прерывания.
Мастер через некоторое время для начала второго цикла обмена должен снова поместить в свой регистр SPDR число. Начнется второй цикл обмена, после которого в SPDR мастера окажется байт переданных слейвом данных, а в регистре SPDR слейва окажется число, помещенное мастером в свой SPDR для начала второго цикла обмена.
Если мастеру требуется получить только один байт, то на этом обмен прекращается, а число, помещенное в SPDR мастера для начала второго цикла обмена, должно сказать слейву, что на этом обмен прекращается и следующие данные можно не готовить.
Далее. Внутри любого обработчика прерываний не надо использовать команды CLI и SEI, так как при вызове любого обработчика прерываний у контроллеров семейства AVR флаг глобального разрешения прерываний I регистра SREG сбрасывается аппаратно, при этом
все прерывания запрещаются, а команда RETI, одновременно с возвратом в точку, из которой был вызван обработчик, наоборот, устанавливает флаг I, глобально разрешая прерывания. Этим, собственно, команда RETI и отличается от команды RET, которая делает все то же самое, что и RETI, но не трогая флаг I.
А Вы, разрешив прерывания внутри обработчика, сможете получить неприятный трудноотлавливаемый глюк, когда у Вас внутри одного обработчика вызовется другой, если в этот момент возникнет какое-то иное прерывание.
Далее. Для того, чтобы слейв был слейвом, на его входе SS должен быть уровень лог.0. Вы, подавая на вывод SS мастера уровень лог.1 чего хотите добиться? У вас вывод SS мастера соединен с выводом SS слейва? Если да, то подачей лог.1 на вывод SS мастера Вы отключаете слейв.
Вот эта строка, которой настраивается мастер,
- Код:
ldi temp,((1<<SPIE)|(1<<SPE)|(1<<MSTR)|(1<<SPR0))
у слейва должна выглядеть точно также, за исключением того, что бит MSTR должен быть сброшен.
То есть, у слейва строка должна быть такой:
- Код:
ldi temp,((1<<SPIE)|(1<<SPE)|(1<<SPR0))
vit007 писал(а):В студии не про симмулировать же...
Настройте правильно мастера, занесите в SPDR число и через время, определенное битами SPI2X, SPR1, SPR0 у Вас вызовется обработчик прерывания SPI_STC. Можно просто в окне I/O View установить галку на бите SPIF.