已经写完了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);
}
在STM8S103F3P6 用 模拟I2C, 不准, 不知是否我的用法不对
main.c 初始化是 Delay_Init(CLK_GetClockFreq()/1000000);
#define IIC_SCL ((pByte_Of_bit)&GPIOB->ODR)->Bit4
#define IIC_SDA ((pByte_Of_bit)&GPIOB->ODR)->Bit5
#define READ_SDA ((pByte_Of_bit)&GPIOB->IDR)->Bit5
//初始化IIC
void IIC_Configuration(void)
{
GPIO_Init(IIC_GPIO, IIC_PIN_SCL, GPIO_MODE_OUT_PP_HIGH_SLOW);
GPIO_Init(IIC_GPIO, IIC_PIN_SDA, GPIO_MODE_OUT_PP_HIGH_SLOW);
IIC_SCL = 1;
IIC_SDA = 1;
}
void IIC_SDA_OUT(void)
{
GPIO_Init(IIC_GPIO, IIC_PIN_SDA, GPIO_MODE_OUT_PP_HIGH_SLOW);
}
void IIC_SDA_IN(void)
{
GPIO_Init(IIC_GPIO, IIC_PIN_SDA, GPIO_MODE_IN_PU_NO_IT);
}
模拟I2C的起始时间
//产生IIC起始信号
void IIC_Start(void)
{
IIC_SDA_OUT(); //sda线输出
IIC_SDA = 1;
IIC_SCL = 1;
delay_us(5);
IIC_SDA = 0; //START:when CLK is high,DATA change form high to low
delay_us(6);
IIC_SCL = 0; //钳住IIC总线,准备发送或接收数据
}
一周热门 更多>