#include "SN_SPI.h" /* 文件名:SN_SPI.c/.h 作者: SN_FAE_黄泽洪 免责声明:无版权,可随意传播和篡改,该代码仅供开发参考,如需使用请自行验证 本人不担负商业使用上带来的风险。 */ /* SN_SPI模块使用方法 1.使用硬件nss uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88}; uint8_t RX_BULL[8] = {0}; int main(void){ SN_SYSCLK_set(SYSCLK_48MHZ); std_delay_init(); SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_PA6 ); SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB ); while(1){ std_delayms(500); SN_SPI_TX_RX(BULL ,RX_BULL ,8); } } 2.使用软件设置普通io做CS片选 uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88}; uint8_t RX_BULL[8] = {0}; int main(void){ SN_SYSCLK_set(SYSCLK_48MHZ); std_delay_init(); SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_NULL ); SN_SPI_IO_SOF_cs(SPI_SOF_CS_PC1); SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB ); while(1){ std_delayms(500); SN_SPI_TX_RX(BULL ,RX_BULL ,8); } } 3.不使用片选,用户将spi从机强制设置CS下拉 uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88}; uint8_t RX_BULL[8] = {0}; int main(void){ SN_SYSCLK_set(SYSCLK_48MHZ); std_delay_init(); SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_NULL ); SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB ); while(1){ std_delayms(500); SN_SPI_TX_RX(BULL ,RX_BULL ,8); } } */ //全局NSS引脚设置标志 uint8_t SPI_NSS_EN = 0; GPIO_t * G_GPIO_X = NULL; uint16_t G_GPIO_PIN_x = 0; //全局唯一软件cs接口 static struct { void (*SN_SPI_CS_H)(void) ; //用户实现这两个函数,并通过SN_SPI_CS_t,传入通信接收和发送函数中使用 void (*SN_SPI_CS_L)(void) ; } SN_SPI_CS_t; //脱裤子放屁函数 static void SN_SPI_SOF_CS_H(void){ std_gpio_set_pin(G_GPIO_X, G_GPIO_PIN_x); } static void SN_SPI_SOF_CS_L(void){ std_gpio_reset_pin(G_GPIO_X, G_GPIO_PIN_x); } /* 函数:void SN_SPI_IO_SOF_cs() 参数:软件cs片选引脚设置 (注意不要io冲突) @SPI_SOF_CS_PA0 @SPI_SOF_CS_PA1 @SPI_SOF_CS_PA2 //注意使用PA2是仿真接口,在线仿真时该io口不能被使用 @SPI_SOF_CS_PA3 @SPI_SOF_CS_PA4 @SPI_SOF_CS_PA5 @SPI_SOF_CS_PA7 @SPI_SOF_CS_PB0 @SPI_SOF_CS_PB1 @SPI_SOF_CS_PB2 @SPI_SOF_CS_PB3 @SPI_SOF_CS_PB4 @SPI_SOF_CS_PB5 @SPI_SOF_CS_PB6 //注意使用PB6是仿真接口,在线仿真时该io口不能被使用 @SPI_SOF_CS_PB7 @SPI_SOF_CS_PC0 @SPI_SOF_CS_PC1 返回:无 */ void SN_SPI_IO_SOF_cs(uint8_t SPI_SOF_CS_Px){ std_gpio_init_t gpio_config = {0}; uint32_t RCC_PERIPH_CLK_GPIOx = 0; RCC_PERIPH_CLK_GPIOx = (SPI_SOF_CS_Px < 9 ) ? RCC_PERIPH_CLK_GPIOA : ( SPI_SOF_CS_Px < 17) ? RCC_PERIPH_CLK_GPIOB : RCC_PERIPH_CLK_GPIOC; //时钟 G_GPIO_X = (SPI_SOF_CS_Px < 9 ) ? GPIOA : ( SPI_SOF_CS_Px < 17) ? GPIOB : GPIOC; //端口 G_GPIO_PIN_x = (SPI_SOF_CS_Px < 9 ) ? (GPIO_PIN_0<< (SPI_SOF_CS_Px - 1)): ( SPI_SOF_CS_Px < 17) ? (GPIO_PIN_0<< (SPI_SOF_CS_Px - 9)) : (GPIO_PIN_0<< (SPI_SOF_CS_Px - 17)); //引脚 //初始化 std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx); gpio_config.pin = G_GPIO_PIN_x; //选择IO编号 gpio_config.mode = GPIO_MODE_OUTPUT; //设置为输出 gpio_config.pull = GPIO_NOPULL; //无上下拉设置 gpio_config.output_type = GPIO_OUTPUT_PUSHPULL; //推挽输出 std_gpio_init(G_GPIO_X, &gpio_config); //初始 //设置输出高 std_gpio_set_pin(G_GPIO_X, G_GPIO_PIN_x); //设置cs为高,取消片选 SN_SPI_CS_t.SN_SPI_CS_H = SN_SPI_SOF_CS_H ; //连接软件片选信号 SN_SPI_CS_t.SN_SPI_CS_L = SN_SPI_SOF_CS_L ; } /* 函数:void SN_SPI_IO_set(uint8_t SPI_MOSI_x , uint8_t SPI_MISO_x , uint8_t SPI_SCK_x, uint8_t SPI_NSS_x) 参数:MOSI @SPI_MOSI_PA0 @SPI_MOSI_PA7 @SPI_MOSI_PB7 参数:MISO @SPI_MISO_PA1 @SPI_MISO_PB6 (PB6是仿真接口,在线仿真时不要用) @SPI_MISO_PC1 参数:SCK @SPI_SCK_PA6 @SPI_SCK_PB0 @SPI_SCK_PB2 参数:NSS @SPI_NSS_NULL (不使用硬件片选,用户要自行设置软件cs使能调用) @SPI_NSS_PA6 @SPI_NSS_PB0 @SPI_NSS_PB2 返回:无 */ void SN_SPI_IO_set(uint8_t SPI_MOSI_x , uint8_t SPI_MISO_x , uint8_t SPI_SCK_x, uint8_t SPI_NSS_x ){ //注意 spi初始化的 sck 电平 std_gpio_init_t gpio_config = {0}; uint32_t RCC_PERIPH_CLK_GPIOx = 0; GPIO_t * GPIO_X = NULL; uint16_t GPIO_PIN_x = 0; uint8_t GPIO_AF0_x = 0; //处理SPI_MOSI GPIO_AF0_x = GPIO_AF0_SPI1; //af复用选项 GPIO_PIN_x = (SPI_MOSI_x == 1) ? GPIO_PIN_0 : GPIO_PIN_7 ; //设置引脚io GPIO_X = (SPI_MOSI_x != 3) ? GPIOA : GPIOB ; //设置io端口 RCC_PERIPH_CLK_GPIOx = ( SPI_MOSI_x != 3) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB ; //设置时钟 std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx); gpio_config.pin = GPIO_PIN_x; //选择IO编号 gpio_config.mode = GPIO_MODE_ALTERNATE; //设置为复用功能 gpio_config.pull = GPIO_NOPULL; //无上下拉设置 gpio_config.output_type = GPIO_OUTPUT_PUSHPULL; //推挽输出 gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1 std_gpio_init(GPIO_X, &gpio_config); //初始 //处理SPI_MISO GPIO_AF0_x = ( SPI_MISO_x != 2 ) ? GPIO_AF0_SPI1 : GPIO_AF4_SPI1 ; //af复用选项 GPIO_PIN_x = ( SPI_MISO_x == 1 ) ? GPIO_PIN_1 : (( SPI_MISO_x == 2 ) ? ( GPIO_PIN_6 ): (GPIO_PIN_1 )) ; //设置引脚io GPIO_X = ( SPI_MISO_x == 1 ) ? GPIOA : (( SPI_MISO_x == 2 ) ? ( GPIOB ): ( GPIOC )) ; //设置io端口 RCC_PERIPH_CLK_GPIOx = ( SPI_MISO_x == 1 ) ? RCC_PERIPH_CLK_GPIOA : (( SPI_MISO_x == 2 ) ? ( RCC_PERIPH_CLK_GPIOB): ( RCC_PERIPH_CLK_GPIOC )) ; //设置时钟 std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx); gpio_config.pin = GPIO_PIN_x ; //选择IO编号 gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1 std_gpio_init(GPIO_X, &gpio_config); //初始 //SPI_SCK GPIO_AF0_x = ( SPI_SCK_x == 1 ) ? GPIO_AF4_SPI1 : GPIO_AF0_SPI1 ; //af复用选项 GPIO_PIN_x = ( SPI_SCK_x == 1 ) ? GPIO_PIN_6 : (( SPI_SCK_x == 2 ) ? ( GPIO_PIN_0 ): (GPIO_PIN_2 )) ; //设置引脚io GPIO_X = ( SPI_SCK_x == 1 ) ? GPIOA : GPIOB ; //设置io端口 RCC_PERIPH_CLK_GPIOx = ( SPI_SCK_x == 1 ) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB; //设置时钟 std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx); gpio_config.pull = GPIO_PULLUP; gpio_config.pin = GPIO_PIN_x ; //选择IO编号 gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1 std_gpio_init(GPIO_X, &gpio_config); //初始 //SPI_NSS if(SPI_NSS_x != 1){ GPIO_AF0_x = GPIO_AF0_SPI1; //af复用选项 GPIO_PIN_x = ( SPI_NSS_x == 2 ) ? GPIO_PIN_6 : ( SPI_NSS_x == 3 ) ? GPIO_PIN_1 : GPIO_PIN_5 ; //设置引脚io GPIO_X = ( SPI_NSS_x == 2 ) ? GPIOA : GPIOB ; //设置io端口 RCC_PERIPH_CLK_GPIOx = ( SPI_NSS_x == 2 ) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB; //设置时钟 std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx); gpio_config.pin = GPIO_PIN_x ; //选择IO编号 gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1 std_gpio_init(GPIO_X, &gpio_config); //初始 }else{ SPI_NSS_EN = 1; //设置全局标志,说明NSS引脚没被使用 } } /* 函数:SN_SPI_MASTER_init(uint32_t SPI_DIV, uint8_t SPI_MODE_X , uint8_t SPI_MSB_OR_LSB ) 参数:spi分频系数(分频系数) @SPI_BAUD_PCLKDIV_2 SPI速率为fPLCK/2 最高24M,系统时钟必须在48MHZ @SPI_BAUD_PCLKDIV_4 SPI速率为fPLCK/4 @SPI_BAUD_PCLKDIV_8 SPI速率为fPLCK/8 @SPI_BAUD_PCLKDIV_16 SPI速率为fPLCK/16 @SPI_BAUD_PCLKDIV_32 SPI速率为fPLCK/32 @SPI_BAUD_PCLKDIV_64 SPI速率为fPLCK/64 @SPI_BAUD_PCLKDIV_128 SPI速率为fPLCK/128 参数:spi通信模式 @SPI_MODE_0 @SPI_MODE_1 @SPI_MODE_2 @SPI_MODE_3 参数:spi数据对齐选择 @SPI_MSB @SPI_LSB 返回:无 */ void SN_SPI_MASTER_init(uint32_t SPI_DIV, uint8_t SPI_MODE_X , uint8_t SPI_MSB_OR_LSB ){ uint32_t SPI_POLARIT_x = 0; uint32_t SPI_PHASE_x = 0; //处理spi模块 std_spi_init_t spi_config = {0}; /* SPI1时钟使能 */ std_rcc_apb2_clk_enable(RCC_PERIPH_CLK_SPI1); /* 禁止SPI */ std_spi_disable(); /* SPI结构体初始化 使用SPI的00模式 */ spi_config.mode = SPI_MODE_MASTER; spi_config.baud_rate_prescaler = SPI_DIV; //spi工作速率 //设置spi模式 SPI_POLARIT_x = ((SPI_MODE_X == 0) || (SPI_MODE_X == 1)) ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH ; SPI_PHASE_x = ((SPI_MODE_X == 0) || (SPI_MODE_X == 2)) ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE ; spi_config.clk_polarity = SPI_POLARIT_x; //时钟空闲下为高电平 spi_config.clk_phase = SPI_PHASE_x; //第一个时钟边沿采样 spi_config.bitorder = SPI_MSB_OR_LSB; //先发高位 std_spi_init(&spi_config); //初始化参数 /* SPI主机模式,配置NSS输出使能 */ if(SPI_NSS_EN == 0 ){ std_spi_nss_output_enable(); SN_SPI_CS_t.SN_SPI_CS_H = NULL; SN_SPI_CS_t.SN_SPI_CS_L = NULL; } /* SPI使能 */ std_spi_enable(); //使能SPI } /* 函数:SN_SPI_TX_RX(uint8_t * send_data ,uint8_t * read_data ,uint16_t len) 功能:通过spi发送数据 参数:发送数组 参数:数组长度 返回: 无 */ void SN_SPI_TX_RX(uint8_t * send_data ,uint8_t * read_data ,uint16_t len){ uint16_t index = 0; /* SPI主机模式,拉低片选信号 */ if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_L(); } std_spi_set_nss_output(SPI_NSS_OUTPUT_LOW); /* SPI数据传输 */ for(index=0; index