PROGCONT.RU

Вход Регистрация
О САЙТЕ ГЛАВНАЯ
 

STM32F SPI настройка и использованные.

 Основная задача интерфейса SPI это обеспечение связью внутри схемы или на не большое растояние между контроллерами, датчиками и устройствами типа TM1638. О принципе работы, недостатках и преимуществах данного интерфейса я описывать не буду так как много информации интернете.
 Для осуществления передачи информации между двумя устройствами или более, одно из них должно быть главным MASTER а все остальные подчиненные SLAVE, задача MASTER полный контроль передачи информации(подчиненные не могут сами начинать передовать данные только с разрешения MASTER). На MASTER лежат обязанности организации передачи данных, выбора устройства(если больше одного) и его тактирования, SLAVE устройство всегда ожидает когда его выберут через NSS вход и начнут тактировать для получения или отправки данных от них.
 Теперь давайте ознакомимся с функциональной схемой из datasheet.

нет рисунка

 Из схемы мы видим что у SPI имеются четыре пина, коротко о них.
MOSI-если настроен модуль как MASTER то пин будет выходом для данных, как SLAVE будет входом.
MISO-тут наоборот MASTER вход для данных, SLAVE выход.
SCK-у MASTER(выход) тактирует SLAVE(вход) устройства.
NSS-через это пин MASTER разрешает работу SLAVE устройства, обычно когда SLAVE несколько или использует для синхронизации.

Описание функций SPL.

SPIx- модуль SPI для которого применяется, варианты SPI1 SPI2 SPI3 зависит от контроллера.

SPI_I2S_DeInit( SPIx)-функция возвращает конфигурацию SPI к начальным настройкам или по умолчанию и выключает модуль.

SPI_InitTypeDef Name-Name произвольное имя вашей структуры которая будет создана для настройки SPI.
Name.SPI_Direction-как осуществляется обмен данными:
SPI_Direction_2Lines_FullDuplex-устройство одновременно может отсылать и принимать данные, принцип даю данные и одновременно забираю.
SPI_Direction_2Lines_RxOnly-только принимает данные.
SPI_Direction_1Line_Rx-настроено на прием но можно сменить на передачу.
SPI_Direction_1Line_Tx-настроено на передачу но можно сменить на прием.
Name.SPI_Mode-режим:
SPI_Mode_Master-главный.
SPI_Mode_Slave-подчиненный.
Name.SPI_DataSize-размер передаваемых данных:
SPI_DataSize_8b-8 бит.
SPI_DataSize_16b-16 бит.
Name.SPI_CPOL-высоким или низким уровнем будет тактовый сигнал:
SPI_CPOL_Low-в ожидании на выходе у MASTER будет низкий уровень, тактовый сигнал высокий.
SPI_CPOL_High-тут наоборот,в ожидании на выходе у MASTER будет высокий уровень, тактовый сигнал низкий.
Name.SPI_CPHA-когда будет производится выборка бита данных, зависит от SPI_CPOL:
SPI_CPHA_1Edge-выборка происходит по первому краю тактового сигнала.
SPI_CPHA_2Edge-выборка уже происходит по второму краю тактового сигнала.

нет рисунка

Name.SPI_NSS-для устройство работающее в режиме SLAVE как будет управляться NSS(выбор нужного SLAVE устройства или синхронизация передачи данных).
SPI_NSS_Soft-программное управление, после инициализации разрешает использовать.
SPI_NSS_Hard-внешнее управление через вывод NSS, если MASTER выставит низкий уровень значит разрешает работу, высокий запрещает.
Name.SPI_BaudRatePrescaler-на какой частоте MASTER будет тактировать SLAVE устройства, частота тактирования модуля делится на следующие варианты:
SPI_BaudRatePrescaler_2
SPI_BaudRatePrescaler_4
SPI_BaudRatePrescaler_8
SPI_BaudRatePrescaler_16
SPI_BaudRatePrescaler_32
SPI_BaudRatePrescaler_64
SPI_BaudRatePrescaler_128
SPI_BaudRatePrescaler_256
SPI_FirstBit-порядок отправки битов данных:
SPI_FirstBit_MSB-начиная со старшего заканчиваем младшим.
SPI_FirstBit_LSB-начиная с младшего заканчиваем старшим.
SPI_CRCPolynomial-полином число участвующее в расчете CRC значение может быть от 0 до 255 если передача осуществляется по 8 бит или от 0 до 65535 по 16 бит, по умолчанию установлено значение 7, необходим когда используется контроль целостности передаваемых данных.

