发新帖本帖赏金 1.00元(功能说明)我要提问
返回列表
打印
[程序源码]

单片机开发10年,单片机例程从易到难连载分享

[复制链接]
32240|172
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 吴鉴鹰 于 2015-7-1 10:40 编辑

       大家好,我叫吴鉴鹰,100%中国制造,长181cm,净重70kg。采用人工智能,各部分零件齐全,软硬件运转稳定,经二十多年的运行,属质量信得过产品。从2004大学毕业开始进行微处理器的开发,算不上技术精湛,但是一路走来,多多少少有一点自己的见解,所有愿意在21IC这块宝地上分享一点自己的东西,交流一点自己的见闻,也希望21IC的前辈同行能够一块交流。
       回想当年鉴鹰刚刚大学本科毕业不久,进入一家大型国企,保守传统思想——“教会徒弟,饿死师傅”这种陋习的影响,只能靠自己死磕书本,硬啃项目慢慢才取得一点进步。所以后来干脆辞职再次回到电子科技大学读了三年研究生!为了让现在毕业的毕业的年轻人不要重蹈吴鉴鹰当年的覆辙,我也愿意将自己多年积累的一点经验分享给大家,想让更多的年轻人看到,获得一点点帮助就足矣!
     
       每一个项目会提供原理图、源程序还有仿真图。
第一讲:一个电子工程师当小心为重——吴鉴鹰最近因为意志蜘蛛引发的惨重后果

第二讲:【愚人节特别奉献】今天被自己愚弄了一把,一个粗心大意引发的BUG,细节决定成败

第三讲:【实战经验分享】一个单片机程序猿如何正确的编写C语言代码

第四讲:基于单片机的Modbus通讯程序设计(一)

第五讲:基于单片机的Modbus通讯程序设计(二)

第六讲:去年招聘硬件电子工程师的笔试题

第七讲:单片机驱动12864多级菜单设计(一)——原理图

第八讲:单片机驱动12864多级菜单设计(二)——主程序设计



打赏榜单

xwuzi 打赏了 1.00 元 2015-07-01

评分
参与人数 2威望 +31 收起 理由
lianziyexiawa + 1 很给力!
xlhtracy + 30 期待更新~

相关帖子

沙发
吴鉴鹰|  楼主 | 2015-4-7 14:24 | 只看该作者
本帖最后由 吴鉴鹰 于 2015-4-8 23:22 编辑

第一讲:一个电子工程师当小心为重——吴鉴鹰最近因为意志蜘蛛引发的惨重后果


少了一个铁钉,丢了一只马掌;
      丢了一只马掌,翻了一匹战马;
      翻了一匹战马,伤了一位骑士;
      伤了一位骑士,败了一场战役;
      败了一场战役,失了一个国家。

     这首英国民谣起源于历史上一场决定由谁来统治英国的战斗。1885年,在英国的波斯沃斯,国王理查三世的军队准备与里奇蒙德伯爵的军队决一死战。战斗开始的那一天,理查三世让马夫备好自己最喜欢的战马,让铁匠给战马钉好马掌,自己信心百倍地准备出征。不料想,铁匠在钉最后一个马掌时,发现缺了一颗铁钉,而国王马上就要出征作战,已经来不及把最后一只马掌钉牢,于是国王骑着战马出发了。

    两军对垒,理查国王冲锋在前,“冲啊,冲啊”,他高喊着,率领队伍冲向敌阵。敌军已经开始乱了阵脚,国王的队伍眼看就要获胜。这时,突然一只马掌掉了,奔跑的战马猛地跌翻在地,国王也被抛出好远。里奇蒙德伯爵率领的军队看见国王落马,立刻反守为攻,冲上来俘获了理查三世。理查三世事后悲愤不已,“一颗铁钉竟让我失去了整个国家!”


                     图1 电阻焊机控制器实物图


     先来给大家普及一下电阻焊机的知识,请看下面的图中主回路,鉴鹰老给大家普及一下电阻焊机的知识。


                          图2 电阻焊机主回路


电阻焊机是将被焊工件压紧于两电极之间,并施以电流,利用电流流经工件接触面及邻近区域产生的电阻热效应将其加热到熔化或塑性状态,使之形成金属结合的一种方法。
如图2中所示,380V电源a相经过双向控规到焊接变压器的1极,然后经过变压器的初级回到380Vb相。变压器的匝比一般在5070之间,如果变压器的初级电流300A,匝比50,则次级电流最大可以出到15000A,可以迅速将焊件融化,从而结合在一块。
初级电流的大小根据控制器驱动双向控规的KKGG,从而控制变压器的导通角,达到控制热量的作用。

