电子技术论坛

 找回密码
 快速注册

QQ登录

只需一步,快速开始

搜索
下载方法|用单线程|避免多扣帖子规范|求助必读|发帖建议积分策略|勋章介绍|新人必读获取金币|推广论坛|出售帖子基本礼节|致会员信|版规总则
禁涉政治|反对低俗|举报专帖征集相片|留下足迹|推荐精华上传附件|制作分卷|使用网盘禁发qq群|恶意灌水|纯表情帖加入团队|监督机制|安全上网
楼主: jimsboy

讲讲单片机吧,给想了解它的人作为启蒙吧

    [复制链接]
 楼主| 发表于 2016-6-19 23:11:54 | 显示全部楼层
下面开始进入软件的时间。主要就是C语言相关的内容和开发环境的使用了。

前面说过,电脑会将我们写的代码变成bin文件,这个过程中叫编译。代码里边详细地“描述”了每个步骤,单片机只要按照步骤一步一步地做就能达到目的。你写的这些步骤就是代码的内容。但你的那么多步骤里,哪个是第一步呢?根据我们的习惯,我们会认为最上面的一句是第一步。这很符合我们的思维习惯。而我们前面的伪代码也是这样写的。

但是C语言不是这样规定的。C语言规定,你的程序的第一句在main()里边的第一句话。
具体的就是这样写
main()
{
  第一句代码;
  第二句代码;  //注释,这是什么什么什么意思
  ...
  ...
  ...

}
规定了,你必须写一个mian(),然后是一对大括写,指明哪里到哪里是main的范围。然后里边就是一条条的指令了。
前面也说过,程序必须是一个死循环,否则单片机执行完最后一条指令之后就去休息了,然后就不知道它干什么去了。

另外,每一句代码的结束处,必须要有一个英文的分号在后面。这也是规定。
两个靠在一起的斜杠//后面是写注释的,你需要养成写注释的习惯。这个方便你维护它们,同时还有利于减少错误。

 楼主| 发表于 2016-6-21 15:04:28 | 显示全部楼层
在C语言里,有很多个类似于
main()
{
....
....
....
}
这种结构的东西。它有一个名子,叫函数。可能有些人听到函数这个名子头就疼。因为在上学时被这个东西折腾得快发疯了。这里你不要害怕它们,因为它们没那么复杂。
为什么需要有很多这种结构,因为我们的一个程序往往都是比较复杂的,如果你写在一个里边,这原则上也是可以的,但是实际上会很麻烦。主要的麻烦还是调试时很头大。因为你不是神仙,写出来的程序一定会有错误,你必须找出它们哪里出错了。我刚开始写程序的时候也就是一个mian函数,所有的功能都写在里边。但这个习惯慢慢就变了。

一个程序有很多个函数组成,每个函数又由很多句代码组成。我们用实物来打比方吧。
如果你购买了一台电视机,它能给你带来什么好处不需要我多说吧。你可以认为这是一个程序。但是你不可以拿电视机代替洗衣机的功能。所以程序也是这样的,我写好之后,它是什么功能就已经定死了。

如果你拆开电视,你会发现,它里边有一堆器件,电容电阻二极管,再加各种集成块。这些小器件就类似于代码。一个电阻,装在电视机上能修复一台电视,如果装在洗衣机上,则能修复一台洗衣机(前提是你必须装对了)。所以当工作制造出这颗电阻来的时候,它是没有考虑过它会被用在哪里。代码也是这样,它们也是基本通用的。只是说你必须用对了。
而函数是什么 ?我们好像没提到,实际上,函数就相当于电视里的电源 伴音电路 这类名词一样,它们在电路板上并没有明显的界线。它们只是为了利于维修而人为地划分出来的一个个功能模块。但这种划分也是有好处的,那就是说你只需要检查相应的部分,而不是整板地找问题。所以我们的函数就像相于这个的功能模块。

如果你看得晕晕乎乎的,也不要紧,先看实例,等熟悉之后,我们再回过头来看它们,你就容易理解了。

下面开始程序的设计。

我们要实现的功能是测量温度,如果温度高于一个值,我们就控制继电器吸合。否则就断开。功能也是很简单明确。
那么我们画出这个程序的流程。
无标题.png

这个图就是说明了整个流程,因为它的功能简单,所以画起来很容易。如果功能复杂的时候,画这个图往往需要花费大量的工作量。但是如果你把这个工作做好了,那么你会减少很多的麻烦。画完之后,你需要尝试走一下,看看它到达的每个地方是否是你想要的,会不会出现你不想要的路径。同时你还得看一看,这个程序会不会出现一去不复返的问题。

我们看这个图,程序开始后,第一件事是测量温度,测完温度之后需要判断温度是否超过26度,如果超过,则打开继电器。如果没有超过,则断开继电器。不管是打开还是关闭继电器,当做完这件事之后,程序又需要回到测量温度这个地方,进行下一次循环。所以程序一旦上电之后,它就永远在执行这个循环直到断电。所以你写完这些内容之后,你就可以得到一个温控器了。