SPI_Init( SPIx, SPI_InitStruct)-применение конфигураций структуры для SPIx, передаем в функцию названием SPI и адрес структуры, добавите к названию структуры знак &(например &Name).

SPI_Cmd( SPIx, NewState)-ENABLE включает модуль SPIx DISABLE отключает.

SPI_I2S_ITConfig( SPIx, SPI_I2S_IT, NewState)-включает и отключает нужные прерывания от SPIx, варианты SPI_I2S_IT:
SPI_I2S_IT_TXE-срабатывает когда будет свободен Tx буфер, даже если будет отправляться данные из сдвигового регистра.
SPI_I2S_IT_RXNE-срабатывает если Rx буфер не свободен то есть приняли данные.
SPI_I2S_IT_ERR-происходит когда возникают ошибки коммуникации или обмена данных.

SPI_I2S_GetITStatus( SPIx, SPI_I2S_IT)-проверяет состояние прерывания, включено или выключено.

SPI_I2S_ClearITPendingBit( SPIx, SPI_I2S_IT)-сбрасывает флаг прерывания, используется для прерывания SPI_IT_CRCERR, остальные сбрасываются контроллером автоматически после определенного действия.

SPI_I2S_GetFlagStatus( SPIx, SPI_I2S_FLAG)-возвращает состояние флага SPIx события или прерывания, SPI_I2S_FLAG:
SPI_I2S_FLAG_RXNE-Rx буфер полон или данные пришли.
SPI_I2S_FLAG_TXE-Tx буфер освободился можно записывать новые данные для отправки.
SPI_FLAG_CRCERR-несоответствие переданных данных и кода контроля( CRC).
SPI_FLAG_MODF-ошибка на NSS выводе в режиме MASTER.
SPI_I2S_FLAG_OVR-переполнение Rx буфера, не успели прочесть принятые данные.
SPI_I2S_FLAG_BSY-SPIx занят отправкой или принимает данные.

SPI_I2S_ClearFlag( SPIx, SPI_I2S_FLAG)-сбрасывает флаг SPI_FLAG_CRCERR, остальные сбрасываются контроллером автоматически после определенного действия.

SPI_I2S_DMACmd( SPIx, SPI_I2S_DMAReq, NewState)-если NewState ENABLE включает событие для DMA в модуле SPIx, DISABLE отключает, SPI_I2S_DMAReq следующие варианты:
SPI_I2S_DMAReq_Tx-если Tx буфер пуст.
SPI_I2S_DMAReq_Rx-пришли данные в Rx буфер.

SPI_I2S_SendData( SPIx, Data)-отправляем данные Data, по 8 или 16 бит, зависит от конфигурации SPIx.

SPI_I2S_ReceiveData( SPIx)-функция читает принятые данные из Rx буфера.

SPI_NSSInternalSoftwareConfig( SPIx, SPI_NSSInternalSoft)-переключает с внешнего управления через вывод NSS к внутреннему программному, где SPI_NSSInternalSoft:
SPI_NSSInternalSoft_Set-включаем программное.
SPI_NSSInternalSoft_Reset-возвращаемся на внешнее управление, через вывод.

SPI_SSOutputCmd( SPIx, NewState)-используется только в режиме MASTER для управления выводом NSS который должен быть настроен как выход, если NewState ENABLE то после выполнения SPI_Cmd( SPIx, ENABLE) на выводе будет низкий уровень, SPI_Cmd( SPIx, DISABLE) выставится автоматически высокий, используется для управления одним SLAVE, NewState DISABLE отключает эту функцию.

SPI_DataSizeConfig( SPIx, SPI_DataSize)-устанавливает размер передаваемых данных SPI_DataSize может быть SPI_DataSize_8b( 8 бит) или SPI_DataSize_16b( 16 бит).

SPI_TransmitCRC( SPIx)-используется для отправки контрольной суммы в случае когда работает CRC calculation.

SPI_CalculateCRC( SPIx, NewState)-NewState ENABLE включает вычисление контрольного кода когда нужно проверять целостность переданных данных, NewState DISABLE отключает.

SPI_GetCRC( SPIx, SPI_CRC)-функция возвращает результат вычисления CalculateCRC.

SPI_GetCRCPolynomial( SPIx)-функция возвращает установленный полином.

