[GD32L233C-START 评测] 【GD32L233C-START评测】19、低功耗串口(深度休眠唤醒、空闲中断不定长数据接收)

freeelectron   2022-3-23 21:46 楼主

相关文章:

【GD32L233C-START评测】1、优点与缺点都很明显的GD32L233C-START(开箱)

【GD32L233C-START评测】2、非阻塞方式点灯,blink,blink,blink……

【GD32L233C-START评测】3、pwm实现呼吸灯

【GD32L233C-START评测】4、串口不定长数据接收

【GD32L233C-START评测】5、Flash读写——使用内部Flash存储数据

【GD32L233C-START评测】6、硬件I2C驱动0.96吋OLED

【GD32L233C-START评测】7、硬件SPI1驱动RC522

【GD32L233C-START评测】8、获取MCU96位唯一ID、SRAM、FLASH大小

【GD32L233C-START评测】9、IAP程序升级——基于YMODEM协议

【GD32L233C-START评测】10、使用内部参考电压校准adc,adc采样更准确

【GD32L233C-START评测】11、GD32 ISP软件还不支持GD32L233

【GD32L233C-START评测】12、按键——外部中断

【GD32L233C-START评测】13、I2C驱动环境光和接近传感器RPR-0521RS

【GD32L233C-START评测】14、RT-Thread移植到GD32L233(内核,finsh移植)

【GD32L233C-START评测】15、RT-Thread消息队列、多线程使用

【GD32L233C-START评测】16、RT-Thread事件集从中断唤醒任务

【GD32L233C-START评测】17、CMSIS-RTOS2 RTX5移植到GD32L233(内核,多线程)

【GD32L233C-START评测】18、硬件SPI驱动(ST7735)1.8吋TFT LCD

 

1、GD32L233低功耗串口

image.png  可以看出GD32L233系列都只有一个低功耗串口。

 

2、串口引脚复用

image.png  使用PA2和PA3,复用功能为AF8。

 

3、开发板LPUART引脚

image.png  

4、mcu从深度休眠唤醒条件

image.png  可以看出唤醒的条件是外部中断或事件。

 

5、串口为什么能从休眠唤醒mcu

image.png  可以看出,LPUART连接到了外部中断28上,属于外部中断,这正是串口为什么能从休眠唤醒mcu的原因。

 

6、串口从休眠唤醒方式

image.png

 

7、代码实现

struct
{
	uint8_t RecvBuff[200];
	uint8_t RecvLen;
	uint8_t Idle:1;
}LpSerialStr;  //串口数据处理结构体
void LpuartInit(void)
{ 
	rcu_lpuart_clock_config(RCU_LPUARTSRC_IRC16MDIV);    //要进入休眠,时钟必须配置为IRC16M或LXTAL

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_LPUART);

    /* connect port to LPUART TX */
    gpio_af_set(GPIOA, GPIO_AF_8, GPIO_PIN_2);
    /* connect port to LPUART RX */
    gpio_af_set(GPIOA, GPIO_AF_8, GPIO_PIN_3);

    /* configure LPUART TX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);

    /* configure LPUART RX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3);

    /* LPUART configure */
    lpuart_deinit();
	
    lpuart_word_length_set(LPUART_WL_8BIT);
    lpuart_stop_bit_set(LPUART_STB_1BIT);
    lpuart_parity_config(LPUART_PM_NONE);
    lpuart_baudrate_set(115200U);
    lpuart_receive_config(LPUART_RECEIVE_ENABLE);
    lpuart_transmit_config(LPUART_TRANSMIT_ENABLE);
	
	exti_init(EXTI_28, EXTI_INTERRUPT, EXTI_TRIG_BOTH); //外部中断28配置
	nvic_irq_enable(LPUART_WKUP_IRQn, 0);              //休眠唤醒中断使能

	lpuart_wakeup_mode_config(LPUART_WUM_RBNE );    //唤醒方式,一定要在串口使能之前配置

	lpuart_wakeup_enable();
    lpuart_interrupt_enable(LPUART_INT_WU);         //休眠唤醒中断
	
	lpuart_enable();                             

	lpuart_interrupt_enable(LPUART_INT_RBNE);       //接收中断
	
	while(RESET == lpuart_flag_get(LPUART_FLAG_IDLE)){};
    lpuart_flag_clear(LPUART_FLAG_IDLE);
	
	lpuart_interrupt_enable(LPUART_INT_IDLE);       //空闲中断
		
	nvic_irq_enable(LPUART_IRQn, 3);                //低功耗串口中断使能

    void LpSerialSend(uint8_t *data,uint8_t len);
	LpSerialSend((uint8_t *)"enter\r\n",7);
		
	rcu_periph_clock_enable(RCU_PMU);
	pmu_to_deepsleepmode(PMU_LDNPDSP_LOWDRIVE, WFI_CMD, PMU_DEEPSLEEP);  //进入休眠
	
	void system_clock_reconfig(void);
	system_clock_reconfig();                      //

	LpSerialSend((uint8_t *)"recover\r\n",9);	
}

 

