这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Let'sdo第1期-功率检测与控制系统DIY】使用nucle-F411RES

共3条 1/1 1 跳转至

【Let'sdo第1期-功率检测与控制系统DIY】使用nucle-F411RESPITFTLCD液晶屏显示INA219模块检测电流并接入NRF24L01模块

菜鸟
2025-06-10 15:16:25     打赏

【Let'sdo第1期-功率检测与控制系统DIY】使用nucle-F411RE SPITFTLCD液晶屏显示INA219模块检测电流

       参加EEPW论坛2025 Let'sdo第1期-功率检测与控制系统DIY,大概任务就是使用nucle-F411RE开发板和INA219模块来检测开发板和用电器模块运行时的电压和电流,不过我这边对实验用器件做出了一些个人意向的修改,首先是我不太喜欢使用OLED屏进行显示,因为OLED屏能显示的信息太少,并且使用不当容易烧坏,因此我使用自己提供的SPITFTLCD液晶屏来显示,除此之外像INA219模块驱动代码都是完全一致的。这个课程需要占用PB8 PB9用作模拟I2C接口,占用PA5 PA6 PA7用作SPI1接口,以及一些GPIO作为液晶屏信号控制,然后再占用一组SPI2与NRF24L01模块进行通信,由于液晶屏和NRF24L01模块的SPI参数有差异,因此不使用同一组SPI接口

1.JPG

