数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 2001|回复: 8

[C51] 单片机入门杂谈(二):程序结构

[复制链接]
发表于 2023-5-7 15:36:24 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
单片机入门杂谈(一):调试器
https://www.mydigit.cn/thread-384952-1-1.html



    本文所讲的东西旨在描述如何把想要实现的功能通过简单的方法在程序上实现,不一定符合大师们的各种规范,也不涉及高级编程手段,如C++编程、带系统编程。

    可能很多人刚开始编写单片机程序的时候会这样:所有功能全部写在一个文件中;想要延时就用等待的delay(),甚至在中断中这么做;认为中断理所当然地的可靠,如定时器定时时间一定是那么多、外中断一定是真的是有效信号触发 ……

    无论使用哪种编程手段,单片机的CPU同一时间只能做一件事,有些事看起来需要同时做,但实际上穿插做也没也没什么问题,比如要实现按下按键点亮一个LED、用NTC检测温度超过阈值点亮一个LED,这几件事似乎必须一刻不停地一件接着一件反复地做(最快就是这样了),但是,这几件事按一定的时间间隔去处理,结果是差不多的,比如每1mS采集一次温度、每10mS读取一次按键、每10mS更新一次LED显示。要实现按一定时间间隔处理各个事务,就要建立计时系统,可以以最短计时单位为基准累积得到其它时间单位,如最短计时单位=1mS,要得到10mS,累积10次1mS即可。

    上述分时处理机制可以这样实现:

    方案1:建立10个1mS分时处理分支

    程序大致如下:
  1. void main(void)
  2. {
  3.         MCU_Init();        //初始化

  4.         while(1)
  5.         {
  6.                 if(Timer_1mS_Flag)        //1mS计时处理,定时器计时产生
  7.                 {
  8.                         Timer_1mS_Flag=0;

  9.                         Clear_WDT();        //清看门狗

  10.                         Diaplay_LED();        //LED显示输出
  11.                         ADC_Process();        //ADC测温

  12.                         switch(Main_Step)        //1mS处理分支
  13.                         {
  14.                                 case 0:
  15.                                 {
  16.                                         System_Timer();        //累积 10mS * N 得到10mS的N倍时间

  17.                                         break;
  18.                                 }
  19.                                 case 1:
  20.                                 {
  21.                                         Key_Scan();                //按键扫描
  22.                                         Key_Debounce();                //按键消抖
  23.                                         Key_Process();                //按键功能处理

  24.                                         break;
  25.                                 }
  26.                                 case 2:
  27.                                 {
  28.                                         Display_Update();        //更新LED显示缓冲区

  29.                                         break;
  30.                                 }
  31.                                 case 3:
  32.                                 {
  33.                                         //空闲

  34.                                         break;
  35.                                 }
  36.                                 case 4:
  37.                                 {
  38.                                         //空闲

  39.                                         break;
  40.                                 }
  41.                                 case 5:
  42.                                 {
  43.                                         //空闲

  44.                                         break;
  45.                                 }
  46.                                 case 6:
  47.                                 {
  48.                                         //空闲

  49.                                         break;
  50.                                 }
  51.                                 case 7:
  52.                                 {
  53.                                         //空闲

  54.                                         break;
  55.                                 }
  56.                                 case 8:
  57.                                 {
  58.                                         //空闲

  59.                                         break;
  60.                                 }
  61.                                 case 9:
  62.                                 {
  63.                                         //空闲

  64.                                         break;
  65.                                 }
  66.                         }

  67.                         Main_Step++;        //1mS * 10 分支
  68.                         if(Main_Step>=10)
  69.                         {
  70.                                 Main_Step=0;
  71.                         }
  72.                 }
  73.         }
  74. }