void LpSerialRecv(uint8_t data)  //串口接收
{
	if(LpSerialStr.RecvLen<200)
	{
		LpSerialStr.RecvBuff[LpSerialStr.RecvLen++]=data;
	}
}


void LpSerialSend(uint8_t *data,uint8_t len)  //串口发送
{
	for(uint8_t i=0; i<len;i++)
	{
		while (RESET == lpuart_flag_get(LPUART_FLAG_TBE  )); 
		lpuart_data_transmit(data[i]);
		while (RESET == lpuart_flag_get(LPUART_FLAG_TC  ));//LPUART_FLAG_TBE
	}
}


void LpSerialPro(void)                  //串口接收数据处理
{
	uint8_t len[2];
		
	if(LpSerialStr.Idle&&LpSerialStr.RecvLen)
	{
		LpSerialSend((uint8_t *)"Recv:",5);
		sprintf((char *)len,"%d",LpSerialStr.RecvLen);
		LpSerialSend(len,strlen((char *)len));
		LpSerialSend((uint8_t *)"[",1);
		LpSerialSend(LpSerialStr.RecvBuff,LpSerialStr.RecvLen);

		LpSerialSend((uint8_t *)"]\r\n",3);
		LpSerialStr.RecvLen=0;
		LpSerialStr.Idle=0;
	}
}

 

void system_clock_reconfig(void)  //唤醒后重新配置时钟
{
    /* enable HXTAL */
    RCU_CTL |= RCU_CTL_HXTALEN;

    while(SUCCESS != rcu_osci_stab_wait(RCU_HXTAL)) {};

    /* configure AHB */
    rcu_ahb_clock_config(RCU_AHB_CKSYS_DIV1);

    /* configure APB1, APB2 */
    rcu_apb1_clock_config(RCU_APB1_CKAHB_DIV1);
    rcu_apb2_clock_config(RCU_APB2_CKAHB_DIV1);

    /* enable PLL */
    RCU_CTL |= RCU_CTL_PLLEN;

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
}

 

void LPUART_IRQHandler(void)  //串口中断处理函数
{
    if(RESET != lpuart_interrupt_flag_get(LPUART_INT_FLAG_RBNE)) //接收中断
	{
		LpSerialRecv(lpuart_data_receive());
    }
	
	
	if(RESET != lpuart_interrupt_flag_get(LPUART_INT_FLAG_IDLE)) //空闲中断
	{
		lpuart_interrupt_flag_clear(LPUART_INT_FLAG_IDLE);
		LpSerialStr.Idle=1;
	}
}



void LPUART_WKUP_IRQHandler(void) //串口唤醒中断处理函数
{
    if(SET == lpuart_interrupt_flag_get(LPUART_INT_FLAG_WU)) 
	{
        lpuart_flag_clear(LPUART_FLAG_WU);
        exti_flag_clear(EXTI_28);
	}
}

8、现象

image.png  打印“enter”提示进入休眠,接收到数据后唤醒,打印“recover”,唤醒后同时处理,唤醒时接收到的串口数据;

之后,发送不定长数据,串口在接收完后,将接收到的数据再打印出来。

 

 

 

stm32/LoRa物联网:304350312

回复评论 (4)

学习一下,如果用普通串口,如usart1是相同配置吗

点赞  2022-8-18 15:56

有测过休眠电流和唤醒电流各是多少吗?否则没任何意义。

点赞  2022-8-19 08:21
睡眠模式电流250uA
点赞  2023-6-29 13:59
GOOD
点赞  2023-9-14 14:39
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复