跟涛哥一起学嵌入式 第05集:一道程序改错题,测出你的嵌入式功底

大家好,欢迎阅读《跟涛哥一起学嵌入式》第05集,我们今天讨论一下中断的基本概念。

中断,是嵌入式开发中经常使用的一个功能,也是嵌入式工程师必须要掌握的一个概念:CPU和外设通信时,一般都采用中断的形式异步通信,可以大大提高CPU资源的利用率。而你对中断的理解,到底有多少呢?不要急,一道程序改错题,就可以测出你的嵌入式系统功底。

比如,我们在嵌入式ARM裸机平台上,要实现一个MP3播放器,要求实现如下功能:当按键按下时,可以播放、暂停、播放下一首、上一首。为此,我们设计一个按键中断服务程序,当有按键发生时,我们去读取按键的值,然后再根据按键值去执行不同的操作,设计的按键中断函数如下:

int keyboard_isr(int irq_num)
{
    char *buf =(char *)malloc(512);
    int key_value = 0,

    key_value = keyboard_scan();
    if(key_value == 1)
    {
        mp3_decode(buf,"xx.mp3");
        sleep(10);
        mp3_play(buf);//play
    }
    else if(key_value == 2)
        mp3_pause(buf);//pause
    else if(key_value == 3)
        mp3_next(buf);//next song
    else if(key_value == 4)
        mp3_prev(buf);//prev song
    else
    {
        printf("UND key !");
        return -1;
    }
    return 0;
} 

这个中断函数差不多有8处错误或设计不合理的地方,先不用急着往下翻,你可以自己先思考下,看自己能找出来几处。

(此处应有掌声,暂停2分钟)...

好,我们接下来继续分析,看看这个中断函数到底有哪些错误。

错误1:中断关键字irq

中断函数没有使用关键字标记。C标准中没有定义中断函数,对于普通的函数调用,编译器会帮我们自动实现函数的调用栈及出栈入栈管理,而对于中断函数,我们知道,中断是可以随时发生的,编译器无法确定你中断函数在哪里发生,所以就无法帮你实现调用栈。那怎么办?难道我们程序员自己实现?没关系,各大编译器厂商一般会通过增加一些关键字,来帮助程序员实现中断的现场保护代码。因此,我们可以使用interrupt或irq关键字声明即可

__irq int keyboard_isr(int irq_num);

错误2:malloc/free

对于MP3解码的数据,我们使用malloc函数申请了一个动态堆内存来存放,但是函数退出后没有及时释放,造成了内存泄露。关于函数的调用栈、调用传参过程、程序的内存分配,如果不是很明白,可以参考《C语言嵌入式Linux高级编程》第4期:堆栈管理。

错误3:C标准库

嵌入式裸机开发中,一般很少使用C标准库的。很多嵌入式编译厂商、IDE开发商并没有完全实现C标准库,或者只是实现了一部分。所以在一般在嵌入式系统中,我们可以使用一个全局数组来代替malloc申请的动态内存。

错误4:中断返回值

中断函数由于没有独立的函数栈,是不能有返回值的。想一想:中断函数在哪里被调用、何时被调用,我们全都不知道,中断函数的返回值应该传给谁?它会破坏当前被中断函数的函数栈。

错误5:中断传参

同上,中断函数也是不能传参的,传给谁?谁调用了它?都是未知的。如果你给中断函数传参,也会破坏当前被中断函数的函数栈。所以中断函数正确的声明形式应该为:

__irq void keyboard_isr(void);

错误6:延时

避免耗时、延时、可重入函数,比如sleep、printf等。

错误7:短小精悍、快速反应

中断函数要求快速响应,短小精悍。要速战速决,快速撤离中断现场,然后等待下一次中断。如果你在中断程序中,要做大量工作:播放、解码、延时,十分不合理。这些耗时的工作应该放到中断外去做。如Linux中的中断处理,就放到了中断下半部去做。

好了,以上都是我们在编写中断函数时必须要掌握的一些基础知识和技能,接下来就卖个关子:想一想,上面这个函数的设计,还有什么不合理之处?思考的越多,你就得到的越多。老司机要下车了,先带你到这里,剩下的就靠你了~

本文根据《C语言嵌入式Linux高级编程》视频教程改编。《跟涛哥一起学嵌入式》,会持续跟大家分享嵌入式相关技术、学习方法、学习路线、求职面试等,有兴趣可加入嵌入式技术交流群:475504428,或微信公众号:宅学部落(armlinuxfun)。如果想系统学习嵌入式C语言进阶,可关注51CTO学院,我的个人主页:http://edu.51cto.com/lecturer/10824150.html

原文地址:http://blog.51cto.com/zhaixue/2136906

时间: 2024-08-11 20:57:44

跟涛哥一起学嵌入式 第05集:一道程序改错题,测出你的嵌入式功底的相关文章

跟涛哥一起学嵌入式 -- 第01集:say you say me

大家好,此时此刻,2018俄罗斯世界杯已暂告一段落,16强已经产生,卫冕冠军德国队提早回家,阿根廷起死回生,C罗一个30多高龄的年纪,还在坚持健身,一身腱子肉,在球场上挥洒青春,演绎着帽子戏法,给观众带来一场场精彩的视觉盛宴.世界杯的最大魅力之处也许就在于其不确定性. 在这足球之夜,<跟涛哥一起学嵌入式>专栏也开始了,关于嵌入式学习.路线.就业.面试相关的问题,我会坚持一点一点地写下去.C罗,一个85后,跟我差不多的年龄,还坚持健身,还这么拼命,我们还有什么理由给自己的不坚持开脱呢? 为什么写

