打印
[其他ST产品]

STM32CUBEMX stm32L151按键低功耗及唤醒

[复制链接]
331|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
CUBEMX配置1、选择芯片,当前示例选择stm32l151c8t6

2、配置RCC及SYS

只需配置高速时钟(HSE)和DEBUG


使用特权

评论回复
沙发
纠结的那些年|  楼主 | 2023-1-27 11:33 | 只看该作者
配置时钟树
时钟源采用外部8M晶振,单片机HCLK采用8M,过高运行功耗高,过低程序运行时精准延时(delay_us)误差大,具体视情况定。

使用特权

评论回复
板凳
纠结的那些年|  楼主 | 2023-1-27 11:51 | 只看该作者
本帖最后由 纠结的那些年 于 2023-1-27 11:56 编辑

配置串口,方便调试
当前波特率设为9600,主要考虑系统时钟最低可设为1M,此时功耗最低,不支持高波特率。且调试可不配置串口中断。



使用特权

评论回复
地板
纠结的那些年|  楼主 | 2023-1-27 11:57 | 只看该作者
配置外部中断
4+4按键矩阵,PA0~PA3选择推挽输出,默认下拉,PA4~PA7选择外部中断模式,默认上拉;打开中断,设置中断优先级,尽量避免优先级为0,不然延时消抖时使用HAL_Delay会死循环,因为HAL库SYSTIC优先级为0,或者采用时钟摘取法自己实现ms、us延时,推荐原子哥的延时初始化函数。

使用特权

评论回复
5
纠结的那些年|  楼主 | 2023-1-27 11:58 | 只看该作者

使用特权

评论回复
6
纠结的那些年|  楼主 | 2023-1-27 11:59 | 只看该作者
生成代码
选择MDK5,.c/.h文件分开。



使用特权

评论回复
7
纠结的那些年|  楼主 | 2023-1-27 12:00 | 只看该作者
运行代码
1、使能printf
将以下代码添加至.c文件

int fputc(int ch,FILE *f)
{
        HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
        return 0;
}

使用特权

评论回复
8
纠结的那些年|  楼主 | 2023-1-27 12:01 | 只看该作者
初始化延时
delay_init(); 当前初始化延时存在问题,按键中断延时消抖会使中断外delay直接结束造成误差,有待改进。
void delay_init()
{
        uint32_t CLKSource = SYSTICK_CLKSOURCE_HCLK;        //选择时钟源
        uint32_t DIV = 1;                                                                //分频系数
        if(SystemCoreClock/1000000 > 16)                                //系统时钟超过16M则8分频,SysTick->LOAD最大值2^24=16,777,216,16M时钟源延时最大值为1048.576ms
        {
                CLKSource = SYSTICK_CLKSOURCE_HCLK_DIV8;
                DIV = 8;
        }
       
        HAL_SYSTICK_CLKSourceConfig(CLKSource);        //选择外部时钟
        fac_us=SystemCoreClock/1000000/DIV;                //为系统时钟的us延时tick数
        fac_ms=(u16)fac_us*1000;                                //非OS下,代表每个ms需要的systick时钟数
}                                                                    

//延时nus                                                                                      
void delay_us(u32 nus)
{               
        u32 temp;                     
        SysTick->LOAD=nus*fac_us;                                         //时间加载                           
        SysTick->VAL=0x00;                                                //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;        //开始倒数          
        do
        {
                temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));                //等待时间到达   
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;        //关闭计数器
        SysTick->VAL =0X00;                                               //清空计数器         
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{                                     
        u32 temp;                  
        SysTick->LOAD=(u32)nms*fac_ms;                                //时间加载(SysTick->LOAD为24bit)
        SysTick->VAL =0x00;                                                        //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;        //开始倒数  
        do
        {
                temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));                //等待时间到达   
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;        //关闭计数器
        SysTick->VAL =0X00;                                               //清空计数器                      
}

使用特权

评论回复
9
纠结的那些年|  楼主 | 2023-1-27 12:02 | 只看该作者
按键扫描
行扫描,通过中断管脚判断,4条中断线(PA4~PA7)对应4行;列扫描,PA0~PA3逐个拉高电平,通过中断管脚电平被拉高判断。最后将PA0~PA3电平重新拉低,此时由于电平高低变化会再次产生中断,记得退出按键扫描后清中断。

使用特权

评论回复
10
纠结的那些年|  楼主 | 2023-1-27 12:02 | 只看该作者
/* 4*4按键矩阵,key0~15及对应value */
uint8_t KEY_NUM[4][4] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint8_t KEY_DATA[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0FF,0xFF};

/* 按键矩阵行对应GPIO管脚 */
#define KEY_PIN_ROW0        GPIO_PIN_4
#define KEY_PIN_ROW1        GPIO_PIN_5
#define KEY_PIN_ROW2        GPIO_PIN_6
#define KEY_PIN_ROW3        GPIO_PIN_7

#define KEY_GPIO_ROW0        GPIOA
#define KEY_GPIO_ROW1        GPIOA
#define KEY_GPIO_ROW2        GPIOA
#define KEY_GPIO_ROW3        GPIOA

