当前位置: 首页 > news >正文

STM32G474RE使用SPI1中断发送和接收8位数据

STM32G474RE使用SPI1工作在主机模式,使用中断发送和接收8位数据,其作用:可以提高系统的整体效率和响应速度。

测试方法:PB3映射到SPI1_SCK,PB4映射到SPI1_MISO,PB5映射到SPI1_MOSI。测试时,将SPI1_MISO和SPI1_MOS短接,实现自发自收。

测试程序:

1、SPI.h程序

#ifndef __SPI1_H__
#define __SPI1_H__#include "stm32g4xx_hal.h"
//使能int8_t,int16_t,int32_t,int64_t
//使能uint8_t,uint16_t,uint32_t,uint64_t
#include "stm32g4xx_hal_spi.h"#define HalfWord  0/** @brief  Check whether the specified SPI flag is set or not.* @param  __SPIx__ specifies the SPI peripheral.*         This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral.* @param  __FLAG__ specifies the flag to check.*         This parameter can be one of the following values:*            @arg SPI_FLAG_RXNE: Receive buffer not empty flag*            @arg SPI_FLAG_TXE: Transmit buffer empty flag*            @arg SPI_FLAG_CRCERR: CRC error flag*            @arg SPI_FLAG_MODF: Mode fault flag*            @arg SPI_FLAG_OVR: Overrun flag*            @arg SPI_FLAG_BSY: Busy flag*            @arg SPI_FLAG_FRE: Frame format error flag*            @arg SPI_FLAG_FTLVL: SPI fifo transmission level*            @arg SPI_FLAG_FRLVL: SPI fifo reception level* @retval The new state of __FLAG__ (TRUE or FALSE).*/
#define _HAL_SPI_GET_FLAG(__SPIx__, __FLAG__) (( ( (__SPIx__)->SR ) & (__FLAG__) ) == (__FLAG__))#define _HAL_SPI_ENABLE(__SPIx__)  SET_BIT((__SPIx__)->CR1, SPI_CR1_SPE)
//SPIx_CR1寄存器bit6(SPE),SPE=1令SPI外设使能#define _HAL_SPI_DISABLE(__SPIx__) CLEAR_BIT((__SPIx__)->CR1, SPI_CR1_SPE)
//SPIx_CR1寄存器bit6(SPE),SPE=0令SPI外设不使能/** @brief  Enable the specified SPI interrupts.* @param  __SPIx__ specifies the SPI Handle.*         This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral.* @param  __INTERRUPT__ specifies the interrupt source to enable.*         This parameter can be one of the following values:*            @arg SPI_IT_TXE: Tx buffer empty interrupt enable*            @arg SPI_IT_RXNE: RX buffer not empty interrupt enable*            @arg SPI_IT_ERR: Error interrupt enable* @retval None*/
#define _HAL_SPI_ENABLE_IT(__SPIx__, __INTERRUPT__)   SET_BIT((__SPIx__)->CR2, (__INTERRUPT__))
//__INTERRUPT__ = SPI_IT_TXE,设置SPIx_CR2寄存器bit7(TXEIE位),TXEIE=1表示使能SPI在TXE标志建立时产生SPI发送中断
//__INTERRUPT__ = SPI_IT_RXNE,设置SPIx_CR2寄存器bit6(RXNEIE位),RXNEIE=1表示使能SPI在RXNE标志建立时产生SPI接收中断
//__INTERRUPT__ = SPI_IT_ERR,设置SPIx_CR2寄存器bit5(ERRIE位),ERRIE=1表示使能SPI在CRCERR,OVR和MODF标志建立时产生SPI错误中断/** @brief  Disable the specified SPI interrupts.* @param  __SPIx__ specifies the SPI handle.*         This parameter can be SPIx where x: 1, 2, or 3 to select the SPI peripheral.* @param  __INTERRUPT__ specifies the interrupt source to disable.*         This parameter can be one of the following values:*            @arg SPI_IT_TXE: Tx buffer empty interrupt enable*            @arg SPI_IT_RXNE: RX buffer not empty interrupt enable*            @arg SPI_IT_ERR: Error interrupt enable* @retval None*/
#define _HAL_SPI_DISABLE_IT(__SPIx__, __INTERRUPT__)  CLEAR_BIT((__SPIx__)->CR2, (__INTERRUPT__))/** @brief  Clear the SPI OVR pending flag.* @param  __SPIx__ specifies the SPI Handle.*         This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral.* @retval None*/
#define _HAL_SPI_CLEAR_OVRFLAG(__SPIx__)        \do{                                              \__IO uint32_t tmpreg_ovr = 0x00U;              \tmpreg_ovr = (__SPIx__)->DR;       \tmpreg_ovr = (__SPIx__)->SR;       \UNUSED(tmpreg_ovr);                            \} while(0U)/** @brief  Clear the SPI MODF pending flag.* @param  __SPIx__ specifies the SPI Handle.*         This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral.* @retval None*/
#define _HAL_SPI_CLEAR_MODFFLAG(__SPIx__)             \do{                                                    \__IO uint32_t tmpreg_modf = 0x00U;                   \tmpreg_modf = (__SPIx__)->SR;            \CLEAR_BIT((__SPIx__)->CR1, SPI_CR1_SPE); \UNUSED(tmpreg_modf);                                 \} while(0U)/** @brief  Clear the SPI FRE pending flag.* @param  __SPIx__ specifies the SPI Handle.*         This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral.* @retval None*/
#define _HAL_SPI_CLEAR_FREFLAG(__SPIx__)        \do{                                              \__IO uint32_t tmpreg_fre = 0x00U;              \tmpreg_fre = (__SPIx__)->SR;       \UNUSED(tmpreg_fre);                            \}while(0U)#define SPI1_RX_Buffer_Size 		      125
extern uint8_t SPI1_RX_Buffer[SPI1_RX_Buffer_Size]; //SPI1接收缓冲区数组
extern uint8_t SPI1_RX_Buffer_Load_Index;          //SPI1_RX_Buffer[]的装载索引值#define SPI1_TX_Buffer_Size 		      125
extern uint8_t SPI1_TX_Buffer[SPI1_TX_Buffer_Size]; //SPI1发送缓冲区数组
extern uint8_t SPI1_TX_Buffer_Load_Index;          //SPI1_TX_Buffer[]的装载索引值extern void SPI1_Init(void);
extern void Start_SPI1_Send_Data(void);
extern void SPI1_Receive_Complete(void);#endif /*__ SPI1_H__ */

