STM32 的定时器延时为何软件仿真误差那么大
这个定时器2是春风电源里的 数码管动态扫描和按键扫描中断函数在中段函数里放置断点,仿真界面里观察每次的断点间隔时间都是在2MS以上
/*********************************************************************************
* 函数名称: Time2_Configuration 数码管动态扫描和按键扫描
* 功 能: 定时器2初始化,3mS (其前面的时钟设为72M啊应该1mS?,软件仿真为2MS)
72000000HZ / 36分频 = 2000000HZ 1 / 2000000HZ = 0.0000005s = 0.5us
每个加1的脉冲周期为0.5us * 2000设定值 =1ms
* 参 数: 无
* 返回值: 无
**********************************************************************************/
void Time2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//TIM_Period设置了在下一个更新事件装入活动的自动重装载寄存器周期的值。它的取值必须在0x0000和0xFFFF之间
TIM_TimeBaseStructure.TIM_Period = 2000; //设置定时器周期
//TIM_Prescaler设置了用来作为TIMx时钟频率除数的预分频值。它的取值必须在0x0000和0xFFFF之间
TIM_TimeBaseStructure.TIM_Prescaler = 36; //设置定时器时钟分频值 它的取值必须在0x0000和0xFFFF之间
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置定时器向上计数
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //设置定时器重装载值
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure); //配置定时器2
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除中断标志(UIF)防止配置完成打开中断时立即产生中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE ); //使能定时器2允许更新中断(UIE)
//*******************************************************************************
//*使能定时器2功能(CEN)
//*在软件设置了CEN位后,外部时钟、门控模式和编码器模式才能工作。触发模式可以自动地
//*通过硬件设置CEN位。 在单脉冲模式下,当发生更新事件时,CEN被自动清除。
//********************************************************************************/
TIM_Cmd(TIM2, ENABLE); //使能定时器2功能(CEN)
}
/*******************************************************************************
* Function Name: TIM2_IRQHandler
* Description : This function handles TIM2 global interrupt request.
数码管动态扫描和按键扫描
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM2_IRQHandler(void)
{
static vu8 W = 0; //Static 局部静态变量
static vu8 keyscan = 0;
static vu16 key5del = 100;//按键5禁止延时
static vu16 key6del = 100;//按键6禁止延时
vu8 a,c,d; //a为延时?/c,d为判断编码器?拨动
vu8 e; //用来设定4个调节发光二极管指示
static vu8 Key0Circs = 0;//按键0状态
static vu8 Key1Circs = 0;//按键1状态
static vu8 Key2Circs = 0;//按键2状态
static vu8 Key3Circs = 0;//按键3状态
static vu8 Key4Circs = 0;//按键4状态
static vu8 Key5Circs = 0;//按键5状态
static vu8 Key6Circs = 0;//按键6状态
static vu8 Key7Circs = 0;//按键7状态
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIOE->ODR^=GPIO_Pin_7; ******************************在此处放置断点,在仿真界面里观察每次的断点间隔时间都是在2MS以上***************************************
if(I_time > 0)
I_time--;
W ++;
if(W >= 8) W = 0;
keyscan ++;
if(keyscan >= 6) keyscan = 0;
if(DispDelay)DispDelay --; //静态显示延时
//b = keyscan;
if(keyscan == 5) keyscan = 7;
//4个调节发光二极管指示
if(AdjustSign == 0) e = 0xE0;
if(AdjustSign == 1) e = 0xD0;
if(AdjustSign == 2) e = 0xB0;
if(AdjustSign == 3) e = 0x70;
SER_SetOut(); //配置输出
/*将各数据移入595中*/ // 595的HGFEDCBA 8位并口
HC595_Tx_BYTE(0x01 << 5); //按键扫描,向595写入一个字节 00100000 直接给0X20也行
HC595_Tx_BYTE(DispNum]);//后4位段码 电流?
HC595_Tx_BYTE(DispNum]); //前4位段码 电压?
HC595_Tx_BYTE((0x01 << (W % 4)) | e); //位码,LED (1%4=1),小于4的被除数结果为被除数
/*将移入的数据输出到并口上*/
RCK_H(); //没这两条旋转编码器不工作,但按键都工作
RCK_L();
SER_SetIn(); //配置输入
for(a = 0;a < 50;a++); //延时?
if(Key_IN == 0)c = 0; //key_IN 被宏定义为一个读取指定端口管脚输入的库函数
else c = 1; //c为1时就说明编码器KA按下
SER_SetOut(); //配置输出 595的 HGFEDCBA 8位并口
HC595_Tx_BYTE(0x01 << 6); //按键扫描 01000000
HC595_Tx_BYTE(DispNum]);//后4位段码
HC595_Tx_BYTE(DispNum]); //前4位段码
HC595_Tx_BYTE((0x01 << (W % 4)) | e); //位码,LED
RCK_H();
RCK_L();
SER_SetIn(); //配置输入
for(a = 0;a < 50;a++);
if(Key_IN == 0)d = 0;
else d = 1; //d为1时就说明编码器KB按下
if(key5del > 0) key5del --; //按键5禁止延时?
if(key6del > 0) key6del --; //按键6禁止延时
//Key5Circs 按键5状态
if((c == 0)&&(d == 0)&&(Key5Circs == 0)&&(key5del == 0))Key5Circs = 1; //c0,d0
else if((c == 0)&&(d == 1)&&(Key5Circs == 1)) Key5Circs = 2; //c0,d1
else if((c == 1)&&(d == 1)&&(Key5Circs == 2)) Key5Circs = 3; //c1,d1
else if((c == 1)&&(d == 0)&&(Key5Circs == 3)) Key5Circs = 4; //c1,d0
else if((c == 0)&&(d == 0)&&(Key5Circs == 4))
{
Key5Circs = 0;Key5Sign = 1;Key6Circs = 0;key6del = 100; //c0,d0 按键有效
} // Key5Sign :全局键5标志
//Key6Circs 按键6状态
if((c == 0)&&(d == 0)&&(Key6Circs == 0)&&(key6del == 0))Key6Circs = 1; //c0,d0
else if((c == 1)&&(d == 0)&&(Key6Circs == 1))Key6Circs = 2; //c1,d0
else if((c == 1)&&(d == 1)&&(Key6Circs == 2))Key6Circs = 3; //c1,d1
else if((c == 0)&&(d == 1)&&(Key6Circs == 3))Key6Circs = 4; //co,d1
else if((c == 0)&&(d == 0)&&(Key6Circs == 4))
{
Key6Circs = 0;Key6Sign = 1;Key5Circs = 0;key5del = 100; //c0,d0 按键有效
}
//if(((c == 0) && (d == 0)) && (Key6Circs == 2)) Key6Circs = 0;
//if(((c == 0) && (d == 0)) && (Key5Circs == 2)) Key5Circs = 0;
SER_SetOut();//配置输出
HC595_Tx_BYTE(0x01 << keyscan); //按键扫描
HC595_Tx_BYTE(DispNum]);//后4位段码
HC595_Tx_BYTE(DispNum]); //前4位段码
HC595_Tx_BYTE((0x01 << (W % 4)) | e); //位码,LED
RCK_H();
RCK_L();
SER_SetIn();//配置输入
for(a = 0;a < 50;a++);
if(keyscan == 0)
{
if((Key_IN == 0)&&(Key0Circs == 0)) Key0Circs = 1; //按键释放状态0
else if((Key_IN == 1)&&(Key0Circs == 1))Key0Circs = 2; //按键按下状态1
else if((Key_IN == 0)&&(Key0Circs == 2)){Key0Circs = 0;Key0Sign = 1;}//按键释放状态2
}
else if(keyscan == 1)
{
if((Key_IN == 0)&&(Key1Circs == 0)) Key1Circs = 1; //按键释放状态0
else if((Key_IN == 1)&&(Key1Circs == 1))Key1Circs = 2; //按键按下状态1
else if((Key_IN == 0)&&(Key1Circs == 2)){Key1Circs = 0;Key1Sign = 1;}//按键释放状态2
}
else if(keyscan == 2)
{
if((Key_IN == 0)&&(Key2Circs == 0)) Key2Circs = 1; //按键释放状态0
else if((Key_IN == 1)&&(Key2Circs == 1))Key2Circs = 2; //按键按下状态1
else if((Key_IN == 0)&&(Key2Circs == 2)){Key2Circs = 0;Key2Sign = 1;}//按键释放状态2
}
else if(keyscan == 3)
{
if((Key_IN == 0)&&(Key3Circs == 0)) Key3Circs = 1; //按键释放状态0
else if((Key_IN == 1)&&(Key3Circs == 1))Key3Circs = 2; //按键按下状态1
else if((Key_IN == 0)&&(Key3Circs == 2)){Key3Circs = 0;Key3Sign = 1;}//按键释放状态2
}
else if(keyscan == 4)
{
if((Key_IN == 0)&&(Key4Circs == 0)) Key4Circs = 1; //按键释放状态0
else if((Key_IN == 1)&&(Key4Circs == 1))Key4Circs = 2; //按键按下状态1
else if((Key_IN == 0)&&(Key4Circs == 2)){Key4Circs = 0;Key4Sign = 1;}//按键释放状态2
}
else if(keyscan == 7)
{
if((Key_IN == 0)&&(Key7Circs == 0)) Key7Circs = 1; //按键释放状态0
else if((Key_IN == 1)&&(Key7Circs == 1))Key7Circs = 2; //按键按下状态1
else if((Key_IN == 0)&&(Key7Circs == 2)){Key7Circs = 0;Key7Sign = 1;}//按键释放状态2
}
if(LockKey) //按键锁定标志有效
{
Key0Sign = 0;//把没有执行的按键标志清掉
//Key1Sign = 0;
Key2Sign = 0;
Key3Sign = 0;
Key4Sign = 0;
Key5Sign = 0;
Key6Sign = 0;
Key7Sign = 0;
}
if(KeyEn == 0) //按键失能
{
Key0Sign = 0;//把所有按键标志清掉
Key1Sign = 0;
Key2Sign = 0;
Key3Sign = 0;
Key4Sign = 0;
Key5Sign = 0;
Key6Sign = 0;
Key7Sign = 0;
}
} 本帖最后由 litin326 于 2013-3-12 15:13 编辑
找到原因,是我对STM32时钟树的不太了解
/*********************************************************************************
* 函数名称: RCC_Configuration
* 功 能: 设置各个系统时钟
* 参 数: 无
* 返回值: 无
**********************************************************************************/
void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
RCC_DeInit(); /* RCC system reset(for debug purpose) */
RCC_HSEConfig(RCC_HSE_ON);//使能外部晶振
HSEStartUpStatus = RCC_WaitForHSEStartUp();//等待外部晶振稳定
if (HSEStartUpStatus == SUCCESS) //如果外部晶振启动成功,则进行下一步操作
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* Enable Prefetch Buffer使能或者失能FLASH半周期访问 */
FLASH_SetLatency(FLASH_Latency_2);/* Flash 2 wait state设置代码延时值 */
RCC_HCLKConfig(RCC_SYSCLK_Div1);/* HCLK = SYSCLK 设置AHB时钟(HCLK)*/
RCC_PCLK2Config(RCC_HCLK_Div1); /* PCLK2 = HCLK设置高速 APB2 时钟(PCLK2)
注意:1:ADC TIME1和TIME8的时钟都从其分支而来
2:TIME1/8的时钟只有当APB2的预分频系数 > 2时,其计数脉冲才会小于72M参RCC时钟树。
3:其分频系数只有5档 1/2/4/8/16.
*/
RCC_PCLK1Config(RCC_HCLK_Div4); /* PCLK1 = HCLK/4设置低速 APB1 时钟
注意:1:当APB1预分频=1时送给定时器的时钟频率不变.当有分频时,送给定时器的
时钟频率=分频后的频率 * 2 .比如这里APB1 / 4 = 18M(可看clock control观
察窗内的PCLK1:),送给定时器的时钟计数脉冲18M * 2 = 36M(可看clock control
观察窗内的TIMXCL:)
2:TIME2-TIME7的计数时钟 = SYSCLK > AHB > APB1(参上面细节) > TIMXCL
3:技术手册里的RCC时钟树和TIME时钟树有详细介绍
*/
RCC_ADCCLKConfig(RCC_PCLK2_Div8);/* ADCCLK = PCLK2(APB2)/8设置ADC时钟(ADCCLK)*/
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* PLLCLK = 8MHz * 9 = 24 MHz (应该是72MHZ吧??)*/
RCC_PLLCmd(ENABLE); /* Enable PLL */ 相对于初学者很有帮助。 原来是这样啊,之前也遇到过,不知道为啥
页:
[1]