OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3942|回复: 12

STM32F103关于系统滴答定时器和普通定时器冲突

[复制链接]

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
发表于 2021-1-17 23:19:54 | 显示全部楼层 |阅读模式
6金钱
原子的延时代码
  1. #include "stm32f10x.h"
  2. #include "delay.h"
  3. static u8  fac_us=0;//us延时倍乘数
  4. static u16 fac_ms=0;//ms延时倍乘数
  5. //初始化延迟函数
  6. //SYSTICK的时钟固定为HCLK时钟的1/8
  7. //SYSCLK:系统时钟
  8. void delay_init(u8 SYSCLK)
  9. {
  10.         SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟  HCLK/8
  11.         fac_us=SYSCLK/8;                    
  12.         fac_ms=(u16)fac_us*1000;
  13. }                                                                    
  14. //延时nms
  15. //注意nms的范围
  16. //SysTick->LOAD为24位寄存器,所以,最大延时为:
  17. //nms<=0xffffff*8*1000/SYSCLK
  18. //SYSCLK单位为Hz,nms单位为ms
  19. //对72M条件下,nms<=1864
  20. void delay_ms(u16 nms)
  21. {                                     
  22.         u32 temp;                  
  23.         SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
  24.         SysTick->VAL =0x00;           //清空计数器
  25.         SysTick->CTRL=0x01 ;          //开始倒数  
  26.         do
  27.         {
  28.                 temp=SysTick->CTRL;
  29.         }
  30.         while(temp&0x01&&!(temp&(1<<16)));//等待时间到达   
  31.         SysTick->CTRL=0x00;       //关闭计数器
  32.         SysTick->VAL =0X00;       //清空计数器                      
  33. }   
  34. //延时nus
  35. //nus为要延时的us数.                                                                                      
  36. void delay_us(u32 nus)
  37. {               
  38.         u32 temp;                     
  39.         SysTick->LOAD=nus*fac_us; //时间加载                           
  40.         SysTick->VAL=0x00;        //清空计数器
  41.         SysTick->CTRL=0x01 ;      //开始倒数          
  42.         do
  43.         {
  44.                 temp=SysTick->CTRL;
  45.         }
  46.         while(temp&0x01&&!(temp&(1<<16)));//等待时间到达   
  47.         SysTick->CTRL=0x00;       //关闭计数器
  48.         SysTick->VAL =0X00;       //清空计数器         
  49. }

复制代码
野火的延时代码
  1. static __IO u32 TimingDelay = 0;
  2. void Delay_us(uint32_t us)
  3. {
  4.         uint32_t i;
  5.         SysTick_Config(72);
  6.         for(i=0;i<us;i++)
  7.         {
  8.                 while( !((SysTick->CTRL)&(1<<16)));
  9.         }
  10.         SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
  11. }
  12. void Delay_ms(uint32_t ms)
  13. {
  14.         uint32_t i;
  15.         SysTick_Config(72000);
  16.         for(i=0;i<ms;i++)
  17.         {
  18.                 while( !((SysTick->CTRL)&(1<<16)));
  19.         }
  20.         SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
  21. }
  22. void TimingDelay_Decrement(void)
  23. {
  24.         if ( TimingDelay != 0x00 )
  25.         {
  26.                 TimingDelay --;
  27.         }
  28. }