/* 按键矩阵列对应GPIO管脚 */
#define KEY_PIN_COLUMN0        GPIO_PIN_0
#define KEY_PIN_COLUMN1        GPIO_PIN_1
#define KEY_PIN_COLUMN2        GPIO_PIN_2
#define KEY_PIN_COLUMN3        GPIO_PIN_3

#define KEY_GPIO_COLUMN0        GPIOA
#define KEY_GPIO_COLUMN1        GPIOA
#define KEY_GPIO_COLUMN2        GPIOA
#define KEY_GPIO_COLUMN3        GPIOA


/* 扫描按键,中断模式下扫描列会反转电平,额外产生一次中断,需清中断 */
uint8_t keyScan(uint16_t GPIO_Pin)
{
        GPIO_TypeDef* GPIOx;
        uint8_t key_row,key_column;
       
        /* 扫描行 */
        switch(GPIO_Pin)
        {
                case KEY_PIN_ROW0:
                        key_row = 0;
                        GPIOx = KEY_GPIO_ROW0;
                        break;
                case KEY_PIN_ROW1:
                        key_row = 1;
                        GPIOx = KEY_GPIO_ROW1;
                        break;
                case KEY_PIN_ROW2:
                        key_row = 2;
                        GPIOx = KEY_GPIO_ROW2;
                        break;
                case KEY_PIN_ROW3:
                        key_row = 3;
                        GPIOx = KEY_GPIO_ROW3;
                        break;
                default:
                        key_row = 3;
                        break;
        }
       
        /* 扫描列-电平反转,会额外产生一次中断 */
        HAL_GPIO_WritePin(KEY_GPIO_COLUMN0,KEY_PIN_COLUMN0,GPIO_PIN_SET);
        if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin))
        {
                key_column = 0;
        }
        else
        {
                HAL_GPIO_WritePin(KEY_GPIO_COLUMN1,KEY_PIN_COLUMN1,GPIO_PIN_SET);
                if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin))
                {
                        key_column = 1;
                }
                else
                {
                        HAL_GPIO_WritePin(KEY_GPIO_COLUMN2,KEY_PIN_COLUMN2,GPIO_PIN_SET);
                        if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin))
                        {
                                key_column = 2;
                        }
                        else
                        {
                                HAL_GPIO_WritePin(KEY_GPIO_COLUMN3,KEY_PIN_COLUMN3,GPIO_PIN_SET);
                                if(HAL_GPIO_ReadPin(GPIOx,GPIO_Pin))
                                {
                                        key_column = 3;
                                }
                        }
                }
        }
        HAL_GPIO_WritePin(KEY_GPIO_COLUMN0,GPIO_PIN_0,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(KEY_GPIO_COLUMN1,GPIO_PIN_1,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(KEY_GPIO_COLUMN2,GPIO_PIN_2,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(KEY_GPIO_COLUMN3,GPIO_PIN_3,GPIO_PIN_RESET);
       
        printf("key%d\r\n",KEY_NUM[key_row][key_column]);
        return KEY_NUM[key_row][key_column];
}

使用特权

评论回复
11
纠结的那些年|  楼主 | 2023-1-27 12:03 | 只看该作者
进入低功耗
进入低功耗之前关闭所有时钟并将IO口设为输入模式以降低功耗,若接入了外设,则该IO口模式不变以保持电平,使得外设正常工作。

使用特权

评论回复
12
纠结的那些年|  楼主 | 2023-1-27 12:04 | 只看该作者
void StopMode_Measure(void)
{
  /* Enter Stop Mode */
        HAL_UART_MspDeInit(&huart1);
        GPIO_RCC_disable();
        HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
/**********关闭GPIO时钟,降低功耗**********/
void GPIO_RCC_disable(void)
{
        /* GPIO Ports Clock Enable */
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_GPIOC_CLK_ENABLE();
        __HAL_RCC_GPIOH_CLK_ENABLE();

        GPIOA->MODER = 0xFFFFFFFF;
        GPIOB->MODER = 0xFFFFFFFF;
        GPIOC->MODER = 0xFFFFFFFF;
        GPIOH->MODER = 0xFFFFFFFF;

        __HAL_RCC_GPIOA_CLK_DISABLE();
        __HAL_RCC_GPIOB_CLK_DISABLE();
        __HAL_RCC_GPIOC_CLK_DISABLE();
        __HAL_RCC_GPIOH_CLK_DISABLE();

}

使用特权

评论回复
13
纠结的那些年|  楼主 | 2023-1-27 12:05 | 只看该作者
退出低功耗
进入按键中断后,系统采用低速时钟,需SystemClock_Config(),重新配置并打开系统时钟(最重要),打开其它被关闭的时钟等。最简单粗暴就把所有外设初始化。

/* 初始化,打开对应外设时钟 */
        SystemClock_Config();
        delay_init();       
        MX_GPIO_Init();
        HAL_UART_MspInit(&huart1);

使用特权

评论回复
14
纠结的那些年|  楼主 | 2023-1-27 12:06 | 只看该作者
我自己测试时(无其它外设),32M时钟工作电流11mA左右,8M时钟工作电流3.5mA左右,进入低功耗电流2.8uA左右。有问题可讨论,大家一起进步。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

46

主题

688

帖子

0

粉丝