在STM32单片机中使用SPI通信的方法

发布时间:2023-07-18  

  在本教程中,我们将使用 STM32F103C8 的 Blue Pill 板替换一个 Arduino 板,并将使用 SPI 总线与 Arduino 板进行通信。在这个STM32 SPI 示例中,我们将使用Arduino UNO作为 Slave,STM32F103C8 作为 Master,两个16X2 LCD 显示器分别连接在一起。两个电位器还与STM32(PA0)和Arduino(A0)相连,通过改变电位器来确定主机到从机和从机到主机的发送值(0到255)。


  STM32F103C8中的SPI

  比较 Arduino 和 STM32F103C8 Blue Pill 板中的 SPI 总线,STM32 有2 条 SPI 总线,而 Arduino Uno 有1 条 SPI 总线。Arduino Uno 有 ATMEGA328 微控制器,STM32F103C8 有 ARM Cortex-M3,比 Arudino Board 更快。

  STM32 SPI 引脚 STM32F103C8

pYYBAGMquJeAbfnTAAlcR116xPU770.pngpoYBAGMquJKAfC8mAAAWgn_caiM477.png

  Arduino 中的 SPI 引脚

poYBAGMquI6AevvjAADxNp7ctlU722.png

poYBAGMquIqAXptFAAAPzvucxx8719.png

  所需组件

  STM32F103C8

  阿杜诺

  液晶 16x2 - 2

  10k 电位器 – 4

  面包板

  连接电线

  STM32 SPI教程的电路图和连接

pYYBAGMquIaARYc9AALiGqnSHao453.png

poYBAGMquIKAHHoAAAiOPVWmu7k492.png

  下表显示了STM32 SPI与 Arduino 通信连接的引脚。

pYYBAGMquH6AbTJnAAAOfofIS-E221.png

  下表显示了两个 LCD (16x2) 分别与 STM32F103C8 和 Arduino连接的引脚。

poYBAGMquHaATapiAAAj2s4JF0Y014.png

  重要的:

  不要忘记将 Arduino GND 和 STM32F103C8 GND 连接在一起。

  STM32 SPI编程

  编程类似于 Arduino 代码。在 STM32F103C8 编程中使用了相同的《SPI.h》库。它可以在不使用 FTDI 编程器的情况下使用 USB 端口进行编程,要了解有关 使用 Arduino IDE 对 STM32 进行编程的更多信息,请 点击链接。

Master STM32 SPI编程讲解

1.首先我们需要 包含 使用SPI通信功能的SPI库和使用LCD功能的LCD库。还为 16x2 LCD 定义 LCD 引脚。在此处了解有关LCD 与 STM32 接口的 更多信息。

 

#include     

#include 

const int rs = PB0, en = PB1, d4 = PB10, d5 = PB11, d6 = PC13, d7 = PC14;  

LiquidCrystal lcd(rs,en,d4,d5,d6,d7);

 

2. 在 void setup()

以波特率 9600 开始串行通信。

 

序列号.开始(9600);

 

接下来开始SPI通信

 

SPI.开始();

 

然后为 SPI 通信设置时钟分频器。我设置了分隔线 16。

 

SPI.setClockDivider(SPI_CLOCK_DIV16);

 

接下来将 SS 引脚设置为高电平,因为我们没有开始向从 arduino 进行任何传输。

 

数字写入(SS,HIGH);

 

3. 在void loop()

在向从机发送任何值之前,我们需要降低从机选择值以开始从主机传输到从机。

 

数字写入(SS,低);

 

接下来从连接到引脚 PA0 的主控 STM32F10C8 POT 读取模拟值。

 

int pot = 模拟读取(PA0);

 

然后将该值转换为一个字节(0 到 255)。

 

字节 MasterSend = map(pot,0,4096,0,255);

 

这是重要的一步,在下面的语句中,我们将存储在Mastersend变量中的转换后的 POT 值发送到从 Arduino,并从从 Arduino 接收值并将其存储在mastereceive变量中。

 

Mastereceive = SPI.transfer(Mastersend);

 

接下来以 500 微秒的延迟显示从从 arduino 接收到的值,然后连续接收并显示这些值。

 

