范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

你的单片机裸机程序框架是怎样的?

  前言
  前不久,我有位做测试的朋友转去做开发的工作,面试遇到了一个问题,他没明白,打电话问了我。题目大概就是:
  在单片机裸机开发时,单片机要处理多个任务,此时你的程序框架是怎样的呢?
  这其实是个经典面试问题,我以前面试也被问过。答案一:轮询系统
  代码结构如:int main(void) {     init_something();          while(1)     {         do_something1();         do_something2();         do_something3();     } }
  这种结构大概是我们初学单片机的时候的代码结构。在没有外部事件驱动时,可以较好使用。
  只答出了这种情况,印象分估计会比较低,多半凉凉。答案二:前后台系统
  代码结构如(该代码来自 《RT-Thread内核实现与应用开发实践指南》 ):int flag1 = 0; int flag2 = 0; int flag3 = 0;  int main(void) {  /* 硬件相关初始化 */  HardWareInit();   /* 无限循环 */  for (;;) {    if (flag1) {      /* 处理事情 1 */      DoSomething1();    }     if (flag2) {      /* 处理事情 2 */      DoSomethingg2();    }     if (flag3) {      /* 处理事情 3 */      DoSomethingg3();    }  } }  void ISR1(void) {  /* 置位标志位 */  flag1 = 1;  /* 如果事件处理时间很短,则在中断里面处理  如果事件处理时间比较长,在回到后台处理 */  DoSomething1(); }  void ISR2(void) {  /* 置位标志位 */  flag2 = 2;   /* 如果事件处理时间很短,则在中断里面处理  如果事件处理时间比较长,在回到后台处理 */  DoSomething2(); }  void ISR3(void) {  /* 置位标志位 */  flag3 = 1;  /* 如果事件处理时间很短,则在中断里面处理  如果事件处理时间比较长,在回到后台处理 */  DoSomething3(); }
  此处,中断称为前台,main中的while循环称为后台。相比于循环系统,这种方式相对可以提高外部事件的实时响应能力。
  可以回答出这种情况,印象分大概一半以上,会再细问。答案三:升级版前后台系统(软件定时器法)
  以前,学C语言时,常常听到有人说:指针是C语言的灵魂,没学会指针就是没学会C语言…
  后来,学单片机时,又听到有人说:中断和定时器是单片机的灵魂,没掌握中断与定时器就没学会单片机…
  大佬们都那么说了,那就拿定时器来搞点事情。定时器浑身都是宝,本篇笔记我们来介绍使用定时器(系统滴答定时器或者其它定时器)来做的裸机框架。软件定时器法也有另一种说法:时间片轮询法。
  可以回答出这种情况,这场面试多半稳了。
  下面以STM32单片机为例看看这种方法的使用。站在巨人的肩膀上
  开源项目—— MultiTimer ,项目仓库地址:
  https://github.com/0x1abin/MultiTimer 1、MultiTimer 简介
  MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。2、MultiTimer 的demo#include "multi_timer.h"  struct Timer timer1; struct Timer timer2;  void timer1_callback() {     printf("timer1 timeout!r "); }  void timer2_callback() {     printf("timer2 timeout!r "); }  int main() {     timer_init(&timer1, timer1_callback, 1000, 1000); //1s loop     timer_start(&timer1);          timer_init(&timer2, timer2_callback, 50, 0); //50ms delay     timer_start(&timer2);          while(1) {                  timer_loop();     } }  void HAL_SYSTICK_Callback(void) {     timer_ticks(); //1ms ticks }3、MultiTimer 的移植、剖析
  想要对MultiTimer 进行深入学习可阅读项目源码及如下这篇文章:MultiTimer,一款可无限扩展的软件定时器自己动手,丰衣足食1、代码模板
  准备一个定时器,可以是系统滴答定时器,也可以是TIM定时器。使用这个定时器拓展出多个软件定时器。比如我们系统中有三个任务:LED翻转、温度采集、温度显示。此时我们可以使用一个硬件定时器拓展出3个软件定时器,定义如下宏定义:#define  MAX_TIMER            3                     // 最大定时器个数 EXT volatile unsigned long    g_Timer1[MAX_TIMER];  #define  LedTimer             g_Timer1[0]           // LED翻转定时器 #define  GetTemperatureTimer  g_Timer1[1]           // 温度采集定时器 #define  SendToLcdTimer       g_Timer1[2]           // 温度显示定时器  #define  TIMER1_SEC          (1)                    // 秒 #define  TIMER1_MIN          (TIMER1_SEC*60)        // 分
  在定时器初始化的时候也顺便给三个软件定时器进行初始化操作:/******************************************************************************************************** ** 函数: TIM1_Init, 通用定时器1初始化 **------------------------------------------------------------------------------------------------------ ** 参数: arr:自动重装值 psc:时钟预分频数 ** 说明: 定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft ** 返回: void  ********************************************************************************************************/ void TIM1_Init(uint16_t arr, uint16_t psc) {     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;     NVIC_InitTypeDef NVIC_InitStructure;       RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);           /* 定时器TIM1初始化 */     TIM_TimeBaseStructure.TIM_Period = arr;      TIM_TimeBaseStructure.TIM_Prescaler =psc;      TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;       TIM_TimeBaseStructure.TIM_RepetitionCounter=0;     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);      TIM_ClearFlag(TIM1,TIM_FLAG_Update );          /* 中断使能 */     TIM_ITConfig(TIM1,TIM_IT_Update, ENABLE );        /* 中断优先级NVIC设置 */     NVIC_InitStructure.NVIC_IRQChannel =  TIM1_UP_IRQn;     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;       NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     NVIC_Init(&NVIC_InitStructure);       TIM_Cmd(TIM1, ENABLE);            // 全局定时器初始化     for(int i = 0; i < MAX_TIMER; i++)     {         g_Timer1[i] = 0;        } }
  在定时器中断中对这些软件定时器进行定时值做递减操作:/******************************************************************************************************** ** 函数: TIM1_IRQHandler,  定时器1中断服务程序 **------------------------------------------------------------------------------------------------------ ** 参数: 无 ** 返回: 无     ********************************************************************************************************/ void TIM1_UP_IRQHandler(void)   //TIM1中断 {     uint8 i;          if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)  // 检查TIM1更新中断发生与否     {         //-------------------------------------------------------------------------------         // 各种定时间器计时         for (i = 0; i < MAX_TIMER; i++)                 // 定时时间递减                                if( g_Timer1[i] ) g_Timer1[i]-- ;         TIM_ClearITPendingBit(TIM1, TIM_IT_Update);     //清除TIMx更新中断标志      } }
  我们在各个定时任务中给这些软件定时器赋予定时值,这些定时值递减到0则该任务会被触发执行,比如:void Task_Led(void) {     //----------------------------------------------------------------     // 等待定时时间     if(LedTimer)    return;     LedTimer = 1 * TIMER1_SEC;     //----------------------------------------------------------------     // LED任务主体     LedToggle(); }  void Task_GetTemperature(void) {     //----------------------------------------------------------------     // 等待定时时间     if(GetTemperatureTimer)    return;     GetTemperatureTimer = 2 * TIMER1_SEC;     //----------------------------------------------------------------     // 温度采集任务主体     GetTemperature(); }  void Task_SendToLcd(void) {     //----------------------------------------------------------------     // 等待定时时间     if(SendToLcdTimer)    return;     SendToLcdTimer = 2 * TIMER1_SEC;     //----------------------------------------------------------------     // 温度显示任务主体     LcdDisplay(); }
  如此一来,每过1、2、4秒则分别触发LED翻转任务、温度采集任务、温度显示任务。
  这里配置的最小定时单位为1秒,当然根据实际需要进行配置(定时器初始化),定时器初始化可以放在系统统一初始化函数里:/******************************************************************************************************** ** 函数: SysInit, 系统上电初始化 **------------------------------------------------------------------------------------------------------ ** 参数:  ** 说明:  ** 返回:  ********************************************************************************************************/ void SysInit(void) {     CpuInit();                      // 配置系统信息函数     SysTickInit();                  // 系统滴答定时器初始化函数     UsartInit(115200);              // 串口初始化函数,波特率115200     TIM1_Init(2000-1, 36000-1);     // 定时周期1s     LedInit();                      // Led初始化     TemperatureInit();              // 温度传感器初始化     LcdInit();                      // LCD初始化 }
  此时我们的main函数就可以设计为:int main(void) {     //-----------------------------------------------------------------------------------------------      // 上电初始化函数     SysInit();            //-----------------------------------------------------------------------------------------------      // 主程序     while (1)     {         //-----------------------------------------------------------------------------------------------          // 定时任务         Task_Led();         Task_GetTemperature();           Task_SendToLcd();     } }
  主函数主要是进行系统上电的一些初始化操作,接着是调用各定时任务函数。
  本demo使用定时器1来扩展出3个软件定时器,如果TIM资源不够用,可以换用系统滴答定时器来做。如:
  其中,时间基数可以根据实际需要进行调整。2、实践(代入法)
  套用以上模板,分享我的一个实例:
  需要思考及注意的问题是给每个任务的定时值设置多大合适?这也是一些朋友有疑问的,这只能是自己对自己的任务做考虑,具体情况具体分析,给经验值、调试调整。就如同常常有人问定义多大的数组合适?在使用RTOS时每个线程的线程栈大小设置多大合适、优先级设置为多少合适?这些都是需要我们自己进行思考的。有模板/轮子套用是好事,但有些问题不能单单依靠模板,否则有可能把自己给套进去。
  以上是以STM32为例的,其它单片机也是可以用这样子的思想的,包括51单片机。
  面对文首提到的面试问题,若是可以提到使用软件定时器来处理,进一步能清楚地表达出来,再进一步能写出一些伪代码,那这场面试多半是稳了。
  不仅仅是为了面试,本文的方法是很经典的,小编曾经接触的产品项目中就有用到,很实用,值得学习掌握。方法掌握多了,实际应用的时候想用屠龙刀还是倚天剑根据实际情况选择使用即可。
  以上就是本次的分享,如有错误,欢迎指出,谢谢。

很良心的物超所值的家用MPV库斯途试驾报告这个标题很平,但我想了很久后我觉得不必用过多的辞藻来填充标题,或许对于北京现代库斯途更直白一点更好如果用它的价格来衡量它的配置功能以及动力,物超所值应该是对它最好的褒奖且这更能表达一文探讨工业(安卓)一体机常见触摸方式类别与工作原理基于工业(安卓)一体机应用面不断普及,用户在产品的选择上往往需要综合考量很多因素,以选择到适合自身需求的产品。一般用户比较关注的常规因素,无非是一体机的尺寸触摸方式使用场景内置系统技术解析触控一体机电阻屏的一点触控VS多点触控大比拼对于触控一体机而言,在触摸方式上的选择,是用户场景使用需要考量的重要因素。在工业领域中,像电气室机柜多变频器干扰的使用场景,用户一般选择触控一体机的电容触摸方式。而实际上,在工业自安装小知识嵌入式工业安卓一体机如何做到与设备无缝贴合?随着工业(安卓)一体机在工业场景中的应用不断扩大,越来越多的工业自动化用户逐渐关注触控显示行业的动态。其中,嵌入式工业(安卓)一体机以应用为中心,以计算机技术为基础,并且软硬件可裁雷诺是掌握了流量密码吗?这款雷诺SuiteN4概念车太绝了复古风愈演愈烈。。雷诺像是掌握了流量密码,近期发布的这款雷诺SuiteN4概念车又火了一把,将经典车型与酒店设计元素相结合,这也能被雷诺想到,真的太绝了。看这外观,真的没有女孩子能预售价13。89万起哈弗H6S即将上市据长城汽车官方消息,哈弗H6S将于10月30日正式上市。这款看上去有些嚣张的SUV此前已经开启预售,预售区间为13。89万16。49万元。H6S作为长城柠檬平台咖啡智能首款轿跑SU这个秋季的白色婚礼长安汽车再当证婚人世界是一封情书。或者说,世界本该是一封情书的。一起看花开花落日出黄昏,浪漫的不是事物,而是和你一起。浪漫的事情有很多,除了上面说到的那些,还有长安一年一度的集体婚礼。10月30日,赛那30日上市提前4天爆料它到底有几个同级最强朝饮木兰之坠露兮,夕餐秋菊之落英。这大概是大多数石头森林里的都市人一直憧憬的慢生活之景象。10月23日,在融入了浓郁的川西庭院式风格以及当地文化,又不失现代雅致的世外桃源青城山六善拿什么理由拒绝女神?哈弗M6PLUS柳岩联名版上市7。99万起售10月29日,哈弗M6PLUS柳岩联名版正式上市,此次新车共推出了2款车型,售价区间为7。99万8。99万元。女神联名车型有什么不同,我必须要说女神真香。配置便捷实用动力强劲可靠先未来纯电动货车长啥样?奔驰Sustaineer概念车了解一下都知道纯电动车是趋势,不过短时间内还无法完全占据市场大头,不过车企都在往新能源汽车靠是真的。日前,奔驰官方发布了Sustaineer概念车的官图,该车定位为纯电动货车。能想象吗?货蓝鲸双雄的魅力你一无所知蓝鲸动力一直都是长安汽车有口皆碑的拳头技术,截止2021年9月30日,蓝鲸家族销量已经累计突破75万台,是当之无愧的长安汽车销售主力。蓝鲸动力有那么厉害?咱们现场去见证。10月30
特斯拉员工猝死在生产线上,官方机构介入调查鞭牛士1月21日消息,据IT之家援引外媒消息,美国当地时间周三早上,特斯拉一名员工猝死在加州弗里蒙特工厂的动力总成系统生产线上,相关机构已经介入调查。加州职业安全与健康管理局发言人荣耀新年2022新年礼盒亮相含春联保温杯等IT之家1月23日消息,今日荣耀终端有限公司CEO赵明发了一条微博,表达了对新春的祝福,感谢一路相伴的新老朋友。赵明同时公布了2022年荣耀新年礼盒,为大家送上新春祝福。这款礼盒采荣耀magic3和小米13,该选哪个?小米13好像还没出捂脸,选荣耀吧,Magic影像,卓尔不凡,相机配置方面,荣耀Magic3Pro搭载了一颗5000万像素主摄(11。56英寸大底)一颗6400万像素黑白镜头一颗64有赞被曝大裁员,公司回应称不属实,正开启事业部化调整新京报讯(记者秦胜南)近日有消息称有赞将裁员超1500人。对此,1月23日,有赞方面回应新京报记者称消息不实,正开启事业部化调整。有消息称有赞启动第一轮裁员,涉及超1500人,首先基于区块链的数字藏品研究报告正式发布恒生电子参与联合编写本报讯近日,由可信区块链推进计划主持编写的基于区块链的数字藏品研究报告(以下简称研究报告)正式发布。作为编写单位之一,恒生电子与中国信通院蚂蚁区块链腾讯云京东科技趣链科技等机构共同家庭空调首选,为宝宝房间安装云米SpaceX全域风空调不当家不知道柴米贵,年初的时候搬到了新房子里面,到了夏天的时候就面临着安装空调的问题。今年夏天的空调价格格外坚挺,从6月份到10月份,即使各种活动也没有很好的价格。而有的地方,空调标准化为智慧城市建设铺平赛道近年来城市数字化转型步伐加快,其中标准化工作不仅是智慧城市建设中不可或缺的软性基础设施,更是实现其高效性集约性协同性的重要抓手。专家表示,标准化在智慧城市建设中作用明显,但当前还要柳善人与恶意返乡柳善人的话题在互联网沸沸扬扬了几近半年时间,而主流媒体却隔岸观火,无动于衷,充当吃瓜群众不动声色。恶意返乡的话题一出,却闻风而起,一哄而上,兴师动众。为什么?难道国有资产流失问题无喜报!中国一拖自动驾驶拖拉机获得大赛金奖近日,由中国机械工业联合会组织开展的2021全国机械工业产品质量创新大赛(以下简称大赛)颁奖。中国一拖自动驾驶拖拉机开发及推广应用获大赛金奖,是拖拉机行业唯一的一个金奖。荣获金奖项为什么很多老年人不用微信支付?是因为他们舍不得花钱买流量吗?问题问的很好,但你的设问暴露了你的年少无知,心胸狭窄,为人刻薄的嘴脸。前一个问题为什么很多老年人不用微信支付,你的问题完全可以到这里,等待大家的回答。那么,老年人不用微信支付的原因酷!5G智慧观赛首次亮相十四运会全沉浸体验!赛场精彩,随处掌握!指尖一动,我的视频我做主!9月2日上午9时,中国移动陕西公司智慧观赛技术在正式比赛中首次亮相,这也是5G技术首次成规模应用于国家顶级体育盛事。作为十