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