OpenEdv-开源电子网

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

把原子哥的delay.c中软件延时更改为中断延时,已经在板子上验证通过!

[复制链接]

1

主题

14

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2012-3-24
在线时间
0 小时
发表于 2012-4-1 15:15:38 | 显示全部楼层 |阅读模式

在这个论坛上用原子的开发板也学习了许多,谢谢大家!
以下更改,如果有更好的实现方法,请指正!
更改的目的是为了将systick计数器用于中断定时,作为一个系统时间,开机后不停运行,
将来可以作为一个多任务的时间节拍使用!

//Delay.c
//使用芯片的 SysTick 部件进行软件延时的操作
//

#include "delay.h"
#include "sys.h"

vu32 system_time =0u;         //系统时间计数器,单位和节拍重装寄存器的设置值有关

static vu16 systick_reload_val;       //系统节拍重装值
static vu16 systick_cnt_of_1us;       //1us时间内的systick的计数值

//初始化延迟函数
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟(MHz)
void delay_init(u8 SYSCLK)
{
 SysTick->CTRL = SysTick_Counter_Clear;    //清除(停止)
 SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;  //选择外部时钟(bit2=0 HCLK/8)
 systick_reload_val= (u16)((SYSCLK *CONST_SYSTICK_NUM_OF_US) >>3); //节拍定时 CONST_SYSTICK_NUM_OF_US(us)
 SysTick->CTRL |= BIT(SYSTICK_CTRL_BIT_TICKINT);  //使能中断
 SysTick->LOAD = systick_reload_val;
 SysTick->VAL = 0x00;        //清空计数器
 MY_NVIC_Init(CONST_NVIC_PP_SYSTEM_TASK, CONST_NVIC_SP_MID_MAX, WWDG_IRQChannel); //属于系统级中断,高于一般的应用中断优先级
 SysTick->CTRL |= SysTick_Counter_Enable;    //开始计数(倒数)
 
 systick_cnt_of_1us =(SYSCLK >>3);      //1us时间内的systick的计数值
 system_time =0u; 
}           

//Systick 中断函数
void SysTick_Handler(void)
{
 system_time ++;

 //???
 //这里增加任务切换
}

//得到系统时间,单位:1/8ms
u32 get_system_time(void)
{
 return system_time;
}

//得到和指定时间thetime的差值,单位:1/8ms
u32 get_system_time_difference(u32 thetime)
{ //无符号数据减法, 0x0000 0001 - 0xffff fffa =0x0000 0007, 不会异常!
 return(system_time -thetime);
}

//延时指定毫秒数时间
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*CONST_SYSTICK_NUM_OF_US/SYSCLK*1000
void delay_xms(u32 Xms)
{
u32 start;

 start =system_time;
 Xms <<= 3;            //系统时间单位是1/8ms
 while(get_system_time_difference(start) <Xms);
}

