找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

请工程化,定制化你的单片机代码

查看数: 180794 | 评论数: 564 | 收藏 408
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2019-6-6 11:48

正文摘要:

- 前言 - 时至今日,依旧看到很多小伙伴们放着单片机里的定时器不用,动辄delay1s(); delay500ms();虽然简单粗暴,但是其实是很不妥当的。还有很多需要按键的程序,动不动就“while(k1==0);”的等按键松开,这样 ...

回复

ID:476527 发表于 2019-6-6 16:41
如果有需要,我可以把相关的主程序和架构打包上传……不过说实话这些代码随便敲敲就有了,需要锻炼的是一种“精准控制”软件的逻辑的思维。
跑快了的东西我们把它放慢些,跑慢了的东西给它放快些。
对于一个系统来说,“平衡”是很重要的事情。

最后再说一句,while(1)大循环里面不要放“delay();”或者“while(按键被按下);”了……
ID:476527 发表于 2019-7-7 19:26
很抱歉的告诉大家,之前的想法还是太乐观,现在每天忙成狗,完全不确定啥时候能抽时间写完,7月15日要是没有更新的话还请大家谅解。

不过我是不会就这么停笔的,只是不知道啥时候有时间写而已。作为打工仔,真的身不由己。
为了不辜负大家的期待,下次更新时我会把文档做成pdf,附带源码,流程图,表格一并上传。

其实还有很多可以写的地方,但是现在这篇帖子就写这3点——时基,模块化,状态机——已经够大家消化一阵子了。而且,如果帖子的篇幅太长了,其实不利于阅读的。
以后如果还有别的分享,我会另开帖子的,多蹭点管理员的黑币,哈哈。
ID:476527 发表于 2019-8-2 20:36
ccdmcu 发表于 2019-8-2 16:22
按键的松手检测呢?怎么用定时器写?

我不是给了个keyPress()程序么,你再好好看看。
简单来说,有键按下时,时间就会++;
无键按下时,时间就会清零。
但在清零之前会先检查,时间是否大于0,时间值大于0(或者消抖值)说明曾经有键按下过,并且刚刚松开。这时候处理“这次按键”不就好了。
ID:385637 发表于 2019-8-10 10:38
楼主这文章比那些所谓的教科书好多了,那些教科书按键消抖动不动就是delay(20ms),真是误人子弟,真正出来做到大型项目才知道 DELAY是多么不实际。希望楼主继续更新,最好转成PDF,多点例程,尤其是一些按键的,短按,长按,双击组合键例程。现在绝大部份写按键程序都喜欢delay消抖,while松手检测。郭天详的书也是这么教的,一点不实用
ID:476527 发表于 2019-8-12 11:46

确实不会“小于”0,但“等于”0是有可能的喔,所以这样写是没问题的。
至于为什么我写了“<=",而不是”==“呢?
理由是 —— 容错机制:
万一手残了,在定义key_press_time的时候忘记加了unsigned,我们的按键程序照样可以正常工作(只是计数最大值只有原来的一半了)
ID:476527 发表于 2019-8-14 14:12
本帖最后由 Similarv 于 2019-8-15 10:40 编辑
IdeaMing 发表于 2019-8-14 10:27
我想问,怎么把DS18B20的加入到你这种机制里?一次通讯时间都要好几毫秒

这个好说,把基础时基变成10ms(或者20ms),也就是定时器中断10ms(或者20ms)产生一次。
然后就是……
  1. unsigned char flag10ms=0,flag100ms=0;
  2. void t0Init()
  3. { /*略*/}
  4. void t0Xint() Interrupt n
  5. {
  6.     flag10ms = 1;//10ms产生一次中断
  7. }
复制代码



ID:476527 发表于 2019-8-19 01:00
IdeaMing 发表于 2019-8-16 16:25
如果同时存在数码管的刷新呢,比如一秒读一次18B20,读的时候数码管的刷新就被卡了一下

