1、初始化spi时钟
void spiRccinit(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
}
2、配置spi的GPIO引脚
void spiGPIOInit(void){
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = GPIO_Pin_4; //片选
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &gpio_init);
gpio_init.GPIO_Pin = GPIO_Pin_5; //时钟
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio_init);
gpio_init.GPIO_Pin = GPIO_Pin_7; //MOSI
GPIO_Init(GPIOA, &gpio_init);
gpio_init.GPIO_Pin = GPIO_Pin_6; //MISO
GPIO_Init(GPIOA, &gpio_init);
}
3、配置并使能spi
void spiConfigure(void){
SPI_InitTypeDef spi_Init;
spi_Init.SPI_CPHA = SPI_CPHA_2Edge;
spi_Init.SPI_CPOL = SPI_CPOL_Low;
spi_Init.SPI_DataSize = SPI_DataSize_8b;
spi_Init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
spi_Init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi_Init.SPI_FirstBit = SPI_FirstBit_MSB;
spi_Init.SPI_Mode = SPI_Mode_Master;
spi_Init.SPI_NSS = SPI_NSS_Soft;
spi_Init.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &spi_Init);
SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE);
SPI_Cmd(SPI1,ENABLE);
}
4、配置spi中断
void spiNivcConfiguration(void){
NVIC_InitTypeDef nvic_init;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
nvic_init.NVIC_IRQChannel = SPI1_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
nvic_init.NVIC_IRQChannelSubPriority = 1;
nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init);
}
5、实现中断处理 函数
void SPI1_IRQHandler(void){
if(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != RESET){
if(send[++sendCount] != '\0'){
SPI_I2S_SendData(SPI1, send[sendCount]);
}
else {
SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_TXE, DISABLE);
}
}
if(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != RESET){
recv[recvCount] = SPI_I2S_ReceiveData(SPI1);
if(recv[recvCount] == '*'){
recv[recvCount + 1] = '\0';
printf("recv data: %s\r\n", recv);
recvCount = 0;
}
else {
recvCount++;
if(recvCount == 1023){
recvCount = 0;
}
}
}
}
注:中断函数里用到的变量均为全局变量:
u8 recv[1024] = {'\0'};
u8 send[1024] = {'\0'};
volatile u16 recvCount = 0;
volatile u16 sendCount = 0;
6、实现简单的发送函数:
void spiWrite(const char *p){
strcpy(send, p);
sendCount = 0;
// while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, send[sendCount]);
SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_TXE, ENABLE);
// while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
// recv[0] = SPI_I2S_ReceiveData(SPI1);
// recv[1] = '\0';
// printf("recv ok! ");
// printf(recv);
}
7、总结:
1、仔细阅读stm32 datasheet关于spi的部分。
2、配置spi时钟(一定要先初始化时钟)
3、配置spi的gpio引脚
4、配置spi
5、配置中断
6、实现中断处理函数
7、简单实现发送函数
8、遗留问题:
采用中断发送的方式,发现在关闭掉SPI中断后(SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_TXE, DISABLE)),
还是能进入到发送中断中,所以sendCount的清零要注意,最好不要在中断中。
原因:猜测是stm32执行SPI_I2S_ITConfig函数时要花费一定的时间,而spi的发送中断在此期间会不断进入。