2、SPI.c程序如下:

#include "SPI1.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()
 

//STM32G474RE使用SPI1中断发送和接收8位数据,其作用:可以提高系统的整体效率和响应速度。
uint8_t SPI1_RX_Buffer[SPI1_RX_Buffer_Size]; //SPI1接收缓冲区数组
uint8_t SPI1_RX_Buffer_Load_Index;          //SPI1_RX_Buffer[]的装载索引值

uint8_t SPI1_TX_Buffer[SPI1_TX_Buffer_Size]; //SPI1发送缓冲区数组
uint8_t SPI1_TX_Buffer_Load_Index;          //SPI1_TX_Buffer[]的装载索引值
uint8_t SPI1_TX_Buffer_Send_Index;          //发送下标值

void SPI1_Init(void);
void Start_SPI1_Send_Data(void);
void SPI1_Receive_Complete(void);

void SPI1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    SPI_HandleTypeDef hspi1;

    __HAL_RCC_SPI1_CLK_ENABLE();  //使能SPI1外设时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); //GPIOB时钟使能

    GPIO_InitStruct.Pin = GPIO_PIN_3;            //选择引脚编号为3
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;      //复用推挽模式
//    GPIO_InitStruct.Pull = GPIO_NOPULL;          //引脚上拉和下拉都没有被激活
    GPIO_InitStruct.Pull = GPIO_PULLUP;           //设置上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;   //PB3映射到SPI1_SCK
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    //根据GPIO_InitStruct结构变量指定的参数初始化GPIOB的外设寄存器
    //配置“SPI1_SCK引脚”

    GPIO_InitStruct.Pin = GPIO_PIN_4;            //选择引脚编号为4
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;      //复用推挽模式
    GPIO_InitStruct.Pull = GPIO_PULLUP;           //设置上拉
