使用STM32F103C8T6 、NRF24L01 、红外热释电传感器组成一个低功耗无线人体传感器,系统采用低功耗设计,在STM32停机模式,整机工作电流37uA,可用电池供电。
SPI接口
STM32引脚NRF24L01PB8NRFIRQPB9NRFCSPB10NRFCEPB13NRF_SCKPB14NRF_MISOPB15NRF_MOSI红外热释电接口 红外热释电为集成感应探头,使用3.3V供电,输出高电平代表有人
STM32引脚红外热释电PB11热释电输出IO口关于NRF24L01的使用,网上有很多的教程和例程,在这里NRF24L01的SPI驱动使用了原子哥的精英版例程。 针对低功耗设计,只需要修改NRF24L01的配置寄存器的PWR_UP位,1代表上电,0代表掉电。 NRF24L01进入掉电之后,STM32的SPI相关脚位必须都输出高电平,否则会在引脚之间存在漏电。实际测试过用模拟输入方式也会有30左右uA的漏电。 NRF24L01进入掉电模式后,输入电流约为1uA。
STM32F103支持三种低功耗模式,可以查看STM32F103的参考手册 睡眠模式,功耗较高,没有实际测试。 停机模式,在1.8V供电区域的的所有时钟都被停止, PLL、 HSI和 HSE RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来(见参考手册)。"SRAM和寄存器保留"这点个人感觉是和待机模式区别最大的一点,停机模式唤醒之后,从进入停机的指令后继续运行;而待机是程序重新运行,相当于重新上电。 在进入停机模式时,可以选择电压调节器开启或处于低功耗模式。低功耗模式会进一步降低功耗,但会增加下次唤醒的启动时间。可以根据实际情况进行选择。 还有注意的一点,从停机模式唤醒后,系统的时钟为内部时钟,如需切换到外部时钟,需要重新初始化时钟。 待机模式,待机模式是功耗最低的,该模式是在Cortex-M3深睡眠模式时关闭电压调节器。1.8V供电区域被断电。 PLL、 HSI和HSE振荡器也被断电。 SRAM和寄存器内容丢失。换言之,就是端口全部不会保持待机前的状态(除WKUP引脚)
完全代码可以在上下载链接,这里列出部分驱动代码
SPI接口初始化,直接使用原子哥的代码,改了端口和引脚
//初始化24L01的IO口 void NRF24L01_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9; //PB9 10推挽 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化指定IO GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //PB6 输入 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10);// SPI2_Init(); //初始化SPI SPI_Cmd(SPI2, DISABLE); // SPI外设不使能 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //SPI主机 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //发送接收8位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟悬空低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第1个时钟沿 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件控制 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; //定义波特率预分频的值:波特率预分频值为16 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式 SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 SPI_Cmd(SPI2, ENABLE); //使能SPI外设 NRF24L01_CE=0; //使能24L01 NRF24L01_CSN=1; //SPI片选取消 }NRF24L01进入发送模式
//该函数初始化NRF24L01到TX模式 //设置TX地址,写TX数据宽度,设置RX自动应答的地址,填充TX发送数据,选择RF频道,波特率和LNA HCURR //PWR_UP,CRC使能 //当CE变高后,即进入RX模式,并可以接收数据了 //CE为高大于10us,则启动发送. void NRF24L01_TX_Mode(void) { NRF24L01_CE=0; NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发送模式,开启所有中断 NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址 NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01); //使能通道0的自动应答 NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址 NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40); //设置RF通道为40 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启 NRF24L01_CE=1;//CE为高,10us后启动发送 }停机模式唤醒后系统时钟为内部时钟,需要切换到外部时钟可以直接调用这个函数。这函数直接拷贝STM32库函数里PWR的例程。
/** * @brief Configures system clock after wake-up from STOP: enable HSE, PLL * and select PLL as system clock source. * @param None * @retval None */ void SYSCLKConfig_STOP(void) { /* Enable HSE */ RCC_HSEConfig(RCC_HSE_ON); /* Wait till HSE is ready */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { #ifdef STM32F10X_CL /* Enable PLL2 */ RCC_PLL2Cmd(ENABLE); /* Wait till PLL2 is ready */ while(RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET) { } #endif /* Enable PLL */ RCC_PLLCmd(ENABLE); /* Wait till PLL is ready */ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /* Select PLL as system clock source */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* Wait till PLL is used as system clock source */ while(RCC_GetSYSCLKSource() != 0x08) { } } }