SPI_BiDirectionalLineConfig( SPIx, SPI_Direction)-с помощью этой функции меняется направление передаваемых дынных, используется SPIx настроенный как SPI_Direction_1Line_Rx или SPI_Direction_1Line_Tx, где SPI_Direction:
SPI_Direction_Rx-может только принимать.
SPI_Direction_Tx-только отправляет данные.

 Вывод NSS-это вывод используется SLAVE устройствами что бы знать когда MASTER захочет с ним работать и помогает синхронизировать передачу данных, возможно использования без него тогда подчиненный будет ждать тактового сигнала. Со стороны MASTER вывод NSS можно настроить как выход и использовать для управление одним SLAVE в автоматическом режиме( пример в SPI_Direction_2Lines_RxOnly), если подчиненных устройств больше одного берется любой подходящий порт для управления. Теперь немного о тонкостях если будете использовать контролер в режиме MASTER настроенный NSS как SPI_NSS_Hard то вывод NSS должен быть подтянут к питанию иначе SPI будет сброшен и переключен в подчиненного.

Практика использования.

 Для практического использования я буду использовать отладочную плату где установлен STM32F105RB, сам эксперимент будет над SPI1 и SPI2.
SPI_Direction_2Lines_FullDuplex-для сопряжения используются выводы SCK, MOSI, MISO и NSS если есть необходимость, данные передаются и получаются одновременно, схема подключения устройств ниже.

нет рисунка

нет рисунка Вот пример в котором мы будем после нажатия штатной кнопки отладочной платы отправлять из SPI1 в SPI2 число 65, если SPI2 его примет то отошлет в SPI1 число 66, после всех этих удачных комбинаций должен поменять состояние вывод Port C пин 7, синий штатный светодиод загорится или погаснет. После первого нажатия не чего не произойдет так как SPI2 в буфере Tx будет ноль поэтому отправит его, после второго передачи пойдет так как надо. Если необходимо использовать все в прерывании то раскомментируйте нужные строки в коде и удалите ненужные.

#include "stm32f10x.h"
void config_spi1(void);
void config_spi2(void);
void pause(uint32_t i){while(i>0){i--;}}
uint8_t data;
int main()
{
//Сбрасываем настройки тактирования.
RCC_DeInit();
//Настраиваем SPI1 и SPI2.
config_spi1();
config_spi2();
//Настройки для светодиода.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef led;
led.GPIO_Pin=GPIO_Pin_7;
led.GPIO_Speed=GPIO_Speed_10MHz;
led.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &led);
//Настройка кнопки.
GPIO_InitTypeDef button;
button.GPIO_Pin=GPIO_Pin_0;
button.GPIO_Speed=GPIO_Speed_2MHz;
button.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &button);
while(1){
//Обработчик кнопки, если нажата выполним.
if(GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_0)){
//Отправляем в SPI2 65.
SPI_I2S_SendData( SPI1, 65);
while(SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_BSY));
pause(200000);
}
// Если используете прерывание то удалите от суда ++++.
if (SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE)){
data=SPI_I2S_ReceiveData(SPI2);
//Если SPI2 принял 65 то отсылаем в SPI1 66.
if( data==65){ SPI_I2S_SendData( SPI2, 66);}
pause(100000);
}
if (SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE)){
//Если SPI1 принял 66 то меняем состояние светодиода.
if(SPI_I2S_ReceiveData(SPI1)==66){ GPIOC->ODR ^= GPIO_Pin_7;}
}
// до суда ++++.
}
return 0;
}
//Два обработчика прерывания SPI1_IRQHandler и SPI2_IRQHandler, удалите если не используете.
void SPI1_IRQHandler(void){
if (SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE)){
//Если SPI1 принял 66 то меняем состояние светодиода.
if(SPI_I2S_ReceiveData(SPI1)==66){ GPIOC->ODR ^= GPIO_Pin_7;}
}
}
void SPI2_IRQHandler(void){
if (SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE)){
SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, DISABLE);
data=SPI_I2S_ReceiveData(SPI2);
//Если SPI2 принял 65 то отсылаем в SPI1 66.
if( data==65){ SPI_I2S_SendData( SPI2, 66);}
SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, ENABLE);
}
}
//Конфигурация для SPI1 .
void config_spi1(void){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef gpio_spi1;
gpio_spi1.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_7;
gpio_spi1.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi1.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio_spi1);
gpio_spi1.GPIO_Pin=GPIO_Pin_6;
gpio_spi1.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi1.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &gpio_spi1);
SPI_InitTypeDef spi1;
spi1.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
spi1.SPI_Mode=SPI_Mode_Master;
spi1.SPI_DataSize=SPI_DataSize_8b;
spi1.SPI_CPOL=SPI_CPOL_Low;
spi1.SPI_CPHA=SPI_CPHA_1Edge;
spi1.SPI_NSS=SPI_NSS_Soft;
spi1.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256;
spi1.SPI_FirstBit=SPI_FirstBit_LSB;
spi1.SPI_CRCPolynomial=7;
SPI_Init( SPI1, &spi1);
//Раскомментируйте следующие две строки для прерывания.
// SPI_I2S_ITConfig( SPI1, SPI_I2S_IT_RXNE, ENABLE);
// NVIC_EnableIRQ( SPI1_IRQn);
SPI_Cmd( SPI1, ENABLE);
}
//Конфигурация для SPI2.
void config_spi2(void){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE);
GPIO_InitTypeDef gpio_spi2;
gpio_spi2.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_15;
gpio_spi2.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi2.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &gpio_spi2);
gpio_spi2.GPIO_Pin=GPIO_Pin_14;
gpio_spi2.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi2.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &gpio_spi2);
SPI_InitTypeDef spi2;
spi2.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
spi2.SPI_Mode=SPI_Mode_Slave;
spi2.SPI_DataSize=SPI_DataSize_8b;
spi2.SPI_CPOL=SPI_CPOL_Low;
spi2.SPI_CPHA=SPI_CPHA_1Edge;
spi2.SPI_NSS=SPI_NSS_Soft;
spi2.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_64;
spi2.SPI_FirstBit=SPI_FirstBit_LSB;
spi2.SPI_CRCPolynomial=7;
SPI_Init( SPI2, &spi2);
//Раскомментируйте следующие две строки для прерывания.
// SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, ENABLE);
// NVIC_EnableIRQ( SPI2_IRQn);
SPI_Cmd( SPI2, ENABLE);
}

 SPI_Direction_2Lines_RxOnly-Рационально использовать этот режим только для SLAVE устройств которым нужно будет только принимать информацию, поэтому в подключении через MISO нет надобности. В этом примере будет показано как использовать вывод NSS у MASTER для управления NSS SLAVE в автоматическом режиме.