我刚刚特意去查了一下,这玩意仅仅是个温度传感器,而且还特么是数字的,读一次温度居然至少要5Ms?!(还不确定是否会更久)
这样,如果你有示波器的话,请你做这么一个实验,把单片机某个端口设为输出,这个端口平时是低电平,然后用18b20读取温度之前拉高它,读取结束的时候又拉低它,然后用示波器好好的看看这个端口被拉高的时间,你就知道它每次采温需要多长时间了。再结合其他子程序的工作时长,设计你的时基。
其实,这种数字型温度传感器在我们实际做项目的人的眼里,只有华而不实四个字可以评价。如果我们的项目里需要测温,我们一般会采用内部自带adc模块的单片机,测温只要一个热敏电阻就可以搞定。整个测温的时间只需大约10us。不但更便宜,精度更好,效率还是你那个测温模块的500倍!具体方案这里就不赘述了。
ID:476527 发表于 2020-1-13 16:52
本帖最后由 Similarv 于 2020-1-13 18:07 编辑
13303022280 发表于 2020-1-7 14:29
如果我只需要执行一次按键之后的程序,为了避免按键长按导致的重复运行,就用一个变量,在每次进入中断检 ...

你的做法当然也没有问题,不过我是这么做的:
按键就只是做按键检测,并且设置相应的“按键已触发”标志(bit变量);至于按键的功能则是在别处比如状态机中去执行。
例子:当按键按下之后开/关灯

key.c 文件:
bit key_flag_light;  //当按键触发时为1,否则为0, 此变量是给状态机使用的
static bit key_press_light; //当按键按下时为1,未按下为0,此变量仅在key.c内使用。
函数1-keyScan()  -- 功能:检测按键是否按下,若按键按下则将key_press_light置一,否则清零。
函数2-keyDeal()   -- 功能:使用某静态变量统计key_press_light的时间;当key_press_light从1变为0的时候,检查静态变量的值是否大于消抖值,若大于消抖时间则将key_flag_light设置为1;

state.c文件
函数1-StateMachine() -- 功能:当key_flag_light==1时,取反led_flag_out的值,随后将key_flag_light设置为0.

led.c文件
bit led_flag_out; //当该值==1,开灯;当该值==0;关灯
函数1-ledOutput() -- 功能:根据led_flag_out的取值开灯或者关灯

main.c文件
在10ms或者20ms的时基中依次调用
keyScan();
keyDeal();
StateMachine();
在100ms的时基中调用
ledOutput();

/******/
稍微修改一下,刚刚没有认真审题,你需要做长按的判定,我这个架构是基于短按的。
修改的地方位于keyDeal()部分,
短按 —— 是等待按键松开时裁决静态变量的计时值。
长按 —— 则是直接在静态变量等于‘长按时间点’的时刻将key_flag_light置一即可。key_flag_light==1的时候,状态机自然会处理长按事件,此后keyDeal()里的静态变量会在按键继续按着的时候继续加,但其值已经‘大于’‘长按时间点’了,所以key_flag_light不会被重复置一,当按键释放之后,此静态变量清零,一切重新开始。


ID:476527 发表于 2020-1-13 17:46
hubj627 发表于 2020-1-13 09:20
这种针对代码量小的项目实时性没有问题。但代码量大的整个程序架构就会显得臃肿,也需针对同一个事情,在主 ...

进阶教程尚待坛友们自己修行,鄙人不才,只能带路到这了
ID:1157185 发表于 2025-8-18 12:19
真的是书上看不到的技术文章~~
ID:1138544 发表于 2025-8-9 09:39
写得太好了
ID:224580 发表于 2025-7-28 15:28
真厉害
ID:65286 发表于 2025-7-3 07:19

好文章,不知楼主能否弄成pdf格式上传呢,想保存起来!!!
ID:67356 发表于 2025-6-30 04:14

