选ADCcss选择器的优先级级 我的思路是不是正确

LOL:T3级别 ADC选择优先级排名,女警不排第一,寒冰与维努斯丢了
LOL:T3级别 ADC选择优先级排名,女警不排第一,寒冰与维努斯丢了
乐盈电竞娱乐
【乐盈电竞APP,欢迎来吐槽】英雄联盟中的射手,即ADC,分为几种类型的英雄。比如高攻速英雄,像克格莫、薇恩、崔丝塔娜;前期高伤害英雄,像德莱文和烬。幸运的是,当前的ADC允许玩家选择符合自己喜好的,因为他们在比赛中都是可行的。这份顶级英雄名单受很多事情影响。有时,除了玩家喜好之外,没有其他明显的原因,但是通常也有一些平衡变化影响着它。这儿是英雄联盟第七赛季单排ADC优先级列表。T1这一层的英雄在目前是最强大,如果用他们玩你不需要在单排rank中花费多大的努力就能获得胜利。德莱文德莱文也许是所有强力单排英雄的缩影。他的旋转飞斧在早期等级伤害太高了,对于单排中协作差的队伍来说,他很难对付。由于早期的施压,他比别的ADC更易滚雪球。他能在比赛各个阶段都造成相当大的伤害,并且在逆风的比赛之中只需要几个人头就能重新掌管比赛。图奇图奇可能没有所有ADC中最高的单体DPS伤害,但是他是团战中无可争议的王。如果使用操作得当,再出一把破败,他就感觉在家一样舒服,绝对有能力最终改变比赛。出了新版多兰盾的他靠着被动可以在塔下安全发育到伤害足够,然后就可以结束对线了,出了卢安娜的飓风的他会变成一个怪物。尽管图奇是一个相当安全的选择,但是如果他被打回家一次两次,他就会比其他ADC更难玩,所以在试着打艰难战斗之前多多练习图奇。崔丝塔娜炮娘是现在游戏中最可怕的ADC之一,她有高技能伤害,也有位移能力,所以她玩起来相当爆炸。崔丝塔娜很难安稳渡过到后期,他很擅长粉碎现在十分流行的前排坦克。不仅仅是这样,如果她在前期对线中取得了领先,她就会变得无可阻挡。她推塔推线的能力都是无与伦比的,尽管她前期偏弱,但是也不枉是一个全能的选择。T2T2级的ADC需要多花一点努力去打好比赛,但是如果正确的使用英雄,他们也能carry比赛,只是要比T1级别的难一点。烬烬的AD伤害要比游戏里任何的其他射手都高,他的E技能陷阱能给他视野并且黏住敌人,并且能在眨眼之间爆死敌人。他在关键和致命攻击上都做得很好,所以不论在哪儿他通常都能找到地方输出。他的弱点显然是无法造成持续伤害,冲破坦克,所以聪明的玩法是用它来打对面灵活的阵容,或者你们这边有个像马尔扎哈的中单去充当坦克杀手。厄运小姐随着最近杀伤力增加,厄运小姐又上升到了最高点,她在单排中表现非常好。像德莱文,她的骚扰在早期是无法阻挡的。像图奇,她在团战中的大招能对图奇造成极大的威胁。至于她为何不能进入T1是因为,杀伤力不够强,她有一点无用了。事实上,在7.14补丁的杀伤力变化之前,她不够强,如果这个因素消失了,厄运小姐可能会变得更好。霞霞有被动让她在极端进攻和团战中用攻击刺穿敌人,为此,她是强力的后期ADC。相比图奇的大招,霞的被动在整场团战中都十分有力,她的大招能提供一个短暂的无敌来躲避敌军的大攻击。霞的弱点是她需要一个结实的前排。她需要一个大的,能分散注意力,并能提供群控的重装英雄去吸引敌军注意力好让她能在战斗中放下羽毛。如果没有这个前排,她就没那么有用的了。T3这是一个有趣的层次,因为这个等级的英雄不是特别强大,但是如果你能学习到如何玩好,你也可以用他们来carry比赛。但是这些要很多额外的努力。凯特琳凯特琳因为她手长可以安全的点到敌人,又不让她自己处于危险之中,所以她在所有类型的比赛中都有作用。她也有逃生技能和追击敌人非常有用的大招。她拥有强大的技能,所以尽管她再进削弱了攻击速度和适合她的卢安娜飓风,她还是很强大。虽然她不在T1层级了,但是她也是任何有抱负的ADC的选择。卢锡安如果你想选一个游戏的ADC,卢锡安是你的选择。他有极高的机动性,可以胜过敌人。他非常强大,也有很多出装套路,但是他手短和操作困难让习惯于其他ADC的人有一点问题。玩卢锡安,如果你不是玩得非常好,他不是很有用,因此如果不喜花很多时间来学习一个英雄,那么卢锡安可能不是你的选择。薇恩现在坦克大行其道,没有任何ADC能比薇恩更擅长撕碎坦克。不仅如此,而且她的carrt比赛的能力也是相当可怕的,一个会玩的薇恩是很难击败的。不幸的是,她必须后期才有这种能力,很多时候在到哪儿之前他们就失败了。她的前期能力是很差的,当她面对前期怪物像德莱文,凯特琳,和卢锡安时她几乎无力招架,所以薇恩无法成为一个坚实的ADC选择。其实看完,小编也很想要吐槽:寒冰与维努斯哪去了? 对此你怎看呢?
本文仅代表作者观点,不代表百度立场。系作者授权百家号发表,未经许可不得转载。
乐盈电竞娱乐
百家号 最近更新:
简介: 娱乐电竞,电影评论,娱人愚己,Just do
作者最新文章LOL:奇怪的ADC优先级,女警不排第一,寒冰丢了
【乐盈电竞APP,欢迎来吐槽】
狮子熊@乐盈电竞
英雄联盟中的射手,即ADC,分为几种类型的英雄。比如高攻速英雄,像克格莫、薇恩、崔丝塔娜;前期高伤害英雄,像德莱文和烬。幸运的是,当前的ADC允许玩家选择符合自己喜好的,因为他们在比赛中都是可行的。这份顶级英雄名单受很多事情影响。有时,除了玩家喜好之外,没有其他明显的原因,但是通常也有一些平衡变化影响着它。
这儿是英雄联盟第七赛季单排ADC优先级列表。
这一层的英雄在目前是最强大,如果用他们玩你不需要在单排rank中花费多大的努力就能获得胜利。
德莱文也许是所有强力单排英雄的缩影。他的旋转飞斧在早期等级伤害太高了,对于单排中协作差的队伍来说,他很难对付。由于早期的施压,他比别的ADC更易滚雪球。他能在比赛各个阶段都造成相当大的伤害,并且在逆风的比
赛之中只需要几个人头就能重新掌管比赛。
图奇可能没有所有ADC中最高的单体DPS伤害,但是他是团战中无可争议的王。如果使用操作得当,再出一把破败,他就感觉在家一样舒服,绝对有能力最终改变比赛。出了新版多兰盾的他靠着被动可以在塔下安全发育到伤害足够,然后就可以结束对线了,出了卢安娜的飓风的他会变成一个怪物。尽管图奇是一个相当安全的选择,但是如果他被打回家一次两次,他就会比其他ADC更难玩,所以在试着打艰难战斗之前多多练习图奇。
炮娘是现在游戏中最可怕的ADC之一,她有高技能伤害,也有位移能力,所以她玩起来相当爆炸。崔丝塔娜很难安稳渡过到后期,他很擅长粉碎现在十分流行的前排坦克。不仅仅是这样,如果她在前期对线中取得了领先,她就会变得无可阻挡。她推塔推线的能力都是无与伦比的,尽管她前期偏弱,但是也不枉是一个全能的选择。
T2级的ADC需要多花一点努力去打好比赛,但是如果正确的使用英雄,他们也能carry比赛,只是要比T1级别的难一点。
烬的AD伤害要比游戏里任何的其他射手都高,他的E技能陷阱能给他视野并且黏住敌人,并且能在眨眼之间爆死敌人。他在关键和致命攻击上都做得很好,所以不论在哪儿他通常都能找到地方输出。他的弱点显然是无法造成持续伤害,冲破坦克,所以聪明的玩法是用它来打对面灵活的阵容,或者你们这边有个像马尔扎哈的中单去充当坦克杀手。
随着最近杀伤力增加,厄运小姐又上升到了最高点,她在单排中表现非常好。像德莱文,她的骚扰在早期是无法阻挡的。像图奇,她在团战中的大招能对图奇造成极大的威胁。至于她为何不能进入T1是因为,杀伤力不够强,她有一点无用了。事实上,在7.14补丁的杀伤力变化之前,她不够强,如果这个因素消失了,厄运小姐可能会变得更好。
霞有被动让她在极端进攻和团战中用攻击刺穿敌人,为此,她是强力的后期ADC。相比图奇的大招,霞的被动在整场团战中都十分有力,她的大招能提供一个短暂的无敌来躲避敌军的大攻击。霞的弱点是她需要一个结实的前排。她需要一个大的,能分散注意力,并能提供群控的重装英雄去吸引敌军注意力好让她能在战斗中放下羽毛。如果没有这个前排,她就没那么有用的了。
这是一个有趣的层次,因为这个等级的英雄不是特别强大,但是如果你能学习到如何玩好,你也可以用他们来carry比赛。但是这些要很多额外的努力。
凯特琳因为她手长可以安全的点到敌人,又不让她自己处于危险之中,所以她在所有类型的比赛中都有作用。她也有逃生技能和追击敌人非常有用的大招。她拥有强大的技能,所以尽管她再进削弱了攻击速度和适合她的卢安娜飓风,她还是很强大。虽然她不在T1层级了,但是她也是任何有抱负的ADC的选择。
如果你想选一个游戏的ADC,卢锡安是你的选择。他有极高的机动性,可以胜过敌人。他非常强大,也有很多出装套路,但是他手短和操作困难让习惯于其他ADC的人有一点问题。玩卢锡安,如果你不是玩得非常好,他不是很有用,因此如果不喜花很多时间来学习一个英雄,那么卢锡安可能不是你的选择。
现在坦克大行其道,没有任何ADC能比薇恩更擅长撕碎坦克。不仅如此,而且她的carrt比赛的能力也是相当可怕的,一个会玩的薇恩是很难击败的。不幸的是,她必须后期才有这种能力,很多时候在到哪儿之前他们就失败了。她的前期能力是很差的,当她面对前期怪物像德莱文,凯特琳,和卢锡安时她几乎无力招架,所以薇恩无法成为一个坚实的ADC选择。
其实看完,小编也很想要吐槽:寒冰与维努斯哪去了? 对此你怎看呢?
责任编辑:
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
【欢乐国庆】德州撩妹,决战8天7夜
【欢乐国庆】德州撩妹,决战8天7夜
今日搜狐热点21ic官方微信-->
后使用快捷导航没有帐号?
ST MCU Finder
安装免费手机应用,
寻找理想的ST MCU
请完成以下验证码
查看: 4561|回复: 17
stm32f303 DMA1-DMA2优先级问题和ADC用DMA传送数据overrun问题求助
&&未结帖(20)
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
本帖最后由 王小毛wxm 于
15:33 编辑
我在使用F303VCT6的芯片做个东西,遇到些问题,求助呀:)
1、关于F3中DMA1和DMA2优先级问题:
原来使用F1系列时候,参考手册13.3.2一节描述中DMA的Arbiter有Note:In high-density, XL-density and connectivity line devices, the DMA1 controller has priority over the DMA2 controller. 那是不是大容量产品中说DMA2通道1设置为VeryHigh优先级也没有DMA1通道7设置为Low的优先级高呢? 那小容量产品中DMA1和DMA2间优先级怎么确定的呢?&&在F303VCT6(256K flash)手册中DMA相应一节的描述中没有提到这个Note。那F3的DMA1和DMA2之间的优先级怎么比较的呢?
使用F3的ADC,用DMA传送数据,根据手册上说的如果DMA没有及时读取ADC-&DR,会发生OVERRUN,置位OVERFLAG,如果不用软件清除该标志,则ADC不会再产生DMA请求,那就是不能再传送数据了。我现在出现了个问题:发生了OVERRUN事件,但我没有清除OVERFLAG,DMA仍然传送数据到内存,当然这个时候传送的数据是错位的。
本帖子中包含更多资源
才可以下载或查看,没有帐号?
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
沉了要.....
主题帖子积分
中级技术员, 积分 193, 距离下一级还需 107 积分
中级技术员, 积分 193, 距离下一级还需 107 积分
主题帖子积分
专家等级:结帖率:50%
主题帖子积分
中级技术员, 积分 193, 距离下一级还需 107 积分
中级技术员, 积分 193, 距离下一级还需 107 积分
准备用STM32F303,楼主问题解决了吗,帮你顶起!
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
lianxi47 发表于
准备用STM32F303,楼主问题解决了吗,帮你顶起!
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
楼主 adc dma 传输的问题你解决了么?&&如何软件清除?&&我也遇到了类似的问题
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
qiaoyang123 发表于
楼主 adc dma 传输的问题你解决了么?&&如何软件清除?&&我也遇到了类似的问题 ...
我的疑问没有解决。
至于清除overrun bit位,手册上有说明,在adc_isr寄存器中,有
固件库里有函数:
本帖子中包含更多资源
才可以下载或查看,没有帐号?
主题帖子积分
主题帖子积分
专家等级:结帖率:26%打赏:0.00受赏:12.00
主题帖子积分
第一,F3的DMA模块和F1应该一样的(不像F2的DMA那么复杂:)),在相同软件优先级(very high、high、medium、low)和相同硬件优先级(相同通道号)的情况下,DMA1上的request优先级高于DMA2上的。
第二,按照手册上说,如果使用DMA传输ADC数据时发生了overrun,ADC不会再产生DMA请求,DMA传输应该停止。LZ是如何判断“DMA仍然传送数据到内存”?
I do not teach, but I coach. I do not feed, but I seed.
欢迎访问我的博客:/BLOG_OWNER_199055.HTM
主题帖子积分
助理工程师, 积分 1675, 距离下一级还需 325 积分
助理工程师, 积分 1675, 距离下一级还需 325 积分
主题帖子积分
专家等级:结帖率:46%
主题帖子积分
助理工程师, 积分 1675, 距离下一级还需 325 积分
助理工程师, 积分 1675, 距离下一级还需 325 积分
ADC+DMA传输出现数据错位的问题,也许跟你写的程序有点关系,要参照官方例程。初始化的顺序等等。
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
本帖最后由 王小毛wxm 于
22:11 编辑
香水城 发表于
第一,F3的DMA模块和F1应该一样的(不像F2的DMA那么复杂:)),在相同软件优先级(very high、high、mediu ...
谢谢香主!
那就是说:
一:DMA 优先级的意思是不是说:1、软件优先级是第一考虑的,DMA1和DMA2的所有通道中,设置了VeryHigh的通道具有最高优先级,设置了 VeryHigh的DMA2_CH3高于设置了High的DMA1_CH1。2、同一个DMA,如果软件优先级相同,则硬件通道号小的优先级高,同样软件优先级,DMA2_CH1高于DMA2_CH2;那都设置了High的DMA2_CH1和DMA1_CH2,是不是DMA2_CH1优先级高呢?3、相同软件优先级,相同硬件通道号,DMA1请求高于DMA2的。
二:我的程序中用DMA1_CH1传送ADC1采样数据到内存变量buf1中,用DMA2_CH5传送ADC3采样数据到buf2中,用在硬件调试过程,设置DMA2通道优先级不够高的话,ADC3状态寄存器会有overrun位被置位,此时如果使能overrun中断,会进中断,但并没有对overrun标志做处理,这时看ADC3采样结果寄存器值还在变,buf2中数据也还在更新。
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
你好 stm32f303 ADC1和ADC2 双通道采集时 ADC_CDR_ADDRESS& & ((uint32_t)0x5000030C)& &&&那我使用ADC3和ADC4他们的ADC_CDR_ADDRESS地址是多少呢?
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
qiaoyang123 发表于
你好 stm32f303 ADC1和ADC2 双通道采集时 ADC_CDR_ADDRESS& & ((uint32_t)0x5000030C)& &&&那我使用ADC3和A ...
你好,ADC3、ADC4的共用数据寄存器ADC_CDR_ADDRESS 是((uint32_t))0x5000070C。
这个东西的计算可参考如下:
该地址=ADC3的基地址(AHB3总线地址+ADC3相对于AHB3的偏移量)+ADC common registers 相对于ADC3的偏移量+ADC CDR register的偏移量
ADC_CDR_ADDRESS=0x (0xx400)+0x300+0x0C=0xC.
另外你可以用KEIL 调试时查看寄存器来查看某寄存器地址。如下:
本帖子中包含更多资源
才可以下载或查看,没有帐号?
主题帖子积分
---------------------
主题帖子积分
---------------------
专家等级:结帖率:96%打赏:0.00受赏:58.00
主题帖子积分
---------------------
我倒是进行了高强度数据交换的测试, 想抓住个 OVERRUN. 却没有.
欢迎进入 !
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
airwill 发表于
我倒是进行了高强度数据交换的测试, 想抓住个 OVERRUN. 却没有.
我用DAC Channel1输出正弦波31.25KHz,每周期64点数据,即2M的输出频率,用DMA2_CH3传送内存正弦波数据到DAC_DR。这个正弦波激励芯片外部的传感器,传感器感应出信号,然后用三路ADC采样信号。ADC在一个正弦激励周期内采样128点,即采样频率4M,ADC1/2common data的采样值用DMA1传送到内存,ADC3的采样值用DMA2 Channel5传送到内存。当DMA2_CH3的优先级设置高于DMA2 Channel5时,ADC3就会出现over run。
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
本帖最后由 qiaoyang123 于
17:03 编辑
王小毛wxm 发表于
你好,ADC3、ADC4的共用数据寄存器ADC_CDR_ADDRESS 是((uint32_t))0x5000070C。
这个东西的计算可参考如 ...
谢谢&&现在又有新问题了&&我之前adc1 和adc2的程序&&改成了adc3和adc4的程序就不能采集数据了,是不是ADC3和ADC4的使用有什么特殊的地方?
刚刚搞定了 查了一下资料发现adc3 和adc4的dma通道不同& &老大能加你好友么?&&我QQ:
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
主题帖子积分
专家等级:结帖率:79%
主题帖子积分
高级技术员, 积分 515, 距离下一级还需 485 积分
高级技术员, 积分 515, 距离下一级还需 485 积分
qiaoyang123 发表于
谢谢&&现在又有新问题了&&我之前adc1 和adc2的程序&&改成了adc3和adc4的程序就不能采集数据了,是不是ADC ...
你这问题问的我没法回答呀?你都改了哪?该改的有没有改,我不知道 啊
adc3/4没有啥特殊的
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 24, 距离下一级还需 26 积分
实习生, 积分 24, 距离下一级还需 26 积分
王小毛wxm 发表于
你这问题问的我没法回答呀?你都改了哪?该改的有没有改,我不知道 啊
adc3/4没有啥特殊的
刚刚搞定了 查了一下资料发现adc3 和adc4的dma通道不同& &老大能加你好友么?&&我QQ:
主题帖子积分
实习生, 积分 33, 距离下一级还需 17 积分
实习生, 积分 33, 距离下一级还需 17 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
实习生, 积分 33, 距离下一级还需 17 积分
实习生, 积分 33, 距离下一级还需 17 积分
谢谢&&现在又有新问题了&&我之前adc1 和adc2的程序&&改成了adc3和adc4的程序就不能采集数据了,是不是ADC3 ...
我想问下,我现在也使用303的ADC3,ADC4,发现dma传输时,使用ADC4的dma通道,ADC3才进行转换,但是,有overrun标志,你最后是怎么搞定的?
主题帖子积分
初级工程师, 积分 2233, 距离下一级还需 767 积分
初级工程师, 积分 2233, 距离下一级还需 767 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
初级工程师, 积分 2233, 距离下一级还需 767 积分
初级工程师, 积分 2233, 距离下一级还需 767 积分
1系列和2系列进行了大量数据传输实验,表示没有发现过过载
时间类勋章
涓涓之细流
发帖类勋章
技术新星奖章
人才类勋章
技术高手奖章
人才类勋章
时间类勋章
荣誉元老奖章
等级类勋章
坚毅之洋流
发帖类勋章
时间类勋章
技术领袖奖章
人才类勋章
欢快之小溪
发帖类勋章
社区建设奖章
等级类勋章
时间类勋章查看: 28019|回复: 249
结合时间触发+消息+protothread思想+支持优先级的非抢占调度器
本帖最后由 summarize 于
14:47 编辑
废话少说,先上stm8s103 IAR库工程代码压缩包。
工程是在stm8s103f3单片机上调度通过,已经用消息实现了 UART1_TX模块的共享,即UART1_RX接收到的数据+0x11后再通过UART_TX模块发送回去,同时ADC1 通道3的转换结果也通过UART1_TX模块发送出去.见下图
1.ADC1转换结果每1秒上传一次到PC。测试式给ADC1通道3供的是5V电,所以结果是0x03ff.即1023.
2.共享时PC接收到的数据: PC端每1.5秒向下发送一次数据 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0xaa,0xaa为简单测试时的包尾识别码,单片机接收到数据后将其加上0x11,之后发送回给PC,下图中可看到0x03ff和0x22 0x33 0x44 0x55 0x66 0x77 0x88 0xbb两种数据。
3.支持非抢占式优先级调度,优先级顺序就是创建任务时的顺序,由高到底。其实现思想是,每一个任务运行结束后,都重新回到第一个创建的任务处按顺序查找某个任务是否满足运行条件,所以先创建的任务会先被“发现”其满足运行条件并运行之,核心代码如下
a.任务控制块数据结构struct SchTcb
{
#if SCH_CFG_Q_EN & 0u
&&void& && && & *pD& && & //消息指针
&&SCH_UINT8 S& && && &//消息大小
#endif
&&SCH_DLY_TYPE& & & & TimeC&&//定时计数器,时基为 &SCH_SYS_TICKS_MS&
&&void& && && & (*pTask)();& &//任务指针
&&struct SchTcb *pNextTCB;& & //下一个任务控制块指针
};复制代码b.调度核心void SCHTaskSchedStart(void)
{
SCHED_SART:
& & & &
&&pCurTCB = pFirstTCB;& && && && && && && && &//指向第一个创建的任务,之后按创建时的顺序执行下去
&&while (1)& && && && && && && && && && && &
&&{
& & SCHTimeTick();& && && && && && && && && & //如果任务Tick满足条件,则将其置于可执行状态
& & if (SCH_TASK_RUN == pCurTCB-&TimeCounter) //任务处于可执行状态
& & {
& && &pCurTCB-&TimeCounter = SCH_TASK_PEND;& &//设置为挂起状态,保证任务只执行一次
& && &pCurTCB-&pTask();& && && && && && && &&&//执行当前任务控制块指向的任务
& && &goto SCHED_SART;& && && && && && && && &//每执行完一个任务,都重新查找一次可执行最高优先级任务
& & }
& & pCurTCB = pCurTCB-&pNextTCB;& && && && &&&//指向下一个任务控制块,查找下个任务是否可执行
&&}
}复制代码“schedule.c”和&schedule.h&已经设置为只读属性,无特殊情况不建议修改,&sch_cfg.h&则为开放给用户的接口,可定义数据类型、调度器节拍和配置是否使用消息。
本人水平有限,欢迎大家测试、指正不足。
本帖子中包含更多资源
才可以下载或查看,没有帐号?
本帖最后由 summarize 于
22:57 编辑
rifjft 发表于
整得不错,还有注释
有时间再弄弄寄存器版本的,这小容量的芯片用库浪费了点 ...
寄存器版本出来了.附件如下!
寄存器版本开启了TIM1_PWM(两个通道)中断和IO下降沿中断(PD4),其中IO这个中断在&iostm8s103f3.h&是没有定义的,这个头文件只定义了从0x0c之后的中断,于是我自己根据手册增加了前面0x00~0x0b中断定义.同时将寄存器版本的所有初始化代码贴出来,这些初始化代码都有详细的注释,有了它,你甚至可以不用看手册了,它必将是初学者的福音及工程师的利器.
/* Includes ------------------------------------------------------------------*/
#include &user.h&
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static void TIM1_PWM_Config(void);
static void TIM4_Config(void);
static void GPIO_Config(void);
static void UART1_Config(void);
static void ADC_Config(void);
static void IWDG_Config(void);
static void WWDG_Config(void);
static void IT_Config(void);
/* Public functions ----------------------------------------------------------*/
void CLK_Config(void)
{
&&//配置内部16M时钟作为时钟源
&&//CLK_ICKR_HSIEN = 1;& && & //使能内部高速时钟(复位值)
&&CLK_ICKR_bit.LSIEN& & = 1;&&//使能内部低速时钟
&&CLK_CKDIVR_bit.HSIDIV = 0;&&//主时钟分频 0-3对应 1 2 4 8分频
&&CLK_CKDIVR_bit.CPUDIV = 0;&&//CPU时钟分频 0-7对应 1 2 4 8 16 32 64 128分频
&&//CLK_SWR = 0xE1;& &&&& & & && &&&//HSI为主时钟源(复位值)
&&//CLK_SWCR_SWEN&&= 1;& && & & && &//使能自动切换时钟
&&//CLK_SWR = 0xD2;& &&&& & & && &&&//0xD2:LSI为主时钟源(仅当LSI_EN选项位为1时)
&&//CLK_SWR = 0xB4;& &&&& & & && &&&//0xB4:HSE为主时钟源
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&asm(&nop&);
&&//外设时钟控制寄存器 CLK_PCKENR1
&&//& & & & CLK_PCKENR1 = 0x00;& & & & //复位值为0xff,即默认为开启状态
&&//& & & & PCKEN10: I2C& &
&&//& & & & PCKEN11: SPI& &
&&//& & & & PCKEN12: UART1& &
&&//& & & & PCKEN13: UART2/3& &实测此位才是UART1时钟使能(stm8s103f3)
&&//& & & & PCKEN14: TIM4& &
&&//& & & & PCKEN15: TIM2
&&//& & & & PCKEN16: TIM3
&&//& & & & PCKEN17: TIM1
&&CLK_PCKENR1 = b;& & //使能TIM1,TIM4,UART1 时钟
&&//外设时钟控制寄存器 CLK_PCKENR2
&&//& & & & CLK_PCKENR2 = 0x00;& & & & //复位值为0xff,即默认为开启状态
&&//& & & & PCKEN20: Reserved
&&//& & & & PCKEN21: Reserved
&&//& & & & PCKEN22: AWU
&&//& & & & PCKEN23: ADC
&&//& & & & PCKEN24: Reserved
&&//& & & & PCKEN25: Reserved
&&//& & & & PCKEN26: Reserved
&&//& & & & PCKEN27: CAN
&&CLK_PCKENR2 = b;&&//使能 ADC 时钟,
&&//LK_CSSR_CSSEN = 1;& & & & & & & && &//使能时钟监控功能,外间时钟出问题时切换到内部时钟源HSI/8& &CLK_CSSR中的CSSD位被置位
&&//LK_CCOR = ;& & & & & & & & & & & && && && &//时钟输出寄存器
}
void Peripherals_Config(void)
{
&&GPIO_Config();
&&TIM1_PWM_Config();
&&TIM4_Config();
&&UART1_Config();
&&ADC_Config();
&&IWDG_Config();
&&WWDG_Config();
&&IT_Config();&&//中断相关配置
}
static void IWDG_Config(void)
{
&&IWDG_KR&&= 0x55;& && &&&//关写保护
&&IWDG_PR&&= 0x00;& && &&&//预分频系数4& &0-6对应&&4 8 16 32 64 128 256 分频
&&IWDG_RLR = 0xFF;& && &&&//最长超时15.90 ms
&&IWDG_KR&&= 0xAA;& && &&&//恢复写保护,同时相关于清狗指令-&用IWDG_RLR的数值刷新计数器的内容,避免了产生看门狗的复位
& && && && && && && && &&&//其实以上看门狗配置均为上电复位值
&&IWDG_KR&&= 0xCC;& && &&&//启动独立看门狗
&&IWDG_KR&&= 0xAA;& && &&&//清狗
}
static void WWDG_Config(void)
{
&&WWDG_WR = 0x7f;
&&WWDG_CR = (uint8_t)(0x80 | WWDG_COUNTER_INIT);
&&WWDG_WR = (uint8_t)((uint8_t)(~0x80) & (uint8_t)(0x40 | WWDG_WINDOW_VALUE));
}
static void GPIO_Config(void)
{
&&PA_ODR = b;& && && &&&//初始化输出低电平
&&PA_DDR = b;& && && &&&// 1=output
&&PA_CR1 = b;& && && &&&//1=上拉输入或推挽输出&&0=浮空输入或开漏输出& & ADC时应选浮空输入,无中断
&&PA_CR2 = b;& && && &&&//1=使能外部中断或10M输出&&0=禁止外部中断或2M输出&&中断边沿在EXTI_CRX中设置
&&PB_ODR = b;& && && &&&//初始化输出低电平
&&PB_DDR = b;& && && &&&// 1=output& & & & & & & && && & & && & PB4 INPUT
&&PB_CR1 = b;& && && &&&//1=上拉输入或推挽输出&&0=浮空输入或开漏输出& & ADC时应选浮空输入,无中断
&&PB_CR2 = b;& && && &&&//1=使能外部中断或10M输出&&0=禁止外部中断或2M输出&&中断边沿在EXTI_CRX中设置
&&PC_ODR = b;& && && &&&//初始化输出电平
&&PC_DDR = b;& && && &&&// 1=output& & & && & PC4 INPUT
&&PC_CR1 = b;& && && &&&//1=上拉输入或推挽输出&&0=浮空输入或开漏输出& & ADC时应选浮空输入,无中断
&&PC_CR2 = b;& && && &&&//1=使能外部中断或10M输出&&0=禁止外部中断或2M输出&&中断边沿在EXTI_CRX中设置
&&//& & & & 如果硬件上没有连接RST脚,则SWIM引脚(PD1)不能配置为输出口,否则不能连上ST-LINK
&&PD_ODR = b;& && && &&&//初始化输出低电平&&PD5=TX初始化输出高电平,PD6=RX配置为输入
&&PD_DDR = b;& && && &&&// 1=output 0=input PD2=AIN3 PD3=AIN4
&&PD_CR1 = b;& && && &&&//1=上拉输入或推挽输出&&0=浮空输入或开漏输出& & ADC时应选浮空输入,无中断
&&PD_CR2 = b;& && && &&&//1=使能外部中断或10M输出&&0=禁止外部中断或2M输出&&中断边沿在EXTI_CRX中设置
& & & & & & & & & & & & //PD4作为下降沿中断测试输入引脚,配置为上拉输入
& & & &
&&PE_ODR = b;& && && &&&//初始化输出低电平
&&PE_DDR = b;& && && &&&// 1=output
&&PE_CR1 = b;& && && &&&//1=上拉输入或推挽输出&&0=浮空输入或开漏输出& & ADC时应选浮空输入,无中断
&&PE_CR2 = b;& && && &&&//1=使能外部中断或10M输出&&0=禁止外部中断或2M输出&&中断边沿在EXTI_CRX中设置
}
static void TIM1_PWM_Config(void)
{
&&//须要在选项字节中配置使能对应的PWM功能管脚,同时开启对应的时钟
&&TIM1_PSCRH = 0x00;& &//预分频器& &16bit&&fCK_CNT = fCK_PSC / (PSCR[15:0] + 1)
&&TIM1_PSCRL = 0x00;
&&TIM1_ARRH = (uint8_t)((800 - 1) && 8); //自动重载值 16bit&&即周期寄存器 16M/800=20K
&&TIM1_ARRL = (uint8_t)((800 - 1));& && &
&&//TIM1_CR1
//TIM1_CR1_bit.CEN&&= 1;&&//CEN:允许计数,最后再开启
&&TIM1_CR1_bit.UDIS = 0;&&//UDIS:禁止更新
&&TIM1_CR1_bit.URS&&= 0;&&//URS:更新请求源
&&TIM1_CR1_bit.OPM&&= 0;&&//0:在发生更新事件时,计数器不停止;
&&TIM1_CR1_bit.DIR&&= 0;&&//0:计数器向上计数;
&&TIM1_CR1_bit.CMS&&= 0;&&//00:边沿对齐模式。计数器依据方向位(DIR)向上或向下计数。
&&TIM1_CR1_bit.ARPE = 1;&&//1:TIM1_ARR寄存器由预装载缓冲器缓冲。
&&TIM1_EGR_bit.UG& &= 1;&&//产生一次更新事件,更新分频系数与TIMx_CNTR
&&TIM1_RCR&&= 0x00; //重复计数寄存器,即Reload事件发生了多少次:TIM1_RCR+1
& && && && && && &&&//这意味着在PWM模式中,(TIM1_RCR+1)对应着:
& && && && && && &&&//- 在边沿对齐模式下,PWM周期的数目;
& && && && && && &&&//- 在中心对称模式下,PWM半周期的数目;
&&//&&通道1;
&&TIM1_CCMR1_bit.CC1S&&= 0;& &//CC1S[1:0]:捕获/比较1 选择
&&TIM1_CCMR1_bit.OC1FE = 0;& &//OC1FE:输出比较1 快速使能
&&TIM1_CCMR1_bit.OC1PE = 1;& &//OC1PE:输出比较1预装载使能
&&TIM1_CCMR1_bit.OC1M&&= 7;& &//110:PWM模式1,111:模式2
&&TIM1_CCMR1_bit.OC1CE = 0;& &//0:OC1REF 不受ETRF输入(来自TIM1_TRIG引脚)的影响;&&1:一旦检测到ETRF输入高电平,OC1REF=0。
&&TIM1_CCER1_bit.CC1E&&= 1;& &//1=输出使能
&&TIM1_CCER1_bit.CC1P&&= 0;& &//0=高电平有效 P
&&TIM1_CCER1_bit.CC1NE = 1;& &//1=输出使能& & & & --
&&TIM1_CCER1_bit.CC1NP = 0;& &//0=高电平有效--互补输出&&N
&&TIM1_CCR1H = 0x00;
&&TIM1_CCR1L = 0x00;& && & & & & & & & & & & & & & & & //占空比寄存器,CH1
&&//&&通道2;
&&TIM1_CCMR2_bit.CC2S&&= 0;& &//CC1S[1:0]:捕获/比较1 选择
&&TIM1_CCMR2_bit.OC2FE = 0;& &//OC1FE:输出比较1 快速使能
&&TIM1_CCMR2_bit.OC2PE = 1;& &//OC1PE:输出比较1预装载使能
&&TIM1_CCMR2_bit.OC2M&&= 7;& &//110:PWM模式1,111:模式2
&&TIM1_CCMR2_bit.OC2CE = 0;& &//0:OC1REF 不受ETRF输入(来自TIM1_TRIG引脚)的影响;&&1:一旦检测到ETRF输入高电平,OC1REF=0。
&&TIM1_CCER1_bit.CC2E&&= 1;& &//1=输出使能
&&TIM1_CCER1_bit.CC2P&&= 0;& &//0=高电平有效 P& &
&&TIM1_CCER1_bit.CC2NE = 1;& &//1=输出使能& & & & --& && && && && && && && && && &//& && && && && && && && && &
&&TIM1_CCER1_bit.CC2NP = 0;& &//0=高电平有效--互补输出&&N
&&TIM1_CCR2H = 0x00;
&&TIM1_CCR2L = 0x00;& && & & & & & & & & & & & & & & & //占空比寄存器,CH2
&&//& & & & TIM1_CR2 = ;
&&//& & & & TIM1_SMCR = ;& & & & 从模式控制寄存器
&&//& & & & TIM1_ETR = ;& & & & 外部触发寄存器
&&//TIM1_IER 中断使能寄存器
&&TIM1_IER_bit.UIE& &= 1; //更新中断
&&TIM1_IER_bit.CC1IE = 0; //捕获/比较1中断
&&TIM1_IER_bit.CC2IE = 0; //捕获/比较2中断
&&TIM1_IER_bit.CC3IE = 0; //捕获/比较3中断
&&TIM1_IER_bit.CC4IE = 0; //捕获/比较4中断
&&TIM1_IE = 0; //COM中断& && && && && && && && &&&
&&TIM1_IER_bit.TIE& &= 0; //触发中断
&&TIM1_IER_bit.BIE& &= 0; //刹车中断
&&//& & & & TIM1_SR1 = ;& & & & 状态寄存器 1
&&//& & & & TIM1_SR2 = ;& & & & 状态寄存器 2
&&//& & & & TIM1_EGR = ;& & & & 事件产生寄存器
&&//刹车寄存器
&&TIM1_BKR_bit.MOE&&= 1;&&//1:如果设置了相应的使能位(TIM1_CCERX寄存器的CCIE位),则使能OC和OCN输出
&&TIM1_CR1_bit.CEN&&= 1;&&//CEN:允许计数
}
/**
&&* @brief&&Configure TIM2 to generate an update interrupt each 0.5ms
&&* @param&&None
&&* @retval None
&&*/
void TIM4_Config(void)
{
&&//IM4_PSCR_bit.PSC = 7; //分频值: 2^PSC[2:0]&&定时器时钟源为内部时钟(fMASTER)。& &(1/16M)*128=8us
&&//IM4_ARR& && &= 124;& & & & & & & & //自动重载值& & (124+1)*8us=1ms
&&TIM4_PSCR_bit.PSC = 4;&&//分频值: 2^PSC[2:0] & & & & 1/16M)*2^4=1us
&&TIM4_ARR& && &= 99;& &&&//自动重载值&&& & & & (99+1)us
&&TIM4_EGR_bit.UG& &= 1;&&//产生一次更新事件,更新分频系数与TIM4_CNTR
&&TIM4_CR1_bit.ARPE = 1;&&//1:TIM4_ARR寄存器通过缓冲预装载
&&TIM4_SR_bit.UIF& &= 0;&&//TIM4 溢出中断标志
&&TIM4_IER_bit.UIE&&= 1;&&//使能TIM4 溢出中断
&&TIM4_CR1_bit.CEN&&= 1;&&//使能TIM4
}
/**
&&* @brief&&UART1 Configuration for interrupt communication
&&* @param&&None
&&* @retval None
&&*/
//
static void UART1_Config(void)
{
&&WORD_UNION UART1_BRR;
&&UART1_CR1_bit.PIEN&&= 0; //校验中断使能&&0:中断被禁止& &1:当USART_SR中的PE为1时,产生USART中断
&&UART1_CR1_bit.PS& & = 0; //0:偶校验。 1:奇校验
&&UART1_CR1_bit.PCEN&&= 0; //1:奇偶校验控制被使能
&&UART1_CR1_bit.WAKE&&= 0; //唤醒方法
&&UART1_CR1_bit.M& &&&= 0; //8bit数据格式
&&UART1_CR1_bit.UART0 = 0; //0:UART使能&&1:UART预分频器和输出禁用
&&UART1_CR1_bit.T8& & = 0; //9bit数据格式 下的发送数据位8
&&UART1_CR1_bit.R8& & = 0; //9bit数据格式 下的接收数据位8
&&UART1_CR3_bit.STOP = 0; //00:1个停止位;01:保留 10:2个停止位;11:1.5个停止位;
&&UART1_BRR.all = 1666;& &//16M/& & & &&&
&&//UART1_BRR2=UART_DIV[15:12]高4位&&UART_DIV[3:0]低4位&&
& & & & UART1_BRR2&&= UART1_BRR.byte.H & 0xf0;
&&UART1_BRR2 |= UART1_BRR.byte.L & 0x0f;
& && && && && &
&&//UART1_BRR1=UART_DIV[11:4]& &
&&UART1_BRR1 = (uint8_t)(UART1_BRR.all&&4); //中间8位
//UART1_CR2_bit.SBK&&= 1;& & & & //SBK: 发送断开帧
//UART1_CR2_bit.RWU&&= 1;& & & & //RWU: 接收唤醒
&&UART1_CR2_bit.REN&&= 1; //接收使能
&&UART1_CR2_bit.TEN&&= 1; //发送使能
//UART1_CR2_bit.ILIEN= 1;& & & & //ILIEN: IDLE中断使能
&&UART1_CR2_bit.RIEN = 1; //接收中断使能&&1:当USART_SR中的OR或者RXNE为1时,产生USART中断。
//UART1_CR2_bit.TCIEN= 1;& & & & //发送完成中断使能 1:当USART_SR中的TC为1时,产生USART中断。要发送时再使能中断(会立即产生中断)
//UART1_CR2_bit.TIEN = 1;& & & & //发送中断使能&&1:当USART_SR中的TXE为1时,产生USART中断。
//UART1_SR_bit.TC &= 0;& & & && &//读该位来清零
//UART1_DR = 0& & & & & & & && &&&//写入要发送的数据
}
/**
&&* @brief&&Configure ADC&&
&&*& && && &
&&* @param&&None
&&* @retval None
&&*/
static void ADC_Config(void)
{
&&//& & & & 当作为模拟输入时可以关闭输入施密特触发器来降低功耗
&&ADC_TDRH = b;& && & //1=ADC输入禁止施密特触发 ***********ADC时应选浮空输入,无中断
&&ADC_TDRL = b;& && & //共16通道& &AIN3-AIN4
&&ADC_CR1_bit.ADON&&= 0;& && &//ADON:&&A/D 转换开/关
&&ADC_CR1_bit.CONT&&= 0;& && &// 0:单次转换模式&&1:连续转换模式
&&ADC_CR1_bit.SPSEL = 0;& && &// 预分频选择位 000-&111对应 2 3 4 6 8 10 12 18分频
//ADC_CR2_bit.SCAN& & = 1;& & & && &//1:使能扫描模式 0:不使能扫描模式
&&ADC_CR2_bit.ALIGN& &= 1;& & //1:数据右对齐。(低8字节在ADC_DRL寄存器,其余高字节位在ADC_DRH寄存器)读顺序
& && && && && && && && && && &//应先读低位,再读高位字节或整个一起读
&&ADC_CR2_bit.EXTSEL&&= 0;& & //外部事件触发和启动ADC& &00:内部定时器1&&TRG事件&&01:ADC_ETR&&引脚上的外部中断 其它值保留
&&ADC_CR2_bit.EXTTRIG = 0;& & //EXTTRIG:&&外触发使能位
& && && && && && && && &&&
//ADC_CR3_bit.OVR&&= 0;& & & & & & & && &&&//1:数据缓存发生了数据溢出事件
&&ADC_CR3_bit.DBUF = 0;& && & //1:数据缓存功能使能,扫描模式时使用.& && && && && && && && &&&
&&ADC_CSR_bit.CH& & = 4;& && &// CH[3:0] : 选择转换通道& & 或指定从AN0到ANx扫描转换
//ADC_CSR_bit.AWDIE = 0;& & & & & & & && &//1: 使能AWD模拟看门狗中断
//ADC_CSR_bit.EOCIE = 1;& & & & & & & && &//1:使能转换结束中断
//ADC_CSR_bit.AWD& &= 0;& & & & & & & && &//AWD:&&模拟看门狗标志
&&ADC_CSR_bit.EOC& &= 0;& && &//EOC:&&转换结束& && && && && && && && && && &
& && && && && && && && && && &
&&ADC_CR1_bit.ADON = 1;& && &&&//第一次置1将把ADC从低功耗模式下唤醒,之后才是启动ADC
//ADC_DBxRH& & & & 缓冲寄存器
//ADC_DBxRL
//ADC_DRL & & & & 数据寄存器
//ADC_DRH
}
void IT_Config(void)
{
//&&中断配置------------------------------------------
//ITC_SPR3_bit.VECT11SPR = 0;//Timer1最低优先级,
//ITC_SPR4_bit.VECT15SPR = 0;//Timer3最低优先级,
//ITC_SPR6_bit.VECT21SPR = 0;& & & & //UART1/3接收满 最低优先级
//ITC_SPR6_bit.VECT22SPR = 2; //adc中断为最高优先级
//ITC_SPR6_bit.VECT23SPR = 0;& & & & //Timer4最低优先级,2为最高,3为禁止优先级(复位默认值)&&
//EXTI_CR1:外部中断控制寄存器1&&设置何种边沿触发
&&EXTI_CR1_bit.PAIS = 0;//[1:0] 00:下降沿和低电平触发
&&EXTI_CR1_bit.PBIS = 0;//[3:2] 01:仅上升沿触发
&&EXTI_CR1_bit.PCIS = 0;//[5:4] 10:仅下降沿触发
&&EXTI_CR1_bit.PDIS = 2;//[7:6] 11:上升沿和下降沿触发
//EXTI_CR2;
&&EXTI_CR2_bit.PEIS = 0;//[1:0] GPIOE,配置同EXTI_CR1
& && && && && && && && &
&&EXTI_CR2_bit.TLIS = 0;//[2] TLI 0:下降沿触发 , 1:上升沿触发
}复制代码同时更正了寄存器版本UART发送时的一个bug,i++应该是在给发送寄存器赋值之后才能执行;否则可能会出现少发送数据的情况,附件及修正部分代码如下
& & for (i = 0; i & u8DataS )//i++)& & & & & & & & & & & & & & & & & & & & //应该是在UART1-&DR=x 后才能执行i++
& & {
& && &if(UART1_GetFlagStatus(UART1_FLAG_TXE) == SET)
& && &{
& & & & & & & & //UART1-&DR = s_u8TxBuffer[i];& & & & & & & &
& & & & & & & & UART1-&DR = s_u8TxBuffer[i++];& & & & & & & & & & & & & & & & & & & & //在此执行i++
& & & & & & & & //UART1_ITConfig(UART1_IT_TXE, ENABLE);
& & & & & & & & SCHCurTaskDly(1 / SCH_SYS_TICKS_MS);& & & & & & & & //延时发送1个字节所须要的时间& & & & & & & & & & & & & & & & & & & & & & & &
& & & & }
& & & & else
& & & & {
& & & && && && &SCHCurTaskDly(0 / SCH_SYS_TICKS_MS);& & & & & & & & //无延时,下次直接进来查询
& & & & }
& & }复制代码如果大家有兴趣,后续我可以出stm32版本的.
本帖子中包含更多资源
才可以下载或查看,没有帐号?
本帖最后由 summarize 于
23:48 编辑
今天下午和SOME PLMM爬山去了,回来心情大好,决定把STM32版本的也搞定(之前已经完成一部分).回来吃饭洗澡后就一直奋斗...直到...
STM32版本终于搞好了,本例是STM32F103C8T6,该死的看门狗在断点时还工作,导致复位(stm8s可不会这样),害我搞得这么晚才搞定.见附件!用到的资源和stm8s的一样,即UART和ADC,同时还配置好了TIM1/2/3,但只启用TIM1,TIM2/3可自行开启.后续再加入8051就停止了(如果响应好再添加PIC和NEC的,富士通和台系的就算了开发工具太麻烦不好验证).
-----------------------------------------------------------------------------
编辑原因:加入私生活^_^
本帖子中包含更多资源
才可以下载或查看,没有帐号?
本帖最后由 summarize 于
21:36 编辑
yj_yulin 发表于
期待8051尽快出来,不过lz要是希望推广还是得有个学习文档才好,人们只有理解了为什么要这样,有如此等等好处, ...
前天下的单(STC89C52单片机最小系统板),今天中午就到了,还挺快;
多年不用51,但使用的还是IAR环境,还算顺利,终于搞定了.附件如下
补充:本来是想省事,买了个带开关的最小系统板(因为STC的单片机ISP下载要冷重启),谁知买到手的板子的开关却是坏的,算了,赶时间不计较了,自己上网找找关于免重启的资料(以前做过,但现在已经找不到了),把免重启的代码加进去,OK,终于不用老拔线了.使用方法见下图,
重点是在 程序文件-&自定义下载-&选择波特率9600并填上自定义命令 0x55 0xa5 0然后点击右边的发送按键即可.
免重启核心代码:& & //加入此段代码,即在收到约定命令时,重启单片机,免重新上电即可下载
& & if((pDataBuffer[u8DataSize-3]==0x55)
& && & &&(pDataBuffer[u8DataSize-2]==0xa5)
& && & &(pDataBuffer[u8DataSize-1]==0xaa))
& & {
& && &SCHCurTaskDly(100 / SCH_SYS_TICKS_MS);&&//delay 100ms& && && && && && &&&
& && &ISP_CONTR = 0x60;& &//软复位进入ISP下载模式
& & }复制代码//代码在串口接收处理函数中
再啰嗦几句,之前的STM8S/32的调度节拍都是1ms,即延时时间是1ms的倍数,而51单片机比较慢,如果还是1ms则会出现异常(具体就不去研究了),实测2ms以上才OK,留点余量外加个人喜好就改为10ms了.
再者之前的STM8S/3只开串口接收中断,而51单片机的串口接收,发送中断是一起的,一开两个都开了,所以串口的发送也改为中断发送了.
还有调度器节拍的定时器0使用的是模式2(自动重载模式),使用此模式是因为我既想获得精确的时间节拍,但又不想去计算进入中断所用时间及向TH0,TL0赋值所用时间再去计算出真正TH0,TL0的初值.
下一步开始写使用说明文档.
本帖子中包含更多资源
才可以下载或查看,没有帐号?
本帖最后由 summarize 于
01:46 编辑
soosqt 发表于
支持楼主,强列希望出个PIC版本
使用说明文档已经出来了:
自制类OS调试器应用与说明
一、调度器功能说明。
本调度器是集时间触发、支持消息、支持非抢占优先级调度,借鉴了protothread思想,而使得其实现与使用类似于OS的调度器(仿ucos),所以暂时叫类OS调度器吧。
1.& &&&时间触发:即任务可以定时执行,如每间隔一定时间执行一次,应用如定时采样、LED闪烁等,而且此间隔在任务执行过程中是可以修改的。2.& &&&支持消息:即任务除了定时执行方式外,还可以等待消息到了才执行,应用如串口接收处理,即等串口接收完一帧数据后,发消息通知处理任务去处理这些数据。每次只发送一个消息时,也可以当邮箱来用。3.& &&&支持非抢占优先级:任务创建的顺序就是优先级顺序(由高到低)。一般调度器都是所以任务顺序执行,那么所以任务执行一圈的时间有时也是比较长的,如5ms,当有一个任务的实时性要求较高,如2ms内必须响应,那么顺序式调度器就不能满足要求了,而我们的非抢占优先级调度就发挥作用了,因为它是每个任务执行完后都会重新查找下一个就绪的最高优先级任务并执行。这个任务的最快响应时间就由执行时间最长的那个任务决定,如执行时间最长的任务的时间为1.5ms,能满足要求。4.& &&&类OS:因为借鉴了protothread思想,使得其实现与使用类似于OS,同时在实现与风格也仿照了ucos,所以对于熟悉OS的朋友,用起来就更顺心了。而且它也可以作为学习OS的前奏。5.& &&&全C语言实现,移植方便,只须一个硬件定时器为其提供调度节拍的“心跳”即可。二、调度器的移植与应用。
1.& &&&下载调度器相关文件,并包含到自己的工程中下载最新版本的“Schedule V1.01.rar”;网址:
解压后“Schedule”文件夹下有“sch_cfg.h”、“schedule.h”、“schedule.c”(后两个已经设置为只读属性文件);
将这三个文件复制到自己的工程目录下,在工程的main函数中包含“sch_cfg.h”,此头文件会自动包含“schedule.h”。
2.& &&&配置”sch_cfg.h”文件”sch_cfg.h”内有三个地方可配置,如下:
#define SCH_SYS_TICKS_MS& && && && &&&1& && &//定义调度系统时钟节拍时间(ms)
#define SCH_HW_TIM_MS& && &&&0.1& &//硬件定时器中断(溢出)周期(ms)
#define SCH_CFG_Q_EN& && &&&1u&&//任务内建消息使能
第①个为定义调度系统时钟节拍时间,单位是ms,一般配置为1~10ms即可,对于执行速度快的单片机选如stm8s、avr等配置1ms,传统的51单片机速度慢的选5ms以上比较好,实在不懂就选个10ms吧。
第②个为硬件定时器中断(溢出)周期,单位也是ms,调度器的时间节拍是基于硬件定时器的,所以最少要有一个硬件定时器并开启中断,还要注意硬件定时的周期必须小于等于调度器的节拍时间,这个硬件定时器的周期也是要根据单片机的执行速度和自己的应用系统要求来定,与调度节拍类似,对于执行速度快的单片机选如stm8s、avr等配置0.1ms,传统的51单片机速度慢的选0.5ms以上比较好,实在不懂就选个1ms。
第③个为任务内建消息使能选项,根据须要使能或禁止。如果使能,则每个任务控制块会增加如下内容:
#if SCH_CFG_Q_EN & 0u
&&void& && && &*pD& && & //消息指针
&&SCH_UINT8& && && && && && &S& && && &//消息的大小
如果是比较简单的系统,不须要用到消息传递功能,则可关闭此功能。以节省内存空间。
3.& &&&硬件定时器中断中增加调度器节拍函数调度器的时间节拍是基于系统硬件定时器的,因为它们之间得有“联系”才行,通过在定时器中断中增加宏“SchedTicksInc()”即可。
4.& &&&定义任务控制块(TCB)调度器管理的对像是任务控制块,所以要为每个任务定义自己的任务控制块。
如我们要建立一个vTestTask,则除了编写vTestTask任务函数外,还要定义它的任务控制块TestTaskTcb,定义格式为:SCH_TCB& &TestTaskT按此方法,我们可以编写更多的任务vTestTaskN,并定义好它的任务控制块 TestTaskNTcb。
5.& &&&创建任务任务编写完全并定义好它的控制块后,就可以创建任务了, 创建任务的顺序就是任务优先级的顺序,由高到低。创建任务的例子如下:
SCHTaskCreate(&TestTaskTcb, vTestTask);& &//创建任务vTestT
SCHTaskCreate(&TestTaskNTcb, vTestTaskN); //创建任务vTestTaskN;
6.& &&&启动调度器。任务创建好后,即可启动调度器,调用启动调度器函数:SCHTaskSchedStart();
7.& &&&使用例子。
以上所说的都是只针对调度器而言,对于一个完整的系统,main函数至少应该包含如下部分:
Void main()
& & disable_interrupt();&&//关全局中断
Peripherals_Config();//硬件系统初始化,必须至少包含一个硬件定时器
SCHTaskCreate(&TestTaskTcb, vTestTask);//至少创建一个任务
enable_interrupt();&&//开全局中断
SCHTaskSchedStart();//启动调度器,永不返回。
定时执行任务例子,每500ms执行一次Fun函数。
void vTestTask (void)
Static unsigned char s_u8V//定义变量,注意任务内应定义为静态变量
&&SCHTaskBegin();&&//任务实体内容开始,必须有的固定语句。
& && && &while(1)&&//每个任务内都要有一个死循环。同时还要有一个挂起任务的操//如延时或等待消息。同时注意不能使用switch语句,但可在调用函数内使用
& & UserFun ();& && & //可以是语句或函数,调用的函数内部可使用局部变量
& & SCHCurTaskDly(500 / SCH_SYS_TICKS_MS);//delay500ms,根据须要调整时间
&&SCHTaskEnd();& &//任务实体内容结束,必须有的固定语句。
等待消息到来再执行的例子,如等待串口接收中断发来消息:
void vUartReceiveData(void)
static uint8_t s_u8RxBuffer[UART_RX_BUF_SIZE];
static uint8_t s_u8RxC
static uint8_t *pDataBuffer, u8DataS
SCHTaskBegin();
&&while(1)
& &SCHTaskQpend();& && && &&&//任务等待接收中断发来消息
& &pDataBuffer = (uint8_t *)UartRxTcb.pD
& &u8DataSize&&= UartRxTcb.S
& & for(s_u8RxCounter = 0; s_u8RxCounter & u8DataS s_u8RxCounter++)
& && && && & s_u8RxBuffer[s_u8RxCounter] =(*pDataBuffer) + 0x11; & &&&pDataBuffer++;
& & for(u8DataSize = 0; u8DataSize & 255; u8DataSize++)&&//借用u8DataSize
{ //检查UART_TX发送任务队列是否可用& && && && &&&if (SCHTaskGetQFree(&UartTxTcb) ==SCH_Q_FREE)& && && && &{
& && & SCHTaskQpost(&UartTxTcb,
& && && && && && && &&s_u8RxBuffer[0],
& && && && && && && &s_u8RxCounter); //将接收的的数据+0x11后发回去
& && & SCHCurTaskDly(1 / SCH_SYS_TICKS_MS); //delay 1ms
SCHTaskEnd();
串口接收中断中接收完一帧数据后向其发送消息:
SCHTaskQpost(&UartRxTcb,//接收处理函数的TCB地址& && && && && && && &&s_u8IsrRxBuffer[0,//串口接收缓冲区首地址& && && && && && && &s_u8IsrRxCounter);& &//接收数据大小(字节)
三、调度器任务控制块及各函数说明。
1.“schedule.h”文件下:
& && &①任务控制块:struct SchTcb{#if SCH_CFG_Q_EN & 0u&&void& && && & *pD& && & //消息指针&&SCH_UINT8& &&&S& && && &//消息的大小#endif &&SCH_DLY_TYPE& && &TimeC&&//定时计数器,时基为 &SCH_SYS_TICKS_MS&&&void& && && & (*pTask)();& &//任务指针&&struct SchTcb *pNextTCB;& & //下一个任务控制块指针}; & &&&②“SchedTicksInc()”,此为调度器节拍计数器递增函数,在硬件定时器中调用。& &&&③“SCHTaskBegin()”,此为固定使用函数,放在任务的开始处(变量定义后)。& &&& ④“SCHTaskEnd()”,此为固定使用函数,放在任务的结尾处。& &&&⑤“SCHCurTaskPend()”, 挂起(暂停)当前任务,即任务自身。
⑥“SCHCurTaskDly(Ticks)”,当前任务延时Ticks个时间节拍。
& && &&&⑦“SCHTaskCallSub(SubTaskName)”,任务内调用子任务,子任务格式与主任务相同。
⑧“SCHTaskQpend()”,当前任务等待消息(到来后才往下执行)。
2.“schedule.c”文件下:
①“void SCHTaskQpost(SCH_TCB& &*pPostTCB,& && && && && && && & void& && &*pData,& && && && && && && &SCH_UINT8 Size)”,此为释放(发送)消息函数,“pPostTCB”指向要接收消息的任务的任务控制块;“pData”指向消息的首地址;“Size”为消息的大小(字节为单位)。 ②“SCH_UINT8 SCHTaskGetQFree(SCH_TCB& &*pTaskTCB)”,此为查询任务消息状态,是否是自由(可用)或忙(不可用),调用SCHTaskQpend()时会将其设置为自由(可用)状态。“pTaskTCB”指向要查询的任务的任务控制块。返回值是“SCH_Q_FREE”或“SCH_Q_BUSY”,即可用或不可用。 ③“void SCHTaskCreate(SCH_TCB& && && &&&*pNewTCB,& && && && && && && & void& && && && &&&(*pNewTask)(void))”,此为创建任务函数,“pNewTCB”指向要创建的任务的任务控制块,“pNewTask”为要创建任务的首地址(或叫函数名)。 & & ④“void SCHTaskSchedStart(void)”,此为启动调度器函数,调用后,则开始进行任务调度,每个任务结束后都会重新查找就绪的最高优先级任务并运行,此函数永不返回。& & ⑤“void SCHTimeTick(void)”,此为任务节拍处理函数,每个调度节拍到来时,将任务的节拍延时计数器减1(如果其值大于0),由“SCHTaskSchedStart()”函数调用。 Stm32/8和8051的工程模板见帖子:
但要注意工程模板那里的调度器并不是最新版本,下载后请自行更新为最新版本。
& && && && && && && && && && &
& && && && && && && && && && && && && && && && && && && && &
本帖子中包含更多资源
才可以下载或查看,没有帐号?
word文档复制过来格式有点不好阅读,大家还是看PDF比较舒服些。
同时如果可以,请版主帮忙更新到LZ位,方便大家。
最新调度器版本如下:
本帖子中包含更多资源
才可以下载或查看,没有帐号?
word文档复制过来格式有点不好阅读,大家还是看PDF比较舒服些。
同时如果可以,请版主帮忙更新到LZ位,方便 ...
鉴于C语言中建议尽量不使用&goto&语句,现将“SCHTaskSchedStart()”函数中的“goto”语句去掉,用&if else&逻辑来实现。同时将版本升级为V1.02
修改细节为将如下函数
void SCHTaskSchedStart(void)
{
SCHED_SART:
& & & &
&&pCurTCB = pFirstTCB;& && && && && && && && &//指向第一个创建的任务,之后按创建时的顺序执行下去
&&while (1)& && && && && && && && && && && &&&//环形链表,可以一直循环下去
&&{
& & SCHTimeTick();& && && && && && && && && & //如果任务Tick满足条件,则将其置于可执行状态
& & if (SCH_TASK_RUN == pCurTCB-&TimeCounter) //任务处于可执行状态
& & {
& && &pCurTCB-&TimeCounter = SCH_TASK_PEND;& &//设置为挂起状态,保证任务只执行一次
& && &pCurTCB-&pTask();& && && && && && && &&&//执行当前任务控制块指向的任务
& && &goto SCHED_SART;& && && && && && && && &//每执行完一个任务,都重新查找一次可执行最高优先级任务
& & }
& & pCurTCB = pCurTCB-&pNextTCB;& && && && &&&//指向下一个任务控制块,查找下个任务是否可执行
&&}
}复制代码
void SCHTaskSchedStart(void)
{
&&pCurTCB = pFirstTCB;& && && && && && && && &//指向第一个创建的任务,之后按创建时的顺序执行下去
&&while (1)& && && && && && && && && && && &&&//环形链表,可以一直循环下去
&&{
& & SCHTimeTick();& && && && && && && && && & //如果任务Tick满足条件,则将其置于可执行状态
& & if (SCH_TASK_RUN == pCurTCB-&TimeCounter) //任务处于可执行状态
& & {
& && &pCurTCB-&TimeCounter = SCH_TASK_PEND;& &//设置为挂起状态,保证任务只执行一次
& && &pCurTCB-&pTask();& && && && && && && &&&//执行当前任务控制块指向的任务
& && &pCurTCB = pFirstTCB;& && && && && && &&&//每执行完一个任务,都回到起点重新查找一次可执行最高优先级任务
& & }
& & else
& & {
& & & & & & pCurTCB = pCurTCB-&pNextTCB;& && && && &//指向下一个任务控制块,查找下个任务是否可执行
& & }
&&}
}复制代码
本帖子中包含更多资源
才可以下载或查看,没有帐号?
我想我也说不明白的,C太弱了!
第一个:就是Ke编译il有警告,同时串口不稳定,经常不能自动发命令IAP,&&...
最新版本调度器V2.0的51单片机KEIL版本出来了。
还没下载 不过从描述上看还是不错的 支持
为了方便大家,接着把UART_TX模块的资源共享相关部分贴出来,分别是UART_RX_ISR,UART接收处理任务,UART发送处理任务和ADC转换结果上传PC任务.
1.UART_RX_ISR: 串口接收中断.INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
&&/* In order to detect unexpected events during development,
& &&&it is recommended to set a breakpoint on the following instruction.
&&*/
&&static uint8_t s_u8IsrRxBuffer[UART_ISR_RX_BUF_SIZE];
&&static uint8_t s_u8IsrRxC
&&s_u8IsrRxBuffer[s_u8IsrRxCounter] = UART1_ReceiveData8();
&&if (s_u8IsrRxBuffer[s_u8IsrRxCounter] == 0xaa) //for test
&&{
& & s_u8IsrRxCounter++;
& & if (SCHTaskGetQFree(&UartRxTcb) == SCH_Q_FREE)
& & {
& && &SCHTaskQpost(&UartRxTcb,
& && && && && && & &s_u8IsrRxBuffer[0],
& && && && && && & s_u8IsrRxCounter);
& & }
& & else
& & {
& && &//出错处理
& & }
& & s_u8IsrRxCounter = 0;
&&}
&&else
&&{
& & s_u8IsrRxCounter++;
&&}
&&if (s_u8IsrRxCounter & UART_RX_BUF_SIZE)
&&{
& & s_u8IsrRxCounter = 0;
& & //溢出出错处理
&&}
&&UART1_ClearFlag(UART1_FLAG_RXNE);
}复制代码2.UART接收处理任务: 将接收到的数据+0x11后交给UART_TX发送到PC.void vUartReceiveData(void)
{
&&static uint8_t s_u8RxBuffer[UART_RX_BUF_SIZE];
&&static uint8_t s_u8RxC
&&static uint8_t *pDataBuffer, u8DataS
&&SCHTaskBegin();
&&while (1)
&&{
& & SCHTaskQpend();& && && &&&//任务等待接收中断发来消息
& & pDataBuffer = (uint8_t *)UartRxTcb.pD
& & u8DataSize&&= UartRxTcb.S
& & if (u8DataSize & UART_RX_BUF_SIZE)
& & {
& && &u8DataSize = UART_RX_BUF_SIZE;
& && &//出错处理
& & }
& & for (s_u8RxCounter = 0; s_u8RxCounter & u8DataS s_u8RxCounter++)
& & {
& && &s_u8RxBuffer[s_u8RxCounter] = (*pDataBuffer) + 0x11; //copy to s_u8TxBuffer (add 0x11)
& && &pDataBuffer++;
& & }
& & //使用如下类似方法便可与其它任务共享UART_TX资源,即任务要使用UART_TX前先检查其队列是否可用,不可用则等待
& & for (u8DataSize = 0; u8DataSize & 255; u8DataSize++)&&//借用u8DataSize
& & {
& && &if (SCHTaskGetQFree(&UartTxTcb) == SCH_Q_FREE)& && &//检查UART_TX发送任务队列是否可用
& && &{
& && &&&SCHTaskQpost(&UartTxTcb,
& && && && && && && &&s_u8RxBuffer[0],
& && && && && && && &s_u8RxCounter); //将接收的的数据+0x11后发回去
& && &&&
& && &}
& && &else
& && &{
& && &&&SCHCurTaskDly(1 / SCH_SYS_TICKS_MS);&&//delay 1ms
& && &}
& & }
& & if (u8DataSize &= 100)
& & {
& && &//出错处理
& & }
&&}
&&SCHTaskEnd();
}复制代码3.UART发送任务: 将其它任务发来的消息发送到PC.void vUartSendData(void)
{
&&static uint8_t s_u8TxBuffer[UART_TX_BUF_SIZE];
&&static uint8_
&&static uint8_t *pDataBuffer, u8DataS
&&SCHTaskBegin();
&&while (1)
&&{
& & SCHTaskQpend();& && && &&&//任务等待消息
& & pDataBuffer = (uint8_t *)UartTxTcb.pD
& & u8DataSize&&= UartTxTcb.S
& & if (u8DataSize & UART_TX_BUF_SIZE)
& & {
& && &u8DataSize = UART_TX_BUF_SIZE;
& && &//出错处理
& & }
& & for (i = 0; i & u8DataS i++)
& & {
& && &s_u8TxBuffer[i] = *pDataB //copy to s_u8TxBuffer
& && &pDataBuffer++;
& & }
& &
& & for (i = 0; i & u8DataS i++)
& & {
& && &if (UART1_GetFlagStatus(UART1_FLAG_TXE) == SET)
& && &{
& && &&&UART1_SendData8(s_u8TxBuffer[i]);
& && &&&//& & & & UART1_ITConfig(UART1_IT_TXE, ENABLE);
& && &}
& && &SCHCurTaskDly(1 / SCH_SYS_TICKS_MS);& && &&&//延时发送1个字节所须要的时间
& & }
&&}
&&SCHTaskEnd();
}复制代码4.ADC转换结果发送任务: 将ADC转换任务传来的相关ADC数据交给UART_TX发送到PC.
void vSendAdcResult(void)
&&static uint8_t s_u8AdcBuffer[ADC_BUF_SIZE];
&&static uint8_
&&static uint8_t *pDataBuffer, u8DataS
&&SCHTaskBegin();
&&while (1)
& & SCHCurTaskDly(1000 / SCH_SYS_TICKS_MS);& &//delay 1000ms
& & SCHTaskQpend();& && && &&&//任务等待消息
& & pDataBuffer = (uint8_t *)SendAdcResultTcb.pD
& & u8DataSize&&= SendAdcResultTcb.S
& & if (u8DataSize & ADC_BUF_SIZE)
& && &u8DataSize = ADC_BUF_SIZE;
& && &//出错处理
& & for (i = 0; i & u8DataS i++)
& && &s_u8AdcBuffer = *pDataB //copy to s_u8AdcBuffer
& && &pDataBuffer++;
& & //使用如下类似方法便可与其它任务共享UART_TX资源,即任务要使用UART_TX前先检查其队列是否可用,不可用则等待
& & for (u8DataSize = 0; u8DataSize & 255; u8DataSize++)&&//借用u8DataSize
& && &if (SCHTaskGetQFree(&UartTxTcb) == SCH_Q_FREE)& && &//检查UART_TX发送任务队列是否可用
& && &&&SCHTaskQpost(&UartTxTcb,
& && && && && && && &&s_u8AdcBuffer[0],
& && && && && && && &i);
& && &else
& && &&&SCHCurTaskDly(1 / SCH_SYS_TICKS_MS);&&//delay 1ms
& & if (u8DataSize &= 100)
& && &//出错处理
&&SCHTaskEnd();
无人问津?白花了一个多星期时间了。冏……
支持一下楼主,但现在实在没时间细细品味
NIC 发表于
支持一下楼主,但现在实在没时间细细品味
谢谢!我倒是觉得是不是写得不够清楚明白或是组织得不好,好吧,我语文是体育老师都教的。那再把调度器所有内容贴出来:
首先是“sch_cfg.h”#ifndef __SCH_CFG_H
#define __SCH_CFG_H
#include &stm8s.h&
//定义数据类型
typedef unsigned char SCH_UINT8;
typedef unsigned int&&SCH_UINT16;
//调度器节拍与硬件系统定时器相关定义
#define SCH_SYS_TICKS_MS & & & && &&&1& & & &&&& & & & //定义调度系统时钟节拍时间(ms),无特殊情况不建议更改此项
#define SCH_HW_TIM_MS & & & && &&&& & & & 0.1& & & &&&& & & & //硬件定时器中断(溢出)周期(ms),此项根据实际系统调整
#define SCH_TIM_TO_TICKS_CMP& & & & (SCH_UINT8)(SCH_SYS_TICKS_MS/SCH_HW_TIM_MS)& & & & //硬件定时器到系统节拍计数比较值
//定义可裁剪部分
#define SCH_CFG_Q_EN& & 1u&&/* 任务内建消息使能 */
#endif& && &//__SCH_CFG_H
复制代码然后是“schedule.h”#ifndef __SCHEDULE_H
#define __SCHEDULE_H
#include &sch_cfg.h&
//U16延时节拍不能大于65534,即任务最大延时时间65534*SCH_SYS_TICKS_MS(1ms)=65.534S
#define SCH_DLY_TYPE & & & && &SCH_UINT16
#define SCH_MAX_TASKS& &255& & & &&&& & & && && && && && &//任务数量,最大为255个。
#if& & & & SCH_MAX_TASKS &= 255
&&#define SCH_MAX_TASK_TYPE& & & && &SCH_UINT8& & & & & & & & & & & & //最大任务数&=255时定义为u8
#else
&&#define SCH_MAX_TASK_TYPE& & & && &SCH_UINT16& & & && &//最大任务为&255则定义为u16
#endif
#define SCH_TASK_RUN& & & & & & & & & & & & & & & & & & & & 0
#define SCH_TASK_PEND& & & & & & & & & & & & & & & & & & & & (SCH_DLY_TYPE)0xffff
#define SCH_CURR_LINE& & & && && && &(SCH_UINT8)(__LINE__+(!__LINE__))& & & & & & & & & & & && && && && & //定义当前行号的具体实现
#define SCHTaskBegin()& && &&&static SCH_UINT8 SchLc=0; switch(SchLc){ case 0://跳转开始,中间可插入延时,调用子函数;(适用主/子函数)
#define SCHTaskEnd()& && && & ;}; SchLc=0; & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & && && && && && && & //跳转结束
struct SchTcb
{
#if SCH_CFG_Q_EN & 0u
&&void& && && & *pD& && & //消息指针
&&SCH_UINT8 & & & & & & & & S& && && &//消息的大小
#endif
& & & & SCH_DLY_TYPE& & & & TimeC&&//定时计数器,时基为 &SCH_SYS_TICKS_MS&
&&void& && && & (*pTask)();& &//任务指针
&&struct SchTcb *pNextTCB;& & //下一个任务控制块指针
};
typedef struct SchTcb SCH_TCB;
//-----------------------------------操作作当前任务及调用子任务------------------------------------------
//挂起(暂停)当前任务,即任务自身
#define SCHCurTaskPend() {SchLc=SCH_CURR_LINE;pCurTCB-&TimeCounter=SCH_TASK_PEND;}case SCH_CURR_LINE:& && && && && && && && && && && && && && && && && && && && && && && &
//当前任务延时X个时间节拍后恢复
#define SCHCurTaskDly(Ticks) {SchLc=SCH_CURR_LINE;pCurTCB-&TimeCounter=T}case SCH_CURR_LINE:
//任务内调用子任务
#define SCHTaskCallSub(SubTaskName)& && && && && && && && && && && && && && && && && &&&\
{& && && && && && && && && && && && && && && && && && && && && && && && && && && && && &\
&&{SchLc=SCH_CURR_LINE;;pCurTCB-&TimeCounter=SCH_TASK_RUN;}case SCH_CURR_LINE:& &\
&&SubTaskName();& && && && && && && && && && && && && && && && && && && && && && && && &\
&&if (pCurTCB-&TimeCounter != SCH_TASK_RUN)& && && && && && && && && && && && && && && &\
& && && && && && && && && && && && && && && && && && && && && && && && && && & \
}
//----------------------------------------消息-------------------------------------------
#if SCH_CFG_Q_EN & 0u
#define SCH_Q_FREE&&1
#define SCH_Q_BUSY&&0
//等待消息
#define SCHTaskQpend() {SchLc=SCH_CURR_LINE;pCurTCB-&TimeCounter=SCH_TASK_PEND;pCurTCB-&pData=(void *)0;}case SCH_CURR_LINE:
//释放消息
extern void SCHTaskQpost(SCH_TCB& &*pPostTCB,
& && && && && && && && & void& && &*pData,
& && && && && && && && & SCH_UINT8 Size);
//获取消息队列状态
extern SCH_UINT8 SCHTaskGetQFree(SCH_TCB& &*pTaskTCB);
#endif
extern SCH_UINT8 g_u8SchedTicksC
extern SCH_TCB& &*pCurTCB;
//extern void SCHTaskPend(SCH_TCB *pTaskPendTCB); //不常用的功能,须要时可去除注释
//extern void SCHTaskResume(SCH_TCB *pTaskTCB);
//extern void SCHTaskDly(SCH_TCB *pTaskDlyTCB, SCH_DLY_TYPE Ticks);
extern void SCHTimeTick(void);
extern void SCHTaskSchedStart();
extern void SCHTaskCreate( SCH_TCB& && &*pNewTCB,
& && && && && && && && && &void& && && &(*pNewTask)());
#endif& & & & //__SCHEDULE_H复制代码最后是“schedule.c”
#include &schedule.h&
SCH_TCB *pFirstTCB, *pCurTCB;
static SCH_MAX_TASK_TYPE TaskNumberSum = 0;
SCH_UINT8 g_u8SchedTicksCnt = 0;
/* 任务节拍处理 */
void SCHTimeTick(void)
{
&&SCH_MAX_TASK_TYPE
&&SCH_TCB *pTCB;
&&if (g_u8SchedTicksCnt &= SCH_TIM_TO_TICKS_CMP)
&&{
& & g_u8SchedTicksCnt -= SCH_TIM_TO_TICKS_CMP;
& &
& & pTCB = pFirstTCB;
& & for (i = 0; i & TaskNumberS i++)
& & {
& && &if ((pTCB-&TimeCounter != SCH_TASK_PEND)
& && && & && (pTCB-&TimeCounter & 0))
& && &{
& && &&&pTCB-&TimeCounter--;
& && &}
& && &pTCB = pTCB-&pNextTCB;
& & }
&&}
}
/* 任务创建,调试时可在任务创建失败处放置断点 */
void SCHTaskCreate(SCH_TCB& && && &&&*pNewTCB,
& && && && && && & void& && && && &&&(*pNewTask)(void))
{
&&if (TaskNumberSum == 0)
&&{
& & pFirstTCB = pNewTCB;& && && && && && &&&//备份第一个任务控制块地址
& & pNewTCB-&pTask = pNewT& && && && &&&//新创建的任务控制块的函数指针指向新创建的任务
& & pCurTCB& &= pNewTCB;& && && && && && &&&//最新任务控制块地址给当前任务控制块指针
& & pCurTCB-&pNextTCB = pCurTCB;& && && && &//因为只有一个任务,所以指令的下一个任务控制块地址就是自己
&&}
&&else if (TaskNumberSum & SCH_MAX_TASKS)
&&{
& & pNewTCB-&pTask = pNewT& && && && &&&//新创建的任务控制块的函数指针指向新创建的任务
& & pNewTCB-&pNextTCB = pCurTCB-&pNextTCB;&&//当前任务控制块指向的下一个任务控制块由新建的任务控制块来指向
& & pCurTCB-&pNextTCB = pNewTCB;& && && && &//当前任务控制块指向的下一个任务控制块更新为新建的任务
& & pCurTCB = pNewTCB;& && && && && && && & //新建的任务控制块更新为当前任务控制块
&&}
&&else
&&{
& & TaskNumberSum--;& && && && && && && && &//任务创建失败,调试时可在此放置断点
&&}
&&TaskNumberSum++;
#if SCH_CFG_Q_EN & 0u
&&pNewTCB-&pData& & = (void *)0;
&&pNewTCB-&Size = 0;
#endif
}
void SCHTaskSchedStart(void)
{
SCHED_SART:
& & & &
&&pCurTCB = pFirstTCB;& && && && && && && && &//指向第一个创建的任务,之后按创建时的顺序执行下去
&&while (1)& && && && && && && && && && &
&&{
& & SCHTimeTick();& && && && && && && && && & //如果任务Tick满足条件,则将其置于可执行状态
& & if (SCH_TASK_RUN == pCurTCB-&TimeCounter) //任务处于可执行状态
& & {
& && &pCurTCB-&TimeCounter = SCH_TASK_PEND;& &//设置为挂起状态,保证任务只执行一次
& && &pCurTCB-&pTask();& && && && && && && &&&//执行当前任务控制块指向的任务
& && &goto SCHED_SART;& && && && && && && && &//每执行完一个任务,都重新查找一次可执行最高优先级任务
& & }
& & pCurTCB = pCurTCB-&pNextTCB;& && && && &&&//指向下一个任务控制块,查找下个任务是否可执行
&&}
}
////----------------------------------操作指定任务,不常用---------------------------------------------------
////操作当前任务及调用子任务在&schedule.h&中
//
////挂起(暂停)指定任务
//void SCHTaskPend(SCH_TCB *pTaskPendTCB)
//{
//&&pTaskPendTCB-&TimeCounter = SCH_TASK_PEND;
//}
//
////恢复指定任务(运行)
//void SCHTaskResume(SCH_TCB *pTaskResumeTCB)
//{
//&&pTaskResumeTCB-&TimeCounter = SCH_TASK_RUN;
//}
//
////指定任务延时X个时间节拍后恢复
//void SCHTaskDly(SCH_TCB *pTaskDlyTCB, SCH_DLY_TYPE Ticks)
//{
//&&pTaskDlyTCB-&TimeCounter = T
//}
//---------------------------------消息-----------------------------------------
//释放消息
#if SCH_CFG_Q_EN & 0u
void SCHTaskQpost(SCH_TCB& &*pPostTCB,
& && && && && && &void& && &*pData,
& && && && && && &SCH_UINT8 Size)
{
&&pPostTCB-&pData = pD
&&pPostTCB-&Size&&= S
&&pPostTCB-&TimeCounter = SCH_TASK_RUN;
}
//查询消息列队状态,是否是自由(可用)或忙(不可用),调用SCHTaskQpend()时会将其设置为自由状态
SCH_UINT8 SCHTaskGetQFree(SCH_TCB& &*pTaskTCB)
{
&&if (pTaskTCB-&pData == ((void *)0))
&&{
& & return SCH_Q_FREE;
&&}
&&else
&&{
& & return SCH_Q_BUSY;
&&}
}
#endif复制代码参考了不少本论坛的帖子,已经记不清具体是哪些了……
顶一下贴,楼主花了不少精力。
学习一下了啊~~
protothread用的人太少,算是曲高和寡吧
hhxb 发表于
protothread用的人太少,算是曲高和寡吧
何为 曲高和寡 ?
整得不错,还有注释
有时间再弄弄寄存器版本的,这小容量的芯片用库浪费了点
rifjft 发表于
整得不错,还有注释
有时间再弄弄寄存器版本的,这小容量的芯片用库浪费了点 ...
谢谢,我会尽快出寄存器版本.
本帖最后由 summarize 于
12:41 编辑
这里补充说明一下为什么要做支持优先级的调度:
之前手里有一个项目有多个任务,main函数简述如下
void main(void)
&&SystemInit();
&&whiile(1)
& & Task1();////经测试执行最长时间约0.8ms
& & Task2();//经测试执行最长时间约1.2ms
& & Task3();//经测试执行最长时间约0.9ms
& & Task4();//经测试执行最长时间约1.5ms
如Task1为通信数据处理任务(数据在中断中接收并放到缓冲区等待处理),要求最慢响应时间是2ms,那么如果是按照常规的顺序执行,则其它三个任务的最大执行时间(1.2+0.9+1.5)&2ms,则数据会丢失.
当时的临时解决办法是,在Task2(),Task3()后面都多调用一次Task1(),即变成下面这样:
void main(void)
&&SystemInit();
&&whiile(1)
& & Task1();////经测试执行最长时间约0.8ms
& & Task2();//经测试执行最长时间约1.2ms
& & Task1();////经测试执行最长时间约0.8ms
& & Task3();//经测试执行最长时间约0.9ms
& & Task1();////经测试执行最长时间约0.8ms
& & Task4();//经测试执行最长时间约1.5ms
显然,问题得到解决,但是main函数的简洁性被破坏,显示得有点杂乱了.而且只有Task1()取得了最高优先级,其它任务还是按原来那样顺序执行;所以后来就有了做一个支持优先级的非抢占式调度器,可以支持配置所有任务的优先级.
本帖最后由 hhxb 于
20:39 编辑
summarize 发表于
何为 曲高和寡 ?
上次看一个protothread的帖子,对宏的使用看的我脑袋都大了
楼主的代码我还没来得及看,今天仔细研读一下
hhxb 发表于
上次看一个protothread的帖子,对宏的使用看的我脑袋都大了
楼主的代码我还没来得及看,今天仔细研读一下 ...
建议你使用SlickEdit或是其它比较专业的编辑器,它们的代码关联等功能很强大,方便阅读编辑。
给你一个我使用SlickEdit时,鼠标光标定在SCHCurTaskDly时的截图
本帖子中包含更多资源
才可以下载或查看,没有帐号?
summarize 发表于
建议你使用SlickEdit或是其它比较专业的编辑器,它们的代码关联等功能很强大,方便阅读编辑。
给你一个 ...
//延时发送1个字节所须要的时间
这个时间怎么取?堵塞了?
留着~~还在学习STM8中~~
不错,顶一下,支持原创...
//延时发送1个字节所须要的时间
这个时间怎么取?堵塞了?
9600/8bit=1200,加上起止停止位等,算位1K频率,对应1ms,再不行可以用示波器看下发送一个字节到底用多长时间。
延时1ms的意思是过了1ms之后再进来查询一下前一字节是否发送完,如果发送完则接着发送下个字节。
summarize 发表于
9600/8bit=1200,加上起止停止位等,算位1K频率,对应1ms,再不行可以用示波器看下发送一个字节到底用多 ...
发的数据比较频繁。会不会单片机。处理其它任务效率低下。
很好的思想
protothread学习提高好参考资料
发的数据比较频繁。会不会单片机。处理其它任务效率低下。
你要明白,每次如果条件符合(即上个字节已经发送完),本次所做的事情只是把要发送的数据放到UART的发送寄存器中,你发送再多的数据,也只是每间隔1ms就把发送缓冲区中的一个字节数据放在UART的发送寄存器中,这个动作应该占用的时间很少吧.而且如果其它任务更紧急,则可以将其配置为更高优先级,数据发送放在低优先级,这样UART发送最多就是因为执行了其它更高优先级任务而被&拖延&了时间,即可能是在发送完一个字节之后,间隔了2ms或更多时间才能发送下个字节.当然,如果你的UART通信不能接受这种情况发生,那你也可以将其改为中断方式发送.
好,有时间看看
顶你,再出其它MCU的版本,同时加上文档。这样就推广开了
soosqt 发表于
顶你,再出其它MCU的版本,同时加上文档。这样就推广开了
谢谢!其实我有一个想法,就是希望它能成为裸机程序框架的一种通用调度器,就像ucos 等OS一样,它们占据OS 地位,我们占据调度器的一片天,但是目前看来好像感冒的人不太多。也许出更多MCU版本就能改变?再次谢谢你的建议,后续我会也更多MCU版本和文档。
不错呀,寄存器的也出来了,有时间再仔细看看
其实像这种在某款芯片的调度器应用,应在标题上注明,这样关注的人可能会更多一点。
谢谢LS,现在已经不能更改标题了,当初起这个标题时,是想尽可能将要讲的内容表达清楚...而且字数都用完了还是觉得表达不够清楚.
同时,我选择在stm32/8论坛发帖,当然默认就是stm32/8的芯片应用了.至于以后如果增加其它单片机版本,倒是不知道放到哪里好.
标记!& &&&
迟点消化消化
期待8051尽快出来,不过lz要是希望推广还是得有个学习文档才好,人们只有理解了为什么要这样,有如此等等好处,用着才欢喜.
是OS还是类OS?
tiger5 发表于
是OS还是类OS?
名字就是调度器,当然就不会是OS了,类OS吧.全C,适用所有单片机平台.现在手头没有51单片机,准备买一块最小系统板,然后再出一版8051的.
学习一下调度器,谢谢!
关注一下,
记号,有空的时候准备仔细看下。
支持楼主,强列希望出个PIC版本
soosqt 发表于
支持楼主,强列希望出个PIC版本
暂时不出别的版本了,得先出文档;其实移植并不难,就是要初始化一个定时器作为调度器的节拍器,了解OS的很容易明白(当然比OS简单得多),关键是使用,所以使用说明文档更重要;
如果有了文档还是不能搞定,那里再出.
本帖最后由 majiansongok 于
15:57 编辑
好东西,谢谢分享!
不知道与单纯的 protothread 比较有什么特别优势,protothread使用简单,适合几乎所有C编译器,
不过上次用C30编译器,芯片用dspic30f4013时,发现C30的中断入口带参数,导致用protothread调度时,出现无规律复位现象,后去掉了参数后才正常。
tdh03z 发表于
不知道与单纯的 protothread 比较有什么特别优势,protothread使用简单,适合几乎所有C编译器,
不过上次用 ...
这个是封装成类OS,支持非抢占优先级调度,消息,用过OS 的人会更喜欢。同时也可作为学习OS的前奏。同样全用C 实现,移植方便。
& &mark!& && && && && && && && && &
好东西,有时间看看。
yj_yulin 发表于
期待8051尽快出来,不过lz要是希望推广还是得有个学习文档才好,人们只有理解了为什么要这样,有如此等等好处, ...
使用说明已经出来,望指点.
mark。。。。。。。。。。。。。。。。。。。。。
summarize 发表于
使用说明已经出来,望指点.
支持,lz有热情,感觉直接上开项目更有助于推广,协作.
yj_yulin 发表于
支持,lz有热情,感觉直接上开项目更有助于推广,协作.
常驻本论坛,未知你说的“”是个什么样的网站?
summarize 发表于
常驻本论坛,未知你说的“”是个什么样的网站?
开源代码项目管理, 请善用搜索.
本帖最后由 smset 于
17:49 编辑
感觉你的这个调度器很不错,和我以前发的“小小调度器”核心思想上非常类似呢。
参考这个帖子:
感觉你的版本很规范,虽然资源上稍微增加了一点点,不过外围辅助功能增加了不少,而且文档写得也非常不错!
protothread确实是的好东西!
本帖最后由 summarize 于
08:49 编辑
smset 发表于
感觉你的这个调度器很不错,和我以前发的“小小调度器”核心思想上非常类似呢。
是的,是参考了你的&小小调度器&.
我是在看了你的调度器,然后自己学习了UCOS3,之后才有了将多种思想结合起来,写一个功能比较完善且使用方法类似OS的调度器.
突然发现自己还可以管理帖子,故将整个过程的重要事件推荐到的LZ位,这样就不用全部看完帖子就能了解整个过程及重点。
markmarkmarkmarkmark
本帖最后由 kinsno 于
13:45 编辑
summarize 发表于
突然发现自己还可以管理帖子,故将整个过程的重要事件推荐到的LZ位,这样就不用全部看完帖子就能了解整个过 ...
最新版本的升级呢? 还有吗?是否用在量产的产品上了啊?
1、应该写出你这个类OS,如果要使用,要注意一些什么点,比如延时,比如程序的写法?比如变量的定义。这些我觉得出也得出一个文档,这样避免很多人中招。
kinsno 发表于
最新版本的升级呢? 还有吗?是否用在量产的产品上了啊?
1、应该写出你这个类OS,如果要使用,要注意一 ...
最新版本在 48楼,简约版本在公司内部推广中(目前这个版本比较完善,不少人理解接受有困难,特别是老员工).使用说明在47楼,已经说明了使用中要注意的大部分问题.具体还有哪些要注意的问题请指出,后续加入完善.
看过& && && && && && && &.............
summarize 发表于
最新版本在 48楼,简约版本在公司内部推广中(目前这个版本比较完善,不少人理解接受有困难,特别是老员工). ...
#define SCH_CURR_LINE& & & && && && &(SCH_UINT8)(__LINE__+(!__LINE__))& & & &&&-&这个定义是不是有问题,应该是只获取当前的行号“__LINE__”,在后面又加上一个!是什么意思呢?
没写出应该程序架构里面应该避免啥东西的?原protolthread应该是不能在程序内部使用SWITCH了。你这个呢?
本帖最后由 summarize 于
21:10 编辑
kinsno 发表于
#define SCH_CURR_LINE& & & && && && &(SCH_UINT8)(__LINE__+(!__LINE__))& & & &&&-&这个定义是不是有问题,应该是只 ...
#define SCH_CURR_LINE& && && && && & (SCH_UINT8)(__LINE__+(!__LINE__))& && && &-&这个定义是不是有问题,应该是只获

我要回帖

更多关于 css选择符优先级 的文章

 

随机推荐