нет рисунка#include "stm32f10x.h"
void config_spi1(void);
void config_spi2(void);
void pause(uint32_t i){while(i>0){i--;}}
uint8_t data;
int main()
{
//Сбрасываем настройки тактирования.
RCC_DeInit();
//Настраиваем SPI1 и SPI2.
config_spi1();
config_spi2();
//Настройки для светодиода.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef led;
led.GPIO_Pin=GPIO_Pin_7;
led.GPIO_Speed=GPIO_Speed_10MHz;
led.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &led);
//Настройка кнопки.
GPIO_InitTypeDef button;
button.GPIO_Pin=GPIO_Pin_0;
button.GPIO_Speed=GPIO_Speed_2MHz;
button.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &button);
while(1){
//Обработчик кнопки, если нажата выполним.
if(GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_0)){
//Включаем SPI1 и автоматически выставится низкий уровень на NSS MASTER.
SPI_Cmd( SPI1, ENABLE);
//Отправляем в SPI2 65.
SPI_I2S_SendData( SPI1, 65);
while(SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_BSY));
//Выключаем SPI1 и автоматически выставится высокий уровень на NSS MASTER.
SPI_Cmd( SPI1, DISABLE);
pause(200000);
}
// Если используете прерывание то удалите от суда ++++.
if (SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE)){
data=SPI_I2S_ReceiveData(SPI2);
//Если SPI2 принял 65 то меняем состояние светодиода.
if( data==65){ GPIOC->ODR ^= GPIO_Pin_7;}
}
// до суда ++++.
}
return 0;
}
//Обработчик SPI2_IRQHandler, удалите если не используете.
void SPI2_IRQHandler(void){
if (SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE)){
SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, DISABLE);
data=SPI_I2S_ReceiveData(SPI2);
//Если SPI2 принял 65 то меняем состояние светодиода.
if( data==65){ GPIOC->ODR ^= GPIO_Pin_7;}
SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, ENABLE);
}
}
//Конфигурация для SPI1 .
void config_spi1(void){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef gpio_spi1;
gpio_spi1.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7;
gpio_spi1.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi1.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio_spi1);
SPI_InitTypeDef spi1;
spi1.SPI_Direction=SPI_Direction_1Line_Tx;
spi1.SPI_Mode=SPI_Mode_Master;
spi1.SPI_DataSize=SPI_DataSize_8b;
spi1.SPI_CPOL=SPI_CPOL_Low;
spi1.SPI_CPHA=SPI_CPHA_1Edge;
spi1.SPI_NSS=SPI_NSS_Hard;
spi1.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_64;
spi1.SPI_FirstBit=SPI_FirstBit_LSB;
spi1.SPI_CRCPolynomial=7;
SPI_Init( SPI1, &spi1);
SPI_SSOutputCmd( SPI1, ENABLE);
SPI_Cmd( SPI1, DISABLE);
}
//Конфигурация для SPI2.
void config_spi2(void){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE);
GPIO_InitTypeDef gpio_spi2;
gpio_spi2.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;
gpio_spi2.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi2.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &gpio_spi2);
SPI_InitTypeDef spi2;
spi2.SPI_Direction=SPI_Direction_2Lines_RxOnly;
spi2.SPI_Mode=SPI_Mode_Slave;
spi2.SPI_DataSize=SPI_DataSize_8b;
spi2.SPI_CPOL=SPI_CPOL_Low;
spi2.SPI_CPHA=SPI_CPHA_1Edge;
spi2.SPI_NSS=SPI_NSS_Hard;
spi2.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_64;
spi2.SPI_FirstBit=SPI_FirstBit_LSB;
spi2.SPI_CRCPolynomial=7;
SPI_Init( SPI2, &spi2);
//Раскомментируйте следующие две строки для прерывания.
// SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, ENABLE);
// NVIC_EnableIRQ( SPI2_IRQn);
SPI_Cmd( SPI2, ENABLE);
}

 SPI_Direction_1Line_Rx и SPI_Direction_1Line_Tx-Два одинаковых режима только направление движение данных разное, один отсылает другой принимает, также одной командой можно сменить направление без перенастройки SPI. Обязательно нужно синхронизировать передачи с помощью вывода NSS у SLAVE, в примере я покажу как с помощью обычного порта можно это сделать, также так нужно делать для управления множества SLAVE устройств, да и обращаю внимание что вывод MOSI или MISO нужно подтянуть внешним сопротивлением 10K к питанию.

