简述
使用STM32F103C8T6 、NRF24L01 、红外热释电传感器组成一个低功耗无线人体传感器,系统采用低功耗设计,在STM32停机模式,整机工作电流37uA,可用电池供电。
硬件接口
SPI接口
[tr]STM32引脚NRF24L01[/tr]
PB8 | NRFIRQ |
PB9 | NRFCS |
PB10 | NRFCE |
PB13 | NRF_SCK |
PB14 | NRF_MISO |
PB15 | NRF_MOSI |
红外热释电接口
红外热释电为集成感应探头,使用3.3V供电,输出高电平代表有人
[tr]STM32引脚红外热释电[/tr]
外设使用
[tr]外设作用[/tr]
系统滴答定时器 | 用于软件延时 |
SPI接口 | 用于驱动NRF24L01 |
RTC | 停机模式下的定时唤醒 |
外部中断 | 停机模式下的中断唤醒 |
NRF24L01低功耗设计
关于NRF24L01的使用,网上有很多的教程和例程,在这里NRF24L01的SPI驱动使用了原子哥的精英版例程。
针对低功耗设计,只需要修改NRF24L01的配置寄存器的PWR_UP位,1代表上电,0代表掉电。
NRF24L01进入掉电之后,STM32的SPI相关脚位必须都输出高电平,否则会在引脚之间存在漏电。实际测试过用模拟输入方式也会有30左右uA的漏电。
NRF24L01进入掉电模式后,输入电流约为1uA。
STM32F103低功耗设计
STM32F103支持三种低功耗模式,可以查看STM32F103的参考手册
睡眠模式,功耗较高,没有实际测试。
停机模式,在1.8V供电区域的的所有时钟都被停止, PLL、 HSI和
HSE RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来(见参考手册)。"SRAM和寄存器保留"这点个人感觉是和待机模式区别最大的一点,停机模式唤醒之后,从进入停机的指令后继续运行;而待机是程序重新运行,相当于重新上电。
在进入停机模式时,可以选择电压调节器开启或处于低功耗模式。低功耗模式会进一步降低功耗,但会增加下次唤醒的启动时间。可以根据实际情况进行选择。
还有注意的一点,从停机模式唤醒后,系统的时钟为内部时钟,如需切换到外部时钟,需要重新初始化时钟。
待机模式,待机模式是功耗最低的,该模式是在Cortex-M3深睡眠模式时关闭电压调节器。1.8V供电区域被断电。 PLL、 HSI和HSE振荡器也被断电。 SRAM和寄存器内容丢失。换言之,就是端口全部不会保持待机前的状态(除WKUP引脚)
代码
NRF24L01驱动
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后启动发送
}
外部中断和RTC中断配置
//PB11外部中断 RTC闹钟中断
void WKUP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);//使能GPIOB和复用功能时钟
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11; //
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;//
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化IO
//使用外部中断方式
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11); //
EXTI_InitStructure.EXTI_Line = EXTI_Line11; //设置按键所有的外部线路
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设外外部中断模式:EXTI线路为中断请求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); // 初始化外部中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级2级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
//RTC中断配置
/* 2 bits for Preemption Priority and 2 bits for Sub Priority */
/* Configure EXTI Line17(RTC Alarm) to generate an interrupt on rising edge */
EXTI_ClearITPendingBit(EXTI_Line17);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
停机模式唤醒后系统时钟为内部时钟,需要切换到外部时钟可以直接调用这个函数。这函数直接拷贝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)
{
}
}
}
简述
使用STM32F103C8T6 、NRF24L01 、红外热释电传感器组成一个低功耗无线人体传感器,系统采用低功耗设计,在STM32停机模式,整机工作电流37uA,可用电池供电。
硬件接口
SPI接口
[tr]STM32引脚NRF24L01[/tr]
PB8 | NRFIRQ |
PB9 | NRFCS |
PB10 | NRFCE |
PB13 | NRF_SCK |
PB14 | NRF_MISO |
PB15 | NRF_MOSI |
红外热释电接口
红外热释电为集成感应探头,使用3.3V供电,输出高电平代表有人
[tr]STM32引脚红外热释电[/tr]
外设使用
[tr]外设作用[/tr]
系统滴答定时器 | 用于软件延时 |
SPI接口 | 用于驱动NRF24L01 |
RTC | 停机模式下的定时唤醒 |
外部中断 | 停机模式下的中断唤醒 |
NRF24L01低功耗设计
关于NRF24L01的使用,网上有很多的教程和例程,在这里NRF24L01的SPI驱动使用了原子哥的精英版例程。
针对低功耗设计,只需要修改NRF24L01的配置寄存器的PWR_UP位,1代表上电,0代表掉电。
NRF24L01进入掉电之后,STM32的SPI相关脚位必须都输出高电平,否则会在引脚之间存在漏电。实际测试过用模拟输入方式也会有30左右uA的漏电。
NRF24L01进入掉电模式后,输入电流约为1uA。
STM32F103低功耗设计
STM32F103支持三种低功耗模式,可以查看STM32F103的参考手册
睡眠模式,功耗较高,没有实际测试。
停机模式,在1.8V供电区域的的所有时钟都被停止, PLL、 HSI和
HSE RC振荡器的功能被禁止, SRAM和寄存器内容被保留下来(见参考手册)。"SRAM和寄存器保留"这点个人感觉是和待机模式区别最大的一点,停机模式唤醒之后,从进入停机的指令后继续运行;而待机是程序重新运行,相当于重新上电。
在进入停机模式时,可以选择电压调节器开启或处于低功耗模式。低功耗模式会进一步降低功耗,但会增加下次唤醒的启动时间。可以根据实际情况进行选择。
还有注意的一点,从停机模式唤醒后,系统的时钟为内部时钟,如需切换到外部时钟,需要重新初始化时钟。
待机模式,待机模式是功耗最低的,该模式是在Cortex-M3深睡眠模式时关闭电压调节器。1.8V供电区域被断电。 PLL、 HSI和HSE振荡器也被断电。 SRAM和寄存器内容丢失。换言之,就是端口全部不会保持待机前的状态(除WKUP引脚)
代码
NRF24L01驱动
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后启动发送
}
外部中断和RTC中断配置
//PB11外部中断 RTC闹钟中断
void WKUP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);//使能GPIOB和复用功能时钟
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11; //
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;//
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化IO
//使用外部中断方式
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11); //
EXTI_InitStructure.EXTI_Line = EXTI_Line11; //设置按键所有的外部线路
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设外外部中断模式:EXTI线路为中断请求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); // 初始化外部中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级2级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
//RTC中断配置
/* 2 bits for Preemption Priority and 2 bits for Sub Priority */
/* Configure EXTI Line17(RTC Alarm) to generate an interrupt on rising edge */
EXTI_ClearITPendingBit(EXTI_Line17);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
停机模式唤醒后系统时钟为内部时钟,需要切换到外部时钟可以直接调用这个函数。这函数直接拷贝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)
{
}
}
}
举报