仿ALIENTEK STM32开发板,写的STM8S的延时函数(基于IAR),汇编精确延时.奉献给大家了.

2019-07-19 20:06发布

已经写完了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          "  //1T,压栈
"DELAY_XUS:      "  
"LD A,fac_us     "   //1T,fac_us加载到累加器A
"DELAY_US_1:     "  
"NOP             "  //1T,nop延时
"DEC A           "  //1T,A--
"JRNE DELAY_US_1 "   //不等于0,则跳转(2T)到DELAY_US_1继续执行,若等于0,则不跳转(1T).
"NOP             "  //1T,nop延时
"DECW X          "  //1T,x--
"JRNE DELAY_XUS  "    //不等于0,则跳转(2T)到DELAY_XUS继续执行,若等于0,则不跳转(1T).
"POP A           "  //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);
}                        
 
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
49条回答
龙胜阳子
2019-07-19 22:43
回复【楼主位】正点原子:
---------------------------------
謝謝了  已經修改為STVD的了呵呵
#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            //1T,压栈
DELAY_XUS:         
LD A,_fac_us        //1T,fac_us加载到累加器A
DELAY_US_1:       
NOP              //1T,nop延时
DEC A             //1T,A--
JRNE DELAY_US_1    //不等于0,则跳转(2T)到DELAY_US_1继续执行,若等于0,则不跳转(1T).
NOP               //1T,nop延时
DECW X            //1T,x--
JRNE DELAY_XUS      //不等于0,则跳转(2T)到DELAY_XUS继续执行,若等于0,则不跳转(1T).
POP A             //1T,出栈
#endasm 

//延时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);
}

一周热门 更多>