下面就该写代码了。
不管三七二十一,先写上
main()
{

}
然后再把光标挪到大括号内写内容。注意,括写必须成对出现,为了忘写括号的另一半,我们写的时候就是成对的写,然后往中间塞内容。
下面的事,就是往大括写里写内容了。







发表于 2016-6-24 05:44:23 | 显示全部楼层
深入浅出,讲得不错,谢谢。
发表于 2016-6-29 22:32:04 来自手机 | 显示全部楼层
楼主辛苦了,启蒙太好了。
发表于 2016-7-2 19:13:37 | 显示全部楼层
深入浅出,讲得不错,又学到C语言了,谢谢。
 楼主| 发表于 2016-7-2 23:02:47 | 显示全部楼层
今天我们开始写程序吧。
打开avr studio这个这软件,在source file里边有wenkong.c。双击wenkong.c你就可以在光标处写内容了。
source file中文叫源文件。我们的代码有一个洋气的名子,叫源文件。所以你记住了,源文件就是我们的代码内容。

写什么内容呢?看我上次帖子里框图。我们要把这框图的内容用代码描述出来。

C语言规定了,程序是从main()这个函数开始的。你必须有这么一个函数,名子叫main()。所以我们得写上
main()
{}

然后我们在大括写里写内容。可能大家看到这里边空荡荡的,心里有点发述,我该写什么啊,好困难啊。呵呵。万事开头难,所以最简单的办法是抄人家的。
我先写几句,大家先抄进来。抄进来之后就不会再觉得空空荡荡的了。
main()
{
    //关闭所有中断
    cli();

    //OSCCAL =0xba;
    ResetGlobeVariable(); //初始化全局变量
    cpu_init();  //初始化硬件

    /*再次打开中断
    到这里,硬件已经初始化完毕
    */
    sei();

    //  UART_Send((UCHAR *)("Hello\r\n"),7);


    while(1)//主循环
    { }
}

这一段我也是抄来的。这样好歹看上去像个程序了。你心里或许就会舒服一点了。
大概地说一下,连续两个斜杠//在C语言里表示本行从这里开始后面都是注释。注释的作用是为了让你N久之后看到这里能回想起当时为什么要这样写。对调试有很大的作用。所以为了你的程序容易读懂,尽量地把你的想法写在程序里。如果你的内容太长了,一行写不下怎么办?你可以在注释内容的每一行前面都写上//。但这样写很麻烦。你可以写/*,软件为认为后面的内容全都是注释,所以你必须在注释的结尾处写上*/告诉软件我的注释到这里为止。

这上面的内容几乎是通用的。就像古装片里开打之前总得先比划上那么一段然后再开始出招一样。
下面说一下每一行的内容

cli(); 这行前面已经有注释了,说关闭所有中断。这种带括号的都是函数。如果它出现别的函数里边,那就是调用的意思。如果不在别的函数里,那么就是定义的作用。如果你读不懂这句,先记住有这么个事情,后面再来理解。我们后面要讲述它的。

为什么要关闭中断呢?前面说过,中断可以让程序临时跳到其他地方,在那里把事情做完了再回来。因为这时单片机刚上电,它里边很多状态都不确定,所以先关闭中断,以免程序跳到我们不知道的地方去。

下一句,
//OSCCAL =0xba;
看到前面的//吗?它现在是注释。但它说的什么你也看不懂。其实它该是一句代码,我们可以在芯片资料时找到OSCAL,这是一个微调振荡频率的,通过设定不同的值可以微调内部RC振荡器的频率。因为芯片出厂时,虽然它标称8M,但实际上可能会高一点或低一点,而且还会随温度的变化而变化。如果你对频率精度有要求,则需要对它进行微调(校准)。因为我们这个对时间精度基本没有要求,所以我们不需要这一句代码。你完全可以删掉。但是我说过,这是通用的,为了让你在需要精度时知道在哪里校正,所以我们这里把它变成注释,如果你需要用到的时候,只要去掉前面的//就可以了。同样,我们对于一些不需要用的代码,也可以用同样的办法让它们变成注释。

再下面两个函数,后面都有注释,是用来初始化全局变量和硬件的。可能有人不知道什么是初始化。因为单片机刚上电时,里边很多状态都是不确定的,初始化就是把我们要用到的内容先设定一个值,这样我们就知道它的值是什么了。

再后面有sei();这是打开中断,如果你的程序用到了中断,那么有必须使用这句话来允许中断执行相应的程序。如果你不需要使用中断,那么可以注释掉。我们等后面看看,如果需要使用中断,则留着这一句,否则用//注释掉。