нет рисунка

 Тут тоже все просто, наш контроллер настроенный как MASTER отправляет другому контроллеру число 65, в ответ должен получить 128, если все удачно светодиод должен поменять состояние.

#include "stm32f10x.h"
void config_spi1(void);
void pause(uint32_t i){while(i>0){i--;}}
uint8_t data;
int main()
{
//Сбрасываем настройки тактирования.
RCC_DeInit();
//Настройки для светодиода.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef led;
led.GPIO_Pin=GPIO_Pin_7;
led.GPIO_Speed=GPIO_Speed_10MHz;
led.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &led);
//Настройка кнопки.
GPIO_InitTypeDef button;
button.GPIO_Pin=GPIO_Pin_0;
button.GPIO_Speed=GPIO_Speed_2MHz;
button.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &button);
//Настраиваем SPI1.
config_spi1();
while(1){
//Обработчик кнопки, если нажата выполним.
if(GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_0)){
//Разрешаем работу SLAVE.
GPIO_ResetBits( GPIOA, GPIO_Pin_8);
//Отправляем 65.
SPI_I2S_SendData( SPI1, 65);
while(!SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ));
while(SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_BSY));
//Запрещаем работу SLAVE.
GPIO_SetBits( GPIOA, GPIO_Pin_8);
//Ждем когда SLAVE приготовит ответ.
pause(200);
//Тут будем принимать ответ.
GPIO_ResetBits( GPIOA, GPIO_Pin_8);
SPI_BiDirectionalLineConfig( SPI1, SPI_Direction_Rx);
//Если используете прерывание удалите от сюда ++++.
while(!SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE));
data=SPI_I2S_ReceiveData(SPI1);
if( data==128){GPIOC->ODR ^= GPIO_Pin_7;}
GPIO_SetBits( GPIOA, GPIO_Pin_8);
SPI_BiDirectionalLineConfig( SPI1, SPI_Direction_Tx);
//до сюда ++++.
pause(200000);
}
}
return 0;
}
//Обработчик SPI1_IRQHandler, удалите если не используете.
void SPI1_IRQHandler(void){
if (SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE)){
data=SPI_I2S_ReceiveData(SPI1);
if( data==128){GPIOC->ODR ^= GPIO_Pin_7;}
GPIO_SetBits( GPIOA, GPIO_Pin_8);
SPI_BiDirectionalLineConfig( SPI1, SPI_Direction_Tx);
}
}
//Конфигурация для SPI1 .
void config_spi1(void){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef gpio_spi1;
gpio_spi1.GPIO_Pin=GPIO_Pin_5;
gpio_spi1.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi1.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio_spi1);
gpio_spi1.GPIO_Pin=GPIO_Pin_7;
gpio_spi1.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi1.GPIO_Mode=GPIO_Mode_AF_OD;
GPIO_Init(GPIOA, &gpio_spi1);
GPIO_InitTypeDef Port_Out;
Port_Out.GPIO_Pin=GPIO_Pin_8;
Port_Out.GPIO_Speed=GPIO_Speed_50MHz;
Port_Out.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &Port_Out);
GPIO_SetBits( GPIOA, GPIO_Pin_8);
SPI_InitTypeDef spi1;
spi1.SPI_Direction=SPI_Direction_1Line_Tx;
spi1.SPI_Mode=SPI_Mode_Master;
spi1.SPI_DataSize=SPI_DataSize_8b;
spi1.SPI_CPOL=SPI_CPOL_Low;
spi1.SPI_CPHA=SPI_CPHA_1Edge;
spi1.SPI_NSS=SPI_NSS_Soft;
spi1.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256;
spi1.SPI_FirstBit=SPI_FirstBit_LSB;
spi1.SPI_CRCPolynomial=7;
SPI_Init( SPI1, &spi1);
//Раскомментируйте следующие две строки для прерывания.
// SPI_I2S_ITConfig( SPI1, SPI_I2S_IT_RXNE, ENABLE);
// NVIC_EnableIRQ( SPI1_IRQn);
SPI_Cmd( SPI1, ENABLE);
}

 Это пример для SLAVE устройства, которое будет отвечать для примера выше.