复制代码
延时代码在普通情况下都能使用
但是在我设置了一个普通定时器中断后,延时就不能用了
分组为2,优先级为 0   0

  1. 设置
  2. static void PS2_NVIC_Config(void)
  3. {
  4.     NVIC_InitTypeDef NVIC_InitStructure;
  5.         
  6.         // 设置中断来源
  7.     NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn ;   
  8.         // 设置主优先级为 0
  9.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     
  10.       // 设置抢占优先级为
  11.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;   
  12.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  13.     NVIC_Init(&NVIC_InitStructure);
  14. }

  15. static void PS2_TIM_Config(void)
  16. {
  17.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  18.         // 开启定时器时钟,即内部时钟CK_INT=72M
  19.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
  20.         // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
  21.     TIM_TimeBaseStructure.TIM_Period = 7999;   
  22.       // 时钟预分频数为
  23.     TIM_TimeBaseStructure.TIM_Prescaler= 71;
  24.     TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
  25.         // 清除计数器中断标志位
  26.     TIM_ClearFlag(TIM7, TIM_FLAG_Update);
  27.         // 开启计数器中断
  28.     TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);   
  29.         // 使能计数器
  30.     TIM_Cmd(TIM7, ENABLE);
  31. }

  32. //中断
  33. void PS2_TIM_IRQHandler(void)
  34. {
  35.         if(TIM_GetITStatus(TIM7,TIM_IT_Update)!=RESET)
  36.         {     PS2_DataKey();
  37.                     if(Handkey !=0xffff){
  38.                                 switch(Handkey)
  39.                     {
  40.                            case stop_ps2:
  41.                             Allstop();break;
  42.                            case straight_ps2:
  43.                                  straight();break;
  44.                            case back_ps2:
  45.                                  Back();break;
  46.                            case left_ps2:
  47.             left_move();break;
  48.                            case right_ps2:
  49.                                     right_move();break;
  50.                            case turn_right_R2:
  51.                                     Turn_right();break;
  52.                            case turn_left_L2:
  53.                                     Turn_left();break;
  54.                            case Steering_gear_left_ps2:
  55.                                     //PCA_MG9XX(0,0,180,1,10);
  56.                               break;
  57.                            case Steering_gear_down_ps2:
  58.                                     break;
  59.                            case Steering_gear_right_ps2:
  60.                                     break;
  61.                            case Steering_gear_up_ps2:
  62.                                     break;
  63.                          }
  64.                                
  65.         TIM_ClearFlag(TIM7,TIM_FLAG_Update);}
  66.                                
  67.         else{
  68.                 Allstop();
  69.           TIM_ClearFlag(TIM7,TIM_FLAG_Update);}
  70.        
  71.         }
  72. }
复制代码

求助大佬,为什么会冲突,导致延时不能使用



最佳答案