//为了兼容开发板的程序
void delay_xus(u32 Xus)
{  
u32 start_val;
u32 target_val;      
u32 all_systick_cnt;
u16 systick_cnt;

 if(Xus ==0) return;
  
 all_systick_cnt =Xus *systick_cnt_of_1us;
 
 start_val = SysTick->VAL;        //得到当前计数器的值(!=0) 
 if(all_systick_cnt <=start_val)
 { //延时在剩余计数值内
  target_val =start_val -(all_systick_cnt -1);   //保证结束值非0![=0 进中断后重装,这里判不到==0的]
  while((SysTick->VAL >target_val) && (SysTick->VAL <=start_val) );
 }
 else if(all_systick_cnt <=systick_reload_val)
 { //延时在剩余值之外,但是在一个节拍之内
  target_val =start_val +(systick_reload_val -all_systick_cnt);
  while(SysTick->VAL !=target_val);
 }
 else
 { //延时在一个节拍之外
  systick_cnt =all_systick_cnt/systick_reload_val;
  all_systick_cnt -= systick_cnt *systick_reload_val; //计数的余数,小于一个节拍
  
  if(all_systick_cnt ==0)
  {
   do
   {
    if(SysTick->VAL ==start_val)
    {
     systick_cnt --;
     while(SysTick->VAL ==start_val);
     //因为在一个systick的计数值单位时间内,会多次执行while循环! 需要特殊处理!!【下同】
     //离开的时候,已经不相等,则不要再 systick_cnt+1 了! 不能直接+1后再判断,因为可能瞬间不等而导致多计数一个节拍! 
    } 
   }while(systick_cnt !=0);
  }
  else if(all_systick_cnt <=start_val)
  {
   //延时余数在剩余计数值内
   target_val =start_val -(all_systick_cnt -1);      //保证结束值非0![=0 进中断后重装,这里判不到==0的]
   if(target_val ==SysTick->VAL)
   {
    while(target_val ==SysTick->VAL);
    //离开的时候,已经不相等,则不要再 systick_cnt+1 了! 
   }
   else
   {
    systick_cnt++; //第一个判断点是延时的余数时间,节拍数要加1! 这里默认这里的语句操作时间小于一个systick的计数单位时间!
   }
   
   do
   {
    if(SysTick->VAL ==target_val)
    {
     systick_cnt --;
     while(SysTick->VAL ==target_val);
     //离开的时候,已经不相等,则不要再 systick_cnt+1 了! 
    } 
   }while(systick_cnt !=0);
  }
  else
  { //延时余数在剩余值之外
   target_val = start_val + (systick_reload_val -all_systick_cnt);
   do
   {
    if(SysTick->VAL ==target_val)
    {
     systick_cnt --;
     while(SysTick->VAL ==target_val);
     //离开的时候,已经不相等,则不要再 systick_cnt+1 了! 
    } 
   }while(systick_cnt !=0);
  }
 } 
}

//End Of File


//Delay.h 文件

#ifndef _DELAY_H_
#define _DELAY_H_      

#include <stm32f10x_lib.h>

//常数的定义
#define CONST_SYSTICK_NUM_OF_US  125      //系统时间单位是1/8ms
#define CONST_SYSTICK_DELAY_MAX_MS (u32)( *CONST_SYSTICK_NUM_OF_US) 

#define SYSTICK_CTRL_BIT_COUNTFLAG 16      //=1 倒计数为0发生过,读取时清除此位
#define SYSTICK_CTRL_BIT_CLKSOURCE 2      //=1 内核时钟
#define SYSTICK_CTRL_BIT_TICKINT 1      //=1 倒计数到0时挂起CPU(进入中断函数)
#define SYSTICK_CTRL_BIT_ENABLE  0      //=1 开始倒计数

extern vu32 system_time;        //系统时间,单位:1/8ms

//函数的声明
extern void delay_init(u8 SYSCLK);
extern void delay_xms(u32 Xms);
extern void delay_xus(u32 Xus);

#endif

//End Of File

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

20

主题

562

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
670
金钱
670
注册时间
2012-2-28
在线时间
0 小时
发表于 2012-4-1 16:25:47 | 显示全部楼层
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2012-4-1 16:33:43 | 显示全部楼层
不建议把延时函数修改为中断延时.
真需要任务调度,直接上操作系统.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

19

主题

248

帖子

2

精华

高级会员

Rank: 4

积分
842
金钱
842
注册时间
2012-2-8
在线时间
19 小时
发表于 2012-4-1 20:24:46 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
原子哥,是否考虑出一份ucos新手入门教程啊?看过ucos那本书,不过还是很晕啊
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2012-4-1 20:34:22 | 显示全部楼层
光看不练,肯定晕了.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

19

主题

248

帖子

2

精华

高级会员

Rank: 4

积分
842
金钱
842
注册时间
2012-2-8
在线时间
19 小时
发表于 2012-4-5 17:09:07 | 显示全部楼层
回复【5楼】正点原子:
光看不练,肯定晕了.
---------------------------------
无从下手啊,没有可以借鉴的。原子哥那例程我有读过了。主要是那滴答时钟不明白是怎么给ucos用的
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-25 10:01

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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