#include "stm32f10x.h"
void config_spi2(void);
uint8_t data;
int main()
{
//Сбрасываем настройки тактирования.
RCC_DeInit();
//Настраиваем SPI2.
config_spi2();
while(1){
// Если используете прерывание то удалите от суда ++++.
if (SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE)){
data=SPI_I2S_ReceiveData(SPI2);
//Если принял 65 то отсылаем 128.
if( data==65){
SPI_BiDirectionalLineConfig( SPI2, SPI_Direction_Tx);
SPI_I2S_SendData( SPI2, 128);
while(!SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_TXE ));
while(SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_BSY));
SPI_BiDirectionalLineConfig( SPI2, SPI_Direction_Rx);
}
}
// до суда ++++.
}
return 0;
}
//Обработчик SPI2_IRQHandler, удалите если не используете.
void SPI2_IRQHandler(void){
if (SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE)){
SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, DISABLE);
data=SPI_I2S_ReceiveData(SPI2);
//Если принял 65 то отсылаем 128.
if( data==65){
SPI_BiDirectionalLineConfig( SPI2, SPI_Direction_Tx);
SPI_I2S_SendData( SPI2, 128);
while(!SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_TXE ));
while(SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_BSY));
SPI_BiDirectionalLineConfig( SPI2, SPI_Direction_Rx);
}
SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, ENABLE);
}
}
//Конфигурация для SPI2.
void config_spi2(void){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE);
GPIO_InitTypeDef gpio_spi2;
gpio_spi2.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13;
gpio_spi2.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi2.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &gpio_spi2);
gpio_spi2.GPIO_Pin=GPIO_Pin_14;
gpio_spi2.GPIO_Speed=GPIO_Speed_50MHz;
gpio_spi2.GPIO_Mode=GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &gpio_spi2);
SPI_InitTypeDef spi2;
spi2.SPI_Direction=SPI_Direction_1Line_Rx;
spi2.SPI_Mode=SPI_Mode_Slave;
spi2.SPI_DataSize=SPI_DataSize_8b;
spi2.SPI_CPOL=SPI_CPOL_Low;
spi2.SPI_CPHA=SPI_CPHA_1Edge;
spi2.SPI_NSS=SPI_NSS_Hard;
spi2.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_64;
spi2.SPI_FirstBit=SPI_FirstBit_LSB;
spi2.SPI_CRCPolynomial=7;
SPI_Init( SPI2, &spi2);
//Раскомментируйте следующие две строки для прерывания.
// SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, ENABLE);
// NVIC_EnableIRQ( SPI2_IRQn);
SPI_Cmd( SPI2, ENABLE);
}
Статья №22 Дата:24/03/2018

Комментарии.