今天下午的时候,一个测试车间的工人,将一台控制器挂在焊机上面测试,如图1中所示,将机器挂上去,刚上电,正在设置参数,听到变压器一直嗡嗡发出巨大的声音,于是慌乱之中,跑到电气柜关掉开关。发现焊极已经焊融化了,好险,要是再慢一点关掉开关,恐怕要将变压器烧掉。

                     电器柜


于是一帮工程师开始检查问题,第一步:检查是不是接线有问题,发现正常;第二步:检查控制器是否异常,拿下来检测,发现也没有问题;第三步:检查控规,发现有一路已经止直通了。然后开始找可控硅直通的原因,经过反复检查,将连接线取下来,发现了一个端倪,大家请看图3,给大家欣赏一个被烧毁的连接线接口


                      图3 被烧毁的连接线接口

在线的三个接口之间,趴着一具尸体,我们拿下来一看,原来是一只被380V电挂了的蜘蛛,可怜的蜘蛛,就这样离开了世间。我们检查了蜘蛛趴的几个引脚,刚好对应了图4中标出的几个点,首先12连在一起,380V之间连到可控硅的G极,会超过G极能承受的电压,从而被击穿。13连连载一块,变压器初级相当于直接将网压接上去。所以热量不受控制器的控制,出现上电满载输出的现象,到最后真像大白,都是一只蜘蛛惹的祸。

            图 4 蜘蛛趴的位置

话说:一个蜘蛛毁掉一个控规,一个控规毁掉一台变压器,一台变压器毁掉一台焊机,一台焊机毁掉一个客户,一个客户丢失毁掉一个企业......
    太可怕了,小心你的蜘蛛吧!

使用特权

评论回复
板凳
吴鉴鹰|  楼主 | 2015-4-7 14:33 | 只看该作者
第二讲:【愚人节特别奉献】今天被自己愚弄了一把,一个粗心大意引发的BUG,细节决定成败

导读

今天吴鉴鹰将程序的一个变量Vol_Device_Data 置为1,但是在主函数里面怎么也进不了if(Vol_Device_Data == 1){ display(); }这个判断语句,你说奇不奇怪,诡异不?貌似很神奇吧。

简化的程序

#include <AT89X52.h>
#define uchar unsigned char//宏定义
#define uint unsigned int    //宏定义
#define KEY P3_7       //定义脚踏关凯

uchar Vol_Device_Data;
uchar disp;      
uchar pic=0,num=0;  
uchar Vp_Fr_Data;      
uchar Pl_Tk_Count=0,Data_Num=0;   

void main()
{   
   uchar Tr_Value;
   uchar Xs_Vk_Dl;      
   uchar Fd_Drt_Pl;
   uchar Vol_Device_Data = 1;   //注意看,我在这里将这个变量置为1了
   uchar Qp_Ml_Data;      
   uchar Pw_Sf_Count=0,Kmv_Num_Ds = 0;   
   while(1)
   {
      Jisuan_Count();
   }
}

void Jisuan_Count()
{     
    uchar Fr_Test_Value;
    uchar X_Voint_Dl;      
    uchar Fs_Doint_Pl;
    unsiged char Vol_Device_Data = 0;   
    uchar Lp_Fr_Data;      
    uchar Pm_Sm_Count=0,Solid_Num=0;   

    if(Vol_Device_Data == 1)
   {
         pic++;
         将断点这子啊这里,可是怎么也进不来,你说奇怪不?
   }
}

原因分析

亲们发现问题了么?为什么就是进不来呢?
我找了很多原因,单步调试,也找不出来在什么地方给Vol_Device_Data置为0了,用变量查看器查看,值是1,但是怎么就进不了中断呢?
怀疑是堆栈溢出了?指针出错了?数据存储区写满了?还是单片机内存分区出错了(定义数组的时候可能会遇到)?经过一系列怀疑后,还是没有找出问题,最后没有办法,将哪些地方用到了这个变量重新查看了一遍,发现原来定义了一个全局变量,还有一个局部变量。请仔细看程序,虽然在主函数的里面初始化的时候给Vol_Device_Data置为1了,但是在子函数void Jisuan_Count()里面将Vol_Device_Data置为0了,所以判断 if(Vol_Device_Data == 1)的条件满足不了,自然也就进不了。在线仿真用变量查看器来看,看到的是全局变量的值,是1,但是在子函数中,其实他的值是0。

