M8系统开发手记(3)

 

M8系统开发手记(3)

Wayne Huang

2011年01月15日

0  写在前面的话

话说,这篇文章更新的有些晚,主要是感觉这周事情比较多的缘故吧。感觉很多时候,我们只是在忙忙碌碌,却不知道自己人生所追求的到底是什么,我们追求的是否会朽坏?很多时候我们并不会去思考这种问题,也会在这事上感到迷茫,感觉没有这种觉悟,作人就好似机器一样,每天重复着类似的事情,一个倒下了,还会有很多很多的替代。在每天的忙忙碌碌中,我们到底寻求的是什么?是这个我们终将离开的世界上的东西么?在缺失这种觉悟的情况下,人渐渐的失去了他所特有的属性,成为了庞大流水线上的一台机器,而他的荣耀就是他的生产效率~

1  M8系统中的Hello World

在上面一章中,我们已经了解到了M8最小系统的构建。接下来,我们将在上一个系统的基础上,尝试我们第一个小作品-流水灯。对于有编程基础的同学来说,"Hello World"一般都是我们写的第一个程序,而在MCU的世界里,流水灯往往也是第一个入门的经典实现。如同"Hello World"程序一样,流水灯的思想也是实现基本的输出操作。不同之处在于,流水灯的输出是动态的。所实现的效果,就如同霓虹灯的闪烁效果,根据喜好和实际的硬件,可以选择不同的效果。那么,接下来我们就分析一下流水灯的实现吧。

1.1  M8流水灯实现的介绍与分析

我们这里所要实现的流水灯,实际上就是一个个依次闪烁的灯而已。但是,既然这通常作为MCU的入门实现,自然有其道理,一方面他能让你熟悉MCU各IO口的操作,其次也让你熟悉MCU相关的一些功能。这样看来,MCU作为入门,是再好不过的实现了。 话说,MCU的中文意思是"微控制器",那么作为IO口的操作,自然是一个重点,这和我们这种搞软件的CPU-"中央处理器"还是有比较大的不同的,因为CPU强调的是运算性能,而MCU强调的是控制性能。所以,你搞MCU如果连基本的IO口操作都不会,那你真的出门连招呼都不好意思和别人打了。不过,感觉现在这种本应该是"羞耻"的事情,却越来越成为"主流"文化了。比如,某些非私有单位的信息化建设负责人,往往可能连什么是信息化系统都不知道。更有甚者是除了windows就不知道其他操作系统,除了SQL Server,就不知道其他的数据库,感觉在他们的眼里,我们就成了"非主流"。言归正传,因为IO口的操作是MCU的生命,所以MCU的学习自然也要从IO口开始,就好像你写了个没有输出的理财程序,然后别人运行了很多次却没有任何提示,难道你和用户说:程序他自己知道结果的,你不用为你的投资操心?那这个程序不成了"浮云"了?

1.1.1  M8系统的IO口操作介绍

如上所述,IO口的操作是相当重要的,所以我们这里开篇就来看看这个灵魂人物-IO口。我个人觉得,衡量IO口能力的参数主要是IO口的驱动力。对于M8来说,输出输入电流是对等的,每个引脚最大不能超过40mA,但是总电流不能超过300mA。当然,针对每个特定的IO口,还是有一些更细化的限制,但是不论是输入还是输出电流,驱动发光二极管还是可以的。为什么这里我要分开说输入和输出呢?因为在51中,比如AT89S52系列,他的输入电流和输出电流是不对称的,因此在为51选择类似七段数码管的时候,会考虑到共阴公阳的问题。同时,M8与常规51比较大的特点是能够启用内置的上拉电阻。

M8控制IO口的寄存器有三个,分别是方向寄存器"DDRx"、数据寄存器"PORTx"和引脚寄存器"PINx"。"DDRx"和"PORTx"是可读写寄存器,"PINx"是只读寄存器。名字里的"x"是只具体的端口字母。而控制寄存器里的"SFIOR"里的"PUD"位是控制传说中的上拉电阻的。表1就是他们不同组合的结果。"PINx",不论是引脚作为输入还是输出,其值总为引脚上实际的电平值。

 
DDRx PORTx PDU I/O 上拉 说明
0 0 X 输入 无效 高阻
0 1 0 输入 有效 外部引脚拉低时输出电流
0 1 1 输入 无效 高阻
1 0 X 输出 无效 低电平推挽输出,吸收电流
1 1 X 输出 无效 高电平推挽输出,输出电流
 

Table 1: IO相关寄存器定义

话说,我一般用IO口的时候,设计的驱动电流一般为5mA左右。因为虽然说手册的最大值离我使用的电流还有一大截。但是考虑到各个引脚的诸多限制,以及总电流不超过300mA的这种限制,采用平均5mA的的设计,可以避免因为一时的疏忽,比如接了8个40mA的负载,那这样虽然感觉每个引脚都没超过限定,但是总体就超额了。