//    GPIO_InitStruct.Pull = GPIO_NOPULL;          //引脚上拉和下拉都没有被激活
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;   //PB4映射到SPI1_MISO
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    //根据GPIO_InitStruct结构变量指定的参数初始化GPIOB的外设寄存器
    //配置“SPI1_MISO引脚”

    GPIO_InitStruct.Pin = GPIO_PIN_5;            //选择引脚编号为5
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;      //复用推挽模式
    GPIO_InitStruct.Pull = GPIO_PULLUP;           //设置上拉
//    GPIO_InitStruct.Pull = GPIO_PULLDOWN;        //设置下拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;   //PB5映射到SPI1_MOSI
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    //根据GPIO_InitStruct结构变量指定的参数初始化GPIOB的外设寄存器
    //配置“SPI1_MOSI引脚”

  hspi1.Instance = SPI1;//选择SPI1
    hspi1.Init.Mode = SPI_MODE_MASTER;
    //SPIx_CR1寄存器bit2(MSTR),MSTR=1配置SPI外设为主机
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    //SPIx_CR1寄存器bit15(BIDIMODE),BIDIMODE=0选择“双线单向数据模式” 
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    //SPIx_CR1寄存器bit0(CPHA)
    //CPHA=0,表示从SPI_SCK的空闲位开始,第1个边沿用来采集第1个位
    //CPHA=1,表示从SPI_SCK的空闲位开始,第2个边沿用来采集第1个位

    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    //SPIx_CR1寄存器bit1(CPOL)
    //CPOL=0,表示SPI_SCK的空闲位为低电平
    //CPOL=1,表示SPI_SCK的空闲位为高电平

    hspi1.Init.NSS = SPI_NSS_SOFT;
    //SPIx_CR1寄存器bit9(SSM),SSM=1,NSS引脚的输入将被替换为来自SSI位的值
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    //SPIx_CR1寄存器bit5(BR[2:0])
    //BR[2:0]=000b,SCK的时钟频率为fPCLK/2
    //BR[2:0]=001b,SCK的时钟频率为fPCLK/4
    //BR[2:0]=010b,SCK的时钟频率为fPCLK/8
    //BR[2:0]=011b,SCK的时钟频率为fPCLK/16
    //BR[2:0]=100b,SCK的时钟频率为fPCLK/32
    //BR[2:0]=101b,SCK的时钟频率为fPCLK/64
    //BR[2:0]=110b,SCK的时钟频率为fPCLK/128
    //BR[2:0]=111b,SCK的时钟频率为fPCLK/256

    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    //SPIx_CR1寄存器bit7(LSBFIRST)
    //LSBFIRST=0,表示先传送最高位
    //LSBFIRST=1,表示先传送最低位

    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    //SPIx_CR1寄存器bit13(CRCEN),CRCEN=0不使能CRC校验
    hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
    //SPIx_CR1寄存器bit11(CRCL)
    //CRCL=0表示CRC的长度为8位
    //CRCL=1表示CRC的长度为16位

    hspi1.Init.CRCPolynomial = 7;
    //SPIx_CRCPR,这个寄存器包含了CRC计算的多项式
    //CRC多项式(0x0007)是该寄存器的默认值。可以根据需要,配置自己的“CRC多项式”。 

#if (HalfWord == 0U)
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    //SPIx_CR2寄存器bit11:8(DS[3:0])
    //DS[3:0]=0011b,表示SPI传输的一帧的数据长度为4位
    //DS[3:0]=0100b,表示SPI传输的一帧的数据长度为5位
    //DS[3:0]=0101b,表示SPI传输的一帧的数据长度为6位
    //DS[3:0]=0110b,表示SPI传输的一帧的数据长度为7位
    //DS[3:0]=0111b,表示SPI传输的一帧的数据长度为8位,这里读写8位数据
    //DS[3:0]=1000b,表示SPI传输的一帧的数据长度为9位
    //DS[3:0]=1001b,表示SPI传输的一帧的数据长度为10位
    //DS[3:0]=1010b,表示SPI传输的一帧的数据长度为11位
    //DS[3:0]=1011b,表示SPI传输的一帧的数据长度为12位
    //DS[3:0]=1100b,表示SPI传输的一帧的数据长度为13位
    //DS[3:0]=1101b,表示SPI传输的一帧的数据长度为14位
    //DS[3:0]=1110b,表示SPI传输的一帧的数据长度为15位
    //DS[3:0]=1111b,表示SPI传输的一帧的数据长度为16位