简化的程序

#include <AT89X52.h>
#define uchar unsigned char//宏定义
#define uint unsigned int    //宏定义
#define KEY P3_7       //定义脚踏关凯

uchar Vol_Device_Data;  //定义的全局变量
uchar disp;      
uchar pic=0,num=0;  
uchar Vp_Fr_Data;      
uchar Pl_Tk_Count=0,Data_Num=0;   

void main()
{   
   uchar Tr_Value;
   uchar Xs_Vk_Dl;      
   uchar Fd_Drt_Pl;
   uchar Qp_Ml_Data;      
   uchar Pw_Sf_Count=0,Kmv_Num_Ds = 0;  

   Vol_Device_Data = 1;   
   while(1)
   {
      Jisuan_Count();
   }
}

void Jisuan_Count()
{     
    uchar Fr_Test_Value;
    uchar X_Voint_Dl;      
    uchar Fs_Doint_Pl;
unsiged char Vol_Device_Data = 0;   //定义的局部变量
uchar Lp_Fr_Data;      
    uchar Pm_Sm_Count=0,Solid_Num=0;   

    if(Vol_Device_Data == 1)
    {
         pic++;
    }
}

这就是愚人节送给自己的礼物,祝大家愚人节快乐,努力工作,明天又是美好的一天!



使用特权

评论回复
评论
le062 2015-4-13 21:17 回复TA
这是因为lz不用codeblocks 在codeblocks里面,双击命名后,所有相同命名会被高亮,一眼能瞅出来! 
地板
黑夜之狼| | 2015-4-7 15:50 | 只看该作者
哈哈,欢迎欢迎

使用特权

评论回复
5
1060652341| | 2015-4-7 16:04 | 只看该作者
感觉在哪里看过

使用特权

评论回复
6
吴鉴鹰|  楼主 | 2015-4-7 16:42 | 只看该作者

这个最初是在我的微信公众号分享的,然后就是在21IC论坛分享。

使用特权

评论回复
7
战神LEBRON| | 2015-4-7 23:20 | 只看该作者
全局变量和局部变量最好不要取同名吧,容易搞混

使用特权

评论回复
8
吴鉴鹰|  楼主 | 2015-4-7 23:23 | 只看该作者
战神LEBRON 发表于 2015-4-7 23:20
全局变量和局部变量最好不要取同名吧,容易搞混

尽量不要,如果用的话也要在用的地方标明,不然除了问题很难排查的。然后就要一个个找,实际工程项目很大,很多文件,一个文件几千行的代码,很难找的。

使用特权

评论回复
9
yangzi6000| | 2015-4-8 08:12 | 只看该作者
继续。。。。。

使用特权

评论回复
10
maxking| | 2015-4-8 08:24 | 只看该作者
哈哈,经验分享,受益了。谢谢!

使用特权

评论回复
11
吴鉴鹰|  楼主 | 2015-4-8 08:41 | 只看该作者
本帖最后由 吴鉴鹰 于 2015-4-8 08:45 编辑

第三讲:【实战经验分享】一个单片机程序猿如何正确的编写C语言代码



导读
    写单片机程序也是程序,也要遵循写软件的一些基本原则,不是仅仅就是为了完成功能那么简单。我看过的所有的C语言单片机教材很少有注重程序的可读性,程序的实时性,程序结构的,注重编程思路的,注重模块化编程的,考虑程序的实时性,完全是拿着C语言当汇编在用,简直是在糟蹋C语言!
如下的问题,几乎所有的单片机初学者都会犯的问题(不要说网上的和现实中的代码了,连教材上都写的那么随便,学的人能怎么能养成一个良好的编程习惯,如何能成为一个合格的工程师):

1、模块化的编程思想
最重要的一点,没有建立模块化的编程思想。一个程序往往要很多功能协同工作,我们需要把不同的部分分离出来单独创建一个.h和.c的文件,然后在头文件中把可以访问的函数调用出来。
比如我们鉴鹰电子现在需要设计一台示波器,那么我们首先就要进行功能的划分,划分成按键,数据采样,数据处理,显示,数据的存储。
然后在写程序的时候,把不同功能放在不同的.h和.c文件之中,这样管理方便,如果把所有的程序放在一个.C文件里面,程序量庞大,可读性差;如果出了问题十分难查找;不方便程序的移植。