void FAKE_I2C_INA_Delay()
{
    uint8_t x;
    for(x=1;x>0;x--)
    {
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
    }
}
void FAKE_I2C_INA_PB8_PB9_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    
    FAKE_I2C_INA_SCL_PB8_CLK_ENABLE;
    FAKE_I2C_INA_SDA_PB9_CLK_ENABLE;
    
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull  = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.Pin = FAKE_I2C_INA_SCL_PB8_PIN;
  HAL_GPIO_Init(FAKE_I2C_INA_SCL_PB8_PORT , &GPIO_InitStruct);
    
  GPIO_InitStruct.Pin = FAKE_I2C_INA_SDA_PB9_PIN;
  HAL_GPIO_Init(FAKE_I2C_INA_SDA_PB9_PORT , &GPIO_InitStruct);
    
    FAKE_I2C_INA_SCL_PB8_HIGH;
    FAKE_I2C_INA_SDA_PB9_HIGH;
    
}
void FAKE_I2C_INA_PB8_PB9_SDA_OUT(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull  = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    
  GPIO_InitStruct.Pin = FAKE_I2C_INA_SDA_PB9_PIN;
  HAL_GPIO_Init(FAKE_I2C_INA_SDA_PB9_PORT , &GPIO_InitStruct);
}
void FAKE_I2C_INA_PB8_PB9_SDA_IN(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    
    GPIO_InitStruct.Mode  = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull  = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    
  GPIO_InitStruct.Pin = FAKE_I2C_INA_SDA_PB9_PIN;
  HAL_GPIO_Init(FAKE_I2C_INA_SDA_PB9_PORT , &GPIO_InitStruct);
}
void FAKE_I2C_INA_PB8_PB9_Start(void)
{
    FAKE_I2C_INA_SDA_PB9_HIGH;
    FAKE_I2C_INA_SCL_PB8_HIGH;
    FAKE_I2C_INA_Delay();
    FAKE_I2C_INA_SDA_PB9_LOW;
    FAKE_I2C_INA_Delay();
    FAKE_I2C_INA_SCL_PB8_LOW;
}
void FAKE_I2C_INA_PB8_PB9_Stop(void)
{
    FAKE_I2C_INA_SDA_PB9_LOW;
    FAKE_I2C_INA_SCL_PB8_HIGH;
    FAKE_I2C_INA_Delay();
    FAKE_I2C_INA_SDA_PB9_HIGH;
    FAKE_I2C_INA_Delay();
    FAKE_I2C_INA_SCL_PB8_LOW;
    
    FAKE_I2C_INA_SCL_PB8_HIGH;
    FAKE_I2C_INA_SDA_PB9_HIGH;
}
bool FAKE_I2C_INA_PB8_PB9_ACK_Read(void)
{
    bool ack;
    FAKE_I2C_INA_SDA_PB9_HIGH;
    FAKE_I2C_INA_PB8_PB9_SDA_IN();
    FAKE_I2C_INA_SCL_PB8_HIGH;
    FAKE_I2C_INA_Delay();
    if(FAKE_I2C_INA_SDA_PB9_READ == SET) 
        ack = false;
    else ack=true;
    FAKE_I2C_INA_SCL_PB8_LOW;
    FAKE_I2C_INA_PB8_PB9_SDA_OUT();
    return ack;
}
void FAKE_I2C_INA_PB8_PB9_ACK_Send(bool ack)
{
    FAKE_I2C_INA_SCL_PB8_LOW;
    if(ack == true) 
    {
        FAKE_I2C_INA_SDA_PB9_LOW;
    }
    else
    {
        FAKE_I2C_INA_SDA_PB9_HIGH;
    }
    FAKE_I2C_INA_SCL_PB8_HIGH;
    FAKE_I2C_INA_Delay();
    FAKE_I2C_INA_SCL_PB8_LOW;
}
void FAKE_I2C_INA_PB8_PB9_Send_Byte(uint8_t byte)
{
    uint8_t i;
    FAKE_I2C_INA_SCL_PB8_LOW;
    for(i=0;i<8;i++)
    {
        if(byte & 0x80)    
        {
            FAKE_I2C_INA_SDA_PB9_HIGH;
        }
        else 
        {
            FAKE_I2C_INA_SDA_PB9_LOW;
        }
        FAKE_I2C_INA_SCL_PB8_HIGH;
        FAKE_I2C_INA_Delay();
        FAKE_I2C_INA_SCL_PB8_LOW;
        FAKE_I2C_INA_Delay();
        byte <<= 1;
    }
    FAKE_I2C_INA_PB8_PB9_ACK_Read();
}
uint8_t FAKE_I2C_INA_PB8_PB9_Read_Byte(void)
{
    uint8_t i,byte=0;
    FAKE_I2C_INA_PB8_PB9_SDA_IN();
    for(i=0;i<8;i++)
    {
        FAKE_I2C_INA_SCL_PB8_HIGH;
        byte<<=1;
        if(FAKE_I2C_INA_SDA_PB9_READ == SET) 
        {
            byte |= 0x01;
        }
        else 
        {
            byte &= 0xFE;
        }
        FAKE_I2C_INA_SCL_PB8_LOW;
        FAKE_I2C_INA_Delay();
    }
    FAKE_I2C_INA_PB8_PB9_SDA_OUT();
    return byte;
}
void FAKE_I2C_INA_PB8_PB9_Read_Bytes(unsigned char reg,unsigned char *data)
{
    FAKE_I2C_INA_PB8_PB9_Start();
    FAKE_I2C_INA_PB8_PB9_Send_Byte(INA219_ADDRESS);
    FAKE_I2C_INA_PB8_PB9_Send_Byte(reg);
    
    FAKE_I2C_INA_PB8_PB9_Start();
    FAKE_I2C_INA_PB8_PB9_Send_Byte(INA219_ADDRESS + 0x01);
    *data = FAKE_I2C_INA_PB8_PB9_Read_Byte();
    data++;
    FAKE_I2C_INA_PB8_PB9_ACK_Send(1);
    *data = FAKE_I2C_INA_PB8_PB9_Read_Byte();
    FAKE_I2C_INA_PB8_PB9_ACK_Send(0);
    FAKE_I2C_INA_PB8_PB9_Stop();
}
void FAKE_I2C_INA_PB8_PB9_REG_Write(unsigned char reg,unsigned int data)
{
    unsigned char data_temp[2];
    data_temp[0]=(unsigned char )(data>>8);
    data_temp[1]=(unsigned char )(data & 0xFF);
    FAKE_I2C_INA_PB8_PB9_Start();
    FAKE_I2C_INA_PB8_PB9_Send_Byte(INA219_ADDRESS);
    FAKE_I2C_INA_PB8_PB9_Send_Byte(reg);
    FAKE_I2C_INA_PB8_PB9_Send_Byte(data_temp[0]);
    data++;
    FAKE_I2C_INA_PB8_PB9_Send_Byte(data_temp[1]);
    FAKE_I2C_INA_PB8_PB9_Stop();
}
void INA_Init(void)
{
    FAKE_I2C_INA_PB8_PB9_Init();
    FAKE_I2C_INA_PB8_PB9_REG_Write(INA219_REG_CONFIG , INA219_CONFIG_value);
    FAKE_I2C_INA_PB8_PB9_REG_Write(INA219_REG_CALIBRATION , INA_CAL);
}
unsigned int INA_GET_Voltage_MV(void)
{
    unsigned char data_temp[2];
    FAKE_I2C_INA_PB8_PB9_Read_Bytes(0x02 , data_temp);
    return (int)((((data_temp[0]<<8) + data_temp[1]) >> 3)*4);
}
unsigned int INA_GET_Current_MA(void)
{
    unsigned char data_temp[2];
    FAKE_I2C_INA_PB8_PB9_REG_Write(INA219_REG_CONFIG , INA219_CONFIG_value);
    FAKE_I2C_INA_PB8_PB9_Read_Bytes(INA219_REG_CURRENT , data_temp);
    return (int)((((data_temp[0]<<8) + data_temp[1]))*IAN_I_LSB);
}
unsigned int INA_GET_Power_MW(void)
{
    unsigned char data_temp[2];
    FAKE_I2C_INA_PB8_PB9_Read_Bytes(INA219_REG_POWER , data_temp);
    return (int)(((data_temp[0]<<8) + data_temp[1]) * INA_Power_LSB);
}


