[51单片机] 给大家提供一个51的软延时例程.

[复制链接]
 楼主| datouyuan 发表于 2016-7-8 16:18 | 显示全部楼层 |阅读模式
  1. #define  MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
  2. #define  MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )

  3. #define FOSC        16.6//11.0592    //
  4. #define MACHINE_NUM 1                //定时器
  5. #define M_NUM       1                //程序  SH88F2051 程序是1T,定时器1T/12T可选

  6. #define COVERT(T) ( (T*FOSC+M_NUM) / (M_NUM*2) -1 )

  7. #if (M_NUM==1)
  8.         #define d_1ms() do{ uint8 x=30; do{ d_uS(33.0); }while(--x); }while(0)
  9. #else
  10.         #if(M_NUM==12)
  11.                 #define d_1ms() do{ d_uS(333.0);d_uS(333.0); d_uS(333.0); }while(0)
  12.         #else

  13.         #endif
  14. #endif

  15. #define d_uS(us) do{ uint8 cnt1=MIN(MAX(COVERT(us),1),256); do{}while(--cnt1); }while(0)
  16.         //Note:实际延时效果C51                12M         4<= us <= 514(uS)
  17.         //Note:实际延时效果88F54        16.6M        1<= us <= 31(uS)
  18. #define d_mS(ms) do{ uint16 cnt2=ms; do{ d_1ms(); }while(--cnt2); }while(0)
 楼主| datouyuan 发表于 2016-7-8 16:22 | 显示全部楼层
  1. //使用示范
  2. d_uS(10);                //延时10us
  3. d_mS(1000);                //延时1秒
  4. uint8 i=10;d_uS(i);//虽然能编译,但延时不准,参数不能为变量
  5. uint8 i=10;d_mS(i);//这还算准确.
使用这例程,只要把晶振频率改成你实际的晶振频率,就可以产生比较准确的软延时了.

例如标准51这样修改.
  1. #define FOSC        11.0592    //
  2. #define MACHINE_NUM 12         //定时器
  3. #define M_NUM       12         //程序  SH88F2051 程序是1T,定时器1T/12T可选


 楼主| datouyuan 发表于 2016-7-8 16:31 | 显示全部楼层
本帖最后由 datouyuan 于 2016-7-8 17:31 编辑

注意假如在88F54使用内振,1T的情况下.(请仔细看注释)
d_uS(0.1);//实际只会延时1uS
d_uS(100);//实际只会延时31uS
d_uS(4.5);//实际会延时4.5uS
假如在标准51使用12M,12T的情况下.(请仔细看注释)
d_uS(0.1);//实际只会延时4uS
d_uS(100);//实际会延时100uS
d_uS(5.5);//实际会延时5uS
d_uS(10000);//实际会延时514uS
 楼主| datouyuan 发表于 2016-7-8 16:34 | 显示全部楼层
我觉得使用定义的方式做软延时,比使用函数的方式好.延时更准确.
伍戈123 发表于 2016-7-8 22:49 | 显示全部楼层
好方法。借鉴一下
 楼主| datouyuan 发表于 2016-7-11 15:15 | 显示全部楼层
怎么没人,这里还是有些技巧的.

自己顶起.
 楼主| datouyuan 发表于 2016-7-11 15:23 | 显示全部楼层
我每接触一个新的mcu,首先要想了解的是端口操作,软延时,开关中断等.

有了上面的定义,可以很方便的在STC 中颖或别的品牌的51MCU移植.

你所需要的是仅仅是填写晶振频率,定时器机器周期,程序机器周期这3个数值.

同样,可以按照上面的技巧配置串口,定时器.
我是楼主呀 发表于 2016-11-9 18:32 | 显示全部楼层
谢谢
linqing171 发表于 2016-11-9 21:02 | 显示全部楼层
本帖最后由 linqing171 于 2016-11-9 21:04 编辑
datouyuan 发表于 2016-7-8 16:31
注意假如在88F54使用内振,1T的情况下.(请仔细看注释)
d_uS(0.1);//实际只会延时1uS
d_uS(100);//实际只会延 ...

