历史上的今天
今天是:2024年11月28日(星期四)
2019年11月28日 | stm8s103f3p6的延时函数
2019-11-28 来源:eefocus
使用stm8s时本来期望能够产生1us精度的脉冲,但是调来调去也没能实现。目前的情况是使用内部16MHz的RC时钟源,然后给到timer4,再经 8分频产生一个25us的中断,我能搞出来的最小中断周期是15us左右,考虑到那不是一个很好的整数,主要是当要延时整数比如100,1000时没办法除尽,所以就只好取25us为一个最小单位了。如果有人能用定时器产生1us的脉冲请指点一下。多谢。
下面上代码吧:
基本的思路就是使用timer4每隔25us计数一次,然后延时函数对timer4的中断次数进行统计。完成指定的延时时间后退出while循环。
#include"stm8s.h"
uint8_t startflag = 0;
uint16_t timercnt = 0;
/*******************************************************************************
函数名;init_clk()
功能 :初始化系统时钟
输入 :无
输出 :无
返回值:无
备注 :无
*******************************************************************************/
void init_clk(void)
{
//初始化时钟
CLK_HSICmd(ENABLE);//开始内部高频RC
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);//不分频
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
}
/*******************************************************************************
函数名:init_timer4()
功能 :初始化timer4
输入 :无
输出 :无
返回值:无
备注 :无
*******************************************************************************/
void init_timer4(void)
{
TIM4_TimeBaseInit(TIM4_PRESCALER_8, 50); //每个计数周期为0.5us@8分频@16MHz
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
TIM4_Cmd(ENABLE);
}
/*******************************************************************************
函数名:init_gpio()
功能 :初始化GPIO
输入 :无
输出 :无
返回值:无
备注 :无
*******************************************************************************/
void init_gpio(void)
{
GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST);
}
/*******************************************************************************
函数名:delayus()
功能 :延时函数
输入 :us 微秒数
输出 :无
返回值:无
备注 :目前支持25us的整数倍,最小为25us,不能再小了
*******************************************************************************/
void delayus(uint16_t us)
{
//Set the flag to make ISR start to count
startflag = 1;
us = (us <= 25?25:us);
us = us / 25 - 1;
// TIM4_Cmd(ENABLE);
//Wait until expire
while(timercnt <= us);
//TIM4_Cmd(DISABLE);
//Clear flag and timer cnt
startflag = 0;
timercnt = 0;
}
/*******************************************************************************
函数名:delayms()
功能 :延时函数
输入 :ms 毫秒数
输出 :无
返回值:无
备注 :最小为1ms
*******************************************************************************/
void delayms(uint16_t ms)
{
uint16_t i=0;
uint16_t j=0;
for(i=0;i delayus(1000); } } /******************************************************************************* 函数名:main() 功能 :主函数 输入 :无 输出 :无 返回值:无 备注 : 无 *******************************************************************************/ int main(void) { init_gpio(); init_clk(); init_timer4(); enableInterrupts(); while(1) { GPIO_WriteReverse(GPIOB, GPIO_PIN_5); delayus(50); //delayms(750); } return 0; } void assert_failed(u8* file, u32 line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %drn", file, line) */ /* Infinite loop */ while (1) { } } 中断函数的: /** * @brief Timer4 Update/Overflow Interrupt routine. * @param None * @retval None */ INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23) { /* In order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction. */ if(startflag == 1) { timercnt++; } TIM4_ClearITPendingBit(TIM4_IT_UPDATE); } 在使用示波器测试的时候发现,delayus(1000);时测出来的延时为1014us,那多出来的14us不知道从哪里来的,且使用其他参数时也会有多出来的10+us,对这个多出来的值看着有点难受,感觉这误差有点大啊。然后看程序觉得有可能是在实现的机制上有问题,因为计数器一直在工作,只有检测到startflag==1时才开始对timercnt进行累加,这在一定程度上存在至少1个计数周期的延误,比如上次计数器刚刚完成中断,此时用户就设置了startflag=1,但是timer4要等到下次中断来的时候才能计数,所以至少有25us不能计数,不对啊,此时写日志时才意识到这个是导致它少计数的,而不是多计数的啊。当时发现这个问题的时候无以为这样会导致它会多计时了,所以就像不使用这个机制,修改一下。先让计数器暂停工作,然后用户调用delayus()时再启动计数,延时时间到了之后再停止timer4,也就是我在上面delayus()中注释掉的TIM4_Cmd()两个接口。因为这样改完后,使用示波器一次,发现误差更大了,还不如一开始使用的那个机制,我猜可能是在delayus()中多调用了2次 使能和禁能接口导致的。所以最后还是换回去开始的机制了,也就是上面的代码。 哦对了,再补充一下,我觉得使用纯软件延时太扯淡了。虽然单次直接使用 while(1) { GPIO_WriteReverse(GPIOB, GPIO_PIN_5); } 这种方法就可以实现100ns左右的延时输出方波,但是如果想延时200ns,300ns,500ns,650ns这样的延时的话实在是很麻烦,因为它并不是像看上去的那样只要简单的成倍数的修改参数就行了,完全没有规律,反正我是找不着,而且找这个规律实在是太烦了,这样里面牵扯一个函数调用时间的消耗,就是即使调用一个空函数也会消耗时间,以及每次调用的误差在多次调用的累加的问题,比如调用1次asm(“nop”),和2次,3次,4次,直到多次的耗时竟然不是一个规矩的线性的递增,反正我是根据它们的差计数得出的延时与实际用示波器测试出来的结果有不小的误差,先不搞了,也许以后有时间再来搞吧
史海拾趣
|
因开发需要在做DirectShow视频采集的程序在开发中遇到为何老是提示:Error Creating Device Enumerator。已安装硬件设备,请高手指点。 程序代码如下: ...… 查看全部问答> |
|
陶瓷材料因本身具有优良的绝缘、耐热及稳定等先天特性,所以被大量运用在电气设备的绝缘上,又因陶瓷金属化技术的成熟,近几年更被应用于led陶瓷散热基板与载板的线路铺设。陶瓷材料金属化技术主要分为「DBC(Direct Bonded Copper) 」及「DPC(Di ...… 查看全部问答> |
|
/****************************************************************************** I2C 主机寄存器 I2CMCON (I2C 主机控制寄存器)I2CMSTA (I2C 主机状态寄存器)I2CMRX&nb ...… 查看全部问答> |
|
记录学习LM3S的点点滴滴 (声明:该学习心得是本人通过学习周立功的相关资料后的个人理解后的笔记,由于本人水平有限,也许会有错误或是偏差,若想要保证准确无误,建议自己去下相关资料学习,本心得只供参考,若有错误之处,敬请指出,万分感谢 ...… 查看全部问答> |
|
在坛子里也算有段时间了,在这里学到了很多东西。大四毕业的时候毕设做的是有关FPGA的,承蒙坛子里的坛友帮助,帮我解决了一个很大的问题。现在我在一所普通院校里读研,已经研一了。上半年搞了半年的FPGA相关的东 ...… 查看全部问答> |
|
我用Verilog HDL编写了一个rs232串口驱动程序。在用串口调试助手进行调试时,当我发送2,4,6,8,A,C,E时,接受没有出现一个乱码,但当我发送1,3,5,7,9,B,D,F时出现乱码,在每300中出现4——5个乱码,有时只出现一个。请问这是什么原因,还是 ...… 查看全部问答> |
|
程序如下,设置断点发下程序执行到红色部分就不再往下执行了,不知道为什么。 int main(void) { unsigned long ulDataTx[NUM_SSI_DATA]; unsigned long ulDataRx[NUM_SSI_DATA]; unsigned long ul ...… 查看全部问答> |