1.1.2  M8系统的定时器/计数器0操作介绍

在前面我们已经介绍了IO口,接下来我们要介绍实现流水灯所必须的另一个部件-定时器。根据我们刚才的介绍,流水灯是依次的让LED闪烁。但是,即使MCU执行速度多慢,总比我们人的反应速度快,甚至是超越人的反应速度。因此,我们需要一个定时器来让我们每一次的变换可以延迟一段时间,让我们迟钝的视觉能有一个反应的时间。话说,人有时候的确是很迟钝的,所以相对来说由人组合起来的集团的反应有时候会更迟钝,一边已经火烧眉毛了,一边却还在那边考虑考虑、研究研究、商量商量、调查调查,到最后往往结果已经并不重要了,无谓的浪费着人力物力财力。

在M8中有3个定时计数器,我们这次用的是功能最弱的定时计数器0。在M8中,定时器的时钟频率是基于他的系统时钟的,我们可以直接使用系统时钟,也可以使用对系统时钟分频后的时钟信号。当然也能使用M8的T0引脚上的信号作为时钟信号,这个时候他就成了一个计数器。M8定时计数器0的时钟选择,是通过TCCR0进行的,对其中CS02、CS01和CS00的设置不同,就能选择不同的时钟信号源。表2就是时钟信号选择的相关定义。

 
CS02 CS01 CS00 说明
0 0 0 无时钟源 (停止定时计数器0)
0 0 1 CLKI/O (系统时钟)
0 1 0 CLKI/0 ÷8 (来自分频器)
0 1 1 CLKI/O ÷64 (来自分频器)
1 0 0 CLKI/O ÷256 (来自分频器)
1 0 1 CLKI/O ÷1024 (来自分频器)
1 1 0 外部引脚T0的下降沿
1 1 1 外部引脚T0的上升沿
 

Table 2: 定时器时钟设置定义

除了刚才说的TCCR0,M8的还有一个叫作TCNT0的寄存器。这是一个8位寄存器,在没次时钟信号到达的时候,这个寄存器都会自加1,由于这个过程是独立于系统运算总线的,所以这个过程并不会被被系统指令所打断。当这个计数器达到最大值0xFF后,将发生一个溢出事件,并置零TCNT0寄存器。在发生TCNT0溢出的时候,TIFR寄存器中的TOV0位会被置"1"。同时,如果你设置了TIMSK寄存器中的TOIE0位,还会发生一次系统中断,不过中断我们这里还没涉及到,所以就不详细描述了。由于是TCNT0是累加的,所以在设置寄存器的时候,要稍微注意一下。

1.2  M8流水灯实现的电路图

既然名字叫流水灯,自然要有灯才可以。说到这里想起了那个"鱼翅粥",话说有个人看到一家店的招牌叫"鱼翅粥店",于是乎进入店堂点了份"鱼翅粥",但是吃了半天都没吃到传说中的鱼翅,随即叫来小二问其缘由,小二答到:"这本来就没鱼翅啊,不过我们老板名叫鱼翅。"言归正传,我们这里用的"灯"其实就是发光二极管,又名LED,他有二极管的单向导通性。在我的电路图中,我一般用1kΩ电阻作为限流电阻。这样,既能保证最大电流不超过额定值,也能保证LED正常发光。当然,由于LED有方向性,所以安装前最好先判断一下极性。

由于Blog的限制问题,以及考虑到电路图的清晰程度。我电路图的格式是采用的PDF,不能上传到Blog。因此,如果你有需要可以在下方留下你的邮箱地址,我会第一时间发送给你。

1.3  M8流水灯程序的实现

如果用生物来形容计算机的话,硬件就相当于肉体,软件就好像精神。而作为MCU系统的开发者,我们往往既需要铸造肉体,也要成就精神。我们赋予他们肉体作为载体,同时又赋予他们灵魂和生命。当然,我们所做的远没有神创造世界那么伟大。但是,创造的乐趣只有你亲身经历才能体会的。但是MCU系统的软件设计和普通PC的软件设计有些不同,因为他是基于硬件的,有时候硬件结构的不同将会同时影响到软件的实现。所以,一般正常的思路是现确定硬件,再根据硬件写软件。

1.3.1  程序的实现

我们这里是让4个LED按照从低位到高位依次亮起,在达到最高位后全部熄灭,并从头开始。这里,我们采用定时器0的忙等方式实现延迟的效果。下面是我实现的程序。根据程序设定,每个LED大约延迟250ms左右。

#include <avr/io.h>

// 1024 * 0xF4 / 1000000 = 250ms
#define T0CNT 0xFF - 0xF4

