STM32L431在STOP2模式下能否将串口的RX配置成EXTI唤醒呢?为什么我的唤醒不了呢?并且空闲中断也不能用,手册中说在硬件上已经将EXTI与RX引脚连到一块了,但是呢STOP2模式不能将串口唤醒,所以它的那种方式好像不能使用,只能用最原始的将RX配置成EXTI的方式了,但是也还是唤醒不了
进入STOP2模式,
void EnterStop2ModeRTC(void) // 自定义的Enter函数
{
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
__HAL_RTC_TIMESTAMP_CLEAR_FLAG(&hrtc, RTC_FLAG_TSF);
__HAL_RTC_TAMPER_TIMESTAMP_EXTI_CLEAR_FLAG();
while (__HAL_UART_GET_FLAG(&huart3, USART_ISR_BUSY) == SET)
;
while (__HAL_UART_GET_FLAG(&huart3, USART_ISR_REACK) == RESET)
;
setUca3RxToExti();//配置串口3的RX为EXTI
HAL_SuspendTick();
//HAL_DBGMCU_EnableDBGStopMode();
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); // 进入STOP2模式
}
退出STOP2
void ExitStop2ModeRTC(void)
{
SystemClock_Config();
HAL_ResumeTick();
SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
}
主函数
while (1)
{
while (getExitLPM3())
{
saveData();
lcdActionPro(); // lcd进程
keyActPro();
// if (uart[_COM3].active)
// {
// }
}
}
EnterStop2ModeRTC();
}
在函数getExitLPM3()中,判断了一个标志位是否被置位,如果置位了就进入里面的while
EXTI回调函数:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if ((GPIO_Pin == GPIO_PIN_5))
{
ExitStop2ModeRTC();
HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
setUca3RxToRx();
// uart[_COM3].active = true;
}
}
在EXTI的回调函数中退出了STOP2模式并重新将串口RX引脚配置为接收引脚
void setUca3RxToExti(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
uart[_COM3].active = false;
}
void setUca3RxToRx(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
// // HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
// // HAL_NVIC_EnableIRQ(USART3_IRQn);
__HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);
// __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE | UART_IT_IDLE);
}
串口中断
void USER_USART3_IRQHandler(void)
{
uint8_t data = 0;
if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) != RESET)
{
data = (uint8_t)huart3.Instance->RDR;
wrEleQueue(&uart[_COM3].Rx, data);
// uart[_COM3].active = true;
// bleAppConfig.rxAct = 1;
// bleAppConfig.tmrResp = bleAppConfig.tmrRxHold = HAL_LPTIM_ReadCounter(&hlptim1);
// __HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_RXNE);
}
// if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE))
// {
// // uart[_COM3].flag = 1;
// uart[_COM3].active = false;
// __HAL_UART_CLEAR_IDLEFLAG(&huart3);
// }
}
中间好像逻辑有点问题,但是我想不明白了哈哈,就是那个标志位被置位true后就会一直在内层的while中循环,出不来了,就进不去STOP2了,但是不知道在哪将它给置为false,本来想使用IDLE空闲中断的,但是空闲中断使用后收不到数据,现在不使用的时候第一包数据永远都是错误的,有没有大佬能帮忙看一下,谢谢大家
另外手册上介绍的是LPUART 才有唤醒 STOP 模式的功能, 且需要波特率最大为9600.
如果波特率太快,即使中断唤醒,从唤醒到开始工作需要一定时间,所以一定会丢掉开始的数据的。
从你代码来看,使用的是UART3,你似乎想问是否可以利用UART RX脚的EXTI来唤醒MCU.
即使是UART的RX脚,也可以配置其EXTI中断能力,并可以通过该中断唤醒STOP2模式下的MCU.
假设你使用STM32cubeMx进行UART配置,创建工程后自己手动再增加基于UART RX脚的EXTI配置,
不要修改该脚的复用配置功能。
假设你使用UART3的RX脚是PC5,我们可以临时选择其它编号为5个GPIO,比方PD5,启用该脚的EXTI并
使能NVIC端的中断响应。
创建工程后,只需在 MX_GPIO_Init()函数里将PD5的 EXTI配置改为PC5的配置即可,其它不用修改。
这样就可以测试了,比起对着手册修改EXTI控制寄存器方便多了。我这样测试屡试不爽。
先一步步来,先将不影响UART功能前提下,将RX脚的EXTI功能弄出来,再来验证唤醒的事情。
如果将RX配置成EXTI方式,串口的空闲中断好像不能用啊,有时候收到一个数据就进入空闲中断了,并且第一包还是乱码,这种怎么办呢?
[md]基于RX脚的EXTI中断主要用来唤醒比较合适,按理你这里用不着借助RX EXTI中断来做数据接收,
RXNE中断做接收,IDLE中断提示接收结束;
RX EXTI中断和IDLE中断是完全不搭界的两个中断,IDLE中断用于不确定数据长度的UART接收比较合适;
[md]我是要做低功耗的,所以才需要借助RX的EXTI中断,如果没有数据的时候不将RX配置为EXTi的话,功耗就降不下去
[md]了解你的需求。
我是说,使用RX中断和IDLE中断是两个不同的事件,你这里使用RX中断主要用作唤醒,往往发生在通信前,IDLE中断是发生在通信后,你合理安排好程序逻辑即可。
[md]你的意思是,接收中断个空闲中断不要同时使能吗?分先后使能?我在将RX配置为接收引脚的时候使能了接收中断,那么空闲中断我不知道放在哪里
[md]基于RX电平跳变的EXTI中断,基于UART接收的RXNE中断,基于空闲事件的中断,
即使这三个中断同时使能也没有关系,各司其职。EXTI中断只负责触发唤醒,进中断服务程序
后只清零EXTI相关标志,不要涉及UART相关寄存器的访问;
RXNE中断只管数据接收;
IDLE中断负责数据处理和做后续通信准备。
具体到这里EXTI中断最好不用时刻使能,只在进低功耗前才使能为宜,唤醒后立即关闭。
[md]对啊,我上面的代码就是这样写的呀