完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一般单片机中定时器资源有限,而PLC中却有几千个定时器,据说里面的定时器也是由一个基础的衍生出来的,有没有烧友研究过在单片机中一次搞出几十个定时器,同时类似PLC中条件成立定时,条件不成立复位,并且有输出的函数?坐等大神。。。
|
|
相关推荐
8个回答
|
|
单片机运行速度较慢,如果定时精度不高的系统,可以通过代码实现
PLC里面的定时器也是一个链表上不同的处理模块,我们公司的PLC使用1G的CPU,可以整很多定时器,注册一个其实就是在定时器的处理链表上增加一个处理节点,正真的定时器硬件提供时基 |
|
|
|
andy_wsj 发表于 2015-6-24 11:38 希望可以详细了解下PLC中制作定时器的源代码,请问大神在哪家公司高就? |
|
|
|
我们公司 是深圳合信,PLC品牌叫科创思,在国产PLC里面比较好,仿西门子,去年还被西门子告侵权,不过官司我们赢了,我们的模块与西门子的可以互换,西门子的程序直接可以在我们的PLC内运行 高性能的中大型PLC不再仿西门子,使用TI的AM335x,有两款配置,一款720M主频,一款1G主频,接口使用最新的EarthCAT,配合我们公司的带EarthCAT的伺服产品,目前带EarthCAT的伺服国内只有我们和汇川有,其他公司都没有,国外公司已经很常见了,机械臂使用的就是这种总线,100M超快。我们有一个CoMotion运动控制平台,目前在国产PLC里面算是高端产品,运动算法是买德国的。 广告完毕。说说PLC的定时器 代码我当然不能直接贴出来,公司秘密,并且是加密的,贴出来也是乱码 不过方式方法可以讨论,说不定遇到大神给出好的建议,获得产品提升空间 实现方法很简单 就是定义一个结构体,类似于 typedef struct strPLC_Timer{ strPLC_Timer *Next; strPLC_Timer *Prev; void (*pFun)(void *); int Flag; int Ticks; void *Param; }PLC_Timer; 结构体里面包含一个函数指针,指向用户定义的定时处理事件 定义PLC的定时器 PLC_Timer Timer[1024] = {0}; //支持1024个定时器 中断处理 void PLC_TimerISR(void) { PLC_Timer *pTemer = Timer; ..... while(pTemer != NULL ) { pTemer->Ticks--; if( pTemer->Ticks == 0 ) { .... pTemer->pFun( pTemer->Param); .... } pTemer = pTemer->Next; } } 中断函数就在一个计时器的中断里面调用,遍历整个链表,然后找到时间到达的节点,处理用户的定时事件 实际代码会更复杂一些,但是思路就是这样子 当然需要初始化函数,初始化静态链表,如果使用系统,可以使用动态链表节省空间 需要一个注册函数,把用户的事件,参数,定时周期初始化到一个节点上 还需要启动、停止和注销函数,以便用户各种操作 基本上一个硬件定时器就能实现N个定时器,还需要考虑的是CPU速度是否能在中断内轻松完成1024个定时器的处理,还有就是时间粒度,如果硬件设置为1us一次中断,那么用户必须这个时间很多才能准时,我们使用720M/1G的处理器,在这一点上还是非常轻松的 如果使用单片机,可能就支持不了多少个,但是可以使用这样的思路,还有就是单片机里面使用函数指针貌似有点不好使哦,STM32就没有这些问题,我用过 |
|
|
|
andy_wsj 发表于 2015-6-25 09:59 非常感谢,构思和我想的差不多,但是比我想的复杂很多。感谢指导。你们公司的这种源代码更新快吗?是一直在改进还是一直在创新?另外想问一下,这种timer为什么放到定时器中,放到主函数中是否可以?主函数每循环一次,定时器扫描一次。定时器的入口是如何处理的,毕竟定时器要时刻检测入口,入口不成立则定时器清零。 |
|
|
|
lydy123 发表于 2015-6-27 10:37 知道为什么必须放到中断里面了,因为Tick--。如果1024个定时器全用了,那么系统的定时器是否会耗费比较多的资源? |
|
|
|
这个看内存和主频了,可以计算,一个结构体大约30个字节,1024个就是30K的内存,使用动态内存分配就不会,当然也可以实现少一点,10个,100个,内存就在3K以内,重要的是处理器能不能处理得过来,所以处理器快一点会比较好,慢速的就几个十几个,把处理函数写好了,也是可以实现的 |
|
|
|
andy_wsj 发表于 2015-6-27 14:46 请问定时器复位和入口的判断如何处理?结构体中的两个函数能否详细讲解下? |
|
|
|
定时器的复位?是用户定时器的复位吧,这个需要自己实现,其实就是初始化结构体的状态变量,但是不能清除入口函数和重装载值,其他的都可以清除,定时器的入口就是一个函数指针而已,时间到了就去执行那个函数就好了。 结构体里面只有一个函数指针,就是pFun,这个函数是用户定义的,例如在用户使用的时候定义了一个10ms执行一次的函数UserTimer1 void UserTimer1( void *arg ) { struct user_str something = ( struct user_str *)arg; if( something == NULL ) retrun; ..... /* do something */ ..... } 假设这个函数就是每10ms执行一次,按前面的定义,最多可以定义1024个这样的函数 但这个函数需要按时间执行,需要注册到成为一个入口 代码类似于 ..... #define TIMER1 1 #define TIME_10MS 10 struct user_str para = {0}; .... ret = TimerRegister(TIMER1, UserTimer1, TIME_10MS, (void *)para); if( ret == FALSE ) { return ret; } StartTimer(TIMER1); .... 这就是我前几天提到的需要实现一个注册的接口和一个开始的接口 上面的意思就是把函数 UserTimer1注册到那1024个里面的第一个,周期是10ms,带一个参数para,para可以是任意结构体,前提是 UserTimer1能够处理这个结构体即可 于是乎就有两个接口函数,需要实现: int TimerRegister( int timer, void (*pFun)(voi *), unsigned int time_ms, void *arg ) { PLC_Timer *pTimer = NULL; pTimer = GetTimerNode(timer); //获取timer的节点,如果使用动态内存分配可以是使用malloc if( pTimer == NULL ) return FALSE; pTimer->pFun = pFun; //设定用户入口 pTimer->Ticks = time_ms * 1000; //假设硬件1us产生一次中断 pTimer->Para = arg; //用户的参数 。。。。。 return TRUE; } void StartTimer( int timer) { PLC_Timer *pTimer = NULL; pTimer = GetTimerNode(timer); if( pTimer == NULL ) return FALSE; pTimer->Flag = ENABLE; //使能这个节点事件,时间到了就执行 pTimer->pFun指向的UserTimer1 ......... } 说道这里,基本都已经说得很清楚了,有开始函数,必然有结束函数,有注册函数,那就还要实现注销函数入口等等.... 代码是我随手敲的,只提供思路,正式用还需要考虑可重入,上下文切换,加一些锁的机制保证数据安全等 但是在单片机里面使用的话,这些因素较少,考虑中断与应用的可重入性就可以了 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
364 浏览 0 评论
356 浏览 0 评论
嵌入式学习-搭建自己的ubuntu系统之ubuntu网络设置
526 浏览 0 评论
龙芯中科胡伟武:3B6600 八核桌面 CPU 性能将达到英特尔中高端酷睿 12~13 代水平
574 浏览 0 评论
树莓派Pico 2发布,搭载RP2350双核RISC-V和Arm Cortex-M33微控制器!
542 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
10691 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-16 06:56 , Processed in 0.793991 second(s), Total 85, Slave 69 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号