int main() {
  unsigned char i = 0;
  //设置D口为输出口
  DDRD = 0xFF; 
  PORTD = 0;
  //设置分频为1024,延迟25ms
  TCNT0 = T0CNT; 
  TCCR0 = _BV(CS02) | _BV(CS00);
  
  do {
    //等待计时器溢出
    while(!(TIFR & _BV(TOV0)));
    //将D口相应的引脚置1
    PORTD = _BV(i);
    
    i += 1;
    if (i == 4) i = 0;
    //重置定时器
    TCNT0 = T0CNT;
    //清除溢出标志
    TIFR |= _BV(TOV0);
  }while(1);
  return 0;
}

1.3.2  程序的编译与下载

众所周知,C语言程序,是要编译才能运行的。所以,接下来我们来介绍一下M8开发相关的套件。在windows下,你可以下载WinAVR这个套件,这是一个基于GCC的编译器,当然还有其他的一些程序。如果你在Linux环境下,也有相应的套件使用,其实WinAVR就是将Linux下相关的套件移植到windows下。

那么,我们使用如下的命令来生成代码,通常M8所下载的代码是以hex格式为主,通过下面的命令我们将得到所需要下载的hex代码。

avr-gcc -mmcu=atmega8 -o code.elf code
avr-objcopy -j .text -j .data -O ihex code.elf code.hex

至于下载的话,我们需要有下载线才能完成。当然,如果你曾经用过C51,那一定会联想到那个编程器。但是M8却不需要那个,因为M8支持ISP即在系统可编程,只要一条下载线,就可以在芯片不离开电路的情况下把程序烧写到MCU上。M8的下载线有很多种,你可以选择最廉价的用并口模拟,也可以自己做一条,或者像我一样用现成的下载线,具体的就要看每个人的具体情况了。我个人用的是一条usbasp下载线,用起来还是很方便的。如果你用的是我所说的WinAVR,那么下载的时候可以用avrdude命令。比如我用的是usbasp下载线,那么下载的命令就是如下所示。

avrdude -p m8 -c usbasp -e -U flash:w:code.hex

至此,程序已经编译了,并下载到了M8上。那么如果一切顺利的话,就能够正常看到结果了。在这里,我想要提一下,不要在一开始就轻易尝试修改fuse,而且尤其不要把reset引脚禁用。因为修改fuse的操作很容易把M8锁定,这样的话将是一件很麻烦的事情,特别是reset引脚,如果被禁用的话,将会造成ISP失效。不过话说回来,有时候人是很奇怪的,越是禁止往往越是有去做的冲动和好奇。所以,如果你好奇的之后变杯具,那可别怪我没提醒你哦。

1.3.3  实现的效果图

话说,之前有人想看一下我的习作。因此,这次在习作上跑了一下流水灯代码。由于条件所限,细节可能看不太清楚,但反正就那个意思吧。不过话说回来,从图片上看,这个效果会不会让人联想到《霹雳游侠》中的那个车上的灯?

 

 

 

M8流水灯效果图

 

 

1.3.4  M8流水灯的实现总结

总体来说,这个流水灯的实现并不是太复杂。时钟电路采用的是内部1MHz的RC振荡电路,外部器件的话主要是LED和电阻之类的。但是,还是有一些新手需要注意的地方,比如LED的极性问题,一般来说从LED外观察封装里的引脚,较窄的一个为负,较宽的为正,电流是从负极流向正极的。还有,在下载线的连接上,要根据下载线的说明弄,如果你使用的是并口模拟,那你还要确认一下你并口的连线是否适合你所用的下载程序,因为不同的下载软件,有不同的并口连接方式。最后,祝你一切都顺利吧。

2  文外音

或许这篇文章所实现的东西,就功能来说并没什么值得兴奋的,但是作为你第一个亲手实践出来的作品,当你看到他按照你的构思"动"起来的时候,那种喜悦感只有亲身经历过才能体会的。也许细心的同学会发现我的实验板上装有8个LED,但我这里却用了4个。其实不论几个,实现起来都是大同小异。选择4个的原因,一则是因为我使用的硬件限制,二则是考虑到如果是从0构建系统,少焊4个LED对于新手要轻松很多。对于电路图的索取,你可以在Blog下方留言索取,只要留下你的邮箱即可,我会在第一时间以附件形式发给你的。

我很欢迎你对我的文章转载,但转载的同时请注明文章的出处。这样做的目的是能让阅读的人能更好更及时的得到回复。另外,由于blog排版的问题,很多地方并不尽如人意。所以,如果你想所要电子版的话,可以在相应的文章后留下你的电子邮箱,我会及时的发送给你。最后,感谢各位长久以来对我的支持。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值