spi通信
·
1:环境
stm32f103c8t6 2个(1个当主机,1个当从机)
keil5
杜邦线 若干
2:代码
主机 main.c
#include "stm32f10x.h"
// 引脚定义(SPI1)
#define SPI_MASTER_PORT GPIOA
#define SPI_SCK_PIN GPIO_Pin_5
#define SPI_MOSI_PIN GPIO_Pin_7
#define SPI_MISO_PIN GPIO_Pin_6
#define SPI_NSS_PIN GPIO_Pin_4 // 软件控制片选
// LED引脚定义 (PC13)
#define LED_PIN GPIO_Pin_13
#define LED_GPIO_PORT GPIOC
#define LED_GPIO_CLK RCC_APB2Periph_GPIOC
////////////////////////////////////////////////////////////////////////
int f_us=9;
int f_ms=9000;
void delay_init(void)
{
//??????? 72MHZ/8=9MHZ
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//9MHZ
}
//????16,777,216??,??????1,864,135us
int delay_us(int nus)//1us?9??,500us?500*9
{
u32 temp;
//????????
SysTick->LOAD = nus*f_us-1;
//??????0,????,??VAL?0?,????????????
SysTick->VAL=0X00;
//?????
SysTick->CTRL|=(0X01<<0);
do
{
temp=SysTick->CTRL;
}//?????????,???????????
while((temp&(0x01<<0))&&(!(temp&(0x01<<16))));
//?????
SysTick->CTRL&=~(0X01<<0);
return 0;
}
//????16,777,216??,??????1,864ms
int delay_ms(int nms)
{
u32 temp;
//????????
SysTick->LOAD = nms*f_ms-1;
//??????0,????,??VAL?0?,????????????
SysTick->VAL=0X00;
//?????
SysTick->CTRL|=(0X01<<0);
do
{
temp=SysTick->CTRL;
}//?????????,???????????
while((temp&(0x01<<0))&&(!(temp&(0x01<<16))));
//?????
SysTick->CTRL&=~(0X01<<0);
return 0;
}
int delay_s(int ns)
{
int n;
for(n=0;n<ns;n++)
{
delay_ms(1000);
}
return 0;
}
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// 使能LED引脚时钟
RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);
// 配置LED引脚(PC13)为推挽输出
GPIO_InitStructure.GPIO_Pin = LED_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
// 初始状态:LED熄灭
GPIO_SetBits(LED_GPIO_PORT, LED_PIN); // 假设LED是低电平点亮
}
// 点亮LED
void LED_On(void) {
GPIO_ResetBits(LED_GPIO_PORT, LED_PIN);
}
// 熄灭LED
void LED_Off(void) {
GPIO_SetBits(LED_GPIO_PORT, LED_PIN);
}
////////////////////////////////////////////////////////////////////////
// 初始化 SPI 主模式
void SPI_Master_Init(void) {
SPI_InitTypeDef SPI_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
// 配置SPI引脚(SCK/PA5, MOSI/PA7, MISO/PA6为复用推挽;NSS/PA4为通用推挽)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // MISO为输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // NSS软件控制
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_SetBits(GPIOA, GPIO_Pin_4); // 初始拉高片选
// SPI主模式配置
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // 36MHz/16=2.25Mbps
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE);
}
int8_t Master_Send_Receive(uint8_t tx_data) {
GPIO_ResetBits(GPIOA, GPIO_Pin_4); // 拉低片选,选中从设备
delay_us(1); // 延时确保从设备就绪
// 发送数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, tx_data);
// 接收从设备返回数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
uint8_t rx_data = SPI_I2S_ReceiveData(SPI1);
GPIO_SetBits(GPIOA, GPIO_Pin_4); // 拉高片选,结束通信
return rx_data;
}
int main(void) {
delay_init();
LED_Init();
uint8_t send_data = 0x11; // 初始发送数据
uint8_t recv_data =0;
SPI_Master_Init();
while (1) {
recv_data = Master_Send_Receive(send_data);
// 示例:如果从设备返回 0xEE,则表示接收成功
if (recv_data == send_data+1) {
send_data++; // 下次发送+1
if(send_data >=127) send_data = 1;
LED_On();
delay_ms(500);
LED_Off();
}
// 简单延时(约1秒)
delay_ms(800);
}
return 0;
}
/*
硬件连接(主从均为 F103C8T6)
主设备引脚 从设备引脚 信号名称
PA5 PA5 SCK(时钟线)
PA7 PA7 MOSI(主发从收)
PA6 PA6 MISO(主收从发)
PA4 PA4 NSS(片选,主控制)
GND GND 共地(必须连接)
*/
从机 main.c
#include "stm32f10x.h"
#include "stm32f10x_spi.h"
// 引脚定义(SPI1)
#define SPI_SLAVE_PORT GPIOA
#define SPI_SCK_PIN GPIO_Pin_5
#define SPI_MOSI_PIN GPIO_Pin_7
#define SPI_MISO_PIN GPIO_Pin_6
#define SPI_NSS_PIN GPIO_Pin_4 // 硬件片选(由主设备控制)
// LED引脚定义 (PC13)
#define LED_PIN GPIO_Pin_13
#define LED_GPIO_PORT GPIOC
#define LED_GPIO_CLK RCC_APB2Periph_GPIOC
////////////////////////////////////////////////////////////////////////
int f_us=9;
int f_ms=9000;
void delay_init(void)
{
//??????? 72MHZ/8=9MHZ
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//9MHZ
}
//????16,777,216??,??????1,864,135us
int delay_us(int nus)//1us?9??,500us?500*9
{
u32 temp;
//????????
SysTick->LOAD = nus*f_us-1;
//??????0,????,??VAL?0?,????????????
SysTick->VAL=0X00;
//?????
SysTick->CTRL|=(0X01<<0);
do
{
temp=SysTick->CTRL;
}//?????????,???????????
while((temp&(0x01<<0))&&(!(temp&(0x01<<16))));
//?????
SysTick->CTRL&=~(0X01<<0);
return 0;
}
//????16,777,216??,??????1,864ms
int delay_ms(int nms)
{
u32 temp;
//????????
SysTick->LOAD = nms*f_ms-1;
//??????0,????,??VAL?0?,????????????
SysTick->VAL=0X00;
//?????
SysTick->CTRL|=(0X01<<0);
do
{
temp=SysTick->CTRL;
}//?????????,???????????
while((temp&(0x01<<0))&&(!(temp&(0x01<<16))));
//?????
SysTick->CTRL&=~(0X01<<0);
return 0;
}
int delay_s(int ns)
{
int n;
for(n=0;n<ns;n++)
{
delay_ms(1000);
}
return 0;
}
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// 使能LED引脚时钟
RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);
// 配置LED引脚(PC13)为推挽输出
GPIO_InitStructure.GPIO_Pin = LED_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
// 初始状态:LED熄灭
GPIO_SetBits(LED_GPIO_PORT, LED_PIN); // 假设LED是低电平点亮
}
// 点亮LED
void LED_On(void) {
GPIO_ResetBits(LED_GPIO_PORT, LED_PIN);
}
// 熄灭LED
void LED_Off(void) {
GPIO_SetBits(LED_GPIO_PORT, LED_PIN);
}
////////////////////////////////////////////////////////////////////////
// 初始化 SPI 从模式
void SPI_Slave_Init(void) {
SPI_InitTypeDef SPI_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
// 配置SPI引脚(SCK/PA5, MOSI/PA7为输入;MISO/PA7为复用推挽;NSS/PA4为输入)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 从设备SCK/MOSI/NSS为输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出!
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;//GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// SPI从模式配置
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Slave; // 关键:从模式
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // 与主设备一致
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // 与主设备一致
SPI_InitStruct.SPI_NSS = SPI_NSS_Hard; // 硬件片选(由主设备控制)
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; // 从模式下无效
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE);
}
// 从设备接收数据并发送应答
uint8_t Slave_Receive_Send(void) {
uint8_t rx_data, tx_data = 0x22;
// 等待片选信号被拉低(主设备选中)
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) == SET);
// 等待主设备发送数据(NSS拉低后)
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
rx_data = SPI_I2S_ReceiveData(SPI1);
// 发送返回数据(与接收同步)
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, rx_data+1);
// 等待片选信号被拉高(通信结束)
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) == RESET);
return rx_data; // 返回收到的主设备数据
}
int main(void) {
delay_init();
LED_Init();
uint8_t recv_data,last_recv_data;
last_recv_data = 0x11;
SPI_Slave_Init();
while (1) {
recv_data = Slave_Receive_Send();
// 可在此处处理接收的数据(如判断、存储等)
if(recv_data == last_recv_data){
last_recv_data++ ;
if(last_recv_data >=127) last_recv_data = 1;
LED_On();
delay_ms(500);
LED_Off();
}else{
delay_ms(200);
}
}
return 0;
}
/*
硬件连接(主从均为 F103C8T6)
主设备引脚 从设备引脚 信号名称
PA5 PA5 SCK(时钟线)
PA7 PA7 MOSI(主发从收)
PA6 PA6 MISO(主收从发)
PA4 PA4 NSS(片选,主控制)
GND GND 共地(必须连接)
*/
说明
GPIO 接线
硬件连接(主从均为 F103C8T6)
主设备引脚 从设备引脚 信号名称
PA5 PA5 SCK(时钟线)
PA7 PA7 MOSI(主发从收)
PA6 PA6 MISO(主收从发)
PA4 PA4 NSS(片选,主控制)
GND GND 共地(必须连接)

