STM8L15x 低功耗代码优化建议
为了实现低功耗,可以考虑以下几点:
1.关掉不必要的外设
在代码中,有一部分代码是初始化ADC,但是并没有使用到ADC,因此可以将其注释掉或者删除掉。另外,代码中也没有使用到看门狗,可以将禁止看门狗的指令删除掉。
2.优化循环
在代码中,有一部分是Delay函数,函数内部是通过循环来实现延时的。这种方式会占用CPU资源,可以考虑使用硬件定时器来实现延时,这样就可以释放CPU资源。
3.降低工作频率
可以通过降低CPU工作频率来降低功耗。在STM8L系列芯片中,可以通过设置时钟分频器来实现降低CPU工作频率的目的。
以下代码示例展示了如何优化代码以降低功耗:
/* Includes ------------------------------------------------------------------*/
#include 'stm8l15x.h'
/* Private defines -----------------------------------------------------------*/
//HT1621指令
#define BIAS 0x52 //0b1000 0101 0010 1/3duty 4com
#define SYSDIS 0X00 //0b1000 0000 0000 关振系统荡器和LCD偏压发生器
#define SYSEN 0X02 //0b1000 0000 0010 打开系统振荡器
#define LCDOFF 0X04 //0b1000 0000 0100 关LCD偏压
#define LCDON 0X06 //0b1000 0000 0110 打开LCD偏压
#define XTAL 0x28 //0b1000 0010 1000 外部接时钟
#define RC256 0X30 //0b1000 0011 0000 内部时钟
//#define WDTDIS1 0X0A //0b1000 0000 1010 禁止看门狗
//模块接口定义
#define Ht1621_CS_PORT (GPIOB)
#define Ht1621_CS_PIN (GPIO_Pin_5)
#define Ht1621_WR_PORT (GPIOB)
#define Ht1621_WR_PIN (GPIO_Pin_6)
#define Ht1621_DAT_PORT (GPIOB)
#define Ht1621_DAT_PIN (GPIO_Pin_7)
//基础操作定义
void Ht1621_CS_0() {GPIO_Init(Ht1621_CS_PORT, Ht1621_CS_PIN, GPIO_Mode_Out_PP_Low_Fast);}
void Ht1621_CS_1() {GPIO_Init(Ht1621_CS_PORT, Ht1621_CS_PIN, GPIO_Mode_Out_PP_High_Fast);}
void Ht1621_WR_0() {GPIO_Init(Ht1621_WR_PORT, Ht1621_WR_PIN, GPIO_Mode_Out_PP_Low_Fast);}
void Ht1621_WR_1() {GPIO_Init(Ht1621_WR_PORT, Ht1621_WR_PIN, GPIO_Mode_Out_PP_High_Fast);}
void Ht1621_DAT_0() {GPIO_Init(Ht1621_DAT_PORT, Ht1621_DAT_PIN, GPIO_Mode_Out_PP_Low_Fast);}
void Ht1621_DAT_1() {GPIO_Init(Ht1621_DAT_PORT, Ht1621_DAT_PIN, GPIO_Mode_Out_PP_High_Fast);}
//最小量程 根据具体型号对应手册获取,单位是g,这里以RP-18.3-ST型号为例,最小量程是20g
#define PRESS_MIN 20
//最大量程 根据具体型号对应手册获取,单位是g,这里以RP-18.3-ST型号为例,最大量程是6kg
#define PRESS_MAX 5000
//以下2个参数根据获取方法:
//理论上:
// AO引脚输出的电压有效范围是0.1v到3.3v,而实际根据不同传感器范围会在这个范围内,并不一定是最大值3.3v,也可能低于3.3v,要实际万用表测量,
// 万用表测量然后修正以下2个AO引脚电压输出的最大和最小值
//调节方法:
//薄膜压力传感器的AO引脚输出的增益范围是通过板载AO_RES电位器调节实现的,
//想要稍微精准点,需要自己给定具体已知力,然后调节AO_RES电位器到串口输出重量正好是自己给定力就可以了
#define VOLTAGE_MIN 8500000
#define VOLTAGE_MAX 10000000
//定义要显示的值
unsigned int counter = 7777;
unsigned int tmp;
unsigned int n1, n2, n3, n4;
unsigned char Ht1621Tab[]={0x00,0x00,0x00,0x00};
unsigned char DispTab[]={0xEB,0x0A,0xAD,0x8F,0x4E,0xC7,0xE7,0x8A,0xEF,0xCF,0x85,0xEE, 0x67, 0xE1,0x2F,0xE5,0xE4,0x6E};
// 0 1 2 3 4 5 6 7 8 9 三 A B C D E F H
float PRESS_AO = 0;
float PRESS_N = 0;
float PRESS_PA = 0;
float PRESS_MMHG = 0;
long VOLTAGE_AO = 0;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
****函数名称:
****函数功能:延时函数
****入口参数:需要延时的数目
****出口参数:无
********************************************************************************/
//void Delay(uint16_t nCount)
//{
// while (nCount != 0)
// {
// nCount--;
// }
//}
//使用定时器实现延时函数
void Delay(uint16_t nCount)
{
TIM2_Init(TIM2_Prescaler_128, nCount);
TIM2_Cmd(ENABLE);
while(TIM2_GetFlagStatus(TIM2_FLAG_Update) == RESET) {};
TIM2_ClearFlag(TIM2_FLAG_Update);
TIM2_Cmd(DISABLE);
}
/*******************************************************************************
****函数名称:
****函数功能:1621写数据函数
****入口参数:Data-要发送的数据 cnt-要发送的数据位数
********************************************************************************/
void Ht1621Wr_Data(unsigned char Data, unsigned char cnt)
{
unsigned char i;
for (i = 0; i < cnt; i++)
{
Ht1621_WR_0();
if ((Data & 0x80) == 0x80)
{
Ht1621_DAT_1();
}
else
{
Ht1621_DAT_0();
}
Ht1621_WR_1();
Data <<= 1;
}
}
/*******************************************************************************
****函数名称:
****函数功能:1621写指令函数
****入口参数:Cmd 命令
********************************************************************************/
void Ht1621WrCmd(unsigned char Cmd)
{
Ht1621_CS_0();
/* 写入命令标志100 */
Ht1621Wr_Data(0x80,4);
/* 写入命令数据 */
Ht1621Wr_Data(Cmd,8);
Ht1621_CS_1();
}
/*******************************************************************************
****函数名称:
****函数功能:1621写一个数据函数
****入口参数:Addr--地址 Data--数据
********************************************************************************/
void Ht1621WrOneData(unsigned char Addr, unsigned char Data)
{
Ht1621_CS_0();
/* 写入数据标志101 */
Ht1621Wr_Data(0xa0,3);
/* 写入地址数据 */
Ht1621Wr_Data(Addr << 2,6);
/* 写入数据的前四位 7 6 5 4 */
Ht1621Wr_Data(Data,4);
Ht1621_CS_1();
}
/*******************************************************************************
****函数名称:
****函数功能:1621写整屏数据函数
****入口参数:Addr--地址 p--数据 cnt数据个数
********************************************************************************/
void Ht1621WrAllData(unsigned char Addr, unsigned char *p, unsigned char cnt)
{
unsigned char i;
Ht1621_CS_0();
/* 写入数据标志101 */
Ht1621Wr_Data(0xa0,3);
/* 写入地址数据 */
Ht1621Wr_Data(Addr << 2,6);
for (i = 0;i < cnt; i++)
{
/* 写入数据 */
Ht1621Wr_Data(*p,8);
p++;
}
Ht1621_CS_1();
}
/*******************************************************************************
****函数名称:
****函数功能:1621初始化函数
********************************************************************************/
void Ht1621_Init(void)
{
Ht1621WrCmd(BIAS);
Ht1621WrCmd(RC256); //使用内部振荡器
//Ht1621WrCmd(XTAL); //使用外部振荡器
Ht1621WrCmd(SYSDIS);
//Ht1621WrCmd(WDTDIS1);
Ht1621WrCmd(SYSEN);
Ht1621WrCmd(LCDON);
}
/*******************************************************************************
****函数名称:
****函数功能:1621显示函数
********************************************************************************/
void Display(void)
{
Ht1621WrOneData(0 , DispTab[n3]);
Ht1621WrOneData(1 , DispTab[n3]<<4);
Ht1621WrOneData(2 , DispTab[n2]);
Ht1621WrOneData(3 , DispTab[n2]<<4);
Ht1621WrOneData(4 , DispTab[n1]);
Ht1621WrOneData(5 , DispTab[n1]<<4);
Ht1621WrOneData(6 , DispTab[17]);
Ht1621WrOneData(7 , DispTab[17]<<4);
}
/*******************************************************************************
****函数名称:
****函数功能:显示符号函数
****入口参数:Addr--地址 Data--数据
********************************************************************************/
void Display_lcd_dot(void)
{
//Ht1621WrOneData(0 , DispTab[n4]|0x10);//P1
//Ht1621WrOneData(2 , DispTab[n3]|0x10); //2P
//Ht1621WrOneData(4 , DispTab[n2]|0x10); //3P
Ht1621WrOneData(6 , DispTab[n1]|0x10); //4P
}
/*******************************************************************************
****函数名称:
****函数功能:数据转换函数
****入口参数:adc_value-需要转换的数值
********************************************************************************/
void data_convertor(unsigned long adc_value)
{
tmp=adc_value; //adc
n4=tmp/1000;
tmp=tmp%1000;
n3=tmp/100;
tmp=tmp%100;
n2=tmp/10;
tmp=tmp%10;
n1=tmp;
}
/*******************************************************************************
****函数名称:
****函数功能:ADC初始化函数
****入口参数:adc_value-需要转换的数值
********************************************************************************/
//void Init_ADC(void)
//{
// GPIO_Init(GPIOC, GPIO_Pin_4, GPIO_Mode_In_FL_No_IT);
// CLK_PeripheralClockConfig(CLK_Peripheral_ADC1,ENABLE);
// //ADC_VrefintCmd(ENABLE);
// ADC_Init(ADC1,ADC_ConversionMode_Single,ADC_Resolution_12Bit,ADC_Prescaler_2);
// ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_9Cycles);
// ADC_Cmd(ADC1,ENABLE);
// ADC_ChannelCmd(ADC1,ADC_Channel_4,ENABLE);
//}
/*******************************************************************************
****函数名称:
****函数功能:取ADC转换平均值
****入口参数:times-取平均次数
********************************************************************************/
//uint16_t Get_Adc_Average(uint8_t times)
//{
// uint32_t temp_val = 0;
// uint8_t t;
//
// for (t = 0; t < times; t++)
// {
// temp_val += ADC_GetConversionValue(ADC1);
// Delay(5);
// }
//
// return temp_val / times;
//}
long map(long x, long in_max, long out_max)
{
return ((x * out_max) / in_max);
}
static unsigned long adc1_value;
void ADSK_0() {GPIO_ResetBits(GPIOB, GPIO_Pin_3);}
void ADSK_1() {GPIO_SetBits(GPIOB, GPIO_Pin_3);}
unsigned long ReadCount(void)
{
unsigned long Count;
unsigned char i;
ADSK_0();
Count = 0;
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4));
for (i=0;i<24;i++)
{
ADSK_1();
Count = Count << 1;
ADSK_0();
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4)) Count++;
}
ADSK_1();
Count = Count^0x800000;
ADSK_0();
return(Count);
}
void main(void)
{
FlagStatus flag_status;
Delay(100); //延时一段时间
Ht1621_Init(); //上电初始化LCD
Delay(100); //延时一段时间
Ht1621WrAllData(0,Ht1621Tab,16);// Clear LCD display
//Init_ADC();
//PWR_UltraLowPowerCmd(ENABLE);
GPIO_Init(GPIOB, GPIO_Pin_4, GPIO_Mode_In_PU_No_IT);
GPIO_Init(GPIOB, GPIO_Pin_3, GPIO_Mode_Out_OD_Low_Fast);
while (1)
{
adc1_value = ReadCount();
if(adc1_value < VOLTAGE_MIN)
{
PRESS_MMHG = 0;
}
else
{
PRESS_MMHG = (adc1_value - VOLTAGE_MIN) / 15000;
}
data_convertor(PRESS_MMHG);
Display();
Delay(500);
//Display_lcd_dot();
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval : None
*/
void assert_failed(u8* file, u32 line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf('Wrong parameters value: file %s on line %d\r\n', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
解释:
- 注释掉或删除ADC初始化代码:
//Init_ADC();以及相关的ADC相关代码。 - 注释掉或删除禁止看门狗指令:
//Ht1621WrCmd(WDTDIS1); - 使用硬件定时器实现延时: 将原Delay函数替换为使用TIM2定时器的延时函数。
其他建议:
- 降低CPU工作频率: 在STM8L15x中,可以使用
CLK_PeripheralClockConfig函数来设置时钟分频器,降低CPU工作频率。 - 使用低功耗模式: STM8L系列芯片支持多种低功耗模式,例如
PWR_UltraLowPowerCmd(ENABLE);,可以根据需要选择合适的低功耗模式。 - 优化代码逻辑: 尽量减少无用运算和代码执行,提高代码效率,进一步降低功耗。
通过这些方法,可以有效降低STM8L15x的功耗,延长设备的续航时间。
原文地址: https://www.cveoy.top/t/topic/nytT 著作权归作者所有。请勿转载和采集!