都24年了,嵌入式开发,你还在用Delay(),写整个工程文件吗?

单片机Delay延时缺点

        对于单片机裸机和单片机移植操作系统来说,延时函数是一个不一样的作用,在操作系统重,任务的延时cpu会使这个任务挂起,从而去执行其他任务,当任务到时间之后会继续执行,但是在大多数的嵌入式开发芯片中,大多数的芯片是不支持移植操作系统的。

        如果在单片机中调用延时函数,在执行延时函数的期间,单片机是不能执行其他任务的,如果单片机在这期间外界有条件发生,单片机不能及时进行相应,得等到单片机延时执行结束,这个就是单片机使用系统提供的Delay的坏处。

        对于单片机不能及时响应外界的情况,对于一些产品是很致命的对于功能来说,当使用Delay延时的时候,有外界条件发生需要执行一些功能的时候,怎么办,总不能说,我知道你很急,但你先别急!

void delay_us(uint32_t us)
{
    uint32_t systickCount;    
    uint32_t count = us * systick_us;  // 计算延时所需的计数值,systick_us为每微秒所需的计数周期
    
    if (us == 1)  // 如果延时为1微秒
    {
        SysTick->LOAD = count - 8;  // 调整LOAD寄存器的值,微调延时,使其接近1微秒
    }
    else
    {
        SysTick->LOAD = count - 10; // 加载计数器的值,稍微调整以准确控制延时时间
    }

    SysTick->VAL = 0x00;  // 清除当前计数器值,使其从0开始计数
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 启动SysTick定时器(使能SysTick计数器)
    
    // 等待SysTick计数器达到设定的延时时间
    do
    {
        systickCount = SysTick->CTRL;  // 读取SysTick控制寄存器
    } while ((systickCount & 0x01) && !(systickCount & (1 << 16)));  // 检查计数器是否完成并且没有溢出
    
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 禁用SysTick定时器(关闭计数器)
    SysTick->VAL = 0x00;  // 清除计数器值,准备下一次使用
}

                                                          延时函数库函数定义       

        如果使用这个delay函数,单片机就是在while(){}循环里面硬等,在等待的期间不会做任何事情。

定时器中断基本思路

        这里需要知道单片机自身时钟,假设单片机自身时钟为24Mhz,以为着单片机在1s,以内能够产生 24000 000 次时钟脉冲周期,单片机时钟在经过预分频系数,还有自动重装载值的,分频之后就是定时器时钟,意味着定时器能够在,1s内产生的时钟脉冲周期是多少。

        同时使能定时器开启中断,1s内定时器开启中断的次数,就是定时器时钟频率的次数,这里中断函数因为自身的特殊性,切记不需要做太多的事情,里面就放变量++就好。  

void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
{
	//检查中断出发条件
  if((LL_TIM_ReadReg(TIM1,SR) & LL_TIM_SR_UIF) == 1 && LL_TIM_IsEnabledIT_UPDATE(TIM1))
  {
		
		//清楚中断标志位
    LL_TIM_ClearFlag_UPDATE(TIM1);
    //调用自己定义的中断回调函数
    APP_Updatefallback();
		
  }
}

//tiemr 频率是4khz 每秒产生 4000 次中断 1s Flag_NVIC =4000
void  APP_Updatefallback(void)
{
	Flag_NVIC ++;
	Flag_NVIC = Flag_NVIC%12001;
}

       这里切记因为是中断所以中断里面不要放太多的东西,同时给大家看一下使能定时器,开启中断的函数配置,这里需要注意的是,单片机自身的时钟是多少,以及定时器的时钟分频系数是多少。