跟涛哥一起学嵌入式 第02集:工作还是考研?

大家好,我是涛哥,今天我们聊聊第一个话题:工作还是考研. 工作与考研,是每个大三大四学生都要去纠结一下的问题,也是一个很难做抉择的话题.对自己的现状不满意,蹉跎了岁月,感觉自己学得不够多,没学到什么技能:对自己能否找到工作.自己能否胜任未来的工作没有自信:高考失利,进了一所非211/985大学,在大学浑浑噩噩已经混了一半时间了,每天吃鸡推搭.小玛利亚,不想再这样颓废下去,想通过考研改变自己.这些都会滋生你考研的念头,希望通过研究生能改变自己.提高自己. 不仅在校学生.工作1~2年后的职场新兵,也

跟涛哥一起学嵌入式 第03集:嵌入式要从u-boot移植学起?

大家好,我是涛哥,欢迎阅读<跟涛哥一起学嵌入式>第3集.俄罗斯仲夏夜,世界杯依旧如火如萘.球场上,夕阳下,梅西没落的身影.C罗的黯淡离场,并没有打击大家太多的热情.战火依旧,老兵不死,梅罗时代是否快要终结?然而新一代巨星冉冉升起,风起云涌.在看球的同时,学习充电也不能落下,今天我们聊聊第3个话题:学习嵌入式,一定要从u-boot移植学起吗? 嵌入式真要从U-boot移植学起? 故事缘起嵌入式技术群(475504428)一位嵌入式学员遇到的问题:这位学员想在他的开发板上移植最新版本的U-boot

跟涛哥一起学嵌入式 第04集:一道面试题,测出你的C语言功底

大家好,我是涛哥,欢迎阅读<跟涛哥一起学嵌入式>第04集,今天聊聊面试题. 嵌入式C语言面试题中,大家经常会看到宏定义的考题.比如:定义一个宏,求两个数中的最大数.别小看这个考题,虽然简单,但是它却陷阱不断,时刻在考验着你的C语言编程功底!根据你的答案,面试官对你的印象肯定不一样.那下面我们看看各个不同版本的答案吧. 合格 对于学过C语言的同学,写出这个宏基本上不是什么难事,使用条件运算符就能完成: #define MAX(x,y) x > y ? x : y 这是最基本的C语言语法,如

跟涛哥一起学嵌入式第11集:一个实现锁机制非常有意思的宏

QQ群(宅学部落)有位学员问了一个很奇怪的宏,觉得很有意思,特拿来分享,它的定义如下: 我们知道,宏定义其实就是为了方便,给一串代码字符串定义一个别名.有时候字符串过于复杂,我们可以分多行书写,然后使用逻辑连接符"\"连接起来,表示一个完整的字符串.但是分析上面的宏定义,你会发现它分别定义了2个宏,但是呢,又使用了一对大括号括起来,很有欺骗性:看起来很像语句表达式,但是呢,有没有小括号括起来,是不是很奇怪?调用的时候,使用方法更是奇怪,如果我们单独使用AA()或BB()调用,你会发现编

【涛哥带你看DC】江西测绘双活数据中心

2014年3月10日,江西省地理信息公共服务平台(政务版)正式上线运行.在半年之后的10月15日,涛哥来到江西省测绘地理信息局仔细了解支持此公共服务平台的后台数据中心的情况. 江西省测绘地理信息局今年8月才搬的家,新办公大楼位于南昌一处偏僻的地方(周围都在建商品房,估计很快也会热闹起来).大楼很气派,但看了内部就知道,很多地方还没有最后完工.新机房也建在这幢大楼里,与旧办公楼的机房构成了相距10多公里的"双活数据中心". 据江西省测绘地理信息局网络中心的负责人介绍,当初在数据中心的建设

涛哥的Python脚本工具箱之批量替换目录所有指定扩展名的文件中的指定字符串

今天发布刚完成的涛哥的Python脚本工具箱之批量替换目录所有指定扩展名的文件中的指定字符串,命令行参数处理改用目前比较好用的argparse库,Python代码如下: #!/usr/bin/python2.7 # -*- encoding: UTF-8 -*- # Copyright 2014 [email protected] """replace old string with new string from all files in path 批量替换目录所有指定扩展

学习用CMake来编写Qt程序

最近开始学习CMake,因为项目需求需要用到Qt,自带的qmake会出现许多问题(比如文件修改之后有时候qmake不会侦测到不会重新编译,需要手动去编译等),于是开始尝试使用CMake来编写Qt程序,顺便学习一下怎么用CMake来使用find_package,也算给自己一次学习的机会. 切入正题,CMake对于一些有名的库都有自带文件夹中Modules里.cmake文件查询的支持,比如你需要编写Qt程序,你就可以去cmake_dir/Moudles/查找 FindQt4.cmake这个文件,里面

Zookeeper实战之嵌入式执行Zookeeper集群模式

非常多使用Zookeeper的情景是须要我们嵌入Zookeeper作为自己的分布式应用系统的一部分来提供分布式服务.此时我们须要通过程序的方式来启动Zookeeper.此时能够通过Zookeeper API的ZooKeeperServerMain类来启动Zookeeper服务. 以下是一个集群模式下启动Zookeeper服务的样例 这里假定我们执行Zookeeper集群的三台机器名分别为fanbinx1,fanbinx2,fanbinx3  首先是zoo.cfg配置文件 tickTime=200