复制代码
   这个方案的好处:
    (1)可以方便按最短计时时间间隔处理事务,如有多个COM的LED显示,每1mS显示一个COM;
    (2)屏蔽某个分支的程序不影响其它程序执行时间间隔,比如查错时把怀疑的分支屏蔽掉,其它程序程序的执行和屏蔽前一样。

    这个方案的坏处:这个方案是基于每个分支的执行时间不超过最短计时单位1mS设计的,当某些分支的执行时间超过2mS/1mS,可能会导致整个(1mS*10)处理超时,比如分支0执行时间超过2mS、分支9执行时间超过1mS。

    方案2:1mS分时处理分支 + 10mS分时处理分支

    程序大致如下:
  1. void main(void)
  2. {
  3.         MCU_Init();        //初始化

  4.         while(1)
  5.         {
  6.                 if(Timer_1mS_Flag)        //1mS计时处理,定时器计时产生
  7.                 {
  8.                         Timer_1mS_Flag=0;

  9.                         Clear_WDT();                //清看门狗

  10.                         Diaplay_LED();                //LED显示输出
  11.                         ADC_Process();                //ADC测温
  12.                 }

  13.                 if(Timer_10mS_Flag)        //10mS计时处理,定时器计时产生
  14.                 {
  15.                         Timer_10mS_Flag=0;
  16.                         
  17.                         System_Timer();                //累积 10mS * N 得到10mS的N倍时间

  18.                         Key_Scan();                //按键扫描
  19.                         Key_Debounce();                //按键消抖
  20.                         Key_Process();                //按键功能处理

  21.                         Display_Update();        //更新LED显示缓冲区

  22.                         if(Timer_100mS_Flag)        //100mS计时处理,累积 10mS得到
  23.                         {
  24.                                 //100mS时间间隔处理事务
  25.                         }

  26.                         if(Timer_500mS_Flag)        //500mS计时处理,累积 10mS得到
  27.                         {
  28.                                 //500mS时间间隔处理事务
  29.                         }

  30.                         if(Timer_1S_Flag)        //1S计时处理,累积 10mS得到
  31.                         {
  32.                                 //1S时间间隔处理事务
  33.                         }
  34.                 }
  35.         }
  36. }
复制代码

    这个方案的好处:只要每循环总处理时间不超过10mS,基于10mS的计时偏差不超过10mS。

    这个方案的坏处:如果10mS间隔处理时间超过1mS,1mS时间间隔就不准,需将1mS讲处理移到定时器中断中。


    以前看过一个故事,说诺基亚的老总让攻城狮修改一个塞班系统功能,攻城狮查看代码后告诉他,找不到那段代码在哪里……

    模块化编程在维护、移植、编写衍生程序时大大减少工作量,有时还能提高编译效率。

    建议将程序分成3个功能层:
    (1)接口层。实现与具体硬件功能,如定时器定时、通讯收发、显示输出,移植时修改这个模块。
    (2)系统层。实现大部分程序都有的功能,如时基计时、按键消抖,移植时不用修改或很少修改这个模块。
    (3)用户层。实现具体功能,如按下按键点亮一个LED,根据需求修改这个模块。



打赏

参与人数 2家元 +50 收起 理由
IlovePLC + 30 原創內容
慕名而来 + 20 優秀文章

查看全部打赏

发表于 2023-5-7 18:17:51 | 显示全部楼层
这个是时间片轮编程?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-7 18:25:50 | 显示全部楼层
yanghc 发表于 2023-5-7 18:17
这个是时间片轮编程?

对,很简单实用的结构。
回复 支持 反对

使用道具 举报

发表于 2023-5-7 20:42:27 | 显示全部楼层
真心希望楼主的“杂谈”能继续下去,读过两篇文字尤其是本帖虽然还很懵懂但真的很开窍。
回复 支持 1 反对 0

使用道具 举报

发表于 2023-5-8 08:38:55 | 显示全部楼层
楼主这个普及的好
STC32位8051的库应用指南中,也放入了这个精神的已完善的完整的支持大项目的任务调度系统




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

发表于 2023-5-11 16:12:25 | 显示全部楼层
非常感谢楼主,学习
回复 支持 反对

使用道具 举报

发表于 2023-5-16 13:23:55 来自手机浏览器 | 显示全部楼层
对初学者是非常好的教程
回复 支持 反对

使用道具 举报

发表于 2023-5-19 12:02:36 | 显示全部楼层
最近也想学学单片机
回复 支持 反对

使用道具 举报

发表于 2025-4-9 23:42:27 | 显示全部楼层
楼主是小专家啊
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-11-14 11:18 , Processed in 0.343200 second(s), 13 queries , Gzip On, Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

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