void Beer_Using_Set(uint32_t State)
{

	//开启时钟
	LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_TIM1);
  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
	  /*配置TIM1*/
  LL_TIM_InitTypeDef TIM1CountInit = {0};
	
	//结构体变量声明
  LL_GPIO_InitTypeDef TIM1CH1MapInit = {0};
  LL_TIM_OC_InitTypeDef TIM_OC_Initstruct = {0};
	
  //GPIOA引脚设置成pwm模式 引脚搞成 af2模式
  TIM1CH1MapInit.Pin        = LL_GPIO_PIN_9;
  TIM1CH1MapInit.Mode       = LL_GPIO_MODE_ALTERNATE;
  TIM1CH1MapInit.Alternate  = LL_GPIO_AF_2; 
  TIM1CH1MapInit.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  TIM1CH1MapInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  TIM1CH1MapInit.Pull = LL_GPIO_PULL_UP; 
  LL_GPIO_Init(GPIOA,&TIM1CH1MapInit);
  
  
  /*配置PWM通道*/
  TIM_OC_Initstruct.OCMode        = LL_TIM_OCMODE_PWM2;       /* 通道模式:PWM2       */
  TIM_OC_Initstruct.OCState       = LL_TIM_OCSTATE_ENABLE;    /* 通道状态:开启       */
  TIM_OC_Initstruct.OCPolarity    = LL_TIM_OCPOLARITY_HIGH;   /* 通道有效极性:高电平 */
  TIM_OC_Initstruct.OCIdleState   = LL_TIM_OCIDLESTATE_LOW;   /* 通道空闲极性:低电平 */
  //这里输出1v
  TIM_OC_Initstruct.CompareValue  = State;
  /*配置通道2*/
  LL_TIM_OC_Init(TIM1,LL_TIM_CHANNEL_CH2,&TIM_OC_Initstruct);


  
  TIM1CountInit.ClockDivision       = LL_TIM_CLOCKDIVISION_DIV1;/* 不分频             */
  TIM1CountInit.CounterMode         = LL_TIM_COUNTERMODE_UP;    /* 计数模式:向上计数 */
  TIM1CountInit.Prescaler           = 3-1;                   		//预分频系数参数
  TIM1CountInit.Autoreload          = 2000-1;                    //这里频率是4khz
  TIM1CountInit.RepetitionCounter   = 0;                        /* 重复计数值:0      */
  
  /*初始化TIM1*/
  LL_TIM_Init(TIM1,&TIM1CountInit);
	
	//清除中断标志位
	LL_TIM_ClearFlag_UPDATE(TIM1);
	
	//开启自动预装载
	LL_TIM_EnableARRPreload(TIM1);
	
	//开启中断标志位
	LL_TIM_EnableIT_UPDATE(TIM1);
	
  
  /*主输出使能*/
  LL_TIM_EnableAllOutputs(TIM1);

  /*使能TIM1计数器*/
  LL_TIM_EnableCounter(TIM1);
	
	//开启TIM1中断函数,同时分配变量
  NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
	NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn,0);

}

        到了这里已经完成对,基本定时器代码初始化的编写,最重要的是完成开始的目的,在完成延时功能的同时,保证单片机没有卡死,同时执行单片机的其他任务。

使能定时器中断代码理解

       这里就不放真正的程序代码了,只给大家讲解怎么调用延时,同时讲解一些关键的点,  下面这个程序写的是延时3s,同时在延时的同时,又能保证程序没有卡死。  

Beer_Using_Set(0);
//读这个变量之前一定要把这个变量给赋值为 0
//因为在真正的程序执行到这里之前不知道这个变量的值到底是多少
//如果直接读取这个全局变量的值,延时计算是不准的
Flag_NVIC = 0;
//在延时3s内 while循环里有执行函数cpu在这里没有卡死 
while (!(Flag_NVIC == 12000) && !exitFlag) {exitFlag = Detection_Up();}

          如果在自己的程序里面使用了这种,延时方法只需要,在while循环体里面,添加自己工程的其他功能就能保证,在延时的同时,程序其他功能能够正常执行,同时程序能够正常响应 ,外界发生的变化,也就是说程序并不会被卡死。        

                                   编写不易,请勿搬运,仅供学习,感谢理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看,是大狗

创作不易,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值