以前都是随便用的延时函数都是c语言的延时函数或者TIM定时器,最近几年才用到正点原子的滴答定时器。
Systick定时器,是一个简单的定时器, Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。 Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。 SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。 Systick中断的优先级也可以设置。这个是寄存器设置函数了。所以这个可以作为设备运行计时函数,目前暂时还没设计到。
固件库中的Systick相关函数,库函数配置:
SysTick_CLKSourceConfig() //Systick时钟源选择
//位于misc.c函数199行
SysTick_Config(uint32_t ticks) //初始化systick,时钟为HCLK,并开启中断
//位于core_cm3.h的1694行
Systick中断服务函数:
void SysTick_Handler(void);
正点原子的delay延时函数:
static u8 fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //ms延时倍乘数
//初始化延迟函数
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init()
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
fac_ms=(u16)fac_us*1000; //代表每个ms需要的systick时钟数
}
//延时nus
//nus为要延时的us数.
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864 ,
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
这里正点原子的最大延时是1864毫秒。然后下放的函数则是我设计冰浴机所使用的超过1864毫秒以后得延时函数,毕竟我当时设计还没用上计时器,所以延时都能到1分钟以上。而且延时会耗费单片机系统资源,所以正点原子估计是不建议设置延时函数太大。
void delay_s(u16 ns)
{
u16 ms;
for(ms=0;ms<ns;ms++)
{
delay_ms(1000);//这里是1250才满足1s,1000不够1s;
// 这里我设计时候进行了秒表计时测试出来的, 不过看了正点原子的前几讲视频,我发现我keil里面的晶振选择是12m,但是实际板子使用的是8M的,所以我觉得有可能是这个造成的,因为我离职了,那个项目我就测试不了,所以我这里就直接改成了1000,不过等之后做学习时候,可以再顺便测试一下。
//正点原子的视频说了,如果使用中发现延时不一致,问题一般都是因为不同内核时钟不一样而已。修改ticks值即可。
}
}
这里用到了do while函数,以前很少用到呢,毕竟我c语言学的也一般。这里就查询了一下,while、do while、break、continue相关的应用。
while 与 if的区别:while循环是若表达式满足条件可循环重复执行语句,if则是执行一次语句。
break、continue 是不仅能用于循环中,也能用于选择分支语句中(switch case语句 ,if 嵌套,多分支语句),以前只是知道能用在while、switch case里面,if嵌套跟还真没用过之后可以试试。
在 do while 循环中先执⾏代码,执⾏完代码以后,再去执⾏“判断表达式”,判断表达式的结果是!=0,则继续循环,执⾏循环语句;判断表达式的结果==0,则循环结束。所以在 do while 语句中循环体是⾄少执⾏⼀次的,这是 do while 循环⽐较特殊的地⽅。这个感觉还是if比较好,毕竟if是先执行判断,再去运行代码,速度快很多,我运行时候多数是选择的if,而不是选择的do while,毕竟if判断以后不会运行后面代码,do while却需要运行再判断,优劣很明显。
break 的作⽤是⽤于永久的终⽌循环,只要 break 被执⾏,直接就会跳出循环,继续往后执⾏。continue 的作⽤是跳过本次循环 continue 后边的代码,在 for 循环和 while 循环中有所差异的。在while循环中 continue 可以帮助我们跳过某⼀次循环 continue 后边的代码,直接到循环的判断部分,进⾏下⼀次循环的判断,如果循环的调整是在 continue 后边的话,可能会造成死循环。而在for循环中 continue 的作⽤是跳过本次循环中 continue 后的代码,直接去到循环的调整部分。未来当某个条件发⽣的时候,本次循环⽆需再执⾏后续某些操作的时候,就可以使⽤continue 来实现。
补:延时函数基本上学到这里,之后有计划要研究sim卡跟语音通话。
1065

被折叠的 条评论
为什么被折叠?