这里使用模拟I2C逻辑来驱动INA219模块,可以很方便移植到别的平台上,并且不受GPIO引脚限制。INA219模块的模拟I2C时序跟一般常用的I2C器件如BMP280 MPU9250 DS3231的时序有细微差别,两者的代码无法直接通用

#define FAKE_I2C_INA_SCL_PB8_PORT                     GPIOB
#define FAKE_I2C_INA_SCL_PB8_PIN                      GPIO_PIN_8
#define FAKE_I2C_INA_SCL_PB8_CLK_ENABLE               __HAL_RCC_GPIOB_CLK_ENABLE();
#define FAKE_I2C_INA_SCL_PB8_HIGH                               HAL_GPIO_WritePin(FAKE_I2C_INA_SCL_PB8_PORT , FAKE_I2C_INA_SCL_PB8_PIN , GPIO_PIN_SET);
#define FAKE_I2C_INA_SCL_PB8_LOW                                HAL_GPIO_WritePin(FAKE_I2C_INA_SCL_PB8_PORT , FAKE_I2C_INA_SCL_PB8_PIN , GPIO_PIN_RESET);
#define FAKE_I2C_INA_SDA_PB9_PORT                     GPIOB
#define FAKE_I2C_INA_SDA_PB9_PIN                      GPIO_PIN_9
#define FAKE_I2C_INA_SDA_PB9_CLK_ENABLE               __HAL_RCC_GPIOB_CLK_ENABLE();
#define FAKE_I2C_INA_SDA_PB9_HIGH                               HAL_GPIO_WritePin(FAKE_I2C_INA_SDA_PB9_PORT , FAKE_I2C_INA_SDA_PB9_PIN , GPIO_PIN_SET);
#define FAKE_I2C_INA_SDA_PB9_LOW                                HAL_GPIO_WritePin(FAKE_I2C_INA_SDA_PB9_PORT , FAKE_I2C_INA_SDA_PB9_PIN , GPIO_PIN_RESET);
#define FAKE_I2C_INA_SDA_PB9_READ                                    HAL_GPIO_ReadPin(FAKE_I2C_INA_SDA_PB9_PORT , FAKE_I2C_INA_SDA_PB9_PIN)
#define INA219_ADDRESS  (0x40 << 1)

INA2219的地址选位0x40,其实是可以通过拨码开关设置为0x45的,使用起来没有任何区别
然后再使用SPI1(PA5 PA6 PA7)来点SPITFTLCD彩屏:

uint8_t SPI1_PA5_PA6_PA7_Read_Write_Byte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi1 , &TxData , &Rxdata , 1 , 1000);       
    return Rxdata;
}
void SPI1_PA5_PA7_Write_Byte(uint8_t TxData)
{
    HAL_SPI_Transmit(&hspi1 , &TxData , 1 , 1000);
}
void SPI1_PA5_PA6_PA7_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
        
  __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_SPI1_CLK_ENABLE();
    __HAL_RCC_DMA2_CLK_ENABLE();
    
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
  HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);
    
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  HAL_SPI_Init(&hspi1);
    
    hdma_spi1_rx.Instance = DMA2_Stream0;
    hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_spi1_rx);
    __HAL_LINKDMA(&hspi1 , hdmarx , hdma_spi1_rx);
    hdma_spi1_tx.Instance = DMA2_Stream2;
    hdma_spi1_tx.Init.Channel = DMA_CHANNEL_2;
    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_tx.Init.Mode = DMA_NORMAL;
    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_spi1_tx);
    __HAL_LINKDMA(&hspi1 , hdmatx , hdma_spi1_tx);
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    
  HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}


还需要PA4 PA8 PB7三个GPIO来控制液晶屏的片选,复位,DC选择:

#define SPITFTLCD_ST7789_CS_GPIO_PORT                 GPIOA
#define SPITFTLCD_ST7789_CS_GPIO_PIN                  GPIO_PIN_4
#define SPITFTLCD_ST7789_CS_GPIO_CLK_ENABLE           __HAL_RCC_GPIOA_CLK_ENABLE();
#define SPITFTLCD_ST7789_CS_HIGH                         HAL_GPIO_WritePin(SPITFTLCD_ST7789_CS_GPIO_PORT , SPITFTLCD_ST7789_CS_GPIO_PIN , GPIO_PIN_SET);
#define SPITFTLCD_ST7789_CS_LOW                         HAL_GPIO_WritePin(SPITFTLCD_ST7789_CS_GPIO_PORT , SPITFTLCD_ST7789_CS_GPIO_PIN , GPIO_PIN_RESET);
#define SPITFTLCD_ST7789_RESET_GPIO_PORT                 GPIOA
#define SPITFTLCD_ST7789_RESET_GPIO_PIN                  GPIO_PIN_8
#define SPITFTLCD_ST7789_RESET_GPIO_CLK_ENABLE           __HAL_RCC_GPIOA_CLK_ENABLE();
#define SPITFTLCD_ST7789_RESET_HIGH                     HAL_GPIO_WritePin(SPITFTLCD_ST7789_RESET_GPIO_PORT , SPITFTLCD_ST7789_RESET_GPIO_PIN , GPIO_PIN_SET);
#define SPITFTLCD_ST7789_RESET_LOW                         HAL_GPIO_WritePin(SPITFTLCD_ST7789_RESET_GPIO_PORT , SPITFTLCD_ST7789_RESET_GPIO_PIN , GPIO_PIN_RESET);
#define SPITFTLCD_ST7789_DC_GPIO_PORT                     GPIOB
#define SPITFTLCD_ST7789_DC_GPIO_PIN                      GPIO_PIN_7
#define SPITFTLCD_ST7789_DC_GPIO_CLK_ENABLE               __HAL_RCC_GPIOB_CLK_ENABLE();
#define SPITFTLCD_ST7789_DC_HIGH                             HAL_GPIO_WritePin(SPITFTLCD_ST7789_DC_GPIO_PORT , SPITFTLCD_ST7789_DC_GPIO_PIN , GPIO_PIN_SET);
#define SPITFTLCD_ST7789_DC_LOW                             HAL_GPIO_WritePin(SPITFTLCD_ST7789_DC_GPIO_PORT , SPITFTLCD_ST7789_DC_GPIO_PIN , GPIO_PIN_RESET);


使用显示ASCII字符的函数显示必要信息:

void SPITFTLCD_ST7789_ShowChar1632(uint16_t x , uint16_t y , uint8_t num , uint16_t fc , uint16_t bc , uint8_t mode)
{
    uint8_t temp,sizex,t,m=0;
    uint16_t i,TypefaceNum;
    uint16_t x0=x;
    sizex=16;
    TypefaceNum=(sizex/8+((sizex%8)?1:0))*32;
    num=num-' ';
    SPITFTLCD_ST7789_Address_Set(x,y,x+sizex-1,y+32-1);
    for(i=0;i<TypefaceNum;i++)
    { 
        temp = ascii_3216[num][i];
        for(t=0;t<8;t++)
        {
            if(!mode)
            {
                if(temp&(0x01<<t))SPITFTLCD_ST7789_WR_DATA(fc);
                else SPITFTLCD_ST7789_WR_DATA(bc);
                m++;
                if(m%sizex==0)
                {
                    m=0;
                    break;
                }
            }
            else
            {
                if(temp&(0x01<<t))SPITFTLCD_ST7789_DrawPoint(x , y , fc);
                x++;
                if((x-x0)==sizex)
                {
                    x=x0;
                    y++;
                    break;
                }
            }
        }
    }              
}
void SPITFTLCD_ST7789_ShowString1632(uint16_t x , uint16_t y , const uint8_t *p , uint16_t fc , uint16_t bc , uint8_t mode)
{         
    while(*p != '\0')
    {       
        SPITFTLCD_ST7789_ShowChar1632(x,y,*p,fc,bc,mode);
        x += 16;
        p++;
    }  
}


定时器2和定时器3初始化:

TIM_HandleTypeDef TIM2_Handler;
TIM_HandleTypeDef TIM3_Handler;
void TIM2_Init(uint16_t arr,uint16_t psc)
{  
    __HAL_RCC_TIM2_CLK_ENABLE();
    TIM2_Handler.Instance=TIM2;
    TIM2_Handler.Init.Prescaler=psc;
    TIM2_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
    TIM2_Handler.Init.Period=arr;
    TIM2_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_Base_Init(&TIM2_Handler);
    HAL_TIM_Base_Start(&TIM2_Handler); 
}
void TIM3_Init(uint16_t arr,uint16_t psc)
{  
    __HAL_RCC_TIM3_CLK_ENABLE();
    TIM3_Handler.Instance=TIM3;
    TIM3_Handler.Init.Prescaler=psc;
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
    TIM3_Handler.Init.Period=arr;
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_Base_Init(&TIM3_Handler);
    HAL_TIM_Base_Start(&TIM3_Handler); 
}


定时器2和定时器3设置参数,定时器2为100ms溢出,定时器3为500ms溢出:

TIM2_Init(1000 - 1 , 5000 - 1); 
TIM3_Init(5000 - 1 , 5000 - 1);


INA219模块的测量口正负极直接接在开发板的供电跳帽上,就可以获取开发板运行电流以及运行功率了:


SPI2初始化:

uint8_t SPI2_PB10_PC2_PC3_Read_Write_Byte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi2 , &TxData , &Rxdata , 1 , 1000);       
    return Rxdata;
}
void SPI2_PB10_PC2_PC3_Init(void)
{
    
    GPIO_InitTypeDef GPIO_InitStruct;
    
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_SPI2_CLK_ENABLE();
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    HAL_GPIO_Init(GPIOB , &GPIO_InitStruct);
    
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    HAL_GPIO_Init(GPIOC , &GPIO_InitStruct);    
    
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    HAL_GPIO_Init(GPIOC , &GPIO_InitStruct);
    
    hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  HAL_SPI_Init(&hspi2);
}


通过SPI2接口设置NRF24L01模块收发模式以及收发函数:

uint8_t NRF24L01_Check(void)
{
    uint8_t buf[5]={0xa5 , 0xa5 , 0xa5 , 0xa5 , 0xa5};
    uint8_t i;
    NRF24L01_Write_Buf(NRF_WRITE_REG + TX_ADDR , buf , 5);
    NRF24L01_Read_Buf(TX_ADDR , buf , 5);
    for(i=0;i<5;i++)
        if(buf[i]!=0XA5)
            break;                                    
    if(i!=5)
        return 1;
    return 0;
}
uint8_t NRF24L01_RxPacket(uint8_t *rxbuf)
{
    uint8_t sta;                                           
    sta = NRF24L01_Read_Reg(STATUS);
    NRF24L01_Write_Reg(NRF_WRITE_REG + STATUS , sta);
    
    if(sta & RX_OK)
    {
        printf("sta = 0x%x RX_OK.\n" , sta);
        NRF24L01_Read_Buf(RD_RX_PLOAD , rxbuf , RX_PLOAD_WIDTH);
        NRF24L01_Write_Reg(FLUSH_RX , 0xff);
        return 0; 
    }       
    return 1;
}    
uint8_t NRF24L01_TxPacket(uint8_t *txbuf)
{
    uint8_t sta;
    NRF24L01_CE_LOW;
  NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
     NRF24L01_CE_HIGH;
    while(NRF24L01_IRQ_READ() != 0);
    sta = NRF24L01_Read_Reg(STATUS); 
    NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
    if(sta&MAX_TX)
    {
        NRF24L01_Write_Reg(FLUSH_TX,0xff);
        return MAX_TX; 
    }
    if(sta&TX_OK)
    {
        return TX_OK;
    }
    return 0xff;
}
void NRF24L01_RX_Mode(void)
{
    NRF24L01_CE_LOW;
    NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);
    
    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);  
    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); 
    NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
    NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
    NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
    NRF24L01_CE_HIGH;
}
void NRF24L01_TX_Mode(void)
{                                                         
    NRF24L01_CE_LOW;
    NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH);//дTX½ÚµãµØÖ· 
    NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);   
    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01); 
    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); 
    NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
    NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40); 
    NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f); 
    NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e); 
    NRF24L01_CE_HIGH;
}

演示视频:

https://www.bilibili.com/video/BV16DMJzbE4z/?vd_source=06455e7f94c397f493f40aba56679e79


院士
2025-06-12 09:38:38     打赏
2楼

F411 的资源和性能还是非常强悍的。

轻松驱动 tft-lcd 了


院士
2025-06-12 09:39:00     打赏
3楼

楼主 要不要跑一下RTOS呀


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]