#else
  hspi1.Init.DataSize = SPI_DATASIZE_16BIT;//这里读写16位数据
#endif

    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    //SPIx_CR2寄存器bit4(FRF)
    //FRF=0,帧格式为SPI Motorola mode,这里使用“Motorola模式”
    //FRF=1,帧格式为SPI TI mode

    hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    //SPIx_CR2寄存器bit3(NSSP)
    //NSSP=0,NSS引脚无脉冲,这里不使用NSS引脚
    //NSSP=1,NSS引脚能产生脉冲

    HAL_SPI_Init(&hspi1);

    _HAL_SPI_ENABLE(SPI1);
    //SPIx_CR1寄存器bit6(SPE),SPE=1令SPI外设使能

  _HAL_SPI_ENABLE_IT(SPI1,SPI_IT_ERR);
  _HAL_SPI_DISABLE_IT(SPI1,SPI_IT_TXE);
    _HAL_SPI_ENABLE_IT(SPI1,SPI_IT_RXNE);
    HAL_NVIC_SetPriority(SPI1_IRQn, 5, 0);
    //设置NVIC中断分组4:4位抢占优先级,0位响应优先级
    //选择中断优先级组4,即抢占优先级为4位,取值为0~15,响应优先级组为0位,取值为0
    //这里设置SPI1的抢占优先级为5,响应优先级为0

    HAL_NVIC_EnableIRQ(SPI1_IRQn);
}

//函数功能:启动SPI1发送
const char SPI1_Test_REG[]="1234567890\r\n";
void Start_SPI1_Send_Data(void)
{
    uint16_t k;

    SPI1_RX_Buffer_Load_Index=0;
    memset(SPI1_RX_Buffer,0,SPI1_RX_Buffer_Size);

    memset(SPI1_TX_Buffer,0,SPI1_TX_Buffer_Size);
    strcpy((char*)SPI1_TX_Buffer,SPI1_Test_REG);//装载发送数据
    printf("SPI1 Send: %s",SPI1_TX_Buffer);     //打印待发送数据
    k=strlen((char*)SPI1_TX_Buffer);            //计算待发送数据的字节总数
    SPI1_TX_Buffer_Load_Index = k;
    SPI1_TX_Buffer_Send_Index=0;  //一定要先准备再启动
启动发送/
    _HAL_SPI_ENABLE_IT(SPI1,SPI_IT_TXE);//使能SPI在TXE标志建立时产生SPI发送中断
}

//函数功能:SPI接收完成
void SPI1_Receive_Complete(void)
{
    char i;

    for(i=0;i<SPI1_RX_Buffer_Size;i++)
    {
        if(SPI1_RX_Buffer[i-1]=='\r'&&SPI1_RX_Buffer[i]=='\n')//收到结束符号
        {
            printf("SPI1 Receive: %s",SPI1_RX_Buffer);
      Start_SPI1_Send_Data();
        }
  }
}