每一家的流水线都不一样。每个项目的优化等级也可能不同。还是实际情况下测试为准吧。
keil3 for arm和keil4 for arm,同样的优化等级下,你的那个while差两倍。别问我怎么知道的,我当时也是这样写的。临时变量多用了一次寄存器倒腾。仔细看了一遍,你这个没有问题。我当时是做成了个函数,而且没有开color优化。
xydzx 发表于 2016-11-10 11:24 | 显示全部楼层
嵌入式学习3026827905
 楼主| datouyuan 发表于 2016-11-10 17:45 | 显示全部楼层
linqing171 发表于 2016-11-9 21:02
每一家的流水线都不一样。每个项目的优化等级也可能不同。还是实际情况下测试为准吧。
keil3 for arm和kei ...

我这个是用于51的mcu的,不能用于arm,arm应该用定时器做软延时。

我使用过的51型号MCU,有STC、中颖、华邦、atmel、NXP,最近在使用十速的。
编译器用keil7、8、9版本,优化等级随便设定。不管怎么编译,延时都是非常准确的,完全符合计算要求。(要填写正确晶振频率,定时器机器周期,程序机器周期这3个数值)。
一个拥抱 发表于 2016-11-10 21:57 | 显示全部楼层
datouyuan 发表于 2016-7-11 15:15
怎么没人,这里还是有些技巧的.

自己顶起.

因为烧录软件自带延时函数
qianggewen2018 发表于 2018-6-4 11:13 | 显示全部楼层
看什么场合吧,还有个办法就是用时间继电器,可以用户手动调节延时参数,不用改程序
ayb_ice 发表于 2018-6-4 13:05 | 显示全部楼层
这哪里好,用定时器比这好多了
 楼主| datouyuan 发表于 2021-8-31 15:13 | 显示全部楼层
ayb_ice 发表于 2018-6-4 13:05
这哪里好,用定时器比这好多了

定时器是比较好,不受中断的影响。但是很多51单片机定时器比较少(只有2个),为了移植方便,空操作软延时适用面更广。
ayb_ice 发表于 2021-8-31 16:00 | 显示全部楼层
本帖最后由 ayb_ice 于 2021-8-31 16:02 编辑
datouyuan 发表于 2021-8-31 15:13
定时器是比较好,不受中断的影响。但是很多51单片机定时器比较少(只有2个),为了移植方便,空操作软延时 ...

利用系统滴答定时器很容易扩展VS级延时(不改变他在项目中原有的功能),再短的直接NOP了
一个宏定义轻易实现任意数NOP插入
比如:
__nops(6);
插入6个NOP指令
 楼主| datouyuan 发表于 2021-8-31 16:26 | 显示全部楼层
本帖最后由 datouyuan 于 2021-8-31 16:39 编辑

在AT89C2051外振12MHz下插入6个NOP,移植到SH88F2051内振16.6MHz就要插入16.6*6个NOP。
换其它型号还会不同。d_us(6)会根据mcu的情况生成对应的nop。
 楼主| datouyuan 发表于 2021-8-31 16:29 | 显示全部楼层
ayb_ice 发表于 2021-8-31 16:00
利用系统滴答定时器很容易扩展VS级延时(不改变他在项目中原有的功能),再短的直接NOP了
一个宏定义轻易实现 ...

虽然大部分需求相差几倍的nop没问题,但总有点不放心。
ayb_ice 发表于 2021-8-31 16:54 | 显示全部楼层
datouyuan 发表于 2021-8-31 16:26
在AT89C2051外振12MHz下插入6个NOP,移植到SH88F2051内振16.6MHz就要插入16.6*6个NOP。
换其它型号还会不同 ...

这不小意思吗
#define vs  *12//@12MHZ,单周期51

__nops(1vs);
__nops(3vs);
ayb_ice 发表于 2021-8-31 16:57 | 显示全部楼层
datouyuan 发表于 2021-8-31 16:26
在AT89C2051外振12MHz下插入6个NOP,移植到SH88F2051内振16.6MHz就要插入16.6*6个NOP。
换其它型号还会不同 ...

这种做法误差太快,循环控制导致误差太大
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

1088

帖子

9

粉丝
快速回复 在线客服 返回列表 返回顶部