3 1主2从
从机片选都是PA4,所以从机代码一样的,
主机代码
#include "stm32f10x.h"
// 引脚定义(SPI1)
#define SPI_MASTER_PORT GPIOA
#define SPI_SCK_PIN GPIO_Pin_5
#define SPI_MOSI_PIN GPIO_Pin_7
#define SPI_MISO_PIN GPIO_Pin_6
#define SPI_NSS_PIN GPIO_Pin_4 // 软件控制片选
#define SPI_NSS_PIN_2 GPIO_Pin_2 // 软件控制片选
// LED引脚定义 (PC13)
#define LED_PIN GPIO_Pin_13
#define LED_GPIO_PORT GPIOC
#define LED_GPIO_CLK RCC_APB2Periph_GPIOC
////////////////////////////////////////////////////////////////////////
int f_us=9;
int f_ms=9000;
void delay_init(void)
{
//??????? 72MHZ/8=9MHZ
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//9MHZ
}
//????16,777,216??,??????1,864,135us
int delay_us(int nus)//1us?9??,500us?500*9
{
u32 temp;
//????????
SysTick->LOAD = nus*f_us-1;
//??????0,????,??VAL?0?,????????????
SysTick->VAL=0X00;
//?????
SysTick->CTRL|=(0X01<<0);
do
{
temp=SysTick->CTRL;
}//?????????,???????????
while((temp&(0x01<<0))&&(!(temp&(0x01<<16))));
//?????
SysTick->CTRL&=~(0X01<<0);
return 0;
}
//????16,777,216??,??????1,864ms
int delay_ms(int nms)
{
u32 temp;
//????????
SysTick->LOAD = nms*f_ms-1;
//??????0,????,??VAL?0?,????????????
SysTick->VAL=0X00;
//?????
SysTick->CTRL|=(0X01<<0);
do
{
temp=SysTick->CTRL;
}//?????????,???????????
while((temp&(0x01<<0))&&(!(temp&(0x01<<16))));
//?????
SysTick->CTRL&=~(0X01<<0);
return 0;
}
int delay_s(int ns)
{
int n;
for(n=0;n<ns;n++)
{
delay_ms(1000);
}
return 0;
}
void LED_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// 使能LED引脚时钟
RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);
// 配置LED引脚(PC13)为推挽输出
GPIO_InitStructure.GPIO_Pin = LED_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
// 初始状态:LED熄灭
GPIO_SetBits(LED_GPIO_PORT, LED_PIN); // 假设LED是低电平点亮
}
// 点亮LED
void LED_On(void) {
GPIO_ResetBits(LED_GPIO_PORT, LED_PIN);
}
// 熄灭LED
void LED_Off(void) {
GPIO_SetBits(LED_GPIO_PORT, LED_PIN);
}
////////////////////////////////////////////////////////////////////////
// 初始化 SPI 主模式
void SPI_Master_Init(void) {
SPI_InitTypeDef SPI_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
// 配置SPI引脚(SCK/PA5, MOSI/PA7, MISO/PA6为复用推挽;NSS/PA4为通用推挽)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // MISO为输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // NSS软件控制
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_SetBits(GPIOA, GPIO_Pin_4); // 初始拉高片选
GPIO_InitStruct.GPIO_Pin = SPI_NSS_PIN_2;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // NSS软件控制2
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_SetBits(GPIOA, SPI_NSS_PIN_2); // 初始拉高片选
// SPI主模式配置
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // 36MHz/16=2.25Mbps
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE);
}
int8_t Master_Send_Receive(uint8_t tx_data) {
GPIO_ResetBits(GPIOA, GPIO_Pin_4); // 拉低片选,选中从设备
delay_us(1); // 延时确保从设备就绪
// 发送数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, tx_data);
// 接收从设备返回数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
uint8_t rx_data = SPI_I2S_ReceiveData(SPI1);
GPIO_SetBits(GPIOA, GPIO_Pin_4); // 拉高片选,结束通信
return rx_data;
}
int8_t Master_Send_Receive_2(uint8_t tx_data) {
GPIO_ResetBits(GPIOA, SPI_NSS_PIN_2); // 拉低片选,选中从设备
delay_us(1); // 延时确保从设备就绪
// 发送数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, tx_data);
// 接收从设备返回数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
uint8_t rx_data = SPI_I2S_ReceiveData(SPI1);
GPIO_SetBits(GPIOA, SPI_NSS_PIN_2); // 拉高片选,结束通信
return rx_data;
}
int main(void) {
delay_init();
LED_Init();
uint8_t send_data1 = 0x11; // 初始发送数据
uint8_t send_data2 = 0x11; // 初始发送数据
uint8_t recv_data1 =0;
uint8_t recv_data2 =0;
uint8_t bswitch = 0;
SPI_Master_Init();
while (1) {
if(bswitch == 0){ //丛机1
bswitch =1 ;
recv_data1 = Master_Send_Receive(send_data1);
// 示例:如果从设备返回 0xEE,则表示接收成功
if (recv_data1== send_data1+1) {
send_data1++; // 下次发送+1
if(send_data1 >=127) send_data1 = 1;
LED_On();
delay_ms(500);
LED_Off();
}
}else{ //丛机2
bswitch =0;
recv_data2 = Master_Send_Receive_2(send_data2);
// 示例:如果从设备返回 0xEE,则表示接收成功
if (recv_data2== send_data2+1) {
send_data2++; // 下次发送+1
if(send_data2 >=127) send_data2 = 1;
LED_On();
delay_ms(200);
LED_Off();
}
}
delay_ms(500);
}
return 0;
}
主 到从1 从2(从1 从2 这4个线是并联)
PA5 PA5 SCK(时钟线)
PA7 PA7 MOSI(主发从收)
PA6 PA6 MISO(主收从发)
GND GND 都跟接主的地
不同的地方
主 从1
PA4 PA4 NSS(片选,主控制)
主 从2
PA2 PA4 NSS(片选,主控制)

4测试
1主1从
地址1
1从
1主2从
地址2
1主2从
5:如果对你又帮助,麻烦点个赞,加个关注
demo 工程
更多推荐


所有评论(0)