Serial.println("从 Arduino 到主 STM32");                               
Serial.println(MasterReceive lcd.setCursor(0,0);                                                          
lcd.print("Master: STM32"); 
lcd.setCursor(0,1);                                                    
lcd.print("SalveVal:");                                                          
lcd.print(MasterReceive delay (500);
数字写入(SS,高);

 

注意:我们使用 serial.println() 在 Arduino IDE 的 Serial Motor 中查看结果。

从机 Arduino SPI 编程说明

1.和master一样,首先我们需要 包含使用I2C通信功能的SPI库 和使用LCD功能的LCD库。还为 16x2 LCD 定义 LCD 引脚。

 

#include   

#include 

LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // 定义 LCD 模块引脚 (RS,EN,D4,D5,D6,D7)

 

2. 在 void setup()

我们以波特率 9600 开始串行通信。

 

序列号.开始(9600);

 

下面的语句将 MISO 设置为 OUTPUT(必须将数据发送到 Master IN)。因此数据通过 Slave Arduino 的 MISO 发送。

 

pinMode(味噌,输出);

 

现在通过使用 SPI 控制寄存器在从模式下打开 SPI

 

SPCR |= _BV(SPE);

 

然后为 SPI 通信打开中断。如果从主机接收到数据,则调用中断服务程序并从 SPDR(SPI 数据寄存器)中获取接收到的值

 

SPI.attachInterrupt();

 

master 的值取自 SPDR 并存储在Slavereceived变量中。这发生在以下中断例程函数中。

 

中断服务程序(SPI_STC_vect)
{
  从机接收 = SPDR;                  
  收到=真;                       
}

 

3.next in void loop()

从连接到引脚 A0 的 Slave Arduino POT 读取模拟值。

 

int pot = 模拟读取(A0);

 

将该值以一个字节为单位转换为 0 到 255。 

 

Slavesend = map(pot,0,1023,0,255);

 

下一个重要步骤是将转换后的值发送到主控 STM32F10C8,因此将值放入 SPDR 寄存器。SPDR 寄存器用于发送和接收值。

 

SPDR = 从发送;

 

然后以 500 微秒的延迟在 LCD 上显示从主控 STM32F103C8 接收到的值(SlaveReceive),然后连续接收并显示这些值。

 

lcd.setCursor(0,0);                     
lcd.print("奴隶:阿杜诺"); 
lcd.setCursor(0,1);                                                    
lcd.print("MasterVal:");   
Serial.println("主 STM32 到从 Arduino");  
Serial.println(SlaveReceived);                  
lcd.print(SlaveReceived);                       
延迟(500);

 

  通过 旋转一侧的电位器,您可以在另一侧的 LCD 上看到不同的值:

pYYBAGMquG2AW-wDAAX7XOyq3IE899.png

这就是 STM32 中 SPI 通信的方式。现在您可以将任何 SPI 传感器与 STM32 板连接。

//STM32F103C8的SPI Master代码

//STM32和Arduino之间的SPI通信

#include // 包含使用 SPI 通信的库


#define SS PA4


#include // 包括LCD显示库


const int rs = PB0, en = PB1, d4 = PB10, d5 = PB11, d6 = PC13, d7 = PC14; // 声明 lcd 的管脚名称和管脚编号


LiquidCrystal lcd(rs,en,d4,d5,d6,d7); // 设置 lcd 及其参数


无效设置(无效)


{

lcd.begin(16,2); // 设置 lcd 为 16x2 模式

lcd.setCursor(0,0); // 在第一行第一列设置光标

lcd.print("CIRCUIT DIGEST"); // 将 CIRCUIT DIGEST 放入 LCD

延迟(3000);// 延迟 3 秒

lcd.clear(); // 清除液晶显示器



Serial.begin(9600); // 以波特率 9600 开始串行通信

pinMode(SS,输出);// 将 SS 作为输出

SPI.begin(); // 开始 SPI 通信

SPI.setClockDivider(SPI_CLOCK_DIV16); // 将 SPI 通信的时钟设置为 16 (72/16=4.5Mhz)

digitalWrite(SS,HIGH); // 将 SlaveSelect 设置为 HIGH(所以 master 不与 slave 连接)

}


无效循环(无效)

{



字节MasterSend,MasterReceive;



int pot = 模拟读取(PA0);// 模拟读取引脚 PA0 的输入电位器值



MasterSend = map(pot,0,4096,0,255); // 用于将 0 到 255 的罐值从 0 转换为 4096



digitalWrite(SS, LOW); // 开始与连接到主控的从属通信



MasterReceive=SPI.transfer(MasterSend); // 将 mastersend 值发送到 slave 也从 slave 接收值

Serial.println("Slave Arduino to Master STM32"); // 用于串行监视器

Serial.println(MasterReceive); // 将接收到的值放入串行监视器

lcd.setCursor(0,0);

lcd.print("主控:STM32");

lcd.setCursor(0,1);

lcd.print("SalveVal:");

lcd.print(MasterReceive); // 将接收到的值从 slave arduino

delay(500);

数字写入(SS,高);// 再次将 SS 线设为高电平,使其不与从属

lcd.clear() 通信;


}





从 Arduino SPI

//Arduino的SPI从代码

//STM32F103C8和Arduino之间的SPI通信

//电路文摘



#include // 包括使用 SPI 通信的库

#include // 包括 LCD 显示库

LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // 定义 LCD 模块引脚 (RS,EN,D4,D5,D6,D7)

接收到的易失布尔值;

易失字节SlaveReceived,Slavesend;

无效设置()


{

lcd.begin(16,2); // 初始化 LCD 显示

lcd.setCursor(0,0); // 在 Display 的第一行设置光标

lcd.print("CIRCUIT DIGEST"); // 在 LCD

delay(3000) 中打印 CIRCUIT DIGEST;// 延迟 3 秒

lcd.clear(); // 清除 LCD 显示



Serial.begin(9600); // 以波特率 9600 开始串行通信



pinMode(MISO,OUTPUT); // 将 MISO 设置为 OUTPUT(必须向 Master IN 发送数据(STM32F103C8)


SPCR |= _BV(SPE); // 在从机模式下打开 SPI

received = false;

SPI.attachInterrupt(); // 为 SPI 通信设置 Interuupt ON

}


ISR (SPI_STC_vect) // Inerrrput 例程函数

{

SlaveReceived = SPDR; // 从主控STM32F103C8接收的值存储在变量slavereceived

received = true; // 设置接收为 True

}


无效循环()

{

int pot =模拟读取(A0);// 模拟从模拟引脚 A0 读取输入电位器值

Slavesend = map(pot,0,1023,0,255); // 将值 pot (0-1023) 转换为 (0-255) 以发送到主控 stm32



SPDR = Slavesend; // 通过 SPDR 将 salvesend 值发送给主控 STM32F103C8

lcd.setCursor(0,0);

lcd.print("奴隶:阿杜诺");

lcd.setCursor(0,1);

lcd.print("MasterVal:");

Serial.println("主 STM32 到从 Arduino");

Serial.println(SlaveReceived);

lcd.print(SlaveReceived); // 将从主控 STM32F103C8 接收到的值置于 LCD 显示

延迟(500)处;

lcd.clear();

}


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>