首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

仿ALIENTEK STM32开发板,写的STM8S的延时函数

仿ALIENTEK STM32开发板,写的STM8S的延时函数

已经写完了STM8S的系统文件(同stm32一样,包括sys.c,delay.c和uart.c三个文件)
这里先分享delay.c和delay.h.
本来想仿效STM32用一个定时器来做,无奈STM8S提供的是一个8位定时器,真是食之无味了...
算来算去,用这个8位的定时器横竖都不好做延时,用16位的定时器嘛又怕浪费.真不知道st的人怎么想的.
这个8位的基本定时器,连ucosii的滴答时钟都不好提供...(24Mhz下,最大只能1.3ms左右中断一次,16Mhz则是2ms左右)
难不成多次中断,触发一次任务切换?
所以,表示蛋疼的很,无奈只能想用汇编的方式来实现精确延时了.
研究了几天,终于小有成就.汇编写了一个us级延时函数,还算比较准.
24M和8M时,差别有点多,24M时STM8S要插入一个flash等待周期,这样st说是可以提供20MIPS的性能,但是我迷糊了...到底此时的指令周期如何算?st没有提到.
最后测试发现,大概是19Mhz的指令运行速度,也就是单周期指令,执行时间在24M时钟频率下约为1/19Mhz 秒.单根据我的计算公式,得不到19这个值,于是只能取近似了,按理说20比较准,不过实测16会准确一些.故采用了16,然后导致的结果就是延时变快了.
比如延时100ms,实际上可能是92ms左右.

而8Mhz时,差别有点多,表示不太理解,因为根据我的设计,刚好是8个周期的,应该是延时准确才对,但事实并非如此.
下面是各时钟频率下的延时准确性(测试时使用的延时至少>10us):
//92%  @24Mhz
//98%   @16Mhz
//98%   @12Mhz
//86%   @8Mhz
可以看到,12M和16M条件下有比较高的准确度,24M稍微差点(主要是偏快).
一般应用,这样的精度,应该都可以满足使用了,源码下面附上,如有改进意见,欢迎提出,开源才能集思广益,而后才能精益求精.


delay.h代码如下:

#ifndef  __DELAY_H
#define  __DELAY_H
#include "sys.h"
////////////////////////////////////////////////////////////////////////////////  
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK
//使用汇编代码进行精确延时处理
//包括delay_us,delay_ms
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2013/6/25
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//******************************************************************************
//V1.0 20130625
//支持不同时钟频率
//提供delay_us,delay_ms两个延时函数.
////////////////////////////////////////////////////////////////////////////////
void delay_init(u8 clk); //延时函数初始化
void delay_us(u16 nus);  //us级延时函数,最大65536us.
void delay_ms(u32 nms);  //ms级延时函数
#endif

delay.c代码如下:

#include "delay.h"
////////////////////////////////////////////////////////////////////////////////  
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK
//使用汇编代码进行精确延时处理
//包括delay_us,delay_ms
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2013/6/25
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//******************************************************************************
//V1.0 20130625
//支持不同时钟频率
//提供delay_us,delay_ms两个延时函数.
////////////////////////////////////////////////////////////////////////////////

volatile u8 fac_us=0; //us延时倍乘数   
//延时函数初始化
//为确保准确度,请保证时钟频率最好为4的倍数,最低8Mhz
//clk:时钟频率(24/16/12/8等)
void delay_init(u8 clk)
{
if(clk>16)fac_us=(16-4)/4;//24Mhz时,stm8大概19个周期为1us
else if(clk>4)fac_us=(clk-4)/4;
else fac_us=1;
}
//延时nus
//延时时间=(fac_us*4+4)*nus*(T)
//其中,T为CPU运行频率(Mhz)的倒数,单位为us.
//准确度:
//92%  @24Mhz
//98%  @16Mhz
//98%  @12Mhz
//86%  @8Mhz
void delay_us(u16 nus)
{  
__asm(
"PUSH A          \n"  //1T,压栈
"DELAY_XUS:      \n"   
"LD A,fac_us     \n"   //1T,fac_us加载到累加器A
"DELAY_US_1:     \n"  
"NOP             \n"  //1T,nop延时
"DEC A           \n"  //1T,A--
"JRNE DELAY_US_1 \n"   //不等于0,则跳转(2T)到DELAY_US_1继续执行,若等于0,则不跳转(1T).
"NOP             \n"  //1T,nop延时
"DECW X          \n"  //1T,x--
"JRNE DELAY_XUS  \n"    //不等于0,则跳转(2T)到DELAY_XUS继续执行,若等于0,则不跳转(1T).
"POP A           \n"  //1T,出栈
);
}
//延时nms  
//为保证准确度,nms不要大于16640.
void delay_ms(u32 nms)
{
u8 t;
if(nms>65)
{
  t=nms/65;
  while(t--)delay_us(65000);
  nms=nms%65;
}
delay_us(nms*1000);
}
继承事业,薪火相传
返回列表