1、休眠唤醒后串口异常问题
STM8L主要用来做低功耗产品,这里就有休眠前跟唤醒后有差异的情况,在调试的时候碰到如果使用串口,在休眠前都正常,当唤醒后,串口发送的数据会出现异常的情况,发送的数据感觉会有丢帧。后来发现跟系统时钟有关,如果系统时钟采用外部时钟就会有问题,内部时钟就OK。
/*
这里要用内部时钟
用外部时钟在进入halt之后会出现
串口发送异常
*/
CLK_HSICmd(ENABLE);
while (CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == RESET);
CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI);
CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);
2、RTC唤醒设置问题
如果要做低功耗,主要是通过RTC来唤醒,这样CPU能进入最低休眠。设置RTC也碰到一个奇怪问题,设置唤醒计数器一定要在开中断之前,不然设置会无效。
CLK_PeripheralClockConfig(CLK_Peripheral_RTC, ENABLE);
CLK_RTCClockConfig(CLK_RTCCLKSource_LSI, CLK_RTCCLKDiv_1);
RTC_WakeUpClockConfig(RTC_WakeUpClock_RTCCLK_Div16); //32768/16 = 2048
RTC_SetWakeUpCounter(2048 * g_RtcCtl.u32WakeInt); //这个要放在开中断前
RTC_ITConfig(RTC_IT_WUT, ENABLE);
RTC_WakeUpCmd(ENABLE);
这也就是为什么,如果你原来设置5s唤醒一次,那么如果你不断电,然后下载10s唤醒一次的程序,RTC还是5s唤醒,除非你重新上电才会有效。
3、ADC多通道切换问题
我程序要用到两个采集,一个用来做IO口的AD采集,一个用来内部参考电压做电源电量采集,这里碰到一个奇葩问题,如果你在切换通道的时候,第一次采集的数据就是不对,需要第二次采集的数据才行。
SMOKE_DET_PWR_EN();
//ADC_DeInit(ADC1);
CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_1);
ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_384Cycles);
ADC_Cmd(ADC1, ENABLE);
ADC_ChannelCmd(ADC1, ADC_Channel_4, ENABLE);
T_U32 u32Delay = 100;
while(u32Delay--);
for(u8i = 0; u8i < 2; u8i++)
{
ADC_SoftwareStartConv(ADC1);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == 0);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
u16Ad = ADC_GetConversionValue(ADC1);
}
SMOKE_DET_PWR_DI();
ADC_ChannelCmd(ADC1, ADC_Channel_4, DISABLE);ADC_Cmd(ADC1, DISABLE);
CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, DISABLE);
CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_1);
ADC_VrefintCmd(ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, ENABLE);
T_U32 u32Delay = 100;
while(u32Delay--);
for(u8i = 0; u8i < 2; u8i++)
{
ADC_SoftwareStartConv(ADC1);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == 0);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
u16Ad = ADC_GetConversionValue(ADC1);
}
ADC_Cmd(ADC1, DISABLE);
ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, DISABLE);