//函数功能:SPI在中断里发送和接收8位数据
void SPI1_IRQHandler(void)
{
//  HAL_SPI_IRQHandler(&hspi1);
  uint32_t itsource;
  uint32_t itflag;
    uint8_t RX_temp;

    (void)RX_temp;//防止RX_temp不使用而产生警告

    itsource = SPI1->CR2;//读SPIx_CR2寄存器
    itflag   = SPI1->SR; //读SPIx_SR寄存器
    if ( (SPI_CHECK_FLAG(itflag, SPI_FLAG_OVR) == RESET) \
        && (SPI_CHECK_FLAG(itflag, SPI_FLAG_RXNE) != RESET) \
       && (SPI_CHECK_IT_SOURCE(itsource, SPI_IT_RXNE) != RESET) )
    {//SPI1接收中断
        RX_temp=*( uint8_t *)&SPI1->DR; //返回通过SPIx最近接收的数据,写读SPI1_DR
        SPI1_RX_Buffer[SPI1_RX_Buffer_Load_Index] = RX_temp;//保存接收到的新数据
        SPI1_RX_Buffer_Load_Index++;
        if(SPI1_RX_Buffer_Load_Index>=SPI1_RX_Buffer_Size-2)
        {
            SPI1_RX_Buffer[SPI1_RX_Buffer_Size-2]='\0';
            SPI1_RX_Buffer_Load_Index = 0;//防止SPI1_RX_Buffer[]溢出
        }
        if(SPI1_RX_Buffer[SPI1_RX_Buffer_Load_Index-2]=='\r'&&SPI1_RX_Buffer[SPI1_RX_Buffer_Load_Index-1]=='\n')
        {//收到"\r\n"结束符号
            SPI1_RX_Buffer[SPI1_RX_Buffer_Load_Index]='\0';
            SPI1_RX_Buffer_Load_Index++;
        }
    }

  if ( (SPI_CHECK_FLAG(itflag, SPI_FLAG_TXE) != RESET) \
        && (SPI_CHECK_IT_SOURCE(itsource, SPI_IT_TXE) != RESET) )
  {//SPI1发送中断
        if(SPI1_TX_Buffer_Send_Index >= SPI1_TX_Buffer_Load_Index)
        {
            _HAL_SPI_DISABLE_IT(SPI1,SPI_IT_TXE);
        }
        else //未发送完全部数据
        {
        *( uint8_t *)&SPI1->DR=SPI1_TX_Buffer[SPI1_TX_Buffer_Send_Index]; //通过外设SPIx发送一个数据,写SPI1_DR
        //发送一个字节

            SPI1_TX_Buffer_Send_Index++;
        }
  }

  if ( ((SPI_CHECK_FLAG(itflag, SPI_FLAG_MODF) != RESET) \
        || (SPI_CHECK_FLAG(itflag, SPI_FLAG_OVR) != RESET) \
      || (SPI_CHECK_FLAG(itflag, SPI_FLAG_FRE) != RESET)) \
      && (SPI_CHECK_IT_SOURCE(itsource, SPI_IT_ERR) != RESET) )
    {//SPI1错误中断
    if (SPI_CHECK_FLAG(itflag, SPI_FLAG_OVR) != RESET)
    {//SPI Overrun error interrupt occurred 
            _HAL_SPI_CLEAR_OVRFLAG(SPI1);//清除溢出错误
    }

    if (SPI_CHECK_FLAG(itflag, SPI_FLAG_MODF) != RESET)
    {//SPI Mode Fault error interrupt occurred
      _HAL_SPI_CLEAR_MODFFLAG(SPI1);
    }

    if (SPI_CHECK_FLAG(itflag, SPI_FLAG_FRE) != RESET)
    {//SPI Frame error interrupt occurred
      _HAL_SPI_CLEAR_FREFLAG(SPI1);
    }
    }
}

3、测试结果:


http://www.mrgr.cn/news/31128.html

相关文章:

  • 热点|创邻图查询范式引爆LDBC TUC2024
  • Unity实现自己的协程系统
  • 文件上传js代码
  • Virtuoso服务在centos中自动停止的原因分析及解决方案
  • 【云安全】云服务安全攻防
  • U 盘显示需要格式化才能用?一针见血的修复方法在这里!速看!
  • 量子噪声流加密(二:如何隐匿通信密文)
  • 蓝队技能-应急响应篇Web内存马查杀JVM分析Class提取诊断反编译日志定性
  • Centos 7 搭建Samba
  • YOLOv5白皮书-第Y1周:调用官方权重进行检测
  • Spring MVC 启动与请求处理流程解析
  • 环保行动中的关键力量:油烟净化器如何发挥重要作用
  • 乐观锁、悲观锁及死锁
  • 抖音怎么录屏保存?网页录屏和直播内容录制屏幕工具软件推荐
  • Ubuntu 22.04 源码下载的几种方法
  • 【用Java学习数据结构系列】对象的比较(Priority Queue实现的前提)
  • 鸿蒙手势交互(三:组合手势)
  • 模型案例:| 篮球识别模型
  • Python学习——【3.1】函数
  • 超详细!百分百安装成功pytorch,建议收藏