查看完整内容[请看2#楼]

假如主循环正在运行到延时函数里,中断里也用了延时函数,就可能造成中断里关闭了计数器,主循环的延时仍在等待计数,就等不到了。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

12

主题

3397

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8670
金钱
8670
注册时间
2020-5-11
在线时间
4135 小时
发表于 2021-1-17 23:19:55 | 显示全部楼层
假如主循环正在运行到延时函数里,中断里也用了延时函数,就可能造成中断里关闭了计数器,主循环的延时仍在等待计数,就等不到了。
专治疑难杂症
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
 楼主| 发表于 2021-1-17 23:26:49 | 显示全部楼层
另外,编译器没有报错
回复

使用道具 举报

11

主题

2149

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4919
金钱
4919
注册时间
2015-1-10
在线时间
617 小时
发表于 2021-1-18 10:31:11 | 显示全部楼层
systick和timer是独立的,原子需要个初始化,野火可以直接使用,检查一下是否是其他程序问题导致在现象上看到delay错误
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
 楼主| 发表于 2021-1-18 10:54:12 | 显示全部楼层
LcwSwust 发表于 2021-1-18 10:35
假如主循环正在运行到延时函数里,中断里也用了延时函数,就可能造成中断里关闭了计数器,主循环的延时仍在 ...
  1. void PS2_ReadData(void)
  2. {
  3.         volatile u8 byte=0;
  4.         volatile u16 ref=0x01;

  5.         CS_L;

  6.         PS2_Cmd(Comd[0]);  //开始命令
  7.         PS2_Cmd(Comd[1]);  //请求数据

  8.         for(byte=2;byte<9;byte++)          //开始接受数据
  9.         {
  10.                 for(ref=0x01;ref<0x100;ref<<=1)
  11.                 {
  12.                         CLK_H;
  13.                         CLK_L;
  14.                         Delay_us(50);
  15.                         CLK_H;
  16.                       if(DI)
  17.                       Data[byte] = ref|Data[byte];
  18.                 }
  19.         Delay_us(50);
  20.         }
  21.         CS_H;       
  22. }
复制代码
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
 楼主| 发表于 2021-1-18 10:55:52 | 显示全部楼层
LcwSwust 发表于 2021-1-18 10:35
假如主循环正在运行到延时函数里,中断里也用了延时函数,就可能造成中断里关闭了计数器,主循环的延时仍在 ...

大佬一针见血,的确,调用的函数里有延时函数,但是这个是必须用到的过程,有什么好的解决办法吗,
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
 楼主| 发表于 2021-1-18 10:59:53 | 显示全部楼层
阿侑kevin 发表于 2021-1-18 10:31
systick和timer是独立的,原子需要个初始化,野火可以直接使用,检查一下是否是其他程序问题导致在现象上看 ...

大哥,小弟别的地方检查过,的确没有问题,可能就是楼下说的,中断里用到了延时,产生了冲突
回复

使用道具 举报

12

主题

3397

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8670
金钱
8670
注册时间
2020-5-11
在线时间
4135 小时
发表于 2021-1-18 11:06:16 | 显示全部楼层
Cauchemar 发表于 2021-1-18 10:55
大佬一针见血,的确,调用的函数里有延时函数,但是这个是必须用到的过程,有什么好的解决办法吗,

1.另写一个不用定时器的:我在STC单片机上用的

void delayms(U16 t)
{
        U16 i;
        for(;t>0;t--)
        for(i=FOSC/13186;i>0;i--);
}

这种方式不是很准,且需多次测试。


2.改变延时机制,比如一个定时器一直开着,通过读取两次计数之差来计算时间。
void delay(U16 t)
{
  U16 t0,t1;
  t0=TCNT;//读当前计数
  do
  {
    t1=TCNT-t0;//当前计数与之前计数之差
  }while(t>t1);
}
专治疑难杂症
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
 楼主| 发表于 2021-1-18 11:15:37 | 显示全部楼层
LcwSwust 发表于 2021-1-18 11:06
1.另写一个不用定时器的:我在STC单片机上用的

void delayms(U16 t)

真心感谢大哥,学到了
回复

使用道具 举报

16

主题

136

帖子

0

精华

高级会员

Rank: 4

积分
577
金钱
577
注册时间
2020-11-19
在线时间
113 小时
发表于 2021-1-18 17:58:44 | 显示全部楼层
延迟函数不要在中断调用
八十、八十、八十!
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
 楼主| 发表于 2021-1-19 20:52:16 | 显示全部楼层
LcwSwust 发表于 2021-1-18 11:06
1.另写一个不用定时器的:我在STC单片机上用的

void delayms(U16 t)

我在CSDN中看到一个修改延时函数的方法,
使得中断进程不提前关闭定时器,大哥你看看这个方法能不能普遍适用
https://blog.csdn.net/ima_xu/article/details/103595720
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
28
金钱
28
注册时间
2020-4-22
在线时间
6 小时
 楼主| 发表于 2021-1-19 20:54:40 | 显示全部楼层
dianyan 发表于 2021-1-18 17:58
延迟函数不要在中断调用

https://blog.csdn.net/ima_xu/article/details/103595720
大哥,这里是一种中断里可以调用延时的方法,我比较菜,还没有验证
回复

使用道具 举报

16

主题

136

帖子

0

精华

高级会员

Rank: 4

积分
577
金钱
577
注册时间
2020-11-19
在线时间
113 小时
发表于 2021-1-22 11:46:23 | 显示全部楼层
Cauchemar 发表于 2021-1-19 20:54
https://blog.csdn.net/ima_xu/article/details/103595720
大哥,这里是一种中断里可以调用延时的方法, ...

他程序有问题
八十、八十、八十!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-10 18:31

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表