再下面是while(1)
{}
while翻译成中文是“当...时”,这个句在C语言中是有含义的,它的意思是当()里的内容不为0,就会执行一遍括号里的内容。执行完一遍之后再看看()里是否为0,如果不为0则再执行一遍,如果为0则执行{}下面的内容。我们这里给它写了一个1,这就意味着()里永远不会为0,所以它就会一遍又一遍地执行{}里的内容,也就是在里边死循环。这个死循环是单片机程序必须的。否则CPU执行完这里的内容之后就会继续向下,当它执行完main里的最后一句的时候,它就去放羊了。它在干什么你永远也无法知道了。所以我们必须把它困死在main()里边。
因为我们的程序永远也不会离开while(1)后面的大括号了,所以写在这个大括号下面的代码永远也没有机会被执行,所以在}之后也不会有任何代码。

 楼主| 发表于 2016-7-2 23:35:55 | 显示全部楼层
到现在,我们已经搭好了框架了。现在我们得向里边填内容了。不需要的东西要删掉
里边有一句 ResetGlobeVariable(); //初始化全局变量
全局变量?什么叫变量?还有全局之说?先解释一下吧。比如我们要对某个管脚上的脉冲个数进行计数。很显然,计数的结果你总不能抓在手上啊。必须放在单片机里的内存中。C语言要求你必须给它起个名子。名子的内容任意,但必须是字母或者数字或_,不允许用中文(明显的地域歧视啊~~),另外名子不能以数字开头。起好名子之后,它里边的值是多少我们是不知道的。所以我们必须给综一个设定一个,像这里计数,我们显然是从0开始,所以我们必须先令它等于0.这就叫初始化。
这个名子就叫变量。至于全局变量,就是哪个函数都可以用的。所以它必须写在所有函数的外边,一般我们习惯写在所有函数的上面。那不全局的,就是写在函数里边的,写在哪个函数里边,就只有哪个函数可以用它。

现在我们也不知道用不用得上,先把它注释掉,等要用到的时候再把它恢复回来。如果你不用//直接删掉效果一样,但是想恢复回来就得手工输入了,没有打两个/来得方便 。

初始化硬件,那是必须的,因为我们要指定哪个管脚是输入,哪个管脚是输出啊。初始化的内容写在哪里呢?写在mian的外边,前面说了,写在外边是定义。所以我们必须在main(){}的外边重起一行写cpu_init(){}。这里{}里就是具体怎么初始化的代码了。

程序从main开始,执行到cli();它就去找cli()这个函数,这个函数是编译器提供的,所以你不需要写它的具体内容。
然后ResetGlobeVariable();但它被我们刚才注释掉了,当作不存在。
再下来cpu_init();  //初始化硬件
这时编译器就会去找cpu_init(){}这一块内容,如果找到了,则会把这里边的内容执行完毕再执行下一条代码,如果没找到,编译就会出错,你就无法生成bin文件,连文件都没有,就更谈不上执行了。
执行完cpu_init()后面{}里的内容,程序会回到main里继续下一句 sei(); 这个也是编译器提供的,也不需要你写。执行完这一句之后就会执行while,
while后面是1,不为0,所以它就把括号里的内容执行一遍(目前我们括号里为空的。但实际上我们要写内容在里边的),执行完一遍之后,它又会回到while这里,括号后面还是1,它又把大括号里的内容执行一遍。这里边永远为1,所以它就一遍又一遍地执行大括号里的内容。

所以我们只要在这个大括号里写上以下的内容(当然,要把这些文字写成代码)
读取PA0脚上的电压(温敏电阻上的电压)
根据电压换算出温度
如果温度高于预定值,则PB0(控制继电器的)输出高电平。否则就输出低电平。

这几些话写在了大括号里,它会被一遍一遍地不停执行。所以温度一旦超过设定值就会引起继电器吸合。直到温度低于预定值。
如果没有这个死循环。程序也会读一次电压,换算出温度,如果高于就吸合,低于就断开,然后程序一去不复返,你后面温度再怎么变它也不会理睬你了。所以必须制造一个死循环给它。



发表于 2016-7-5 11:31:28 来自手机 | 显示全部楼层
通俗易懂,写的真好,虽然第一次接触这个东西,但还是学懂了很多很
发表于 2016-7-25 22:43:15 | 显示全部楼层
感谢你的无私奉献!
发表于 2016-7-27 08:15:39 | 显示全部楼层
深入浅出,讲得不错,又学到C语言了,谢谢。
您需要登录后才可以回帖 登录 | 快速注册

本版积分规则

手机版|家电维修技术论坛 ( 鄂ICP备09003585号-2 )

GMT+8, 2024-11-21 23:06 , Processed in 0.058098 second(s), 4 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

CopyRight © 电子技术论坛
电子邮箱:8794149@qq.com | 联系 QQ:3081868839 | 官方网址:www.dzdu.com

Qiji. All Rights Reserved


服务条款 | 站长声明

Wuhan Qiji Technology Co., Ltd.武汉奇迹科技有限公司版权所有


鄂ICP备09003585号-2鄂公网安备42010602000420号

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