您的位置 首页 芯闻

单片机代码写入的三种常用句子,看完之后不翻车!

单片机代码写入的三种常用语句,看完之后不翻车!-种方法,这应用程序比较简单,实时性,并行性要求不太高的情况下是不错的方法,程序设计简单,思路比较清晰。但是当应用程序比较复杂的时候,如果没有一个完整的流

  作业中经过探索试验,总结出单片机大致运用程序的架构有三种:

  1. 简略的前后台次序履行程序,这类写法是大多数人运用的办法,不需用考虑程序的详细架构,直接经过履行次序编写运用程序即可。

  2. 时刻片轮询法,此办法是介于次序履行与操作体系之间的一种办法。

  3. 操作体系,此法应该是运用程序编写的最高境地。

  下面就别离谈谈这三种办法的利害和习惯规模等。

  一、次序履行法

  这种办法,这运用程序比较简略,实时性,并行性要求不太高的情况下是不错的办法,程序规划简略,思路比较明晰。可是当运用程序比较杂乱的时分,假如没有一个完好的流程图,恐怕他人很难看懂程序的运转状况,并且跟着程序功用的增加,编写运用程序的工程师的大脑也开端紊乱。即不利于晋级保护,也不利于代码优化。自己写个几个比较杂乱一点的运用程序,刚开端便是运用此法,终究尽管能够完结功用,可是自己的思想一向处于紊乱状况。导致程序一向不能让自己满足。

  这种办法大多数人都会选用,并且咱们承受的教育也根本都是运用此法。关于咱们这些根本没有学习过数据结构,程序架构的单片机工程师来说,无疑很难在运用程序的规划上有一个很大的进步,也导致了不同工程师编写的运用程序很难彼此利于和学习。

  自己主张,假如喜爱运用此法的网友,假如编写比较杂乱的运用程序,必定要先理清脑筋,规划好完好的流程图再编写程序,不然结果很严重。当然应该程序自身很简略,此法仍是一个十分有必要的挑选。

  下面就写一个次序履行的程序模型,便利和下面两种办法比照:

  代 码

  /**************************************************************************************

  * FuncTIonName : main()

  * DescripTIon : 主函数

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  int main(void)

  {

  uint8 keyValue;

  InitSys(); // 初始化

  while (1)

  {

  TaskDisplayClock();

  keyValue = TaskKeySan();

  switch (keyValue)

  {

  case x: TaskDispStatus(); break;

  。。。

  default: break;

  }

  }

  }

  二、时刻片轮询法

  时刻片轮询法,在许多书本中有说到,并且有许多时分都是与操作体系一同呈现,也便是说许多时分是操作体系中运用了这一办法。不过咱们这儿要说的这个时刻片轮询法并不是挂在操作体系下,而是在前后台程序中运用此法。也是本贴要详细阐明和介绍的办法。

  关于时刻片轮询法,尽管有不少书本都有介绍,但大多说得并不体系,仅仅提提概念罢了。下面自己将详细介绍这种形式,并参阅他人的代码树立的一个时刻片轮询架构程序的办法,我想将给初学者有必定的学习性。

  在这儿咱们先介绍一下守时器的复用功用。

  运用1个守时器,可所以恣意的守时器,这儿不做特别阐明,下面假定有3个使命,那么咱们应该做如下作业:

  1. 初始化守时器,这儿假定守时器的守时中止为1ms(当然你能够改成10ms,这个和操作体系相同,中止过于频频功率就低,中止太长,实时性差)。

  2. 界说一个数值:

  代 码

  #define TASK_NUM (3) // 这儿界说的使命数为3,表明有三个使命会运用此守时器守时。

  uint16 TaskCount[TASK_NUM] ; // 这儿为三个使命界说三个变量来寄存守时值

  uint8 TaskMark[TASK_NUM]; // 相同对应三个标志位,为0表明时刻没到,为1表明守时时刻到。

  3. 在守时器中止服务函数中增加:

  代 码

  /**************************************************************************************

  * FuncTIonName : TImerInterrupt()

  * Description : 守时中止服务函数

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  void TimerInterrupt(void)

  {

  uint8 i;

  for (i=0; i《TASKS_NUM; i++)

  {

  if (TaskCount[i])

  {

  TaskCount[i]–;

  if (TaskCount[i] == 0)

  {

  TaskMark[i] = 0x01;

  }

  }

  }

  }

  代码解说:守时中止服务函数,在中止中逐一判别,假如守时值为0了,表明没有运用此守时器或此守时器现已完结守时,不着处理。不然守时器减一,知道为零时,相应标志位值1,表明此使命的守时值到了。

  4. 在咱们的运用程序中,在需求的运用守时的当地增加如下代码,下面就以使命1为例:

  代 码

  TaskCount[0] = 20; // 延时20ms

  TaskMark[0] = 0x00; // 发动此使命的守时器

  到此咱们只需求在使命中判别TaskMark[0] 是否为0x01即可。其他使命增加相同,至此一个守时器的复用问题就完结了。用需求的朋友能够试试,作用不错哦。。。。。。。。。。。

  经过上面临1个守时器的复用咱们能够看出,在等候一个守时的到来的一起咱们能够循环判别标志位,一起也能够去履行其他函数。

  循环判别标志位:

  那么咱们能够想想,假如循环判别标志位,是不是就和上面介绍的次序履行程序是相同的呢?一个大循环,仅仅这个延时比一般的for循环准确一些,能够完结准确延时。

  履行其他函数:

  那么假如咱们在一个函数延时的时分去履行其他函数,充分运用CPU时刻,是不是和操作体系有些相似了呢?可是操作体系的使命办理和切换是十分杂乱的。下面咱们就将运用此办法架构一向新的运用程序。

  时刻片轮询法的架构:

  1.规划一个结构体:

  代 码

  // 使命结构

  typedef struct _TASK_COMPONENTS

  {

  uint8 Run; // 程序运转符号:0-不运转,1运转

  uint8 Timer; // 计时器

  uint8 ItvTime; // 使命运转间隔时刻

  void (*TaskHook)(void); // 要运转的使命函数

  } TASK_COMPONENTS; // 使命界说

  这个结构体的规划十分重要,一个用4个参数,注释说的十分详细,这儿不在描绘。

  2. 使命运转标志出来,此函数就相当于中止服务函数,需求在守时器的中止服务函数中调用此函数,这儿独立出来,并于移植和了解。

  代 码

  /**************************************************************************************

  * FunctionName : TaskRemarks()

  * Description : 使命标志处理

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  void TaskRemarks(void)

  {

  uint8 i;

  for (i=0; i《TASKS_MAX; i++) // 逐一使命时刻处理

  {

  if (TaskComps[i].Timer) // 时刻不为0

  {

  TaskComps[i].Timer–; // 减去一个节拍

  if (TaskComps[i].Timer == 0) // 时刻减完了

  {

  TaskComps[i].Timer = TaskComps[i].ItvTime; // 康复计时器值,重新下一次

  TaskComps[i].Run = 1; // 使命能够运转

  }

  }

  }

  }

  咱们仔细比照一下次函数,和上面守时复用的函数是不是相同的呢?

  3. 使命处理:

  代 码

  /**************************************************************************************

  * FunctionName : TaskProcess()

  * Description : 使命处理

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  void TaskProcess(void)

  {

  uint8 i;

  for (i=0; i《TASKS_MAX; i++) // 逐一使命时刻处理

  {

  if (TaskComps[i].Run) // 时刻不为0

  {

  TaskComps[i].TaskHook(); // 运转使命

  TaskComps[i].Run = 0; // 标志清0

  }

  }

  }

  此函数便是判别什么时分该履行那一个使命了,完结使命的办理操作,运用者只需求在main()函数中调用此函数就能够了,并不需求去别离调用和处理使命函数。

  到此,一个时刻片轮询运用程序的架构就建好了,咱们看看是不是十分简略呢?此架构只需求两个函数,一个结构体,为了运用方面 下面将再树立一个枚举型变量。

  下面就说说怎样运用吧,假定咱们有三个使命:时钟显现,按键扫描,和作业状况显现。

  1. 界说一个上面界说的那种结构体变量:

  代 码

  /**************************************************************************************

  * Variable definition

  **************************************************************************************/

  static TASK_COMPONENTS TaskComps[] =

  {

  {0, 60, 60, TaskDisplayClock}, // 显现时钟

  {0, 20, 20, TaskKeySan}, // 按键扫描

  {0, 30, 30, TaskDispStatus}, // 显现作业状况

  // 这儿增加你的使命。。。。

  };

  在界说变量时,咱们现已初始化了值,这些值的初始化,十分重要,跟详细的履行时刻优先级等都有联系,这个需求自己把握。

  ①大约意思是,咱们有三个使命,没1s履行以下时钟显现,由于咱们的时钟最小单位是1s,所以在秒改变后才显现一次就够了。

  ②由于按键在按下时会参数颤动,而咱们知道一般按键的颤动大约是20ms,那么咱们在次序履行的函数中一般是延伸20ms,而这儿 咱们每20ms扫描一次,是十分不错的出来,即达到了消抖的意图,也不会漏掉按键输入。

  ③为了能够显现按键后的其他提示和作业界面,咱们这儿规划每30ms显现一次,假如你觉得反响慢了,你能够让这些值小一点。后边的称号是对应的函数名,你有必要在运用程序中编写这函数称号和这三个相同的使命。

  2. 使命列表:

  代 码

  // 使命清单

  typedef enum _TASK_LIST

  {

  TAST_DISP_CLOCK, // 显现时钟

  TAST_KEY_SAN, // 按键扫描

  TASK_DISP_WS, // 作业状况显现

  // 这儿增加你的使命。。。。

  TASKS_MAX // 总的可供分配的守时使命数目

  } TASK_LIST;

  好好看看,咱们这儿界说这个使命清单的意图其实便是参数TASKS_MAX的值,其他值是没有详细的含义的,仅仅为了明晰的外表使命的联系罢了。

  3. 编写使命函数:

  代 码

  /**************************************************************************************

  * FunctionName : TaskDisplayClock()

  * Description : 显现使命

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  void TaskDisplayClock(void)

  {

  }

  /**************************************************************************************

  * FunctionName : TaskKeySan()

  * Description : 扫描使命

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  void TaskKeySan(void)

  {

  }

  /**************************************************************************************

  * FunctionName : TaskDispStatus()

  * Description : 作业状况显现

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  void TaskDispStatus(void)

  {

  }

  // 这儿增加其他使命。。。。。。。。。

  现在你就能够依据自己的需求编写使命了。

  4. 主函数:

  代 码

  /**************************************************************************************

  * FunctionName : main()

  * Description : 主函数

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  int main(void)

  {

  InitSys(); // 初始化

  while (1)

  {

  TaskProcess(); // 使命处理

  }

  }

  到此咱们的时刻片轮询这个运用程序的架构就完结了,你只需求在咱们提示的当地增加你自己的使命函数就能够了。是不是很简略啊,有没有点操作体系的感觉在里面?

  不防试试把,看看使命之间是不是彼此并不搅扰?并行运转呢?当然重要的是,还需求,留意使命之间进行数据传递时,需求选用全局变量,除此之外还需求留意区分使命以及使命的履行时刻,在编写使命时,尽量让使命赶快履行完结。。。。。。。。

  三、操作体系

  操作体系的自身是一个比较杂乱的东西,使命的办理,履行本事并不需求咱们去了解。可是光是移植都是一件十分困难的是,尽管有人说过“你假如运用过体系,将不会在去运用前后台程序”。可是真实能运用操作体系的人并不多,不只是由于体系的运用自身很杂乱,并且还需%&&&&&%买许可证(ucos也不破例,假如商用的话)。

  这儿自己并不想过多的介绍操作体系自身,由于不是一两句话能过阐了解的,下面列出UCOS下编写应该程序的模型。咱们能够比照一下,这三种方法下的各自的优缺点。

  代 码

  /**************************************************************************************

  * FunctionName : main()

  * Description : 主函数

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  int main(void)

  {

  OSInit(); // 初始化uCOS-II

  OSTaskCreate((void (*) (void *)) TaskStart, // 使命指针

  (void *) 0, // 参数

  (OS_STK *) TaskStartStk[TASK_START_STK_SIZE – 1], // 仓库指针

  (INT8U ) TASK_START_PRIO); // 使命优先级

  OSStart(); // 发动多使命环境

  return (0);

  }

  代 码

  /**************************************************************************************

  * FunctionName : TaskStart()

  * Description : 使命创立,只创立使命,不完结其他作业

  * EntryParameter : None

  * ReturnValue : None

  **************************************************************************************/

  void TaskStart(void* p_arg)

  {

  OS_CPU_SysTickInit(); // Initialize the SysTick.

  #if (OS_TASK_STAT_EN 》 0)

  OSStatInit(); // 这东西能够丈量CPU运用量

  #endif

  OSTaskCreate((void (*) (void *)) TaskLed, // 使命1

  (void *) 0, // 不带参数

  (OS_STK *) TaskLedStk[TASK_LED_STK_SIZE – 1], // 仓库指针

  (INT8U ) TASK_LED_PRIO); // 优先级

  // Here the task of creating your

  while (1)

  {

  OSTimeDlyHMSM(0, 0, 0, 100);

  }

  }

  不难看出,时刻片轮询法优势仍是比较大的,即由次序履行法的长处,也有操作体系的长处。结构明晰,简略,十分简单了解。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/news/xinwen/182776.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部