2、变量定义随意性太强
变量到处定义,根本不管变量的生命周期是否合适(请回答:全局变量、局部变量、静态变量、volatile变量有什么区别联系?)
变量定义随意,不结合硬件资源,不看数据存储空间是否够,不管变量定义是否会造成堆栈溢出。

3、变量名称极不规范
变量名称极不规范,根本从名字上看不出来这个变量类型是什么,到底想干什么。因而造成程序的可读性极差。
如定义个个变量uchar XX;uchar XY根本看不出含义和用途。

4、函数定义几乎不用参数
函数定义几乎不用参数,定义所有的函数都是void,如:void  delay(void);如果调用的时候,就用for循环,for(i = 0;i < 1000;i++){delay();}其实调用一个形参,完全可以解决,为何要让程序看起来冗余。

5、不考虑程序的实时性
调用延时函数,动不动来一个delay(1000);delay(10000);这样单片机还能干别的事吗?定义一个标志位,用一个定时器完全可以做,这样程序就不用啥事不用干,空在这里延时了。具体内容可以参考吴鉴用的—编程思路那一讲,杜绝纯延时。

6、语句写的一点不直观
语句写的一点都不直观,根本就是在用汇编。比如:想取一个字长的高字节和低字节,应该定义一个宏或是函数来做,如#define HIBYTE(w) ((BYTE)((DWORD)(w) >> 8)),以后直接用HIBYTE()多直观,难道非得用(BYTE)((DWORD)(w) >> 8)代表你的移位操作的水平很高吗?

7、写程序缺乏总结思考
不思考曾经做过的程序是否还有改进的余地,写程序如果只是为了写而写,不考虑程序有没有更加简单的实现方法,有没有办法节省更多的空间,程序的算法能不能优化,如果这些问题都不思考,不总结,也不借鉴别人的一些好的方法,一辈子也长进不了多少!


使用特权

评论回复
12
吴鉴鹰|  楼主 | 2015-4-8 08:46 | 只看该作者

只要有一个读者,我就会继续分享下去的:lol

使用特权

评论回复
13
ningling_21| | 2015-4-8 09:02 | 只看该作者
吴鉴鹰 发表于 2015-4-8 08:41
第三讲:【实战经验分享】一个单片机程序猿如何正确的编写C语言代码

楼主总结的很不错

关于常量和变量和函数的命名,有个华为C编程规范可以供大家参考

使用特权

评论回复
14
sevenjul| | 2015-4-8 09:30 | 只看该作者
学习了。

使用特权

评论回复
15
战神LEBRON| | 2015-4-8 09:58 | 只看该作者
本帖最后由 战神LEBRON 于 2015-4-8 10:00 编辑

:):):)

使用特权

评论回复
16
战神LEBRON| | 2015-4-8 10:01 | 只看该作者
吴鉴鹰 发表于 2015-4-7 23:23
尽量不要,如果用的话也要在用的地方标明,不然除了问题很难排查的。然后就要一个个找,实际工程项目很大 ...

#define KEY P3_7       //定义脚踏关凯

uchar Vol_Device_Data;
uchar disp;   
-------------------------------------------------------------------
uchar Fd_Drt_Pl;
   uchar Vol_Device_Data = 1;   //注意看,我在这里将这个变量置为1了
   uchar Qp_Ml_Data;   
--------------------------------------------------------------------
uchar Fs_Doint_Pl;
    unsiged char Vol_Device_Data = 0;   
    uchar Lp_Fr_Data;

这个就是因为全局变量和局部变量同名了导致理解出错

使用特权

评论回复
17
justtest111| | 2015-4-8 10:35 | 只看该作者
吴鉴鹰 发表于 2015-4-8 08:41
第三讲:【实战经验分享】一个单片机程序猿如何正确的编写C语言代码

楼主能否推荐一本专门讲单片机编程的书呢,谢谢。

使用特权

评论回复
18
ooppllmm| | 2015-4-8 11:04 | 只看该作者

使用特权

评论回复
19
c126| | 2015-4-8 11:08 | 只看该作者

使用特权

评论回复
20
涛声依旧00| | 2015-4-8 11:11 | 只看该作者
很不错的东西,学习了

使用特权

评论回复
发新帖 本帖赏金 1.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:更多资料可以关注订阅号:单片机精讲吴鉴鹰 随时随地学习在论坛的分享

14

主题

261

帖子

44

粉丝