不错学习了
ID:1155019 发表于 2025-6-23 14:40
good!!
ID:1150101 发表于 2025-6-16 21:16
绝世好贴!
ID:1152335 发表于 2025-6-1 11:31
很好
ID:1152287 发表于 2025-5-31 17:02
感谢分享
ID:1149576 发表于 2025-5-24 17:02
这是教的程序整体架构,对于裸机(没有操作系统)开发是堪称经典的教程。
ID:1150783 发表于 2025-5-17 21:09
学会了,谢谢楼主
ID:1131105 发表于 2025-4-30 09:03
我是白菜,这个思路一下子就打开了我的思维,大多教程都是老的那一套,感谢大神的分享!!
ID:987365 发表于 2025-4-21 03:42
秒啊,好文
ID:1148059 发表于 2025-4-15 17:30
必须收藏了好吧
ID:18253 发表于 2025-4-13 15:29
真不错,有耳目一新的感觉。
ID:158391 发表于 2025-3-31 02:46
几年前的贴子怎么没有留意到呢,点了好几年的灯,看来有望进阶八级点灯大师啦
ID:1146304 发表于 2025-3-25 22:41
学到很多,单片机的学习最终还是必须回归到给客户服务
ID:1110477 发表于 2025-3-13 06:02
长文看不完,收藏吧
ID:446156 发表于 2025-3-10 13:26
denggong 发表于 2025-3-9 08:28
我直接在中断里调用显示程序,虽然占用点时间,但保证每次中断能刷新显示,不用每次刷新显存后调用显示程序 ...

中断讲究快进快出,除非不得已不得在中断里做太多工作
ID:200869 发表于 2025-3-9 08:28
我直接在中断里调用显示程序,虽然占用点时间,但保证每次中断能刷新显示,不用每次刷新显存后调用显示程序。
ID:1144925 发表于 2025-3-6 09:49
受益匪浅
ID:297408 发表于 2025-2-27 14:52
谢谢分享,学习一下
ID:299910 发表于 2025-2-8 12:03
还以为是新帖,仔细一看原来是2019年的帖子,但是直到现在还有回复,内容真的干货。
感谢大神的无私分享。
ID:1143011 发表于 2025-1-31 19:36
把定时器封装成DELAY()MS,这样用也方便,
ID:67356 发表于 2025-1-10 03:36
很好,能看到这样的帖子很好
ID:1140926 发表于 2024-12-23 09:53
太棒了我正愁不知道该怎么办
ID:901570 发表于 2024-12-20 10:11
感谢大佬!!值得学习!!
ID:966260 发表于 2024-12-12 11:31
14页都看了一遍,深深认识到:感谢【51黑电子论坛】及其创办者和维护人员!!!有了这个平台和这些人,才有我们学习的机会,非常感谢!
ID:966260 发表于 2024-12-12 10:08
Similarv 发表于 2019-8-19 01:00
我刚刚特意去查了一下,这玩意仅仅是个温度传感器,而且还是数字的,读一次温度居然至少要5Ms?!( ...

我自已做的开发板就用了个温感芯片,还自以为很高级,惭愧啊,热敏电阻,受教受教!
ID:966260 发表于 2024-12-12 09:57
首先,感谢楼主的分享!其次,本人愚钝,看时还未茅塞顿开,但有豁然开朗的感觉,需要慢慢消化吸收。
最后,再次致谢楼主的无私分享!
ID:897854 发表于 2024-12-11 13:45
干货
ID:1138306 发表于 2024-12-2 14:27
不错,很有用。
ID:1088029 发表于 2024-11-18 18:21
看了楼主的教程,学到了知识
ID:1115103 发表于 2024-11-17 09:47
越学越感觉深奥
ID:466997 发表于 2024-11-11 15:21
很好,记录一下,学习
ID:1063561 发表于 2024-11-8 09:10
不错的文章。点赞,学习了
ID:1135214 发表于 2024-11-2 22:00
新手进阶必读
ID:876606 发表于 2024-10-31 11:30
经典,不知道楼主如今何处开新贴了~~
ID:1134207 发表于 2024-10-21 10:34
谢谢分享,多发一些类似文章。
ID:1133323 发表于 2024-10-11 16:09
大佬原来是这么厉害的吗,学到了继续努力

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表